vxx2 / vlib / v3 / tests / parser_regression_test.v
162 lines · 154 sloc · 5.35 KB · 288feee4702b35beadb4037d02b96b5c8674156b
Raw
1import os
2import v3.flat
3import v3.parser
4import v3.pref
5import v3.types
6
7// parse_parser_regression_source reads parse parser regression source input for v3 tests.
8fn parse_parser_regression_source(name string, source string) &flat.FlatAst {
9 src := os.join_path(os.temp_dir(), 'v3_${name}.v')
10 os.write_file(src, source) or { panic(err) }
11 mut prefs := pref.new_preferences()
12 mut p := parser.Parser.new(prefs)
13 p.parse_into(src)
14 return p.a
15}
16
17fn parse_parser_regression_sources(name string, sources []string) &flat.FlatAst {
18 mut prefs := pref.new_preferences()
19 mut p := parser.Parser.new(prefs)
20 for i, source in sources {
21 src := os.join_path(os.temp_dir(), 'v3_${name}_${i}.v')
22 os.write_file(src, source) or { panic(err) }
23 p.parse_into(src)
24 }
25 return p.a
26}
27
28// interface_method_param_types supports interface method param types handling for v3 tests.
29fn interface_method_param_types(a &flat.FlatAst, iface string, method string) []string {
30 for node in a.nodes {
31 if node.kind != .interface_decl || node.value != iface {
32 continue
33 }
34 for i in 0 .. node.children_count {
35 field := a.child_node(&node, i)
36 if field.kind != .interface_field || field.value != method {
37 continue
38 }
39 mut params := []string{}
40 for j in 0 .. field.children_count {
41 param := a.child_node(field, j)
42 if param.kind == .param {
43 params << param.typ
44 }
45 }
46 return params
47 }
48 }
49 return []string{}
50}
51
52fn fn_decl_param_pairs(a &flat.FlatAst, kind flat.NodeKind, name string) []string {
53 for node in a.nodes {
54 if node.kind != kind || node.value != name {
55 continue
56 }
57 mut pairs := []string{}
58 for i in 0 .. node.children_count {
59 param := a.child_node(&node, i)
60 if param.kind == .param {
61 pairs << '${param.value}:${param.typ}'
62 }
63 }
64 return pairs
65 }
66 return []string{}
67}
68
69// test_interface_method_generic_type_only_param_is_not_parsed_as_name
70// validates this v3 regression case.
71fn test_interface_method_generic_type_only_param_is_not_parsed_as_name() {
72 a := parse_parser_regression_source('interface_generic_param',
73 'const max_len = 16\nstruct Result[T] {}\nstruct Node {}\n\ninterface Sink {\n\tput(Result[int])\n\tappend(values []int)\n\tvisit(node &Node)\n\tread(buf [max_len]u8)\n}\n')
74 assert interface_method_param_types(a, 'Sink', 'put') == ['Result[int]']
75 assert interface_method_param_types(a, 'Sink', 'append') == ['[]int']
76 assert interface_method_param_types(a, 'Sink', 'visit') == ['&Node']
77 assert interface_method_param_types(a, 'Sink', 'read') == ['[max_len]u8']
78}
79
80fn test_c_function_anonymous_params_are_parsed_as_types() {
81 a := parse_parser_regression_source('c_anon_params',
82 'struct T {}\nstruct C.FILE {}\nstruct C.Widget {}\nstruct C.Node {}\ntype MyHandle = voidptr\n\nfn C.anon(&C.FILE, voidptr, int, &&T, [4]&C.Widget, ?&C.Node, !&C.Node, fn (&C.Node) int) int\nfn C.custom(MyHandle, int, MyHandle) int\nfn C.lower(size_t, int, pthread_t) int\nfn C.named(stream &C.FILE, a, b int) int\nfn C.named_custom(handle MyHandle, a, b int) int\nfn C.named_arrays(m [16]f32, r []rune) int\nfn C.variadic(...int) int\nfn JS.js_anon(JS.Number) JS.Number\nfn JS.js_named(x JS.Number) JS.Number\nfn JS.setInterval(any, int, ...any) int\nfn JS.console.dir(any, any)\nfn JS.named_any(x any) any\nfn ordinary(int) {}\n')
83 assert fn_decl_param_pairs(a, .c_fn_decl, 'anon') == [
84 ':&C.FILE',
85 ':voidptr',
86 ':int',
87 ':&&T',
88 ':[4]&C.Widget',
89 ':?&C.Node',
90 ':!&C.Node',
91 ':fn(&C.Node) int',
92 ]
93 assert fn_decl_param_pairs(a, .c_fn_decl, 'custom') == [
94 ':MyHandle',
95 ':int',
96 ':MyHandle',
97 ]
98 assert fn_decl_param_pairs(a, .c_fn_decl, 'lower') == [
99 ':size_t',
100 ':int',
101 ':pthread_t',
102 ]
103 assert fn_decl_param_pairs(a, .c_fn_decl, 'named') == [
104 'stream:&C.FILE',
105 'a:int',
106 'b:int',
107 ]
108 assert fn_decl_param_pairs(a, .c_fn_decl, 'named_custom') == [
109 'handle:MyHandle',
110 'a:int',
111 'b:int',
112 ]
113 assert fn_decl_param_pairs(a, .c_fn_decl, 'named_arrays') == [
114 'm:[16]f32',
115 'r:[]rune',
116 ]
117 assert fn_decl_param_pairs(a, .c_fn_decl, 'variadic') == [':...int']
118 assert fn_decl_param_pairs(a, .c_fn_decl, 'js_anon') == [':JS.Number']
119 assert fn_decl_param_pairs(a, .c_fn_decl, 'js_named') == ['x:JS.Number']
120 assert fn_decl_param_pairs(a, .c_fn_decl, 'setInterval') == [
121 ':any',
122 ':int',
123 ':...any',
124 ]
125 assert fn_decl_param_pairs(a, .c_fn_decl, 'console.dir') == [
126 ':any',
127 ':any',
128 ]
129 assert fn_decl_param_pairs(a, .c_fn_decl, 'named_any') == ['x:any']
130 assert fn_decl_param_pairs(a, .fn_decl, 'ordinary') == ['int:']
131}
132
133fn test_moduleless_file_does_not_inherit_previous_parser_module() {
134 a := parse_parser_regression_sources('moduleless_export', [
135 'module expmod\n\nfn helper() {}\n',
136 "@[export: '1bad']\nfn lonely() {}\n",
137 ])
138 mut tc := types.TypeChecker.new(a)
139 tc.collect(a)
140 tc.check_semantics()
141 assert tc.errors.len == 1, tc.errors.str()
142 assert tc.errors[0].msg.contains('for `lonely`'), tc.errors.str()
143 assert !tc.errors[0].msg.contains('expmod.lonely'), tc.errors.str()
144 assert fn_decl_param_pairs(a, .fn_decl, 'lonely') == []
145}
146
147fn test_sql_identifier_calls_are_not_parsed_as_sql_expr() {
148 a := parse_parser_regression_source('sql_identifier_call',
149 'fn sql(x int) int {\n\treturn x + 1\n}\n\nfn main() {\n\tx := sql(2)\n\tsql := 1\n\t_ := sql + 2\n}\n')
150 mut sql_expr_count := 0
151 mut call_count := 0
152 for node in a.nodes {
153 if node.kind == .sql_expr {
154 sql_expr_count++
155 }
156 if node.kind == .call {
157 call_count++
158 }
159 }
160 assert sql_expr_count == 0
161 assert call_count == 1
162}
163