#![cfg(feature = "go-parser")]
#![allow(deprecated)]
mod common;
use common::decode_u32_words;
use common::go::{pack_source as pack, run, tokenize, zeroed_u32_words as zeroed};
use vyre::ir::Expr;
use vyre_libs::parsing::go::lex::{TOK_ARROW, TOK_ASSIGN, TOK_IDENTIFIER, TOK_NEWLINE, TOK_STRING};
use vyre_libs::parsing::go::parse::ast_ops::{
go_extract_channel_receives, go_extract_channel_sends,
};
use vyre_libs::parsing::go::parse::structure::{
go_extract_packages_and_imports, GO_SPAN_RECORD_WORDS,
};
#[derive(Debug, Clone, PartialEq, Eq)]
struct Token {
kind: u32,
text: String,
}
fn tokens(source: &str) -> Vec<Token> {
let dense = tokenize(source);
let kinds = decode_u32_words(&dense.types);
let starts = decode_u32_words(&dense.starts);
let lens = decode_u32_words(&dense.lens);
(0..dense.count)
.map(|i| {
let start = starts[i] as usize;
let end = (start + lens[i] as usize).min(source.len());
Token {
kind: kinds[i],
text: source[start..end].to_string(),
}
})
.collect()
}
fn tokens_without_newlines(source: &str) -> Vec<Token> {
tokens(source)
.into_iter()
.filter(|token| token.kind != TOK_NEWLINE)
.collect()
}
fn dense_arrays(source: &str) -> (Vec<u8>, Vec<u8>, Vec<u8>, usize) {
let dense = tokenize(source);
(dense.types, dense.starts, dense.lens, dense.count)
}
fn send_count(source: &str) -> u32 {
let (kinds, starts, lens, count) = dense_arrays(source);
let program = go_extract_channel_sends(
"tok_types",
"tok_starts",
"tok_lens",
"haystack",
Expr::u32(count as u32),
"out_ops",
"out_counts",
);
let out = run(
&program,
vec![
kinds,
starts,
lens,
pack(source),
zeroed(count.saturating_mul(GO_SPAN_RECORD_WORDS as usize).max(1)),
zeroed(1),
],
);
decode_u32_words(&out[1])[0] / GO_SPAN_RECORD_WORDS
}
fn receive_count(source: &str) -> u32 {
let (kinds, starts, lens, count) = dense_arrays(source);
let program = go_extract_channel_receives(
"tok_types",
"tok_starts",
"tok_lens",
"haystack",
Expr::u32(count as u32),
"out_ops",
"out_counts",
);
let out = run(
&program,
vec![
kinds,
starts,
lens,
pack(source),
zeroed(count.saturating_mul(GO_SPAN_RECORD_WORDS as usize).max(1)),
zeroed(1),
],
);
decode_u32_words(&out[1])[0] / GO_SPAN_RECORD_WORDS
}
fn import_count(source: &str) -> u32 {
let (kinds, starts, lens, count) = dense_arrays(source);
let program = go_extract_packages_and_imports(
"tok_types",
"tok_starts",
"tok_lens",
"haystack",
Expr::u32(count as u32),
"out_packages",
"out_package_counts",
"out_imports",
"out_import_counts",
);
let out = run(
&program,
vec![
kinds,
starts,
lens,
pack(source),
zeroed(count.saturating_mul(GO_SPAN_RECORD_WORDS as usize).max(1)),
zeroed(1),
zeroed(count.saturating_mul(GO_SPAN_RECORD_WORDS as usize).max(1)),
zeroed(1),
],
);
decode_u32_words(&out[3])[0] / GO_SPAN_RECORD_WORDS
}
#[test]
fn one_string_literal_produces_exactly_one_string_token() {
let strings: Vec<Token> = tokens_without_newlines("package p\nvar s = \"fmt\"\n")
.into_iter()
.filter(|token| token.kind == TOK_STRING)
.collect();
assert_eq!(
strings,
vec![Token {
kind: TOK_STRING,
text: "\"fmt\"".to_string()
}]
);
}
#[test]
fn two_string_literals_produce_exactly_two_string_tokens() {
let strings: Vec<String> = tokens_without_newlines("package p\nvar a = \"x\"\nvar b = \"y\"\n")
.into_iter()
.filter(|token| token.kind == TOK_STRING)
.map(|token| token.text)
.collect();
assert_eq!(strings, vec!["\"x\"", "\"y\""]);
}
#[test]
fn an_empty_string_literal_is_a_single_token() {
let strings: Vec<String> = tokens_without_newlines("package p\nvar s = \"\"\n")
.into_iter()
.filter(|token| token.kind == TOK_STRING)
.map(|token| token.text)
.collect();
assert_eq!(strings, vec!["\"\""]);
}
#[test]
fn the_contents_of_a_string_literal_are_not_lexed_as_code() {
let texts: Vec<String> = tokens_without_newlines("package p\nvar s = \"x\"\n")
.into_iter()
.map(|token| token.text)
.collect();
assert_eq!(texts, vec!["package", "p", "var", "s", "=", "\"x\""]);
}
#[test]
fn punctuation_inside_a_string_literal_is_not_tokenized() {
let texts: Vec<String> = tokens_without_newlines("package p\nvar s = \"a.b(c)\"\n")
.into_iter()
.map(|token| token.text)
.collect();
assert_eq!(texts, vec!["package", "p", "var", "s", "=", "\"a.b(c)\""]);
}
#[test]
fn an_escaped_quote_does_not_terminate_the_literal() {
let strings: Vec<String> = tokens_without_newlines("package p\nvar s = \"say \\\"hi\\\"\"\n")
.into_iter()
.filter(|token| token.kind == TOK_STRING)
.map(|token| token.text)
.collect();
assert_eq!(strings, vec!["\"say \\\"hi\\\"\""]);
}
#[test]
fn a_doubled_backslash_does_not_escape_the_closing_quote() {
let texts: Vec<String> = tokens_without_newlines("package p\nvar s = \"a\\\\\"\nvar t = 1\n")
.into_iter()
.map(|token| token.text)
.collect();
assert_eq!(
texts,
vec![
"package",
"p",
"var",
"s",
"=",
"\"a\\\\\"",
"var",
"t",
"="
]
);
}
#[test]
fn code_after_an_escaped_quote_is_still_lexed() {
let texts: Vec<String> = tokens_without_newlines("package p\nvar s = \"\\\"\"\nvar t = 1\n")
.into_iter()
.map(|token| token.text)
.collect();
assert!(
texts.contains(&"t".to_string()),
"the declaration after the literal must survive: {texts:?}"
);
}
#[test]
fn a_slashed_import_path_is_one_import_and_one_token() {
let source = "package p\n\nimport (\n\t\"net/http\"\n)\n";
assert_eq!(import_count(source), 1);
let strings: Vec<String> = tokens_without_newlines(source)
.into_iter()
.filter(|token| token.kind == TOK_STRING)
.map(|token| token.text)
.collect();
assert_eq!(strings, vec!["\"net/http\""]);
}
#[test]
fn a_line_break_emits_a_terminator_token() {
let kinds: Vec<u32> = tokens("package p\n").into_iter().map(|t| t.kind).collect();
assert!(
kinds.contains(&TOK_NEWLINE),
"the newline after the package clause must be tokenized: {kinds:?}"
);
}
#[test]
fn consecutive_receive_statements_are_two_receives_and_no_send() {
let source = "package p\nfunc f() {\n<-a\n<-b\n}\n";
assert_eq!(receive_count(source), 2, "both receives must be counted");
assert_eq!(send_count(source), 0, "neither line is a send");
}
#[test]
fn a_send_then_a_receive_is_one_of_each() {
let source = "package p\nfunc f() {\nout <- 1\n<-in\n}\n";
assert_eq!(send_count(source), 1);
assert_eq!(receive_count(source), 1);
}
#[test]
fn a_receive_only_channel_parameter_is_not_a_send() {
let source = "package p\nfunc f(in <-chan int) {\n}\n";
assert_eq!(send_count(source), 0);
assert_eq!(receive_count(source), 0);
}
#[test]
fn a_send_only_channel_parameter_is_not_an_operation() {
let source = "package p\nfunc f(out chan<- int) {\n}\n";
assert_eq!(send_count(source), 0);
assert_eq!(receive_count(source), 0);
}
#[test]
fn a_signature_with_both_channel_directions_reports_no_operations() {
let source = "package p\ntype S interface {\nExecute(<-chan int, chan<- int)\n}\n";
assert_eq!(send_count(source), 0);
assert_eq!(receive_count(source), 0);
}
#[test]
fn a_send_on_a_directional_channel_parameter_is_counted() {
let source = "package p\nfunc f(out chan<- int) {\nout <- 1\n}\n";
assert_eq!(send_count(source), 1);
assert_eq!(receive_count(source), 0);
}
#[test]
fn a_receive_from_a_directional_channel_parameter_is_counted() {
let source = "package p\nfunc f(in <-chan int) {\n<-in\n}\n";
assert_eq!(send_count(source), 0);
assert_eq!(receive_count(source), 1);
}
#[test]
fn a_returned_receive_is_a_receive() {
let source = "package p\nfunc f() int {\nreturn <-ch\n}\n";
assert_eq!(receive_count(source), 1);
assert_eq!(send_count(source), 0);
}
#[test]
fn a_short_declaration_from_a_channel_is_a_receive() {
let source = "package p\nfunc f() {\nv := <-ch\n}\n";
assert_eq!(receive_count(source), 1);
assert_eq!(send_count(source), 0);
}
#[test]
fn forwarding_a_received_value_is_one_send_and_one_receive() {
let source = "package p\nfunc f() {\nout <- <-in\n}\n";
assert_eq!(send_count(source), 1);
assert_eq!(receive_count(source), 1);
}
#[test]
fn an_ungrouped_import_counts_once() {
assert_eq!(import_count("package p\n\nimport \"time\"\n"), 1);
}
#[test]
fn a_grouped_import_with_one_spec_counts_once() {
assert_eq!(import_count("package p\n\nimport (\n\t\"fmt\"\n)\n"), 1);
}
#[test]
fn a_grouped_import_counts_each_spec_once() {
assert_eq!(
import_count("package p\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n)\n"),
3
);
}
#[test]
fn string_literals_elsewhere_in_the_file_are_not_imports() {
let source =
"package p\n\nimport (\n\t\"fmt\"\n)\n\nfunc f() {\n\tlog(\"a\")\n\tlog(\"b\")\n}\n";
assert_eq!(import_count(source), 1);
}
#[test]
fn the_token_stream_matches_the_source_order_exactly() {
let actual: Vec<(u32, String)> = tokens_without_newlines("package p\nvar s = \"x\"\n")
.into_iter()
.map(|token| (token.kind, token.text))
.collect();
assert_eq!(
actual,
vec![
(TOK_IDENTIFIER, "package".to_string()),
(TOK_IDENTIFIER, "p".to_string()),
(TOK_IDENTIFIER, "var".to_string()),
(TOK_IDENTIFIER, "s".to_string()),
(TOK_ASSIGN, "=".to_string()),
(TOK_STRING, "\"x\"".to_string()),
]
);
}
#[test]
fn a_channel_arrow_is_a_single_token() {
let arrows: Vec<String> = tokens_without_newlines("package p\nfunc f() {\nout <- 1\n}\n")
.into_iter()
.filter(|token| token.kind == TOK_ARROW)
.map(|token| token.text)
.collect();
assert_eq!(arrows, vec!["<-"]);
}