use std::sync::Arc;
use arcstr::ArcStr;
use crate::{
project::{file::FileContents, PkgHandle},
syntax::{
buildctx::BuildCtx, cst::tree::Cst, lexer::bsv::BsvLexer, location::ROOT_ORIGIN, streams::TextCharStream
},
};
use super::{bsv, parser::Parser};
pub fn parse_output(source: &str, rule: impl Fn(&mut Parser)) -> String {
let file = Arc::new(FileContents::new(ArcStr::from(source)));
let mut ctx = BuildCtx::new(PkgHandle::default(), file.clone());
let mut tokens = Vec::new();
let mut lexer = BsvLexer::new(&mut ctx);
lexer.run(
TextCharStream::new(file.chunks(ROOT_ORIGIN).iter()),
&mut tokens,
);
let mut parser = Parser::new(&mut ctx, tokens.clone());
rule(&mut parser);
let nodes = parser.make_tree();
let cst = Cst::new(nodes);
format!("{:?}\n{}", ctx.diagnostics, cst)
}
macro_rules! snapshot {
($name:ident, $fun:expr, $text:literal) => {
#[test]
pub fn $name() {
insta::assert_snapshot!(parse_output($text, $fun))
}
};
}
use bsv::*;
snapshot!(
package_empty_1,
package,
r#"
"#
);
snapshot!(
package_empty_2,
package,
r#"
pacakge Foo;
endpackage: Foo
"#
);
snapshot!(
package_helloworld,
package,
r#"
pacakge Hello;
(* synthesize *)
module mTb;
rule hello;
$display("Hello world! %d", 42);
$finish;
endrule
endmodule
endpackage: Hello
"#
);
snapshot!(
package_bvi,
package,
r#"
import "BVI" vFoo = module Foo (Foo_IFC)
provisos (Foos, Bars);
// No parsing for these currently,
// just check if they get detected as
// stubs
default_clock;
default_reset;
no_reset;
input_clock;
input_reset;
inout;
ancestor;
same_family;
parameter;
port;
schedule;
path;
unsync;
method;
output_clock;
output_reset;
ifc_inout;
interface Bar bar;
endinterface: Bar
endmodule: Foo
"#
);
snapshot!(
pacakge_for,
package,
r#"
for(int i = 0, int j = 1, int k = 1 + 1; i < 10; i = i + 1, j = j + 1)
$display("%d %d %d", i, j, k);
"#
);
snapshot!(
pacakge_instance,
package,
r#"
instance Foo#(a)
provisos (Bar#(a));
function int foo1(int a);
return a;
endfunction
function int foo2(int a) = a + 1;
module [Module] bar #(bar_ty bar_arg) (Bar_IFC);
endmodule: bar
baz = 2 + 2;
endinstance: Foo
"#
);
snapshot!(
package_typeclass,
package,
r#"
typeclass Foo#(type a, type b)
provisos ()
dependencies (a determines b, b determines a);
function int foo1(int a);
return a;
endfunction
function int foo2(int a) = a + 1;
function int foo3(int a);
module [Module] bar1 #(bar_ty bar_arg) (Bar_IFC);
module [Module] bar2 #(bar_ty bar_arg) (Bar_IFC);
endmodule: bar
int baz1 = 2 + 2;
int baz2;
endtypeclass: Foo
"#
);
snapshot!(
pacakge_typedef_alias,
package,
r#"
typedef Foo#(a, b, c, d)
Bar#(
type a,
parameter type b,
numeric type c,
string type d
);
"#
);
snapshot!(
package_typedef_enum,
package,
r#"
typedef enum {
Foo0,
Foo1[1],
Foo2[2:3],
Foo3 = 4
} Foo deriving (Bar, Baz);
"#
);
snapshot!(
package_typedef_struct,
package,
r#"
typedef struct {
int a;
void b;
struct {
int c;
} d;
union tagged {
int e;
void f;
} g;
} Foo deriving (Bar, Baz);
"#
);
snapshot!(
package_typedef_union,
package,
r#"
typedef union tagged {
int a;
void b;
struct {
int c;
} d;
union tagged {
int e;
void f;
} g;
} Foo deriving (Bar, Baz);
"#
);
snapshot!(
package_interface,
package,
r#"
interface Foo #(type a);
(* attribute *) method int foo() provisos(Bar);
(* attribute *) interface Baz baz;
endinterface: Foo
"#
);
snapshot!(
package_subinterface,
package,
r#"
module Foo;
interface Bar bar1 = 0;
interface Bar bar2;
method int baz() = 0;
endinterface: bar2
endmodule
"#
);
snapshot!(
package_goto,
package,
r#"
goto foo;
"#
);
snapshot!(
package_continue,
package,
r#"
continue;
"#
);
snapshot!(
package_break,
package,
r#"
break;
"#
);
snapshot!(
package_while,
package,
r#"
while (1)
$display("Home Sweet ");
"#
);
snapshot!(
package_repeat,
package,
r#"
repeat (10)
$display("Home Sweet ");
"#
);
snapshot!(
package_case_if,
package,
r#"
case target
1 : 1;
2, 3, 4 : 2;
default : 3;
endcase
"#
);
snapshot!(
package_case_match,
package,
r#"
case target matches
.a &&& 1 : 1;
.b : 2;
default : 3;
endcase
"#
);
snapshot!(
package_abortif,
package,
r#"
abortif (1) 2; with 3;
"#
);
snapshot!(
package_if,
package,
r#"
if (1)
1;
else
2;
"#
);
snapshot!(
package_method,
package,
r#"
method int foo_1() provisos (Bar) if (1) = 2;
method int foo_2();
return 2;
endmethod: foo_2
"#
);
snapshot!(
package_rule,
package,
r#"
rule foo_1 if (1);
2;
endrule: foo_1
rule foo_2 (1);
2;
endrule: foo_2
"#
);
snapshot!(
package_function,
package,
r#"
function int foo_1() provisos (Bar) = 2;
function int foo_2();
return 2;
endfunction: foo_2
"#
);
snapshot!(
package_return,
package,
r#"
return 1;
"#
);
snapshot!(
package_expr_or_bind,
package,
r#"
1;
let a = 1;
match .a = 1;
ty_foo a = 1;
ty_foo a = 1, b, c = 2;
a = 1;
a <- 1;
a <= 1;
let {a, b} = 1;
"#
);
snapshot!(
package_attributes,
package,
r#"
(* foo *)
(* foo=1 *)
(* foo="2" *)
(* foo={3, "4"} *)
(* clocked_by, reset_by, parameter *)
int important = 0;
"#
);
snapshot!(
package_bdpi,
package,
r#"
import "BDPI" vFoo = function int foo() provisos (Bar);
"#
);
snapshot!(
package_import,
package,
r#"
import Foo::*, Bar::*;
"#
);
snapshot!(
package_export,
package,
r#"
export Foo, Bar::*, Baz (..);
"#
);
snapshot!(
package_module,
package,
r#"
module [Module] Foo#() (a_type a, Foo_IFC ifc) provisos (Bar);
endmodule: Foo
"#
);
snapshot!(
package_module_var,
package,
r#"
module#(Foo) foo;
"#
);
snapshot!(
package_module_expr,
package,
r#"
module#(Foo);
endmodule
"#
);
snapshot!(
pacakge_patterns,
package,
r#"
match .a = 1;
match .* = 2;
match 1 = 1;
match "1" = 1;
match tagged Foo .a = 1;
match {.a, .b} = 1;
match {a: 1, b} = 1;
match Foo {a, b} = 1;
match Bar = 1;
match (.a) = 1;
"#
);
snapshot!(
package_stmt_blocks,
package,
r#"
action: foo endaction: foo
actionvalue: foo endactionvalue: foo
begin: foo end: foo
seq: foo endseq: foo
par: foo endpar: foo
"#
);
snapshot!(
package_types,
package,
r#"
bit[1:2] foo;
int foo;
real foo;
void foo;
Action foo;
ActionValue#(int) foo;
Foo#(function int foo(int a)) foo;
module#(Foo) foo;
1 foo;
"1" foo;
ty_var foo;
Ty_cons foo;
Foo#((int)) foo;
"#
);
snapshot!(
package_exprs_binary,
package,
r#"
1 ** 2;
1 * 2;
1 / 2;
1 % 2;
1 + 2;
1 - 2;
1 << 2;
1 >> 2;
1 < 2;
1 <= 2;
1 > 2;
1 >= 2;
1 == 2;
1 != 2;
1 & 2;
1 ^ 2;
1 ^~ 2;
1 ~^ 2;
1 | 2;
1 && 2;
1 || 2;
1 &&& 2;
1 ? 2 : 3;
1 matches .a;
"#
);
snapshot!(
package_exprs_prefix,
package,
r#"
((* attribute *) a);
+a;
-a;
!a;
~a;
&a;
|a;
^a;
~&a;
~|a;
~^a;
^~a;
"#
);
snapshot!(
package_expr_lit,
package,
r#"
1;
"2";
"#
);
snapshot!(
package_expr_blocks,
package,
r#"
(action: foo endaction: foo);
(actionvalue: foo endactionvalue: foo);
(rules: foo endrules: foo);
(begin: foo end: foo);
(seq: foo endseq: foo);
(par: foo endpar: foo);
"#
);
snapshot!(
package_expr_interface,
package,
r#"
(
interface Foo;
endinterface: Foo
);
"#
);
snapshot!(
package_expr_case_if,
package,
r#"
(case target
1 : 1;
2, 3, 4 : 2;
default : 3;
endcase);
"#
);
snapshot!(
package_expr_case_match,
package,
r#"
(case target matches
.a &&& 1 : 1;
.b : 2;
default : 3;
endcase);
"#
);
snapshot!(
package_expr_bit_concat,
package,
r#"
{1, 2, 3};
"#
);
snapshot!(
package_expr_sys_task,
package,
r#"
$foo;
"#
);
snapshot!(
package_expr_valueof,
package,
r#"
valueof(1);
valueOf(1);
"#
);
snapshot!(
package_expr_stringof,
package,
r#"
stringof(1);
stringOf(1);
"#
);
snapshot!(
package_expr_dontcare,
package,
r#"
?;
"#
);
snapshot!(
package_expr_tagged,
package,
r#"
tagged Foo 1;
tagged Bar { a: 1 };
"#
);
snapshot!(
package_expr_postfix,
package,
r#"
a.b;
a(b, clocked_by c, reset_by d, powered_by e);
a[1];
a[1:2];
"#
);