v / vlib / v2 / eval / eval.v
6244 lines · 6006 sloc · 149.78 KB · 16e9dff060e9e7db1a6fdd8d171127734d6a6849
Raw
1module eval
2
3import os
4import os.cmdline as host_cmdline
5import strconv
6import time
7import v2.ast
8import v2.parser
9import v2.pref
10import v2.token
11
12type Value = ArrayValue
13 | FlagsValue
14 | MapValue
15 | ModuleValue
16 | RangeValue
17 | StructValue
18 | TupleValue
19 | TypeValue
20 | VoidValue
21 | bool
22 | f64
23 | i64
24 | string
25
26fn value_f64_payload(value Value) f64 {
27 data := unsafe { (&u64(&value))[1] }
28 if data == 0 {
29 return 0.0
30 }
31 return unsafe { *(&f64(voidptr(data))) }
32}
33
34struct ArrayValue {
35mut:
36 elem_type_name string
37 values []Value
38}
39
40struct FlagsValue {}
41
42struct MapEntry {
43 key Value
44 value Value
45}
46
47struct MapValue {
48 default_value Value
49mut:
50 entries []MapEntry
51}
52
53struct ModuleValue {
54 name string
55}
56
57struct RangeValue {
58 start i64
59 end i64
60 inclusive bool
61}
62
63struct StructValue {
64 type_name string
65mut:
66 fields map[string]Value
67}
68
69struct TupleValue {
70 values []Value
71}
72
73struct TypeValue {
74 name string
75}
76
77struct VoidValue {}
78
79struct FunctionDef {
80 decl ast.FnDecl
81 file_name string
82}
83
84struct ConstEntry {
85 expr ast.Expr
86 file_name string
87mut:
88 cached bool
89 evaluating bool
90 value Value
91}
92
93struct SumTypeInfo {
94 module_name string
95 name string
96mut:
97 variant_tags map[string]int
98 tag_field_aliases map[int][]string
99}
100
101struct InferredSumTypeVariant {
102 tag int
103 variant_name string
104}
105
106struct WrappedSumTypeVariant {
107 tag int
108 payload Value
109}
110
111struct ScopeFrame {
112mut:
113 vars map[string]Value
114 defers [][]ast.Stmt
115}
116
117struct CallFrame {
118 module_name string
119 file_name string
120 fn_name string
121}
122
123struct MaybeValue {
124 found bool
125 value Value
126}
127
128struct MaybeCallResult {
129 found bool
130 result CallResult
131}
132
133struct MaybeFunctionTarget {
134 found bool
135 module_name string
136 fn_name string
137}
138
139struct CallResult {
140 values []Value
141mut:
142 mut_args map[int]Value
143}
144
145enum FlowKind {
146 normal
147 break_
148 continue_
149 goto_
150 return_
151}
152
153struct FlowSignal {
154 kind FlowKind
155 label string
156 values []Value
157}
158
159fn void_value() Value {
160 return VoidValue{}
161}
162
163fn wrap_result_ok(value Value) Value {
164 return StructValue{
165 type_name: 'Result'
166 fields: {
167 'is_error': Value(false)
168 'err': Value('')
169 'data': value
170 }
171 }
172}
173
174fn wrap_result_err(message string) Value {
175 return StructValue{
176 type_name: 'Result'
177 fields: {
178 'is_error': Value(true)
179 'err': Value(message)
180 'data': void_value()
181 }
182 }
183}
184
185fn wrap_option_ok(value Value) Value {
186 return StructValue{
187 type_name: 'Option'
188 fields: {
189 'state': Value(i64(0))
190 'err': Value('')
191 'data': value
192 }
193 }
194}
195
196fn wrap_option_none() Value {
197 return StructValue{
198 type_name: 'Option'
199 fields: {
200 'state': Value(i64(1))
201 'err': Value('')
202 'data': void_value()
203 }
204 }
205}
206
207fn os_result_value(result os.Result) Value {
208 return StructValue{
209 type_name: 'os.Result'
210 fields: {
211 'exit_code': Value(i64(result.exit_code))
212 'output': Value(result.output)
213 }
214 }
215}
216
217fn is_option_value(value Value) bool {
218 return value is StructValue && 'state' in value.fields && 'err' in value.fields
219 && 'data' in value.fields
220}
221
222fn is_result_value(value Value) bool {
223 return value is StructValue && 'is_error' in value.fields && 'err' in value.fields
224 && 'data' in value.fields
225}
226
227// Eval interprets the v2 AST directly for a limited subset of V.
228pub struct Eval {
229pub mut:
230 capture_output bool
231 prefs pref.Preferences
232mut:
233 stdout_data string
234 stderr_data string
235 functions map[string]map[string]FunctionDef
236 consts map[string]map[string]ConstEntry
237 sum_types map[string]SumTypeInfo
238 struct_field_types map[string]map[string]map[string]ast.Expr
239 struct_embeds map[string]map[string][]string
240 type_kinds map[string]map[string]string
241 type_names map[string]map[string]bool
242 file_import_alias map[string]map[string]string
243 modules map[string]bool
244 scopes []ScopeFrame
245 call_stack []CallFrame
246 next_token_pos_id i64
247}
248
249// new returns a new evaluator configured for direct execution.
250pub fn new(prefs_ &pref.Preferences) Eval {
251 return Eval{
252 capture_output: false
253 prefs: *prefs_
254 }
255}
256
257// create returns a capturing evaluator convenient for tests.
258pub fn create() Eval {
259 return Eval{
260 capture_output: true
261 prefs: pref.new_preferences()
262 }
263}
264
265// stdout returns the captured stdout stream.
266pub fn (e &Eval) stdout() string {
267 return e.stdout_data
268}
269
270// stderr returns the captured stderr stream.
271pub fn (e &Eval) stderr() string {
272 return e.stderr_data
273}
274
275// run_text parses and executes a single V source string.
276pub fn (mut e Eval) run_text(code string) ![]Value {
277 tmp_file := os.join_path(os.temp_dir(), 'v2_eval_${os.getpid()}_${time.now().unix_micro()}.v')
278 os.write_file(tmp_file, code)!
279 defer {
280 os.rm(tmp_file) or {}
281 }
282 mut file_set := token.FileSet.new()
283 mut par := parser.Parser.new(&e.prefs)
284 files := par.parse_files([tmp_file], mut file_set)
285 return e.run_files(files)
286}
287
288// run_files executes parsed AST files and invokes `main.main`.
289pub fn (mut e Eval) run_files(files []ast.File) ![]Value {
290 e.reset()
291 e.register_files(files)!
292 return e.call_function('main', 'main', []Value{})!.values
293}
294
295fn (mut e Eval) reset() {
296 e.stdout_data = ''
297 e.stderr_data = ''
298 e.functions = map[string]map[string]FunctionDef{}
299 e.consts = map[string]map[string]ConstEntry{}
300 e.sum_types = map[string]SumTypeInfo{}
301 e.struct_field_types = map[string]map[string]map[string]ast.Expr{}
302 e.struct_embeds = map[string]map[string][]string{}
303 e.type_kinds = map[string]map[string]string{}
304 e.type_names = map[string]map[string]bool{}
305 e.file_import_alias = map[string]map[string]string{}
306 e.modules = map[string]bool{}
307 e.scopes = []ScopeFrame{}
308 e.call_stack = []CallFrame{}
309 e.next_token_pos_id = 0
310}
311
312fn (mut e Eval) register_files(files []ast.File) ! {
313 for file in files {
314 e.modules[file.mod] = true
315 mut import_aliases := map[string]string{}
316 for imp in file.imports {
317 import_aliases[imp.alias] = imp.name.all_after_last('.')
318 }
319 e.file_import_alias[file.name] = import_aliases.clone()
320 if file.mod !in e.functions {
321 e.functions[file.mod] = map[string]FunctionDef{}
322 }
323 if file.mod !in e.consts {
324 e.consts[file.mod] = map[string]ConstEntry{}
325 }
326 if file.mod !in e.type_names {
327 e.type_names[file.mod] = map[string]bool{}
328 }
329 if file.mod !in e.struct_field_types {
330 e.struct_field_types[file.mod] = map[string]map[string]ast.Expr{}
331 }
332 if file.mod !in e.struct_embeds {
333 e.struct_embeds[file.mod] = map[string][]string{}
334 }
335 if file.mod !in e.type_kinds {
336 e.type_kinds[file.mod] = map[string]string{}
337 }
338 for stmt in file.stmts {
339 match stmt {
340 ast.ConstDecl {
341 for field in stmt.fields {
342 key := if field.name.contains('.') {
343 field.name.all_after_last('.')
344 } else {
345 field.name
346 }
347 e.consts[file.mod][key] = ConstEntry{
348 expr: field.value
349 file_name: file.name
350 value: void_value()
351 }
352 }
353 }
354 ast.EnumDecl {
355 e.type_names[file.mod][stmt.name] = true
356 e.type_kinds[file.mod][stmt.name] = 'Enum'
357 is_flag := stmt.attributes.has('flag')
358 mut next_value := if is_flag { i64(1) } else { i64(0) }
359 for field in stmt.fields {
360 key := field.name
361 value := if field.value is ast.EmptyExpr {
362 Value(next_value)
363 } else if field.value is ast.BasicLiteral && field.value.kind == .number {
364 Value(strconv.parse_int(field.value.value, 0, 64)!)
365 } else {
366 Value(next_value)
367 }
368 int_value := e.value_as_int(value)!
369 e.consts[file.mod][key] = ConstEntry{
370 expr: ast.empty_expr
371 file_name: file.name
372 cached: true
373 value: int_value
374 }
375 next_value = if is_flag {
376 if int_value <= 0 { i64(1) } else { int_value * 2 }
377 } else {
378 int_value + 1
379 }
380 }
381 }
382 ast.InterfaceDecl {
383 e.type_names[file.mod][stmt.name] = true
384 e.type_kinds[file.mod][stmt.name] = 'Interface'
385 }
386 ast.FnDecl {
387 e.functions[file.mod][stmt.name] = FunctionDef{
388 decl: stmt
389 file_name: file.name
390 }
391 if stmt.is_method {
392 receiver_type_name := stmt.receiver.typ.name()
393 if receiver_type_name != '' && receiver_type_name != 'EmptyExpr' {
394 e.functions[file.mod]['${receiver_type_name}__${stmt.name}'] = FunctionDef{
395 decl: stmt
396 file_name: file.name
397 }
398 short_receiver_name := receiver_type_name.all_after_last('.')
399 if short_receiver_name != receiver_type_name {
400 e.functions[file.mod]['${short_receiver_name}__${stmt.name}'] = FunctionDef{
401 decl: stmt
402 file_name: file.name
403 }
404 }
405 normalized_receiver_name :=
406 receiver_type_name.trim_left('&').trim_right('*')
407 if normalized_receiver_name != ''
408 && normalized_receiver_name != receiver_type_name {
409 e.functions[file.mod]['${normalized_receiver_name}__${stmt.name}'] = FunctionDef{
410 decl: stmt
411 file_name: file.name
412 }
413 short_normalized_name :=
414 normalized_receiver_name.all_after_last('.')
415 if short_normalized_name != normalized_receiver_name {
416 e.functions[file.mod]['${short_normalized_name}__${stmt.name}'] = FunctionDef{
417 decl: stmt
418 file_name: file.name
419 }
420 }
421 }
422 }
423 }
424 }
425 ast.StructDecl {
426 e.type_names[file.mod][stmt.name] = true
427 e.type_kinds[file.mod][stmt.name] = 'Struct'
428 mut field_types := map[string]ast.Expr{}
429 for field in stmt.fields {
430 field_types[field.name] = field.typ
431 }
432 e.struct_field_types[file.mod][stmt.name] = field_types.clone()
433 e.struct_embeds[file.mod][stmt.name] = stmt.embedded.map(e.type_expr_name(it))
434 }
435 ast.TypeDecl {
436 e.type_names[file.mod][stmt.name] = true
437 if stmt.variants.len > 0 {
438 e.type_kinds[file.mod][stmt.name] = 'SumType'
439 e.register_sum_type(file.mod, stmt)
440 } else {
441 e.type_kinds[file.mod][stmt.name] = 'Alias'
442 }
443 }
444 else {}
445 }
446 }
447 }
448 if 'main' !in e.functions || 'main' !in e.functions['main'] {
449 return error('v2.eval: missing main.main entry point')
450 }
451}
452
453fn add_type_name_alias(mut aliases []string, alias string) {
454 if alias != '' && alias !in aliases {
455 aliases << alias
456 }
457}
458
459fn (e &Eval) type_name_aliases(module_name string, type_name string) []string {
460 mut aliases := []string{}
461 if type_name == '' {
462 return aliases
463 }
464 add_type_name_alias(mut aliases, type_name)
465 if type_name.starts_with('[]') {
466 for inner_alias in e.type_name_aliases(module_name, type_name[2..]) {
467 add_type_name_alias(mut aliases, '[]${inner_alias}')
468 }
469 return aliases
470 }
471 if type_name.starts_with('map[') {
472 inner := type_name[4..]
473 if bracket_idx := inner.index(']') {
474 key_name := inner[..bracket_idx]
475 value_name := inner[bracket_idx + 1..]
476 key_aliases := e.type_name_aliases(module_name, key_name)
477 value_aliases := e.type_name_aliases(module_name, value_name)
478 for key_alias in key_aliases {
479 for value_alias in value_aliases {
480 add_type_name_alias(mut aliases, 'map[${key_alias}]${value_alias}')
481 }
482 }
483 }
484 return aliases
485 }
486 if type_name.contains('__') {
487 add_type_name_alias(mut aliases, type_name.replace('__', '.'))
488 add_type_name_alias(mut aliases, type_name.all_after_last('__'))
489 return aliases
490 }
491 if type_name.contains('.') {
492 add_type_name_alias(mut aliases, type_name.replace('.', '__'))
493 add_type_name_alias(mut aliases, type_name.all_after_last('.'))
494 return aliases
495 }
496 if module_name != '' {
497 add_type_name_alias(mut aliases, '${module_name}.${type_name}')
498 add_type_name_alias(mut aliases, '${e.mangled_module_name(module_name)}__${type_name}')
499 }
500 return aliases
501}
502
503fn (e &Eval) sumtype_variant_field_name(variant_name string) string {
504 if variant_name.starts_with('[]') {
505 return 'Array_${variant_name[2..].replace('.', '__')}'
506 }
507 if variant_name.starts_with('map[') {
508 inner := variant_name[4..]
509 if bracket_idx := inner.index(']') {
510 key := inner[..bracket_idx].replace('.', '__')
511 val := inner[bracket_idx + 1..].replace('.', '__')
512 return 'Map_${key}_${val}'
513 }
514 }
515 if variant_name.contains('__') {
516 return variant_name.all_after_last('__')
517 }
518 if variant_name.contains('.') {
519 return variant_name.all_after_last('.')
520 }
521 return variant_name
522}
523
524fn (mut e Eval) register_sum_type(module_name string, decl ast.TypeDecl) {
525 mut info := SumTypeInfo{
526 module_name: module_name
527 name: decl.name
528 variant_tags: map[string]int{}
529 tag_field_aliases: map[int][]string{}
530 }
531 for tag, variant in decl.variants {
532 variant_name := e.type_expr_name(variant)
533 for alias in e.type_name_aliases(module_name, variant_name) {
534 info.variant_tags[alias] = tag
535 field_alias := '_' + e.sumtype_variant_field_name(alias)
536 mut field_aliases := []string{}
537 if tag in info.tag_field_aliases {
538 field_aliases = info.tag_field_aliases[tag]
539 }
540 if field_alias !in field_aliases {
541 field_aliases << field_alias
542 }
543 info.tag_field_aliases[tag] = field_aliases
544 }
545 }
546 for alias in e.type_name_aliases(module_name, decl.name) {
547 e.sum_types[alias] = info
548 }
549}
550
551fn is_composite_sumtype_lookup_name(name string) bool {
552 return name.starts_with('[]') || name.starts_with('map[')
553 || (name.starts_with('[') && name.contains(']')) || name.starts_with('?')
554 || name.starts_with('!') || name.starts_with('chan ')
555 || name.starts_with('thread ')
556}
557
558fn (e &Eval) sum_type_info(type_name string) ?SumTypeInfo {
559 trimmed := type_name.trim_left('&').trim_right('*')
560 if trimmed in e.sum_types {
561 return e.sum_types[trimmed]
562 }
563 if is_composite_sumtype_lookup_name(trimmed) {
564 return none
565 }
566 if trimmed.contains('.') {
567 short_name := trimmed.all_after_last('.')
568 if short_name in e.sum_types {
569 return e.sum_types[short_name]
570 }
571 }
572 if trimmed.contains('__') {
573 short_name := trimmed.all_after_last('__')
574 if short_name in e.sum_types {
575 return e.sum_types[short_name]
576 }
577 dotted := trimmed.replace('__', '.')
578 if dotted in e.sum_types {
579 return e.sum_types[dotted]
580 }
581 }
582 return none
583}
584
585fn (e &Eval) is_sum_type_name(type_name string) bool {
586 _ = e.sum_type_info(type_name) or { return false }
587 return true
588}
589
590fn (e &Eval) lookup_sumtype_variant_tag(info SumTypeInfo, variant_name string) ?int {
591 for alias in e.type_name_aliases(info.module_name, variant_name) {
592 if alias in info.variant_tags {
593 return info.variant_tags[alias]
594 }
595 }
596 return none
597}
598
599fn builtin_type_kind_alias(name string) ?string {
600 trimmed := name.all_after_last('.')
601 return match trimmed {
602 'bool', 'f32', 'f64', 'float_literal', 'i8', 'i16', 'i32', 'int', 'i64', 'int_literal',
603 'u8', 'byte', 'u16', 'u32', 'u64' {
604 'Primitive'
605 }
606 'byteptr', 'charptr', 'voidptr' {
607 'Alias'
608 }
609 'char' {
610 'Char'
611 }
612 'isize' {
613 'ISize'
614 }
615 'nil' {
616 'Nil'
617 }
618 'none' {
619 'None'
620 }
621 'rune' {
622 'Rune'
623 }
624 'string' {
625 'String'
626 }
627 'usize' {
628 'USize'
629 }
630 'void' {
631 'Void'
632 }
633 else {
634 none
635 }
636 }
637}
638
639fn (e &Eval) registered_type_kind(type_name string) ?string {
640 for alias in struct_field_lookup_candidates(type_name) {
641 mut module_name := ''
642 mut short_type_name := alias
643 if alias.contains('.') {
644 module_name = alias.all_before_last('.')
645 short_type_name = alias.all_after_last('.')
646 }
647 if module_name != '' {
648 if module_kinds := e.type_kinds[module_name] {
649 if short_type_name in module_kinds {
650 return module_kinds[short_type_name] or { return none }
651 }
652 }
653 continue
654 }
655 current_module := e.current_module_name()
656 if module_kinds := e.type_kinds[current_module] {
657 if short_type_name in module_kinds {
658 return module_kinds[short_type_name] or { return none }
659 }
660 }
661 for module_kinds in e.type_kinds.values() {
662 if short_type_name in module_kinds {
663 return module_kinds[short_type_name] or { return none }
664 }
665 }
666 }
667 return none
668}
669
670fn (e &Eval) type_value_variant_aliases(info SumTypeInfo, value TypeValue) []string {
671 mut aliases := e.type_name_aliases(info.module_name, value.name)
672 if type_kind := e.registered_type_kind(value.name) {
673 add_type_name_alias(mut aliases, type_kind)
674 }
675 if builtin_kind := builtin_type_kind_alias(value.name) {
676 add_type_name_alias(mut aliases, builtin_kind)
677 }
678 add_type_name_alias(mut aliases, 'Type')
679 return aliases
680}
681
682fn (e &Eval) canonical_sumtype_variant_name(info SumTypeInfo, alias string) string {
683 if alias.contains('.') {
684 return alias
685 }
686 if alias.contains('__') {
687 dotted := alias.replace('__', '.')
688 if dotted.contains('.') {
689 return dotted
690 }
691 }
692 short_name := alias.all_after_last('__')
693 if info.module_name != '' && short_name != '' {
694 return '${info.module_name}.${short_name}'
695 }
696 if short_name != '' {
697 return short_name
698 }
699 return alias
700}
701
702fn (e &Eval) lookup_struct_field_names(type_name string) ?[]string {
703 for candidate in struct_field_lookup_candidates(type_name) {
704 mut module_name := ''
705 mut short_type_name := candidate
706 if candidate.contains('.') {
707 module_name = candidate.all_before_last('.')
708 short_type_name = candidate.all_after_last('.')
709 }
710 if module_name != '' {
711 if module_fields := e.struct_field_types[module_name] {
712 if type_fields := module_fields[short_type_name] {
713 return type_fields.keys()
714 }
715 }
716 continue
717 }
718 current_module := e.current_module_name()
719 if module_fields := e.struct_field_types[current_module] {
720 if type_fields := module_fields[short_type_name] {
721 return type_fields.keys()
722 }
723 }
724 for _, module_fields in e.struct_field_types {
725 if type_fields := module_fields[short_type_name] {
726 return type_fields.keys()
727 }
728 }
729 }
730 return none
731}
732
733fn (e &Eval) zero_value_for_type_name(type_name string) Value {
734 if type_name == '' {
735 return void_value()
736 }
737 if type_name.starts_with('[]') {
738 return ArrayValue{}
739 }
740 if type_name.starts_with('map[') {
741 inner := type_name[4..]
742 if bracket_idx := inner.index(']') {
743 return MapValue{
744 default_value: e.zero_value_for_type_name(inner[bracket_idx + 1..])
745 }
746 }
747 return MapValue{}
748 }
749 if type_name.starts_with('?') || type_name.starts_with('!') {
750 return void_value()
751 }
752 match type_name {
753 'bool' {
754 return false
755 }
756 'byte', 'char', 'i8', 'i16', 'i32', 'int', 'i64', 'isize', 'rune', 'u8', 'u16', 'u32',
757 'u64', 'usize' {
758 return i64(0)
759 }
760 'f32', 'f64' {
761 return f64(0.0)
762 }
763 'string' {
764 return ''
765 }
766 else {
767 return e.zero_struct_value(type_name)
768 }
769 }
770}
771
772fn (e &Eval) zero_value_for_sumtype_data_field(data_type_name string, field_name string) ?Value {
773 if !data_type_name.ends_with('._data') || !field_name.starts_with('_') {
774 return none
775 }
776 parent_sumtype_name := data_type_name.all_before_last('._data')
777 info := e.sum_type_info(parent_sumtype_name) or { return none }
778 mut variant_alias := ''
779 for alias in info.variant_tags.keys() {
780 if '_' + e.sumtype_variant_field_name(alias) == field_name {
781 variant_alias = e.canonical_sumtype_variant_name(info, alias)
782 break
783 }
784 }
785 if variant_alias == '' {
786 return none
787 }
788 return e.zero_value_for_type_name(variant_alias)
789}
790
791fn (e &Eval) sumtype_variant_field_value(sum_value StructValue, field_name string) ?Value {
792 if !field_name.starts_with('_') {
793 return none
794 }
795 info := e.sum_type_info(sum_value.type_name) or { return none }
796 tag_value := sum_value.fields['_tag'] or { return none }
797 tag := int(e.value_as_int(tag_value) or { return none })
798 mut variant_alias := ''
799 mut variant_tag := -1
800 for alias, alias_tag in info.variant_tags {
801 if '_' + e.sumtype_variant_field_name(alias) == field_name {
802 variant_alias = e.canonical_sumtype_variant_name(info, alias)
803 variant_tag = alias_tag
804 break
805 }
806 }
807 if variant_alias == '' {
808 return none
809 }
810 if tag == variant_tag {
811 if payload := e.unwrap_sumtype_value(sum_value, variant_alias) {
812 if !is_semantically_empty_value(payload) {
813 return payload
814 }
815 }
816 }
817 return e.zero_value_for_type_name(variant_alias)
818}
819
820fn (e &Eval) infer_bare_sumtype_variant(info SumTypeInfo, value StructValue) ?InferredSumTypeVariant {
821 if '_tag' in value.fields || '_data' in value.fields {
822 return none
823 }
824 if value.fields.len == 0 {
825 return none
826 }
827 mut matches := map[int]string{}
828 for alias, tag in info.variant_tags {
829 field_names := e.lookup_struct_field_names(alias) or { continue }
830 if field_names.len != value.fields.len {
831 continue
832 }
833 mut all_fields_match := true
834 for field_name in value.fields.keys() {
835 if field_name !in field_names {
836 all_fields_match = false
837 break
838 }
839 }
840 if !all_fields_match {
841 continue
842 }
843 if tag !in matches {
844 matches[tag] = e.canonical_sumtype_variant_name(info, alias)
845 }
846 }
847 if matches.len != 1 {
848 return none
849 }
850 for tag, variant_name in matches {
851 return InferredSumTypeVariant{
852 tag: tag
853 variant_name: variant_name
854 }
855 }
856 return none
857}
858
859fn (e &Eval) infer_nested_sumtype_variant(info SumTypeInfo, value Value) ?WrappedSumTypeVariant {
860 for alias, tag in info.variant_tags {
861 nested_info := e.sum_type_info(alias) or { continue }
862 if nested_info.name == info.name && nested_info.module_name == info.module_name {
863 continue
864 }
865 nested_payload := e.cast_value(value, alias) or { continue }
866 match nested_payload {
867 StructValue {
868 if e.type_name_matches(nested_payload.type_name, alias)
869 && '_tag' in nested_payload.fields && '_data' in nested_payload.fields {
870 return WrappedSumTypeVariant{
871 tag: tag
872 payload: nested_payload
873 }
874 }
875 }
876 else {}
877 }
878 }
879 return none
880}
881
882fn (e &Eval) sumtype_tag_from_value(info SumTypeInfo, value Value) ?int {
883 match value {
884 StructValue {
885 if e.type_name_matches(value.type_name, '${info.module_name}.${info.name}') {
886 if tag_value := value.fields['_tag'] {
887 return int(e.value_as_int(tag_value) or { return none })
888 }
889 }
890 for alias in e.type_name_aliases(info.module_name, value.type_name) {
891 if alias in info.variant_tags {
892 return info.variant_tags[alias]
893 }
894 }
895 if inferred := e.infer_bare_sumtype_variant(info, value) {
896 return inferred.tag
897 }
898 }
899 string {
900 return e.lookup_sumtype_variant_tag(info, 'string')
901 }
902 bool {
903 return e.lookup_sumtype_variant_tag(info, 'bool')
904 }
905 i64 {
906 for alias in ['int', 'i64', 'i32', 'i16', 'i8', 'u64', 'u32', 'u16', 'u8', 'byte',
907 'char', 'rune'] {
908 if tag := e.lookup_sumtype_variant_tag(info, alias) {
909 return tag
910 }
911 }
912 }
913 f64 {
914 for alias in ['f64', 'f32'] {
915 if tag := e.lookup_sumtype_variant_tag(info, alias) {
916 return tag
917 }
918 }
919 }
920 ArrayValue {
921 mut tags := []int{}
922 for alias, tag in info.variant_tags {
923 if alias.starts_with('[]') && tag !in tags {
924 tags << tag
925 }
926 }
927 if tags.len == 1 {
928 return tags[0]
929 }
930 }
931 MapValue {
932 mut tags := []int{}
933 for alias, tag in info.variant_tags {
934 if alias.starts_with('map[') && tag !in tags {
935 tags << tag
936 }
937 }
938 if tags.len == 1 {
939 return tags[0]
940 }
941 }
942 TypeValue {
943 for alias in e.type_value_variant_aliases(info, value) {
944 if alias in info.variant_tags {
945 return info.variant_tags[alias]
946 }
947 }
948 }
949 else {}
950 }
951
952 if nested := e.infer_nested_sumtype_variant(info, value) {
953 return nested.tag
954 }
955 return none
956}
957
958fn (e &Eval) lookup_const_expr(module_name string, name string) ?ast.Expr {
959 if module_name !in e.consts {
960 return none
961 }
962 entry := e.consts[module_name][name] or { return none }
963 if entry.expr is ast.EmptyExpr {
964 return none
965 }
966 return entry.expr
967}
968
969fn (e &Eval) sumtype_variant_name_from_expr(expr ast.Expr) ?string {
970 return e.sumtype_variant_name_from_expr_with_depth(expr, 0)
971}
972
973fn (e &Eval) sumtype_variant_name_from_expr_with_depth(expr ast.Expr, depth int) ?string {
974 if depth > 8 {
975 return none
976 }
977 return match expr {
978 ast.ArrayInitExpr {
979 if expr.typ is ast.EmptyExpr {
980 none
981 } else {
982 e.type_expr_name(expr.typ)
983 }
984 }
985 ast.BasicLiteral {
986 match expr.kind {
987 .key_false, .key_true {
988 'bool'
989 }
990 .char {
991 'char'
992 }
993 .number {
994 if expr.value.contains('.') || expr.value.contains('e')
995 || expr.value.contains('E') {
996 'f64'
997 } else {
998 'int'
999 }
1000 }
1001 else {
1002 none
1003 }
1004 }
1005 }
1006 ast.CallOrCastExpr {
1007 if e.is_type_expr(expr.lhs) {
1008 e.type_expr_name(expr.lhs)
1009 } else {
1010 none
1011 }
1012 }
1013 ast.CastExpr {
1014 e.type_expr_name(expr.typ)
1015 }
1016 ast.InitExpr {
1017 e.type_expr_name(expr.typ)
1018 }
1019 ast.Ident {
1020 cur_module := e.current_module_name()
1021 if const_expr := e.lookup_const_expr(cur_module, expr.name) {
1022 e.sumtype_variant_name_from_expr_with_depth(const_expr, depth + 1)
1023 } else {
1024 if const_expr2 := e.lookup_const_expr('builtin', expr.name) {
1025 e.sumtype_variant_name_from_expr_with_depth(const_expr2, depth + 1)
1026 } else {
1027 none
1028 }
1029 }
1030 }
1031 ast.MapInitExpr {
1032 if expr.typ is ast.EmptyExpr {
1033 none
1034 } else {
1035 e.type_expr_name(expr.typ)
1036 }
1037 }
1038 ast.SelectorExpr {
1039 if expr.lhs is ast.Ident {
1040 module_name := e.resolve_module_name(expr.lhs.name)
1041 if module_name != '' {
1042 if const_expr := e.lookup_const_expr(module_name, expr.rhs.name) {
1043 e.sumtype_variant_name_from_expr_with_depth(const_expr, depth + 1)
1044 } else {
1045 none
1046 }
1047 } else {
1048 none
1049 }
1050 } else {
1051 none
1052 }
1053 }
1054 ast.StringInterLiteral, ast.StringLiteral {
1055 'string'
1056 }
1057 else {
1058 none
1059 }
1060 }
1061}
1062
1063fn (e &Eval) build_sumtype_wrapper(type_name string, info SumTypeInfo, tag int, payload Value) StructValue {
1064 mut data_fields := map[string]Value{}
1065 mut field_aliases := []string{}
1066 if tag in info.tag_field_aliases {
1067 field_aliases = info.tag_field_aliases[tag]
1068 }
1069 for field_alias in field_aliases {
1070 data_fields[field_alias] = payload
1071 }
1072 return StructValue{
1073 type_name: type_name
1074 fields: {
1075 '_tag': Value(i64(tag))
1076 '_data': Value(StructValue{
1077 type_name: '${type_name}._data'
1078 fields: data_fields
1079 })
1080 }
1081 }
1082}
1083
1084fn (e &Eval) wrap_sumtype_value(sum_type_name string, value Value, expr ast.Expr) !Value {
1085 if value is StructValue && value.type_name == sum_type_name && '_tag' in value.fields
1086 && '_data' in value.fields {
1087 return value
1088 }
1089 info := e.sum_type_info(sum_type_name) or {
1090 return error('v2.eval: unknown sum type `${sum_type_name}`')
1091 }
1092 if value is StructValue {
1093 if inferred := e.infer_bare_sumtype_variant(info, value) {
1094 payload := StructValue{
1095 type_name: inferred.variant_name
1096 fields: value.fields.clone()
1097 }
1098 return e.build_sumtype_wrapper(sum_type_name, info, inferred.tag, payload)
1099 }
1100 }
1101 if nested := e.infer_nested_sumtype_variant(info, value) {
1102 return e.build_sumtype_wrapper(sum_type_name, info, nested.tag, nested.payload)
1103 }
1104 if variant_name := e.sumtype_variant_name_from_expr(expr) {
1105 if tag := e.lookup_sumtype_variant_tag(info, variant_name) {
1106 return e.build_sumtype_wrapper(sum_type_name, info, tag, value)
1107 }
1108 }
1109 if tag := e.sumtype_tag_from_value(info, value) {
1110 return e.build_sumtype_wrapper(sum_type_name, info, tag, value)
1111 }
1112 return error('v2.eval: can not wrap `${e.runtime_type_name(value)}` into `${sum_type_name}` in `${e.current_function_label()}` stack `${e.call_stack_trace()}`')
1113}
1114
1115fn (e &Eval) unwrap_sumtype_value(sum_value StructValue, target_type string) ?Value {
1116 info := e.sum_type_info(sum_value.type_name) or { return none }
1117 tag_value := sum_value.fields['_tag'] or { return none }
1118 tag := int(e.value_as_int(tag_value) or { return none })
1119 target_tag := e.lookup_sumtype_variant_tag(info, target_type) or { return none }
1120 if tag != target_tag {
1121 return none
1122 }
1123 data_value := sum_value.fields['_data'] or { return none }
1124 if data_value !is StructValue {
1125 return none
1126 }
1127 data_struct := data_value as StructValue
1128 mut field_aliases := []string{}
1129 if tag in info.tag_field_aliases {
1130 field_aliases = info.tag_field_aliases[tag]
1131 }
1132 for field_alias in field_aliases {
1133 for key, payload in data_struct.fields {
1134 if key == field_alias {
1135 return payload
1136 }
1137 }
1138 }
1139 for _, payload in data_struct.fields {
1140 return payload
1141 }
1142 return none
1143}
1144
1145fn (e &Eval) current_module_name() string {
1146 if e.call_stack.len == 0 {
1147 return 'main'
1148 }
1149 return e.call_stack[e.call_stack.len - 1].module_name
1150}
1151
1152fn (e &Eval) current_file_name() string {
1153 if e.call_stack.len == 0 {
1154 return ''
1155 }
1156 return e.call_stack[e.call_stack.len - 1].file_name
1157}
1158
1159fn (e &Eval) current_function_label() string {
1160 if e.call_stack.len == 0 {
1161 return 'main.main'
1162 }
1163 frame := e.call_stack[e.call_stack.len - 1]
1164 return '${frame.module_name}.${frame.fn_name}'
1165}
1166
1167fn (e &Eval) call_stack_trace() string {
1168 if e.call_stack.len == 0 {
1169 return 'main.main'
1170 }
1171 return e.call_stack.map('${it.module_name}.${it.fn_name}').join(' <- ')
1172}
1173
1174fn (e &Eval) unknown_variable_error(name string) IError {
1175 return error('v2.eval: unknown variable `${name}` in `${e.current_function_label()}`')
1176}
1177
1178fn call_result_value(result CallResult) Value {
1179 return if result.values.len == 0 {
1180 void_value()
1181 } else if result.values.len == 1 {
1182 result.values[0]
1183 } else {
1184 TupleValue{
1185 values: result.values
1186 }
1187 }
1188}
1189
1190fn (mut e Eval) writeback_mut_args(arg_exprs []ast.Expr, result CallResult) ! {
1191 for idx, value in result.mut_args {
1192 if idx < 0 || idx >= arg_exprs.len {
1193 continue
1194 }
1195 if can_update_target(arg_exprs[idx]) {
1196 e.update_target(arg_exprs[idx], value)!
1197 }
1198 }
1199}
1200
1201fn (mut e Eval) call_function(module_name string, fn_name string, args []Value) !CallResult {
1202 if builtin_call_result := e.maybe_call_builtin_call_result(module_name, fn_name, args) {
1203 return builtin_call_result.result
1204 }
1205 builtin_result := e.maybe_call_builtin_function(module_name, fn_name, args)
1206 if builtin_result.found {
1207 return CallResult{
1208 values: [builtin_result.value]
1209 mut_args: map[int]Value{}
1210 }
1211 }
1212 if target := e.resolve_mangled_function_target(fn_name) {
1213 return e.call_function(target.module_name, target.fn_name, args)
1214 }
1215 if module_name !in e.functions {
1216 return error('v2.eval: unknown module `${module_name}`')
1217 }
1218 def := e.functions[module_name][fn_name] or {
1219 return error('v2.eval: unknown function `${module_name}.${fn_name}`')
1220 }
1221 e.call_stack << CallFrame{
1222 module_name: module_name
1223 file_name: def.file_name
1224 fn_name: fn_name
1225 }
1226 defer {
1227 e.call_stack.pop()
1228 }
1229 scope_start := e.scopes.len
1230 e.open_scope()
1231 defer {
1232 for e.scopes.len > scope_start {
1233 e.close_scope() or {}
1234 }
1235 }
1236 has_receiver_arg := def.decl.is_method && !def.decl.is_static
1237 expected_args := def.decl.typ.params.len + if has_receiver_arg { 1 } else { 0 }
1238 if expected_args != args.len {
1239 return error('v2.eval: `${module_name}.${fn_name}` expected ${expected_args} arguments, got ${args.len}')
1240 }
1241 arg_offset := if has_receiver_arg { 1 } else { 0 }
1242 if has_receiver_arg && def.decl.receiver.name != '' && def.decl.receiver.name != '_' {
1243 receiver_value := if def.decl.receiver.typ is ast.EmptyExpr {
1244 args[0]
1245 } else {
1246 e.adapt_value_to_type(args[0], def.decl.receiver.typ)
1247 }
1248 e.declare_var(def.decl.receiver.name, receiver_value)
1249 }
1250 for i, param in def.decl.typ.params {
1251 param_value := if param.typ is ast.EmptyExpr {
1252 args[i + arg_offset]
1253 } else {
1254 e.adapt_value_to_type(args[i + arg_offset], param.typ)
1255 }
1256 e.declare_var(param.name, param_value)
1257 }
1258 signal := e.exec_stmts(def.decl.stmts)!
1259 mut returned_values := []Value{}
1260 if signal.kind == .return_ {
1261 returned_values = signal.values.clone()
1262 } else if signal.kind == .goto_ {
1263 return error('v2.eval: unknown goto label `${signal.label}`')
1264 } else if signal.kind != .normal {
1265 return error('v2.eval: unexpected `${signal.kind}` escaped `${module_name}.${fn_name}`')
1266 }
1267 if def.decl.typ.return_type is ast.Type {
1268 match def.decl.typ.return_type {
1269 ast.OptionType {
1270 if returned_values.len == 1 && is_option_value(returned_values[0]) {
1271 return CallResult{
1272 values: [returned_values[0]]
1273 mut_args: map[int]Value{}
1274 }
1275 }
1276 if returned_values.len == 0
1277 || (returned_values.len == 1 && returned_values[0] is VoidValue) {
1278 return CallResult{
1279 values: [wrap_option_none()]
1280 mut_args: map[int]Value{}
1281 }
1282 }
1283 payload := if returned_values.len == 1 {
1284 e.adapt_value_to_type(returned_values[0], def.decl.typ.return_type.base_type)
1285 } else {
1286 Value(TupleValue{
1287 values: returned_values
1288 })
1289 }
1290 return CallResult{
1291 values: [wrap_option_ok(payload)]
1292 mut_args: map[int]Value{}
1293 }
1294 }
1295 ast.ResultType {
1296 if returned_values.len == 1 && is_result_value(returned_values[0]) {
1297 return CallResult{
1298 values: [returned_values[0]]
1299 mut_args: map[int]Value{}
1300 }
1301 }
1302 payload := if returned_values.len == 0 {
1303 void_value()
1304 } else if returned_values.len == 1 {
1305 e.adapt_value_to_type(returned_values[0], def.decl.typ.return_type.base_type)
1306 } else {
1307 Value(TupleValue{
1308 values: returned_values
1309 })
1310 }
1311 return CallResult{
1312 values: [wrap_result_ok(payload)]
1313 mut_args: map[int]Value{}
1314 }
1315 }
1316 else {}
1317 }
1318 }
1319 if returned_values.len == 1 && def.decl.typ.return_type !is ast.EmptyExpr {
1320 returned_values[0] = e.adapt_value_to_type(returned_values[0], def.decl.typ.return_type)
1321 }
1322 mut result := CallResult{
1323 values: returned_values
1324 mut_args: map[int]Value{}
1325 }
1326 if has_receiver_arg && def.decl.receiver.is_mut && def.decl.receiver.name != ''
1327 && def.decl.receiver.name != '_' {
1328 receiver_value := e.lookup_var(def.decl.receiver.name)
1329 if receiver_value.found {
1330 result.mut_args[0] = receiver_value.value
1331 }
1332 }
1333 for i, param in def.decl.typ.params {
1334 if !param.is_mut || param.name == '' || param.name == '_' {
1335 continue
1336 }
1337 param_value := e.lookup_var(param.name)
1338 if param_value.found {
1339 result.mut_args[i + arg_offset] = param_value.value
1340 }
1341 }
1342 return result
1343}
1344
1345fn (mut e Eval) maybe_call_builtin_call_result(module_name string, fn_name string, args []Value) ?MaybeCallResult {
1346 if module_name !in ['', 'builtin'] && !fn_name.starts_with('__Map_') {
1347 return none
1348 }
1349 if map_result := e.maybe_call_map_builtin_result(fn_name, args) {
1350 return map_result
1351 }
1352 return none
1353}
1354
1355fn builtin_map_helper_matches(fn_name string, suffix string) bool {
1356 return fn_name == 'map__${suffix}' || fn_name.ends_with('map__${suffix}')
1357 || (fn_name.starts_with('__Map_') && fn_name.ends_with('_${suffix}'))
1358}
1359
1360fn mut_call_result(value Value, index int, updated Value) CallResult {
1361 mut mut_args := map[int]Value{}
1362 mut_args[index] = updated
1363 return CallResult{
1364 values: [value]
1365 mut_args: mut_args
1366 }
1367}
1368
1369fn (mut e Eval) maybe_call_map_builtin_result(fn_name string, args []Value) ?MaybeCallResult {
1370 if args.len == 0 || args[0] !is MapValue {
1371 return none
1372 }
1373 receiver := args[0] as MapValue
1374 if builtin_map_helper_matches(fn_name, 'set') && args.len >= 3 {
1375 updated := e.map_set_value(receiver, args[1], args[2])
1376 return MaybeCallResult{
1377 found: true
1378 result: mut_call_result(void_value(), 0, updated)
1379 }
1380 }
1381 if builtin_map_helper_matches(fn_name, 'get') && args.len >= 3 {
1382 value, found := e.map_lookup(receiver, args[1])
1383 return MaybeCallResult{
1384 found: true
1385 result: CallResult{
1386 values: [if found { value } else { args[2] }]
1387 mut_args: map[int]Value{}
1388 }
1389 }
1390 }
1391 if builtin_map_helper_matches(fn_name, 'get_and_set') && args.len >= 3 {
1392 value, found := e.map_lookup(receiver, args[1])
1393 if found {
1394 return MaybeCallResult{
1395 found: true
1396 result: CallResult{
1397 values: [value]
1398 mut_args: map[int]Value{}
1399 }
1400 }
1401 }
1402 updated := e.map_set_value(receiver, args[1], args[2])
1403 return MaybeCallResult{
1404 found: true
1405 result: mut_call_result(args[2], 0, updated)
1406 }
1407 }
1408 if builtin_map_helper_matches(fn_name, 'exists') && args.len >= 2 {
1409 return MaybeCallResult{
1410 found: true
1411 result: CallResult{
1412 values: [e.map_contains_key(receiver, args[1])]
1413 mut_args: map[int]Value{}
1414 }
1415 }
1416 }
1417 if builtin_map_helper_matches(fn_name, 'delete') && args.len >= 2 {
1418 updated := e.map_delete_value(receiver, args[1])
1419 return MaybeCallResult{
1420 found: true
1421 result: mut_call_result(void_value(), 0, updated)
1422 }
1423 }
1424 if builtin_map_helper_matches(fn_name, 'keys') {
1425 return MaybeCallResult{
1426 found: true
1427 result: CallResult{
1428 values: [e.map_keys(receiver)]
1429 mut_args: map[int]Value{}
1430 }
1431 }
1432 }
1433 if builtin_map_helper_matches(fn_name, 'values') {
1434 return MaybeCallResult{
1435 found: true
1436 result: CallResult{
1437 values: [e.map_values(receiver)]
1438 mut_args: map[int]Value{}
1439 }
1440 }
1441 }
1442 if builtin_map_helper_matches(fn_name, 'clone') {
1443 return MaybeCallResult{
1444 found: true
1445 result: CallResult{
1446 values: [e.map_clone(receiver)]
1447 mut_args: map[int]Value{}
1448 }
1449 }
1450 }
1451 if builtin_map_helper_matches(fn_name, 'clear') {
1452 return MaybeCallResult{
1453 found: true
1454 result: mut_call_result(void_value(), 0, e.map_clear(receiver))
1455 }
1456 }
1457 if builtin_map_helper_matches(fn_name, 'move') {
1458 return MaybeCallResult{
1459 found: true
1460 result: mut_call_result(receiver, 0, e.map_clear(receiver))
1461 }
1462 }
1463 return none
1464}
1465
1466fn safe_arg(args []Value, idx int) Value {
1467 if idx < args.len {
1468 return args[idx]
1469 }
1470 return void_value()
1471}
1472
1473fn builtin_method_name(fn_name string) string {
1474 if !fn_name.contains('__') {
1475 return fn_name
1476 }
1477 return fn_name.all_after_last('__')
1478}
1479
1480fn builtin_receiver_name(fn_name string) string {
1481 if !fn_name.contains('__') {
1482 return ''
1483 }
1484 mut prefix := fn_name.all_before_last('__')
1485 if prefix.contains('__') {
1486 prefix = prefix.all_after_last('__')
1487 }
1488 return prefix
1489}
1490
1491fn (e &Eval) expect_token_arg(args []Value, index int) !token.Token {
1492 raw := e.value_as_int(safe_arg(args, index))!
1493 // Enum values are stored as ints in eval, so host-side token helpers need a narrow cast here.
1494 return unsafe { token.Token(int(raw)) }
1495}
1496
1497fn (e &Eval) expect_byte_arg(args []Value, index int) !u8 {
1498 raw := e.value_as_int(safe_arg(args, index))!
1499 return u8(raw)
1500}
1501
1502fn (e &Eval) infer_array_elem_type(values []Value) string {
1503 if values.len == 0 {
1504 return ''
1505 }
1506 return e.runtime_type_name(values[0])
1507}
1508
1509fn (e &Eval) array_elem_type_name(expr ast.Expr) string {
1510 return match expr {
1511 ast.Type {
1512 match expr {
1513 ast.ArrayType, ast.ArrayFixedType {
1514 e.type_expr_name(expr.elem_type)
1515 }
1516 else {
1517 ''
1518 }
1519 }
1520 }
1521 else {
1522 type_name := e.type_expr_name(expr)
1523 if type_name.starts_with('[]') {
1524 type_name[2..]
1525 } else if type_name.starts_with('[') && type_name.contains(']') {
1526 type_name.all_after(']')
1527 } else {
1528 ''
1529 }
1530 }
1531 }
1532}
1533
1534fn (e &Eval) annotate_value_for_type(value Value, typ ast.Expr) Value {
1535 match value {
1536 ArrayValue {
1537 elem_type_name := if value.elem_type_name != '' {
1538 value.elem_type_name
1539 } else {
1540 e.array_elem_type_name(typ)
1541 }
1542 return ArrayValue{
1543 elem_type_name: elem_type_name
1544 values: value.values
1545 }
1546 }
1547 else {
1548 return value
1549 }
1550 }
1551}
1552
1553fn (e &Eval) is_existing_sumtype_wrapper(value Value, target_name string) bool {
1554 return match value {
1555 StructValue {
1556 e.type_name_matches(value.type_name, target_name)
1557 }
1558 else {
1559 false
1560 }
1561 }
1562}
1563
1564fn (e &Eval) adapt_value_to_type_name(value Value, type_name string) Value {
1565 if type_name == '' {
1566 return value
1567 }
1568 if type_name.starts_with('?') {
1569 if is_option_value(value) {
1570 return value
1571 }
1572 if value is VoidValue {
1573 return wrap_option_none()
1574 }
1575 return wrap_option_ok(e.adapt_value_to_type_name(value, type_name[1..]))
1576 }
1577 if type_name.starts_with('!') {
1578 if is_result_value(value) {
1579 return value
1580 }
1581 return wrap_result_ok(e.adapt_value_to_type_name(value, type_name[1..]))
1582 }
1583 if type_name.starts_with('[]') && value is ArrayValue {
1584 array_value := value as ArrayValue
1585 return ArrayValue{
1586 elem_type_name: e.qualify_type_name(e.current_module_name(), type_name[2..])
1587 values: array_value.values
1588 }
1589 }
1590 if e.is_sum_type_name(type_name) {
1591 if e.is_existing_sumtype_wrapper(value, type_name) {
1592 return value
1593 }
1594 return e.cast_value(value, type_name) or { value }
1595 }
1596 match type_name {
1597 'bool' {
1598 return e.value_as_bool(value) or { return value }
1599 }
1600 'byte', 'char', 'i8', 'i16', 'i32', 'int', 'i64', 'isize', 'rune', 'u8', 'u16', 'u32',
1601 'u64', 'usize' {
1602 return e.value_as_int(value) or { return value }
1603 }
1604 'f32', 'f64' {
1605 return e.value_as_f64(value) or { return value }
1606 }
1607 'string' {
1608 return e.value_string(value)
1609 }
1610 else {
1611 if value is StructValue {
1612 return e.cast_value(value, type_name) or { Value(value) }
1613 }
1614 return value
1615 }
1616 }
1617}
1618
1619fn (e &Eval) adapt_value_to_type(value Value, typ ast.Expr) Value {
1620 adapted := e.annotate_value_for_type(value, typ)
1621 if typ is ast.Type {
1622 match typ {
1623 ast.OptionType {
1624 if is_option_value(adapted) {
1625 return adapted
1626 }
1627 if adapted is VoidValue {
1628 return wrap_option_none()
1629 }
1630 return wrap_option_ok(e.adapt_value_to_type(adapted, typ.base_type))
1631 }
1632 ast.ResultType {
1633 if is_result_value(adapted) {
1634 return adapted
1635 }
1636 return wrap_result_ok(e.adapt_value_to_type(adapted, typ.base_type))
1637 }
1638 else {}
1639 }
1640 }
1641 target_name := e.type_expr_name(typ)
1642 if target_name != '' && e.is_sum_type_name(target_name) {
1643 if e.is_existing_sumtype_wrapper(adapted, target_name) {
1644 return adapted
1645 }
1646 return e.cast_value(adapted, target_name) or { adapted }
1647 }
1648 return adapted
1649}
1650
1651fn (e &Eval) should_append_many(container ArrayValue, value ArrayValue) bool {
1652 if container.elem_type_name != '' && value.elem_type_name != '' {
1653 return container.elem_type_name == value.elem_type_name
1654 }
1655 if container.elem_type_name != '' && value.values.len > 0 {
1656 return container.elem_type_name == e.runtime_type_name(value.values[0])
1657 }
1658 if container.values.len > 0 && value.values.len > 0 {
1659 return e.runtime_type_name(container.values[0]) == e.runtime_type_name(value.values[0])
1660 }
1661 return false
1662}
1663
1664fn (e &Eval) inferred_sumtype_tag(value Value) ?int {
1665 mut matches := map[string]int{}
1666 for _, info in e.sum_types {
1667 if tag := e.sumtype_tag_from_value(info, value) {
1668 key := '${info.module_name}.${info.name}:${tag}'
1669 matches[key] = tag
1670 }
1671 }
1672 if matches.len != 1 {
1673 return none
1674 }
1675 for _, tag in matches {
1676 return tag
1677 }
1678 return none
1679}
1680
1681fn (mut e Eval) contextual_sumtype_tag(target_expr ast.Expr, value Value) ?int {
1682 match target_expr {
1683 ast.SelectorExpr {
1684 base := e.eval_expr(target_expr.lhs) or { return none }
1685 if base is StructValue {
1686 if field_type := e.lookup_struct_field_type(base.type_name, target_expr.rhs.name) {
1687 target_name := e.type_expr_name(field_type)
1688 if info := e.sum_type_info(target_name) {
1689 return e.sumtype_tag_from_value(info, value)
1690 }
1691 }
1692 }
1693 }
1694 ast.IndexExpr {
1695 container := e.eval_expr(target_expr.lhs) or { return none }
1696 match container {
1697 ArrayValue {
1698 if info := e.sum_type_info(container.elem_type_name) {
1699 return e.sumtype_tag_from_value(info, value)
1700 }
1701 }
1702 MapValue {
1703 if container.default_value is StructValue {
1704 default_value := container.default_value as StructValue
1705 if info := e.sum_type_info(default_value.type_name) {
1706 return e.sumtype_tag_from_value(info, value)
1707 }
1708 }
1709 }
1710 else {}
1711 }
1712 }
1713 else {}
1714 }
1715
1716 return none
1717}
1718
1719fn eval_token_method_value(tok token.Token, method_name string) ?Value {
1720 return match method_name {
1721 'str' { Value(tok.str()) }
1722 'left_binding_power' { Value(i64(int(tok.left_binding_power()))) }
1723 'right_binding_power' { Value(i64(int(tok.right_binding_power()))) }
1724 'is_keyword' { Value(tok.is_keyword()) }
1725 'is_prefix' { Value(tok.is_prefix()) }
1726 'is_infix' { Value(tok.is_infix()) }
1727 'is_postfix' { Value(tok.is_postfix()) }
1728 'is_assignment' { Value(tok.is_assignment()) }
1729 'is_overloadable' { Value(tok.is_overloadable()) }
1730 'is_comparison' { Value(tok.is_comparison()) }
1731 else { none }
1732 }
1733}
1734
1735fn eval_byte_method_value(c u8, method_name string) ?Value {
1736 return match method_name {
1737 'is_space' {
1738 Value(c == 32 || (c > 8 && c < 14) || c == 0x85 || c == 0xa0)
1739 }
1740 'is_digit' {
1741 Value(c >= `0` && c <= `9`)
1742 }
1743 'is_hex_digit' {
1744 Value((c >= `0` && c <= `9`) || (c >= `a` && c <= `f`) || (c >= `A` && c <= `F`))
1745 }
1746 'is_oct_digit' {
1747 Value(c >= `0` && c <= `7`)
1748 }
1749 'is_bin_digit' {
1750 Value(c == `0` || c == `1`)
1751 }
1752 'is_letter' {
1753 Value((c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`))
1754 }
1755 'is_alnum' {
1756 Value((c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`) || (c >= `0` && c <= `9`))
1757 }
1758 'is_capital' {
1759 Value(c >= `A` && c <= `Z`)
1760 }
1761 else {
1762 none
1763 }
1764 }
1765}
1766
1767fn (e &Eval) maybe_call_token_builtin(fn_name string, args []Value) MaybeValue {
1768 method_name := builtin_method_name(fn_name)
1769 receiver_name := builtin_receiver_name(fn_name)
1770 if receiver_name == 'Token' {
1771 tok := e.expect_token_arg(args, 0) or { return MaybeValue{} }
1772 if value := eval_token_method_value(tok, method_name) {
1773 return MaybeValue{
1774 found: true
1775 value: value
1776 }
1777 }
1778 return MaybeValue{}
1779 }
1780 if method_name == 'from_string_tinyv' && receiver_name in ['', 'Token'] {
1781 name := e.expect_string_arg(args, args.len - 1) or { return MaybeValue{} }
1782 return MaybeValue{
1783 found: true
1784 value: i64(int(token.Token.from_string_tinyv(name)))
1785 }
1786 }
1787 return MaybeValue{}
1788}
1789
1790fn (e &Eval) maybe_call_ast_builtin(fn_name string, args []Value) MaybeValue {
1791 method_name := builtin_method_name(fn_name)
1792 receiver_name := builtin_receiver_name(fn_name)
1793 if receiver_name in ['', 'StringLiteralKind'] {
1794 match method_name {
1795 'str' {
1796 raw := e.value_as_int(safe_arg(args, 0)) or { return MaybeValue{} }
1797 // StringLiteralKind is stored as an int in eval and only used with known enum values here.
1798 kind := unsafe { ast.StringLiteralKind(int(raw)) }
1799 return MaybeValue{
1800 found: true
1801 value: kind.str()
1802 }
1803 }
1804 'from_string_tinyv' {
1805 name := e.expect_string_arg(args, args.len - 1) or { return MaybeValue{} }
1806 return MaybeValue{
1807 found: true
1808 value: i64(int(ast.StringLiteralKind.from_string_tinyv(name)))
1809 }
1810 }
1811 else {}
1812 }
1813 }
1814 return MaybeValue{}
1815}
1816
1817fn (e &Eval) maybe_call_byte_builtin(module_name string, fn_name string, args []Value) MaybeValue {
1818 if module_name !in ['', 'builtin'] {
1819 return MaybeValue{}
1820 }
1821 receiver_name := builtin_receiver_name(fn_name)
1822 if receiver_name !in ['u8', 'byte'] {
1823 return MaybeValue{}
1824 }
1825 c := e.expect_byte_arg(args, 0) or { return MaybeValue{} }
1826 if value := eval_byte_method_value(c, builtin_method_name(fn_name)) {
1827 return MaybeValue{
1828 found: true
1829 value: value
1830 }
1831 }
1832 return MaybeValue{}
1833}
1834
1835fn is_semantically_empty_value(value Value) bool {
1836 return match value {
1837 VoidValue {
1838 true
1839 }
1840 StructValue {
1841 for field_value in value.fields.values() {
1842 if !is_semantically_empty_value(field_value) {
1843 return false
1844 }
1845 }
1846 true
1847 }
1848 else {
1849 false
1850 }
1851 }
1852}
1853
1854fn (e &Eval) type_sum_data_is_nil(value Value) bool {
1855 match value {
1856 StructValue {
1857 if '_data' !in value.fields {
1858 return false
1859 }
1860 data_value := value.fields['_data'] or { return false }
1861 return is_semantically_empty_value(data_value)
1862 }
1863 TypeValue {
1864 return false
1865 }
1866 else {
1867 return is_semantically_empty_value(value)
1868 }
1869 }
1870}
1871
1872fn has_flag_bit(bits i64, flag i64) bool {
1873 return (bits & flag) != 0
1874}
1875
1876fn (e &Eval) primitive_type_name(value StructValue) string {
1877 props := e.value_as_int(value.fields['props'] or { Value(i64(0)) }) or { 0 }
1878 size := e.value_as_int(value.fields['size'] or { Value(i64(0)) }) or { 0 }
1879 if has_flag_bit(props, 1) {
1880 return 'bool'
1881 }
1882 if has_flag_bit(props, 16) {
1883 if has_flag_bit(props, 4) {
1884 return 'int_literal'
1885 }
1886 if has_flag_bit(props, 2) {
1887 return 'float_literal'
1888 }
1889 }
1890 if has_flag_bit(props, 2) {
1891 return if size == 32 { 'f32' } else { 'f64' }
1892 }
1893 if has_flag_bit(props, 4) {
1894 if has_flag_bit(props, 8) {
1895 return match size {
1896 8 { 'u8' }
1897 16 { 'u16' }
1898 32 { 'u32' }
1899 64 { 'u64' }
1900 else { 'u64' }
1901 }
1902 }
1903 return match size {
1904 8 { 'i8' }
1905 16 { 'i16' }
1906 32 { 'i32' }
1907 64 { 'i64' }
1908 else { 'int' }
1909 }
1910 }
1911 return 'int'
1912}
1913
1914fn (e &Eval) option_payload_type_name(value Value) string {
1915 if !is_option_value(value) || value !is StructValue {
1916 return ''
1917 }
1918 option_value := value as StructValue
1919 state := e.value_as_int(option_value.fields['state'] or { Value(i64(1)) }) or { 1 }
1920 if state != 0 {
1921 return ''
1922 }
1923 return e.types_value_name(option_value.fields['data'] or { return '' })
1924}
1925
1926fn (e &Eval) tuple_type_name(value StructValue) string {
1927 if types_value := value.fields['types'] {
1928 if types_value is ArrayValue {
1929 return '(' + types_value.values.map(e.types_value_name(it)).join(',') + ')'
1930 }
1931 }
1932 return '()'
1933}
1934
1935fn (e &Eval) sumtype_payload_name(value StructValue) string {
1936 data_value := value.fields['_data'] or { return 'void' }
1937 if data_value is StructValue {
1938 data_struct := data_value as StructValue
1939 if tag_value := value.fields['_tag'] {
1940 tag := int(e.value_as_int(tag_value) or { -1 })
1941 if info := e.sum_type_info(value.type_name) {
1942 if field_aliases := info.tag_field_aliases[tag] {
1943 for field_alias in field_aliases {
1944 if payload := data_struct.fields[field_alias] {
1945 return e.types_value_name(payload)
1946 }
1947 }
1948 }
1949 }
1950 }
1951 for payload in data_struct.fields.values() {
1952 if !is_semantically_empty_value(payload) {
1953 return e.types_value_name(payload)
1954 }
1955 }
1956 for payload in data_struct.fields.values() {
1957 return e.types_value_name(payload)
1958 }
1959 }
1960 return 'void'
1961}
1962
1963fn (e &Eval) types_value_name(value Value) string {
1964 return match value {
1965 StructValue {
1966 mut short_name := value.type_name.all_after_last('.')
1967 if short_name.contains('__') {
1968 short_name = short_name.all_after_last('__')
1969 }
1970 match short_name {
1971 'Type' {
1972 e.sumtype_payload_name(value)
1973 }
1974 'Primitive' {
1975 e.primitive_type_name(value)
1976 }
1977 'Alias' {
1978 name_value := value.fields['name'] or { Value('') }
1979 name := e.value_string(name_value)
1980 if name != '' {
1981 name
1982 } else if base_type := value.fields['base_type'] {
1983 e.types_value_name(base_type)
1984 } else {
1985 'alias'
1986 }
1987 }
1988 'Array' {
1989 elem_type := value.fields['elem_type'] or { return '[]void' }
1990 '[]' + e.types_value_name(elem_type)
1991 }
1992 'ArrayFixed' {
1993 len_value := value.fields['len'] or { return '[0]void' }
1994 elem_type := value.fields['elem_type'] or { return '[0]void' }
1995 '[${e.value_as_int(len_value) or { 0 }}]${e.types_value_name(elem_type)}'
1996 }
1997 'Channel' {
1998 elem_type_name := e.option_payload_type_name(value.fields['elem_type'] or {
1999 return 'chan'
2000 })
2001 if elem_type_name == '' {
2002 'chan'
2003 } else {
2004 'chan ${elem_type_name}'
2005 }
2006 }
2007 'Char' {
2008 'char'
2009 }
2010 'Enum', 'Interface', 'Struct', 'SumType' {
2011 e.value_string(value.fields['name'] or { Value(short_name.to_lower()) })
2012 }
2013 'FnType' {
2014 'fn'
2015 }
2016 'ISize' {
2017 'isize'
2018 }
2019 'Map' {
2020 key_type := value.fields['key_type'] or { return 'map[void]void' }
2021 value_type := value.fields['value_type'] or { return 'map[void]void' }
2022 'map[${e.types_value_name(key_type)}]${e.types_value_name(value_type)}'
2023 }
2024 'None' {
2025 'none'
2026 }
2027 'OptionType' {
2028 base_type := value.fields['base_type'] or { return '?void' }
2029 '?' + e.types_value_name(base_type)
2030 }
2031 'Pointer' {
2032 base_type := value.fields['base_type'] or { return '&void' }
2033 '&' + e.types_value_name(base_type)
2034 }
2035 'ResultType' {
2036 base_type := value.fields['base_type'] or { return '!void' }
2037 '!' + e.types_value_name(base_type)
2038 }
2039 'Rune' {
2040 'rune'
2041 }
2042 'String' {
2043 'string'
2044 }
2045 'Thread' {
2046 elem_type_name := e.option_payload_type_name(value.fields['elem_type'] or {
2047 return 'thread'
2048 })
2049 if elem_type_name == '' {
2050 'thread'
2051 } else {
2052 'thread ${elem_type_name}'
2053 }
2054 }
2055 'Tuple' {
2056 e.tuple_type_name(value)
2057 }
2058 'USize' {
2059 'usize'
2060 }
2061 'Void' {
2062 'void'
2063 }
2064 'Nil' {
2065 'nil'
2066 }
2067 else {
2068 e.value_string(value.fields['name'] or { Value(short_name) })
2069 }
2070 }
2071 }
2072 TypeValue {
2073 mut short_name := value.name.all_after_last('.')
2074 if short_name.contains('__') {
2075 short_name = short_name.all_after_last('__')
2076 }
2077 short_name
2078 }
2079 else {
2080 e.runtime_type_name(value)
2081 }
2082 }
2083}
2084
2085fn (mut e Eval) maybe_call_builtin_function(module_name string, fn_name string, args []Value) MaybeValue {
2086 if fn_name == 'free' || fn_name.ends_with('__free') {
2087 return MaybeValue{
2088 found: true
2089 value: void_value()
2090 }
2091 }
2092 if fn_name == 'type_data_ptr_is_nil' || fn_name.ends_with('__type_data_ptr_is_nil')
2093 || fn_name == 'type_has_null_data' || fn_name.ends_with('__type_has_null_data') {
2094 return MaybeValue{
2095 found: true
2096 value: e.type_sum_data_is_nil(safe_arg(args, 0))
2097 }
2098 }
2099 if module_name == 'types'
2100 && (fn_name == 'type_name' || fn_name == 'Type__name' || fn_name.ends_with('Type__name')) {
2101 return MaybeValue{
2102 found: true
2103 value: e.types_value_name(safe_arg(args, 0))
2104 }
2105 }
2106 if fn_name == 'map__get_check' || fn_name.ends_with('map__get_check')
2107 || (fn_name.starts_with('__Map_') && fn_name.ends_with('_get_check')) {
2108 if args.len >= 2 && args[0] is MapValue {
2109 map_value := args[0] as MapValue
2110 value, found := e.map_lookup(map_value, args[1])
2111 return MaybeValue{
2112 found: true
2113 value: if found { value } else { void_value() }
2114 }
2115 }
2116 }
2117 if fn_name in ['sync__RwMutex_lock', 'sync__RwMutex_unlock', 'sync__RwMutex_rlock', 'sync__RwMutex_runlock']
2118 || fn_name.ends_with('RwMutex_lock') || fn_name.ends_with('RwMutex_unlock')
2119 || fn_name.ends_with('RwMutex_rlock') || fn_name.ends_with('RwMutex_runlock') {
2120 return MaybeValue{
2121 found: true
2122 value: void_value()
2123 }
2124 }
2125 if module_name == 'token' {
2126 token_result := e.maybe_call_token_builtin(fn_name, args)
2127 if token_result.found {
2128 return token_result
2129 }
2130 }
2131 if module_name == 'ast' {
2132 ast_result := e.maybe_call_ast_builtin(fn_name, args)
2133 if ast_result.found {
2134 return ast_result
2135 }
2136 }
2137 if fn_name.ends_with('__str') && args.len == 1 {
2138 return MaybeValue{
2139 found: true
2140 value: e.value_string(args[0])
2141 }
2142 }
2143 if fn_name.ends_with('__eq') && args.len == 2 {
2144 return MaybeValue{
2145 found: true
2146 value: e.value_eq(args[0], args[1])
2147 }
2148 }
2149 if fn_name.starts_with('string__') && args.len >= 1 {
2150 receiver := e.value_string(args[0])
2151 method_name := fn_name.all_after('string__')
2152 if result := e.call_string_method(receiver, method_name, args[1..]) {
2153 return MaybeValue{
2154 found: true
2155 value: result
2156 }
2157 }
2158 }
2159 if array_helper := e.maybe_call_generated_array_helper(fn_name, args) {
2160 return array_helper
2161 }
2162 byte_result := e.maybe_call_byte_builtin(module_name, fn_name, args)
2163 if byte_result.found {
2164 return byte_result
2165 }
2166 if fn_name in ['builtin__new_array_from_c_array_noscan', 'builtin__new_array_from_c_array', 'new_array_from_c_array_noscan', 'new_array_from_c_array']
2167 && args.len >= 4 {
2168 mut values := []Value{}
2169 if args[3] is ArrayValue {
2170 array_arg := args[3] as ArrayValue
2171 values = array_arg.values.clone()
2172 } else if args[3] is string {
2173 string_arg := args[3] as string
2174 for b in string_arg.bytes() {
2175 values << i64(b)
2176 }
2177 }
2178 target_len := int(e.value_as_int(args[0]) or { values.len })
2179 if target_len >= 0 && target_len < values.len {
2180 values = values[..target_len].clone()
2181 }
2182 return MaybeValue{
2183 found: true
2184 value: ArrayValue{
2185 values: values
2186 }
2187 }
2188 }
2189 if fn_name == '__new_array_with_default_noscan' && args.len >= 4 {
2190 target_len := int(e.value_as_int(args[0]) or { 0 })
2191 init_value := args[3]
2192 mut values := []Value{cap: target_len}
2193 for _ in 0 .. target_len {
2194 values << init_value
2195 }
2196 return MaybeValue{
2197 found: true
2198 value: ArrayValue{
2199 values: values
2200 }
2201 }
2202 }
2203 if module_name in ['', 'builtin'] {
2204 match fn_name {
2205 'arguments' {
2206 return MaybeValue{
2207 found: true
2208 value: ArrayValue{
2209 values: e.program_args().map(Value(it))
2210 }
2211 }
2212 }
2213 'array__slice' {
2214 if args.len < 3 || args[0] !is ArrayValue {
2215 return MaybeValue{}
2216 }
2217 arr := args[0] as ArrayValue
2218 start := int(e.value_as_int(args[1]) or { return MaybeValue{} })
2219 end := int(e.value_as_int(args[2]) or { return MaybeValue{} })
2220 return MaybeValue{
2221 found: true
2222 value: ArrayValue{
2223 values: arr.values[start..end]
2224 }
2225 }
2226 }
2227 'print' {
2228 e.write_stdout(e.value_string(safe_arg(args, 0)))
2229 return MaybeValue{
2230 found: true
2231 value: void_value()
2232 }
2233 }
2234 'println' {
2235 e.write_stdout(e.value_string(safe_arg(args, 0)) + '\n')
2236 return MaybeValue{
2237 found: true
2238 value: void_value()
2239 }
2240 }
2241 'eprint' {
2242 e.write_stderr(e.value_string(safe_arg(args, 0)))
2243 return MaybeValue{
2244 found: true
2245 value: void_value()
2246 }
2247 }
2248 'eprintln' {
2249 e.write_stderr(e.value_string(safe_arg(args, 0)) + '\n')
2250 return MaybeValue{
2251 found: true
2252 value: void_value()
2253 }
2254 }
2255 'panic' {
2256 panic(e.value_string(safe_arg(args, 0)))
2257 }
2258 else {}
2259 }
2260 }
2261 if module_name == 'token' && fn_name.ends_with('File__pos') && args.len >= 2 {
2262 offset := e.value_as_int(args[1]) or { return MaybeValue{} }
2263 mut base := i64(0)
2264 mut size := i64(0)
2265 if args[0] is StructValue {
2266 file := args[0] as StructValue
2267 if base_value := file.fields['base'] {
2268 base = e.value_as_int(base_value) or { 0 }
2269 }
2270 if size_value := file.fields['size'] {
2271 size = e.value_as_int(size_value) or { 0 }
2272 }
2273 }
2274 if offset > size {
2275 return MaybeValue{}
2276 }
2277 e.next_token_pos_id++
2278 return MaybeValue{
2279 found: true
2280 value: StructValue{
2281 type_name: 'token__Pos'
2282 fields: {
2283 'offset': Value(base + offset)
2284 'id': Value(e.next_token_pos_id)
2285 }
2286 }
2287 }
2288 }
2289 if module_name == 'os' {
2290 match fn_name {
2291 'execute' {
2292 cmd := e.expect_string_arg(args, 0) or { return MaybeValue{} }
2293 return MaybeValue{
2294 found: true
2295 value: os_result_value(os.execute(cmd))
2296 }
2297 }
2298 'execute_opt' {
2299 cmd := e.expect_string_arg(args, 0) or { return MaybeValue{} }
2300 res := os.execute(cmd)
2301 if res.exit_code != 0 {
2302 return MaybeValue{
2303 found: true
2304 value: wrap_result_err(res.output)
2305 }
2306 }
2307 return MaybeValue{
2308 found: true
2309 value: wrap_result_ok(os_result_value(res))
2310 }
2311 }
2312 'arguments' {
2313 return MaybeValue{
2314 found: true
2315 value: ArrayValue{
2316 values: e.program_args().map(Value(it))
2317 }
2318 }
2319 }
2320 'dir' {
2321 return MaybeValue{
2322 found: true
2323 value: os.dir(e.expect_string_arg(args, 0) or { return MaybeValue{} })
2324 }
2325 }
2326 'file_name' {
2327 return MaybeValue{
2328 found: true
2329 value: os.file_name(e.expect_string_arg(args, 0) or { return MaybeValue{} })
2330 }
2331 }
2332 'join_path' {
2333 mut parts := e.array_args_to_strings(args)
2334 if parts.len == 0 {
2335 return MaybeValue{
2336 found: true
2337 value: ''
2338 }
2339 }
2340 mut joined := parts[0]
2341 for part in parts[1..] {
2342 joined = os.join_path(joined, part)
2343 }
2344 return MaybeValue{
2345 found: true
2346 value: joined
2347 }
2348 }
2349 'exists' {
2350 return MaybeValue{
2351 found: true
2352 value: os.exists(e.expect_string_arg(args, 0) or { return MaybeValue{} })
2353 }
2354 }
2355 'is_dir' {
2356 return MaybeValue{
2357 found: true
2358 value: os.is_dir(e.expect_string_arg(args, 0) or { return MaybeValue{} })
2359 }
2360 }
2361 'getwd' {
2362 return MaybeValue{
2363 found: true
2364 value: os.getwd()
2365 }
2366 }
2367 'temp_dir' {
2368 return MaybeValue{
2369 found: true
2370 value: os.temp_dir()
2371 }
2372 }
2373 'getenv' {
2374 return MaybeValue{
2375 found: true
2376 value: os.getenv(e.expect_string_arg(args, 0) or { return MaybeValue{} })
2377 }
2378 }
2379 'getenv_opt' {
2380 key := e.expect_string_arg(args, 0) or { return MaybeValue{} }
2381 if value := os.getenv_opt(key) {
2382 return MaybeValue{
2383 found: true
2384 value: wrap_option_ok(value)
2385 }
2386 }
2387 return MaybeValue{
2388 found: true
2389 value: wrap_option_none()
2390 }
2391 }
2392 'is_abs_path' {
2393 return MaybeValue{
2394 found: true
2395 value: os.is_abs_path(e.expect_string_arg(args, 0) or { return MaybeValue{} })
2396 }
2397 }
2398 'norm_path' {
2399 return MaybeValue{
2400 found: true
2401 value: os.norm_path(e.expect_string_arg(args, 0) or { return MaybeValue{} })
2402 }
2403 }
2404 'real_path' {
2405 return MaybeValue{
2406 found: true
2407 value: os.real_path(e.expect_string_arg(args, 0) or { return MaybeValue{} })
2408 }
2409 }
2410 'quoted_path' {
2411 return MaybeValue{
2412 found: true
2413 value: os.quoted_path(e.expect_string_arg(args, 0) or { return MaybeValue{} })
2414 }
2415 }
2416 'base' {
2417 return MaybeValue{
2418 found: true
2419 value: os.base(e.expect_string_arg(args, 0) or { return MaybeValue{} })
2420 }
2421 }
2422 'user_os' {
2423 return MaybeValue{
2424 found: true
2425 value: os.user_os()
2426 }
2427 }
2428 'ls' {
2429 path := e.expect_string_arg(args, 0) or { return MaybeValue{} }
2430 if path == '' {
2431 return MaybeValue{
2432 found: true
2433 value: wrap_result_err('os.ls empty path in `${e.current_function_label()}` stack `${e.call_stack_trace()}`')
2434 }
2435 }
2436 items := os.ls(path) or {
2437 return MaybeValue{
2438 found: true
2439 value: wrap_result_err(err.msg())
2440 }
2441 }
2442 return MaybeValue{
2443 found: true
2444 value: wrap_result_ok(ArrayValue{
2445 values: items.map(Value(it))
2446 })
2447 }
2448 }
2449 'read_file' {
2450 path := e.expect_string_arg(args, 0) or { return MaybeValue{} }
2451 if path == '' {
2452 return MaybeValue{
2453 found: true
2454 value: wrap_result_err('os.read_file empty path in `${e.current_function_label()}` stack `${e.call_stack_trace()}`')
2455 }
2456 }
2457 content := os.read_file(path) or {
2458 return MaybeValue{
2459 found: true
2460 value: wrap_result_err(err.msg())
2461 }
2462 }
2463 return MaybeValue{
2464 found: true
2465 value: wrap_result_ok(content)
2466 }
2467 }
2468 'read_lines' {
2469 path := e.expect_string_arg(args, 0) or { return MaybeValue{} }
2470 lines := os.read_lines(path) or {
2471 return MaybeValue{
2472 found: true
2473 value: wrap_result_err(err.msg())
2474 }
2475 }
2476 return MaybeValue{
2477 found: true
2478 value: wrap_result_ok(ArrayValue{
2479 elem_type_name: 'string'
2480 values: lines.map(Value(it))
2481 })
2482 }
2483 }
2484 'read_bytes' {
2485 path := e.expect_string_arg(args, 0) or { return MaybeValue{} }
2486 bytes := os.read_bytes(path) or {
2487 return MaybeValue{
2488 found: true
2489 value: wrap_result_err(err.msg())
2490 }
2491 }
2492 return MaybeValue{
2493 found: true
2494 value: wrap_result_ok(ArrayValue{
2495 elem_type_name: 'u8'
2496 values: bytes.map(Value(i64(it)))
2497 })
2498 }
2499 }
2500 'write_file' {
2501 os.write_file(e.expect_string_arg(args, 0) or { return MaybeValue{} }, e.expect_string_arg(args,
2502 1) or { return MaybeValue{} }) or {
2503 return MaybeValue{
2504 found: true
2505 value: wrap_result_err(err.msg())
2506 }
2507 }
2508 return MaybeValue{
2509 found: true
2510 value: wrap_result_ok(void_value())
2511 }
2512 }
2513 'write_file_array' {
2514 path := e.expect_string_arg(args, 0) or { return MaybeValue{} }
2515 bytes := e.value_to_byte_array(safe_arg(args, 1)) or { return MaybeValue{} }
2516 os.write_file_array(path, bytes) or {
2517 return MaybeValue{
2518 found: true
2519 value: wrap_result_err(err.msg())
2520 }
2521 }
2522 return MaybeValue{
2523 found: true
2524 value: wrap_result_ok(void_value())
2525 }
2526 }
2527 'mkdir_all' {
2528 path := e.expect_string_arg(args, 0) or { return MaybeValue{} }
2529 os.mkdir_all(path) or {
2530 return MaybeValue{
2531 found: true
2532 value: wrap_result_err(err.msg())
2533 }
2534 }
2535 return MaybeValue{
2536 found: true
2537 value: wrap_result_ok(void_value())
2538 }
2539 }
2540 'rmdir_all' {
2541 path := e.expect_string_arg(args, 0) or { return MaybeValue{} }
2542 os.rmdir_all(path) or {
2543 return MaybeValue{
2544 found: true
2545 value: wrap_result_err(err.msg())
2546 }
2547 }
2548 return MaybeValue{
2549 found: true
2550 value: wrap_result_ok(void_value())
2551 }
2552 }
2553 'rm' {
2554 os.rm(e.expect_string_arg(args, 0) or { return MaybeValue{} }) or {
2555 return MaybeValue{
2556 found: true
2557 value: wrap_result_err(err.msg())
2558 }
2559 }
2560 return MaybeValue{
2561 found: true
2562 value: wrap_result_ok(void_value())
2563 }
2564 }
2565 'cp' {
2566 os.cp(e.expect_string_arg(args, 0) or { return MaybeValue{} }, e.expect_string_arg(args,
2567 1) or { return MaybeValue{} }) or {
2568 return MaybeValue{
2569 found: true
2570 value: wrap_result_err(err.msg())
2571 }
2572 }
2573 return MaybeValue{
2574 found: true
2575 value: wrap_result_ok(void_value())
2576 }
2577 }
2578 else {}
2579 }
2580 }
2581 if module_name == 'time' {
2582 match fn_name {
2583 'sys_mono_now', 'sys_mono_now_darwin', 'vpc_now', 'vpc_now_darwin' {
2584 return MaybeValue{
2585 found: true
2586 value: i64(time.now().unix_micro() * 1000)
2587 }
2588 }
2589 else {}
2590 }
2591 }
2592 if module_name == 'token' {
2593 match fn_name {
2594 'File__line_start', 'line_start' {
2595 if args.len < 2 || args[0] !is StructValue {
2596 return MaybeValue{}
2597 }
2598 file_value := args[0] as StructValue
2599 line := int(e.value_as_int(args[1]) or { return MaybeValue{} })
2600 if line <= 0 {
2601 return MaybeValue{
2602 found: true
2603 value: i64(0)
2604 }
2605 }
2606 line_offsets := file_value.fields['line_offsets'] or { return MaybeValue{} }
2607 if line_offsets !is ArrayValue {
2608 return MaybeValue{}
2609 }
2610 offsets := line_offsets as ArrayValue
2611 idx := line - 1
2612 if idx < 0 || idx >= offsets.values.len {
2613 return MaybeValue{
2614 found: true
2615 value: i64(0)
2616 }
2617 }
2618 return MaybeValue{
2619 found: true
2620 value: offsets.values[idx]
2621 }
2622 }
2623 else {}
2624 }
2625 }
2626 if module_name == 'cmdline' {
2627 match fn_name {
2628 'option' {
2629 if args.len < 1 {
2630 return MaybeValue{}
2631 }
2632 str_arr := e.value_to_string_array(args[0]) or { return MaybeValue{} }
2633 opt_arg1 := e.expect_string_arg(args, 1) or { return MaybeValue{} }
2634 opt_arg2 := e.expect_string_arg(args, 2) or { return MaybeValue{} }
2635 return MaybeValue{
2636 found: true
2637 value: host_cmdline.option(str_arr, opt_arg1, opt_arg2)
2638 }
2639 }
2640 'options' {
2641 if args.len < 1 {
2642 return MaybeValue{}
2643 }
2644 str_arr := e.value_to_string_array(args[0]) or { return MaybeValue{} }
2645 opt_arg1 := e.expect_string_arg(args, 1) or { return MaybeValue{} }
2646 return MaybeValue{
2647 found: true
2648 value: ArrayValue{
2649 values: host_cmdline.options(str_arr, opt_arg1).map(Value(it))
2650 }
2651 }
2652 }
2653 'only_options' {
2654 if args.len < 1 {
2655 return MaybeValue{}
2656 }
2657 str_arr := e.value_to_string_array(args[0]) or { return MaybeValue{} }
2658 return MaybeValue{
2659 found: true
2660 value: ArrayValue{
2661 values: host_cmdline.only_options(str_arr).map(Value(it))
2662 }
2663 }
2664 }
2665 else {}
2666 }
2667 }
2668 return MaybeValue{}
2669}
2670
2671fn (e &Eval) clone_array_item_to_depth(value Value, depth int) Value {
2672 if depth < 0 {
2673 return value
2674 }
2675 return match value {
2676 ArrayValue {
2677 e.clone_array_to_depth(value, depth)
2678 }
2679 string {
2680 value.clone()
2681 }
2682 else {
2683 value
2684 }
2685 }
2686}
2687
2688fn (e &Eval) clone_array_to_depth(array_value ArrayValue, depth int) ArrayValue {
2689 if depth <= 0 {
2690 return ArrayValue{
2691 elem_type_name: array_value.elem_type_name
2692 values: array_value.values.clone()
2693 }
2694 }
2695 mut values := []Value{cap: array_value.values.len}
2696 for item in array_value.values {
2697 values << e.clone_array_item_to_depth(item, depth - 1)
2698 }
2699 return ArrayValue{
2700 elem_type_name: array_value.elem_type_name
2701 values: values
2702 }
2703}
2704
2705fn (mut e Eval) maybe_call_generated_array_helper(fn_name string, args []Value) ?MaybeValue {
2706 if args.len > 0 && args[0] is ArrayValue {
2707 array_value := args[0] as ArrayValue
2708 if fn_name == 'array__first' || fn_name.ends_with('array__first') {
2709 return MaybeValue{
2710 found: true
2711 value: e.array_first_value(array_value) or { return none }
2712 }
2713 }
2714 if fn_name == 'array__last' || fn_name.ends_with('array__last') {
2715 return MaybeValue{
2716 found: true
2717 value: e.array_last_value(array_value) or { return none }
2718 }
2719 }
2720 if fn_name == 'array__clone' || fn_name.ends_with('array__clone') {
2721 return MaybeValue{
2722 found: true
2723 value: e.clone_array_to_depth(array_value, 0)
2724 }
2725 }
2726 if (fn_name == 'array__clone_to_depth' || fn_name.ends_with('array__clone_to_depth'))
2727 && args.len >= 2 {
2728 depth := int(e.value_as_int(args[1]) or { return none })
2729 return MaybeValue{
2730 found: true
2731 value: e.clone_array_to_depth(array_value, depth)
2732 }
2733 }
2734 }
2735 if !fn_name.starts_with('Array_') || args.len == 0 || args[0] !is ArrayValue {
2736 return none
2737 }
2738 array_value := args[0] as ArrayValue
2739 if fn_name.ends_with('_first') {
2740 return MaybeValue{
2741 found: true
2742 value: e.array_first_value(array_value) or { return none }
2743 }
2744 }
2745 if fn_name.ends_with('_last') {
2746 return MaybeValue{
2747 found: true
2748 value: e.array_last_value(array_value) or { return none }
2749 }
2750 }
2751 if fn_name.ends_with('_contains') && args.len >= 2 {
2752 return MaybeValue{
2753 found: true
2754 value: e.array_contains(array_value, args[1])
2755 }
2756 }
2757 if fn_name.ends_with('_has') && args.len >= 2 {
2758 return MaybeValue{
2759 found: true
2760 value: e.array_has(array_value, args[1])
2761 }
2762 }
2763 if fn_name.ends_with('_index') && !fn_name.ends_with('_last_index') && args.len >= 2 {
2764 return MaybeValue{
2765 found: true
2766 value: e.array_index(array_value, args[1], false)
2767 }
2768 }
2769 if fn_name.ends_with('_last_index') && args.len >= 2 {
2770 return MaybeValue{
2771 found: true
2772 value: e.array_index(array_value, args[1], true)
2773 }
2774 }
2775 if fn_name.ends_with('_join') && args.len >= 2 {
2776 return MaybeValue{
2777 found: true
2778 value: array_value.values.map(e.value_string(it)).join(e.expect_string_arg(args, 1) or {
2779 return none
2780 })
2781 }
2782 }
2783 if fn_name.ends_with('_str') {
2784 return MaybeValue{
2785 found: true
2786 value: e.value_string(array_value)
2787 }
2788 }
2789 return none
2790}
2791
2792fn (mut e Eval) open_scope() {
2793 e.scopes << ScopeFrame{
2794 vars: map[string]Value{}
2795 }
2796}
2797
2798fn (mut e Eval) close_scope() ! {
2799 if e.scopes.len == 0 {
2800 return
2801 }
2802 scope_idx := e.scopes.len - 1
2803 defers := e.scopes[scope_idx].defers.clone()
2804 for i := defers.len - 1; i >= 0; i-- {
2805 signal := e.exec_stmts(defers[i])!
2806 if signal.kind != .normal {
2807 return error('v2.eval: control flow inside defer is not supported')
2808 }
2809 }
2810 e.scopes.pop()
2811}
2812
2813fn (mut e Eval) declare_var(name string, value Value) {
2814 if name == '' || name == '_' {
2815 return
2816 }
2817 if e.scopes.len == 0 {
2818 e.open_scope()
2819 }
2820 e.scopes[e.scopes.len - 1].vars[name] = value
2821}
2822
2823fn (mut e Eval) set_var(name string, value Value) ! {
2824 for i := e.scopes.len - 1; i >= 0; i-- {
2825 if name in e.scopes[i].vars {
2826 e.scopes[i].vars[name] = value
2827 return
2828 }
2829 }
2830 return e.unknown_variable_error(name)
2831}
2832
2833fn (e &Eval) lookup_var(name string) MaybeValue {
2834 for i := e.scopes.len - 1; i >= 0; i-- {
2835 if value := e.scopes[i].vars[name] {
2836 return MaybeValue{
2837 found: true
2838 value: value
2839 }
2840 }
2841 }
2842 return MaybeValue{}
2843}
2844
2845fn (mut e Eval) exec_stmts(stmts []ast.Stmt) !FlowSignal {
2846 mut label_positions := map[string]int{}
2847 for i, stmt in stmts {
2848 if stmt is ast.LabelStmt {
2849 label_positions[stmt.name] = i
2850 }
2851 }
2852 mut i := 0
2853 for i < stmts.len {
2854 stmt := stmts[i]
2855 signal := e.exec_stmt(stmt)!
2856 if signal.kind == .goto_ {
2857 if signal.label in label_positions {
2858 i = label_positions[signal.label]
2859 continue
2860 }
2861 return signal
2862 }
2863 if signal.kind != .normal {
2864 return signal
2865 }
2866 i++
2867 }
2868 return FlowSignal{
2869 kind: .normal
2870 }
2871}
2872
2873fn (mut e Eval) exec_block(stmts []ast.Stmt) !FlowSignal {
2874 e.open_scope()
2875 signal := e.exec_stmts(stmts)!
2876 e.close_scope()!
2877 return signal
2878}
2879
2880fn (mut e Eval) exec_stmt(stmt ast.Stmt) !FlowSignal {
2881 match stmt {
2882 ast.AssertStmt {
2883 passed := e.value_as_bool(e.eval_expr(stmt.expr)!)!
2884 if !passed {
2885 message := if stmt.extra is ast.EmptyExpr {
2886 'assertion failed'
2887 } else {
2888 e.value_string(e.eval_expr(stmt.extra)!)
2889 }
2890 return error('v2.eval: ${message}')
2891 }
2892 }
2893 ast.AssignStmt {
2894 return e.exec_assign_stmt(stmt)
2895 }
2896 ast.BlockStmt {
2897 return e.exec_block(stmt.stmts)
2898 }
2899 ast.ComptimeStmt {
2900 return e.exec_stmt(stmt.stmt)
2901 }
2902 ast.DeferStmt {
2903 if e.scopes.len == 0 {
2904 return error('v2.eval: defer used outside of a scope')
2905 }
2906 e.scopes[e.scopes.len - 1].defers << stmt.stmts
2907 }
2908 ast.ExprStmt {
2909 return e.exec_expr_stmt(stmt.expr)
2910 }
2911 ast.FlowControlStmt {
2912 return match stmt.op {
2913 .key_break {
2914 FlowSignal{
2915 kind: .break_
2916 }
2917 }
2918 .key_continue {
2919 FlowSignal{
2920 kind: .continue_
2921 }
2922 }
2923 .key_goto {
2924 FlowSignal{
2925 kind: .goto_
2926 label: stmt.label
2927 }
2928 }
2929 else {
2930 return error('v2.eval: unsupported flow control `${stmt.op}`')
2931 }
2932 }
2933 }
2934 ast.ForStmt {
2935 return e.exec_for_stmt(stmt)
2936 }
2937 ast.ReturnStmt {
2938 mut values := []Value{cap: stmt.exprs.len}
2939 for expr in stmt.exprs {
2940 values << e.eval_expr(expr)!
2941 }
2942 return FlowSignal{
2943 kind: .return_
2944 values: values
2945 }
2946 }
2947 ast.ConstDecl, ast.Directive, ast.EnumDecl, ast.FnDecl, ast.GlobalDecl, ast.ImportStmt,
2948 ast.InterfaceDecl, ast.ModuleStmt, ast.StructDecl, ast.TypeDecl, []ast.Attribute {
2949 return FlowSignal{
2950 kind: .normal
2951 }
2952 }
2953 ast.LabelStmt {
2954 if stmt.stmt is ast.EmptyStmt {
2955 return FlowSignal{
2956 kind: .normal
2957 }
2958 }
2959 return e.exec_stmt(stmt.stmt)
2960 }
2961 else {
2962 return error('v2.eval: unsupported statement `${stmt.type_name()}`')
2963 }
2964 }
2965
2966 return FlowSignal{
2967 kind: .normal
2968 }
2969}
2970
2971fn (mut e Eval) exec_expr_stmt(expr ast.Expr) !FlowSignal {
2972 match expr {
2973 ast.ComptimeExpr {
2974 if expr.expr is ast.IfExpr {
2975 return e.exec_if_stmt(expr.expr)
2976 }
2977 _ = e.eval_expr(expr.expr)!
2978 }
2979 ast.IfExpr {
2980 return e.exec_if_stmt(expr)
2981 }
2982 ast.InfixExpr {
2983 if expr.op == .left_shift {
2984 e.exec_array_append(expr)!
2985 } else {
2986 _ = e.eval_expr(expr)!
2987 }
2988 }
2989 ast.PostfixExpr {
2990 _ = e.eval_postfix_expr(expr)!
2991 }
2992 ast.UnsafeExpr {
2993 return e.exec_block(expr.stmts)
2994 }
2995 else {
2996 _ = e.eval_expr(expr)!
2997 }
2998 }
2999
3000 return FlowSignal{
3001 kind: .normal
3002 }
3003}
3004
3005fn (mut e Eval) exec_assign_stmt(stmt ast.AssignStmt) !FlowSignal {
3006 mut values := []Value{}
3007 for rhs in stmt.rhs {
3008 values << e.eval_expr(rhs)!
3009 }
3010 if stmt.lhs.len > 1 && values.len == 1 && values[0] is TupleValue {
3011 tuple_value := values[0] as TupleValue
3012 values = tuple_value.values.clone()
3013 }
3014 if stmt.lhs.len != values.len {
3015 return error('v2.eval: assignment arity mismatch')
3016 }
3017 for i, lhs in stmt.lhs {
3018 match stmt.op {
3019 .decl_assign {
3020 e.assign_target(lhs, values[i], true)!
3021 }
3022 .assign {
3023 e.assign_target(lhs, values[i], false)!
3024 }
3025 .plus_assign, .minus_assign, .mul_assign, .div_assign, .mod_assign, .and_assign,
3026 .or_assign, .xor_assign, .left_shift_assign, .right_shift_assign,
3027 .right_shift_unsigned_assign {
3028 current := e.eval_expr(lhs)!
3029 op := assign_to_infix_token(stmt.op)
3030 updated := e.apply_infix(op, current, values[i])!
3031 e.assign_target(lhs, updated, false)!
3032 }
3033 else {
3034 return error('v2.eval: unsupported assignment operator `${stmt.op}`')
3035 }
3036 }
3037 }
3038 return FlowSignal{
3039 kind: .normal
3040 }
3041}
3042
3043fn assign_to_infix_token(op token.Token) token.Token {
3044 return match op {
3045 .plus_assign { .plus }
3046 .minus_assign { .minus }
3047 .mul_assign { .mul }
3048 .div_assign { .div }
3049 .mod_assign { .mod }
3050 .and_assign { .amp }
3051 .or_assign { .pipe }
3052 .xor_assign { .xor }
3053 .left_shift_assign { .left_shift }
3054 .right_shift_assign { .right_shift }
3055 .right_shift_unsigned_assign { .right_shift_unsigned }
3056 else { .unknown }
3057 }
3058}
3059
3060fn (mut e Eval) assign_target(lhs ast.Expr, value Value, declare bool) ! {
3061 if name := assignable_ident_name(lhs) {
3062 if name == '_' {
3063 return
3064 }
3065 if declare {
3066 e.declare_var(name, value)
3067 } else {
3068 e.update_target(lhs, value)!
3069 }
3070 return
3071 }
3072 if declare {
3073 return error('v2.eval: unsupported declaration target `${lhs.type_name()}`')
3074 }
3075 return e.update_target(lhs, value)
3076}
3077
3078fn can_update_target(expr ast.Expr) bool {
3079 if assignable_ident_name(expr) != none || expr is ast.IndexExpr || expr is ast.SelectorExpr {
3080 return true
3081 }
3082 match expr {
3083 ast.CastExpr, ast.ModifierExpr, ast.ParenExpr {
3084 return can_update_target(expr.expr)
3085 }
3086 else {}
3087 }
3088
3089 if expr is ast.PrefixExpr && expr.op in [.mul, .amp] {
3090 return can_update_target(expr.expr)
3091 }
3092 return false
3093}
3094
3095fn (mut e Eval) update_target(expr ast.Expr, value Value) ! {
3096 if name := assignable_ident_name(expr) {
3097 var_result := e.lookup_var(name)
3098 if var_result.found {
3099 e.set_var(name, value)!
3100 return
3101 }
3102 if e.set_runtime_const(e.current_module_name(), name, value) {
3103 return
3104 }
3105 return e.unknown_variable_error(name)
3106 }
3107 if expr is ast.IndexExpr {
3108 return e.update_index_target(expr, value)
3109 }
3110 if expr is ast.SelectorExpr {
3111 return e.update_selector_target(expr, value)
3112 }
3113 match expr {
3114 ast.CastExpr, ast.ModifierExpr, ast.ParenExpr {
3115 return e.update_target(expr.expr, value)
3116 }
3117 else {}
3118 }
3119
3120 if expr is ast.PrefixExpr && expr.op in [.mul, .amp] {
3121 return e.update_target(expr.expr, value)
3122 }
3123 return error('v2.eval: unsupported assignment target `${expr.type_name()}`')
3124}
3125
3126fn assignable_ident_name(expr ast.Expr) ?string {
3127 match expr {
3128 ast.Ident {
3129 return expr.name
3130 }
3131 ast.ModifierExpr {
3132 if expr.expr is ast.Ident {
3133 return expr.expr.name
3134 }
3135 }
3136 else {}
3137 }
3138
3139 return none
3140}
3141
3142fn (mut e Eval) update_index_target(expr ast.IndexExpr, value Value) ! {
3143 container := e.eval_expr(expr.lhs)!
3144 index_value := e.eval_expr(expr.expr)!
3145 match container {
3146 ArrayValue {
3147 index := int(e.value_as_int(index_value)!)
3148 if index < 0 || index >= container.values.len {
3149 return error('v2.eval: array index out of bounds')
3150 }
3151 mut updated := ArrayValue{
3152 ...container
3153 values: container.values.clone()
3154 }
3155 assigned_value := e.adapt_value_to_type_name(value, updated.elem_type_name)
3156 updated.values[index] = assigned_value
3157 e.update_target(expr.lhs, updated)!
3158 return
3159 }
3160 MapValue {
3161 expected_type_name := if container.default_value is VoidValue {
3162 ''
3163 } else {
3164 e.runtime_type_name(container.default_value)
3165 }
3166 assigned_value := e.adapt_value_to_type_name(value, expected_type_name)
3167 e.update_target(expr.lhs, e.map_set_value(container, index_value, assigned_value))!
3168 return
3169 }
3170 else {
3171 return error('v2.eval: indexed assignment expects an array or map')
3172 }
3173 }
3174}
3175
3176fn (mut e Eval) update_selector_target(expr ast.SelectorExpr, value Value) ! {
3177 container := e.eval_expr(expr.lhs)!
3178 match container {
3179 ArrayValue {
3180 if expr.rhs.name == 'flags' {
3181 return
3182 }
3183 }
3184 StructValue {
3185 mut updated := container
3186 mut assigned_value := value
3187 if field_type := e.lookup_struct_field_type(container.type_name, expr.rhs.name) {
3188 assigned_value = e.adapt_value_to_type(value, field_type)
3189 }
3190 updated.fields[expr.rhs.name] = assigned_value
3191 e.update_target(expr.lhs, updated)!
3192 return
3193 }
3194 else {
3195 return error('v2.eval: selector assignment expects a struct, got `${e.runtime_type_name(container)}` in `${e.current_function_label()}`')
3196 }
3197 }
3198}
3199
3200fn (mut e Eval) exec_array_append(expr ast.InfixExpr) ! {
3201 container := e.eval_expr(expr.lhs)!
3202 value := e.eval_expr(expr.rhs)!
3203 match container {
3204 ArrayValue {
3205 mut updated := container
3206 if value is ArrayValue && e.should_append_many(container, value) {
3207 if updated.elem_type_name == '' {
3208 updated.values << value.values
3209 } else {
3210 for item in value.values {
3211 updated.values << e.adapt_value_to_type_name(item, updated.elem_type_name)
3212 }
3213 }
3214 } else {
3215 updated.values << e.adapt_value_to_type_name(value, updated.elem_type_name)
3216 }
3217 if updated.elem_type_name == '' {
3218 updated.elem_type_name = e.infer_array_elem_type(updated.values)
3219 }
3220 e.update_target(expr.lhs, updated)!
3221 return
3222 }
3223 else {
3224 return error('v2.eval: `<<` is only supported for arrays')
3225 }
3226 }
3227}
3228
3229fn (mut e Eval) exec_for_stmt(stmt ast.ForStmt) !FlowSignal {
3230 e.open_scope()
3231 defer {
3232 e.close_scope() or {}
3233 }
3234 if stmt.init is ast.ForInStmt {
3235 return e.exec_for_in(stmt.init, stmt.stmts)
3236 }
3237 if stmt.init !is ast.EmptyStmt {
3238 init_signal := e.exec_stmt(stmt.init)!
3239 if init_signal.kind != .normal {
3240 return init_signal
3241 }
3242 }
3243 for {
3244 if stmt.cond !is ast.EmptyExpr {
3245 if !e.value_as_bool(e.eval_expr(stmt.cond)!)! {
3246 break
3247 }
3248 }
3249 body_signal := e.exec_block(stmt.stmts)!
3250 if body_signal.kind == .return_ {
3251 return body_signal
3252 }
3253 if body_signal.kind == .break_ {
3254 break
3255 }
3256 if stmt.post !is ast.EmptyStmt {
3257 post_signal := e.exec_stmt(stmt.post)!
3258 if post_signal.kind == .return_ {
3259 return post_signal
3260 }
3261 if post_signal.kind == .break_ {
3262 break
3263 }
3264 }
3265 }
3266 return FlowSignal{
3267 kind: .normal
3268 }
3269}
3270
3271fn (mut e Eval) exec_for_in(for_in ast.ForInStmt, body []ast.Stmt) !FlowSignal {
3272 mut key_name := assignable_ident_name(for_in.key) or { '' }
3273 mut value_name := assignable_ident_name(for_in.value) or { '' }
3274 if value_name == '' {
3275 value_name = key_name
3276 key_name = ''
3277 }
3278 iterable := e.eval_expr(for_in.expr)!
3279 match iterable {
3280 RangeValue {
3281 mut i := iterable.start
3282 limit := iterable.end
3283 for {
3284 if iterable.inclusive {
3285 if i > limit {
3286 break
3287 }
3288 } else if i >= limit {
3289 break
3290 }
3291 e.open_scope()
3292 if value_name != '' && value_name != '_' {
3293 e.declare_var(value_name, i)
3294 }
3295 body_signal := e.exec_stmts(body)!
3296 e.close_scope()!
3297 if body_signal.kind == .return_ {
3298 return body_signal
3299 }
3300 if body_signal.kind == .break_ {
3301 break
3302 }
3303 i++
3304 }
3305 }
3306 ArrayValue {
3307 for idx, item in iterable.values {
3308 e.open_scope()
3309 if key_name != '' && key_name != '_' {
3310 e.declare_var(key_name, i64(idx))
3311 }
3312 if value_name != '' && value_name != '_' {
3313 e.declare_var(value_name, item)
3314 }
3315 body_signal := e.exec_stmts(body)!
3316 e.close_scope()!
3317 if body_signal.kind == .return_ {
3318 return body_signal
3319 }
3320 if body_signal.kind == .break_ {
3321 break
3322 }
3323 }
3324 }
3325 MapValue {
3326 for entry in iterable.entries {
3327 e.open_scope()
3328 if key_name != '' && key_name != '_' {
3329 e.declare_var(key_name, entry.key)
3330 }
3331 if value_name != '' && value_name != '_' {
3332 e.declare_var(value_name, entry.value)
3333 }
3334 body_signal := e.exec_stmts(body)!
3335 e.close_scope()!
3336 if body_signal.kind == .return_ {
3337 return body_signal
3338 }
3339 if body_signal.kind == .break_ {
3340 break
3341 }
3342 }
3343 }
3344 string {
3345 for idx, ch in iterable.runes() {
3346 e.open_scope()
3347 if key_name != '' && key_name != '_' {
3348 e.declare_var(key_name, i64(idx))
3349 }
3350 if value_name != '' && value_name != '_' {
3351 e.declare_var(value_name, ch.str())
3352 }
3353 body_signal := e.exec_stmts(body)!
3354 e.close_scope()!
3355 if body_signal.kind == .return_ {
3356 return body_signal
3357 }
3358 if body_signal.kind == .break_ {
3359 break
3360 }
3361 }
3362 }
3363 else {
3364 return error('v2.eval: unsupported for-in iterable `${e.runtime_type_name(iterable)}`')
3365 }
3366 }
3367
3368 return FlowSignal{
3369 kind: .normal
3370 }
3371}
3372
3373fn (mut e Eval) exec_if_stmt(expr ast.IfExpr) !FlowSignal {
3374 should_run := if expr.cond is ast.EmptyExpr {
3375 true
3376 } else {
3377 e.value_as_bool(e.eval_expr(expr.cond)!)!
3378 }
3379 if should_run {
3380 return e.exec_block(expr.stmts)
3381 }
3382 if expr.else_expr is ast.IfExpr {
3383 return e.exec_if_stmt(expr.else_expr)
3384 }
3385 if expr.else_expr is ast.EmptyExpr {
3386 return FlowSignal{
3387 kind: .normal
3388 }
3389 }
3390 _ = e.eval_expr(expr.else_expr)!
3391 return FlowSignal{
3392 kind: .normal
3393 }
3394}
3395
3396fn (mut e Eval) eval_expr(expr ast.Expr) !Value {
3397 match expr {
3398 ast.ArrayInitExpr {
3399 mut elem_type_name := if expr.typ is ast.EmptyExpr {
3400 ''
3401 } else {
3402 e.array_elem_type_name(expr.typ)
3403 }
3404 if expr.len !is ast.EmptyExpr && expr.exprs.len == 0 {
3405 size := int(e.value_as_int(e.eval_expr(expr.len)!)!)
3406 init_value := if expr.init is ast.EmptyExpr {
3407 void_value()
3408 } else {
3409 e.eval_expr(expr.init)!
3410 }
3411 mut values := []Value{len: size, init: init_value}
3412 if elem_type_name == '' {
3413 elem_type_name = e.infer_array_elem_type(values)
3414 }
3415 return ArrayValue{
3416 elem_type_name: elem_type_name
3417 values: values
3418 }
3419 }
3420 mut values := []Value{cap: expr.exprs.len}
3421 // Spread syntax `[...base, e1, e2]` — prepend the base array's
3422 // values before any explicit elements. Deep-clone each item so
3423 // the new array does not alias the base's nested storage (mirrors
3424 // the runtime `array__clone_to_depth` semantics used by lowered
3425 // codegen paths).
3426 if expr.update_expr !is ast.EmptyExpr {
3427 base_value := e.eval_expr(expr.update_expr)!
3428 if base_value is ArrayValue {
3429 cloned_base := e.clone_array_to_depth(base_value, 100)
3430 for v in cloned_base.values {
3431 values << v
3432 }
3433 if elem_type_name == '' {
3434 elem_type_name = base_value.elem_type_name
3435 }
3436 }
3437 }
3438 for item in expr.exprs {
3439 values << e.eval_expr(item)!
3440 }
3441 if elem_type_name == '' {
3442 elem_type_name = e.infer_array_elem_type(values)
3443 }
3444 return ArrayValue{
3445 elem_type_name: elem_type_name
3446 values: values
3447 }
3448 }
3449 ast.InitExpr {
3450 mut fields := map[string]Value{}
3451 mut data_fields := map[string]Value{}
3452 type_name := expr.typ.name()
3453 for field in expr.fields {
3454 mut value := e.eval_expr(field.value)!
3455 if field.name != '' && !field.name.starts_with('_data.') {
3456 if field_type := e.lookup_struct_field_type(type_name, field.name) {
3457 value = e.adapt_value_to_type(value, field_type)
3458 }
3459 }
3460 if field.name.starts_with('_data.') {
3461 data_fields[field.name.all_after('_data.')] = value
3462 continue
3463 }
3464 fields[field.name] = value
3465 }
3466 if data_fields.len > 0 {
3467 mut data_struct := StructValue{
3468 type_name: type_name + '._data'
3469 fields: map[string]Value{}
3470 }
3471 if existing_data := fields['_data'] {
3472 if existing_data is StructValue {
3473 data_struct = existing_data
3474 }
3475 }
3476 mut merged_data_fields := data_struct.fields.clone()
3477 for name, value in data_fields {
3478 merged_data_fields[name] = value
3479 }
3480 fields['_data'] = StructValue{
3481 type_name: data_struct.type_name
3482 fields: merged_data_fields
3483 }
3484 }
3485 return StructValue{
3486 type_name: type_name
3487 fields: fields
3488 }
3489 }
3490 ast.AsCastExpr {
3491 return e.eval_as_cast_expr(expr)
3492 }
3493 ast.BasicLiteral {
3494 return e.eval_basic_literal(expr)
3495 }
3496 ast.CallExpr {
3497 return e.eval_call_expr(expr)
3498 }
3499 ast.CallOrCastExpr {
3500 if e.is_type_expr(expr.lhs) {
3501 value := e.eval_expr(expr.expr)!
3502 target_name := expr.lhs.name()
3503 if e.is_sum_type_name(target_name) {
3504 return e.wrap_sumtype_value(target_name, value, expr.expr) or {
3505 e.cast_value(value, target_name)!
3506 }
3507 }
3508 return e.cast_value(value, target_name)
3509 }
3510 return e.eval_call_expr(ast.CallExpr{
3511 lhs: expr.lhs
3512 args: [expr.expr]
3513 pos: expr.pos
3514 })
3515 }
3516 ast.CastExpr {
3517 value := e.eval_expr(expr.expr)!
3518 target_name := expr.typ.name()
3519 if e.is_sum_type_name(target_name) {
3520 return e.wrap_sumtype_value(target_name, value, expr.expr) or {
3521 e.cast_value(value, target_name)!
3522 }
3523 }
3524 return e.cast_value(value, target_name)
3525 }
3526 ast.ComptimeExpr {
3527 return e.eval_expr(expr.expr)
3528 }
3529 ast.GenericArgs {
3530 if e.is_type_expr(expr) {
3531 return TypeValue{
3532 name: generic_args_name(expr)
3533 }
3534 }
3535 return error('v2.eval: unsupported generic expression `${generic_args_name(expr)}`')
3536 }
3537 ast.Ident {
3538 return e.eval_ident(expr.name)
3539 }
3540 ast.IfExpr {
3541 return e.eval_if_value(expr)
3542 }
3543 ast.IndexExpr {
3544 return e.eval_index_expr(expr)
3545 }
3546 ast.InfixExpr {
3547 return e.eval_infix_expr(expr)
3548 }
3549 ast.KeywordOperator {
3550 return e.eval_keyword_operator(expr)
3551 }
3552 ast.MapInitExpr {
3553 mut entries := []MapEntry{cap: expr.keys.len}
3554 for i, key_expr in expr.keys {
3555 key := e.eval_expr(key_expr)!
3556 val := if i < expr.vals.len {
3557 e.eval_expr(expr.vals[i])!
3558 } else {
3559 void_value()
3560 }
3561 entries << MapEntry{
3562 key: key
3563 value: val
3564 }
3565 }
3566 default_value := if expr.typ is ast.Type && expr.typ is ast.MapType {
3567 e.zero_value_for_type_expr((expr.typ as ast.MapType).value_type)
3568 } else if entries.len > 0 {
3569 e.zero_value_like(entries[0].value)
3570 } else {
3571 void_value()
3572 }
3573 return MapValue{
3574 default_value: default_value
3575 entries: entries
3576 }
3577 }
3578 ast.ModifierExpr {
3579 return e.eval_expr(expr.expr)
3580 }
3581 ast.ParenExpr {
3582 return e.eval_expr(expr.expr)
3583 }
3584 ast.PostfixExpr {
3585 return e.eval_postfix_expr(expr)
3586 }
3587 ast.PrefixExpr {
3588 return e.eval_prefix_expr(expr)
3589 }
3590 ast.RangeExpr {
3591 return RangeValue{
3592 start: e.value_as_int(e.eval_expr(expr.start)!)!
3593 end: e.value_as_int(e.eval_expr(expr.end)!)!
3594 inclusive: expr.op == .ellipsis
3595 }
3596 }
3597 ast.SelectorExpr {
3598 return e.eval_selector_expr(expr)
3599 }
3600 ast.StringInterLiteral {
3601 return e.eval_string_inter(expr)
3602 }
3603 ast.StringLiteral {
3604 return decode_string_literal(expr.value)
3605 }
3606 ast.Tuple {
3607 mut values := []Value{cap: expr.exprs.len}
3608 for item in expr.exprs {
3609 values << e.eval_expr(item)!
3610 }
3611 return TupleValue{
3612 values: values
3613 }
3614 }
3615 ast.Type {
3616 match expr {
3617 ast.NilType, ast.NoneType {
3618 return void_value()
3619 }
3620 else {}
3621 }
3622
3623 return TypeValue{
3624 name: e.type_node_name(expr)
3625 }
3626 }
3627 ast.UnsafeExpr {
3628 return e.eval_unsafe_expr(expr)
3629 }
3630 ast.EmptyExpr {
3631 return void_value()
3632 }
3633 else {
3634 return error('v2.eval: unsupported expression `${expr.type_name()}`')
3635 }
3636 }
3637}
3638
3639fn (mut e Eval) eval_as_cast_expr(expr ast.AsCastExpr) !Value {
3640 value := e.eval_expr(expr.expr)!
3641 target_name := e.type_expr_name(expr.typ)
3642 if value is StructValue {
3643 if payload := e.unwrap_sumtype_value(value, target_name) {
3644 return payload
3645 }
3646 if e.value_matches_type_name(value, target_name) {
3647 return value
3648 }
3649 return error('v2.eval: `${value.type_name}` is not `${target_name}` in `${e.current_function_label()}` stack `${e.call_stack_trace()}`')
3650 }
3651 if e.value_matches_type_name(value, target_name) {
3652 return e.cast_value(value, target_name)
3653 }
3654 return error('v2.eval: `${e.runtime_type_name(value)}` is not `${target_name}` in `${e.current_function_label()}` stack `${e.call_stack_trace()}`')
3655}
3656
3657fn (mut e Eval) eval_basic_literal(expr ast.BasicLiteral) !Value {
3658 if expr.kind == .key_true {
3659 v := Value(true)
3660 return v
3661 } else if expr.kind == .key_false {
3662 v := Value(false)
3663 return v
3664 } else if expr.kind == .number {
3665 if expr.value.contains('.') || expr.value.contains('e') || expr.value.contains('E') {
3666 f := strconv.atof64(expr.value)!
3667 v := Value(f)
3668 return v
3669 } else {
3670 n := strconv.parse_int(expr.value, 0, 64)!
3671 v := Value(n)
3672 return v
3673 }
3674 } else if expr.kind == .char {
3675 if expr.value.len == 0 {
3676 v := Value(i64(0))
3677 return v
3678 } else {
3679 decoded := decode_string_literal(expr.value)
3680 if decoded.len == 0 {
3681 v := Value(i64(0))
3682 return v
3683 }
3684 v := Value(i64(decoded.runes()[0]))
3685 return v
3686 }
3687 } else {
3688 return error('v2.eval: unsupported literal `${expr.kind}`')
3689 }
3690}
3691
3692fn (mut e Eval) eval_ident(name string) !Value {
3693 value_result := e.lookup_var(name)
3694 if value_result.found {
3695 return value_result.value
3696 }
3697 module_name := e.resolve_module_name(name)
3698 if module_name != '' {
3699 return ModuleValue{
3700 name: module_name
3701 }
3702 }
3703 if name == 'nil' || name == 'none' {
3704 return void_value()
3705 }
3706 if e.is_builtin_type_name(name) {
3707 return TypeValue{
3708 name: name
3709 }
3710 }
3711 cur_module := e.current_module_name()
3712 if e.has_type_name(cur_module, name) {
3713 return TypeValue{
3714 name: '${cur_module}.${name}'
3715 }
3716 }
3717 if type_value := e.resolve_mangled_type_value(name) {
3718 return type_value
3719 }
3720 const_result := e.lookup_const(cur_module, name)
3721 if const_result.found {
3722 return const_result.value
3723 }
3724 builtin_const := e.lookup_const('builtin', name)
3725 if builtin_const.found {
3726 return builtin_const.value
3727 }
3728 if mangled_const := e.resolve_mangled_const(name) {
3729 return mangled_const
3730 }
3731 return error('v2.eval: unknown identifier `${name}` in `${e.current_function_label()}` stack `${e.call_stack_trace()}`')
3732}
3733
3734fn (e &Eval) resolve_module_name(name string) string {
3735 file_name := e.current_file_name()
3736 if file_name != '' {
3737 if aliases := e.file_import_alias[file_name] {
3738 if name in aliases {
3739 return aliases[name]
3740 }
3741 }
3742 }
3743 if name in e.modules {
3744 return name
3745 }
3746 return ''
3747}
3748
3749fn (e &Eval) has_type_name(module_name string, type_name string) bool {
3750 if module_name !in e.type_names {
3751 return false
3752 }
3753 return type_name in e.type_names[module_name]
3754}
3755
3756fn (mut e Eval) resolve_mangled_const(name string) ?Value {
3757 for module_name in e.consts.keys() {
3758 prefix := e.mangled_module_name(module_name) + '__'
3759 if !name.starts_with(prefix) {
3760 continue
3761 }
3762 key := name[prefix.len..].all_after_last('__')
3763 const_result := e.lookup_const(module_name, key)
3764 if const_result.found {
3765 return const_result.value
3766 }
3767 }
3768 if name.contains('__') {
3769 type_name := name.all_before_last('__')
3770 field_name := name.all_after_last('__')
3771 for module_name, module_types in e.type_names {
3772 if type_name !in module_types {
3773 continue
3774 }
3775 const_result := e.lookup_const(module_name, field_name)
3776 if const_result.found {
3777 return const_result.value
3778 }
3779 }
3780 }
3781 return none
3782}
3783
3784fn (e &Eval) resolve_mangled_type_value(name string) ?TypeValue {
3785 for module_name, module_types in e.type_names {
3786 prefix := e.mangled_module_name(module_name) + '__'
3787 if !name.starts_with(prefix) {
3788 continue
3789 }
3790 type_name := name[prefix.len..]
3791 if type_name in module_types {
3792 return TypeValue{
3793 name: '${module_name}.${type_name}'
3794 }
3795 }
3796 }
3797 return none
3798}
3799
3800fn (e &Eval) mangled_module_name(name string) string {
3801 if name == '' {
3802 return ''
3803 }
3804 return name.replace('.', '__')
3805}
3806
3807fn (mut e Eval) lookup_const(module_name string, name string) MaybeValue {
3808 if module_name !in e.consts {
3809 return MaybeValue{}
3810 }
3811 mut entry := e.consts[module_name][name] or { return MaybeValue{} }
3812 if entry.cached {
3813 return MaybeValue{
3814 found: true
3815 value: entry.value
3816 }
3817 }
3818 if entry.evaluating {
3819 return MaybeValue{}
3820 }
3821 entry.evaluating = true
3822 e.consts[module_name][name] = entry
3823 e.call_stack << CallFrame{
3824 module_name: module_name
3825 file_name: entry.file_name
3826 fn_name: 'const ${name}'
3827 }
3828 value := e.eval_expr(entry.expr) or {
3829 entry.evaluating = false
3830 e.consts[module_name][name] = entry
3831 e.call_stack.pop()
3832 return MaybeValue{}
3833 }
3834 e.call_stack.pop()
3835 entry.cached = true
3836 entry.evaluating = false
3837 entry.value = value
3838 e.consts[module_name][name] = entry
3839 return MaybeValue{
3840 found: true
3841 value: value
3842 }
3843}
3844
3845fn (mut e Eval) set_runtime_const(module_name string, name string, value Value) bool {
3846 if module_name !in e.consts {
3847 return false
3848 }
3849 mut entry := e.consts[module_name][name] or { return false }
3850 entry.cached = true
3851 entry.evaluating = false
3852 entry.value = value
3853 e.consts[module_name][name] = entry
3854 return true
3855}
3856
3857fn (mut e Eval) eval_call_expr(expr ast.CallExpr) !Value {
3858 if expr.lhs is ast.SelectorExpr {
3859 selector := expr.lhs as ast.SelectorExpr
3860 if builder_result := e.maybe_call_builder_wrapper(selector.rhs.name, expr.args) {
3861 return builder_result
3862 }
3863 if selector.lhs is ast.SelectorExpr {
3864 inner := selector.lhs as ast.SelectorExpr
3865 if inner.rhs.name == 'flags' {
3866 _ = e.eval_expr(inner.lhs)!
3867 for arg in expr.args {
3868 _ = e.eval_expr(arg)!
3869 }
3870 return match selector.rhs.name {
3871 'set', 'clear' { void_value() }
3872 'has' { Value(false) }
3873 else { return error('v2.eval: unsupported array flags method `${selector.rhs.name}`') }
3874 }
3875 }
3876 }
3877 if selector.lhs is ast.Ident {
3878 module_name := e.resolve_module_name(selector.lhs.name)
3879 if module_name != '' {
3880 mut args := []Value{cap: expr.args.len}
3881 for arg in expr.args {
3882 args << e.eval_expr(arg)!
3883 }
3884 result := e.call_function(module_name, selector.rhs.name, args)!
3885 e.writeback_mut_args(expr.args, result)!
3886 return call_result_value(result)
3887 }
3888 }
3889 receiver := e.eval_expr(selector.lhs)!
3890 mut args := []Value{cap: expr.args.len}
3891 for arg in expr.args {
3892 args << e.eval_expr(arg)!
3893 }
3894 if target := e.resolve_method_target(receiver, selector.rhs.name) {
3895 mut method_args := []Value{cap: args.len + 1}
3896 method_args << receiver
3897 method_args << args
3898 result := e.call_function(target.module_name, target.fn_name, method_args)!
3899 e.writeback_method_mut_args(selector.lhs, expr.args, result)!
3900 return call_result_value(result)
3901 }
3902 return e.call_value_method(receiver, selector.rhs.name, args)
3903 }
3904 if expr.lhs is ast.Ident {
3905 if builder_result := e.maybe_call_builder_wrapper(expr.lhs.name, expr.args) {
3906 return builder_result
3907 }
3908 mut args := []Value{cap: expr.args.len}
3909 for arg in expr.args {
3910 args << e.eval_expr(arg)!
3911 }
3912 if target := e.resolve_mangled_function_target(expr.lhs.name) {
3913 result := e.call_function(target.module_name, target.fn_name, args)!
3914 e.writeback_mut_args(expr.args, result)!
3915 return call_result_value(result)
3916 }
3917 result := e.call_function(e.current_module_name(), expr.lhs.name, args) or {
3918 if result := e.call_function('builtin', expr.lhs.name, args) {
3919 e.writeback_mut_args(expr.args, result)!
3920 return call_result_value(result)
3921 }
3922 return error(err.msg())
3923 }
3924 e.writeback_mut_args(expr.args, result)!
3925 return call_result_value(result)
3926 }
3927 return error('v2.eval: unsupported call target `${expr.lhs.type_name()}`')
3928}
3929
3930fn (mut e Eval) writeback_method_mut_args(receiver_expr ast.Expr, arg_exprs []ast.Expr, result CallResult) ! {
3931 for idx, value in result.mut_args {
3932 if idx == 0 {
3933 if can_update_target(receiver_expr) {
3934 e.update_target(receiver_expr, value)!
3935 }
3936 continue
3937 }
3938 arg_idx := idx - 1
3939 if arg_idx >= 0 && arg_idx < arg_exprs.len && can_update_target(arg_exprs[arg_idx]) {
3940 e.update_target(arg_exprs[arg_idx], value)!
3941 }
3942 }
3943}
3944
3945fn (mut e Eval) maybe_call_builder_wrapper(name string, args []ast.Expr) ?Value {
3946 if !name.contains('Builder__') || args.len == 0 {
3947 return none
3948 }
3949 method_name := name.all_after('Builder__')
3950 target_expr := builder_target_expr(args[0]) or { return none }
3951 target_value := e.eval_expr(target_expr) or { return none }
3952 if target_value !is ArrayValue {
3953 return none
3954 }
3955 mut receiver := target_value as ArrayValue
3956 match method_name {
3957 'cut_last' {
3958 if args.len < 2 {
3959 return none
3960 }
3961 count_value := e.eval_expr(args[1]) or { return none }
3962 n := int(e.value_as_int(count_value) or { return none })
3963 mut items := receiver.values.clone()
3964 if n <= 0 || n > items.len {
3965 return ''
3966 }
3967 cut := items[items.len - n..].clone()
3968 items = items[..items.len - n].clone()
3969 e.update_target(target_expr, ArrayValue{
3970 values: items
3971 }) or { return none }
3972 return e.builder_array_to_string(ArrayValue{
3973 values: cut
3974 })
3975 }
3976 'go_back' {
3977 if args.len < 2 {
3978 return none
3979 }
3980 count_value := e.eval_expr(args[1]) or { return none }
3981 n := int(e.value_as_int(count_value) or { return none })
3982 if n <= 0 {
3983 return void_value()
3984 }
3985 keep_len := if n > receiver.values.len { 0 } else { receiver.values.len - n }
3986 e.update_target(target_expr, ArrayValue{
3987 values: receiver.values[..keep_len].clone()
3988 }) or { return none }
3989 return void_value()
3990 }
3991 'go_back_to' {
3992 if args.len < 2 {
3993 return none
3994 }
3995 pos_value := e.eval_expr(args[1]) or { return none }
3996 pos := int(e.value_as_int(pos_value) or { return none })
3997 keep_len := if pos < 0 {
3998 0
3999 } else if pos > receiver.values.len {
4000 receiver.values.len
4001 } else {
4002 pos
4003 }
4004 e.update_target(target_expr, ArrayValue{
4005 values: receiver.values[..keep_len].clone()
4006 }) or { return none }
4007 return void_value()
4008 }
4009 'last_n' {
4010 if args.len < 2 {
4011 return none
4012 }
4013 count_value := e.eval_expr(args[1]) or { return none }
4014 n := int(e.value_as_int(count_value) or { return none })
4015 return e.builder_tail_string(receiver, n)
4016 }
4017 'after' {
4018 if args.len < 2 {
4019 return none
4020 }
4021 start_value := e.eval_expr(args[1]) or { return none }
4022 start := int(e.value_as_int(start_value) or { return none })
4023 return e.builder_slice_string(receiver, start, receiver.values.len - start)
4024 }
4025 'spart' {
4026 if args.len < 3 {
4027 return none
4028 }
4029 start_value := e.eval_expr(args[1]) or { return none }
4030 len_value := e.eval_expr(args[2]) or { return none }
4031 start := int(e.value_as_int(start_value) or { return none })
4032 n := int(e.value_as_int(len_value) or { return none })
4033 return e.builder_slice_string(receiver, start, n)
4034 }
4035 'str' {
4036 result := e.builder_array_to_string(receiver)
4037 e.update_target(target_expr, ArrayValue{
4038 values: []Value{}
4039 }) or { return none }
4040 return result
4041 }
4042 'write_ptr' {
4043 return void_value()
4044 }
4045 'write_byte', 'write_rune', 'write_repeated_rune', 'write_string', 'write_string2',
4046 'write_u8', 'writeln', 'writeln2' {
4047 mut items := receiver.values.clone()
4048 match method_name {
4049 'write_string' {
4050 if args.len < 2 {
4051 return none
4052 }
4053 value := e.eval_expr(args[1]) or { return none }
4054 e.append_builder_string(mut items, e.value_string(value))
4055 }
4056 'write_string2' {
4057 if args.len < 3 {
4058 return none
4059 }
4060 first_value := e.eval_expr(args[1]) or { return none }
4061 second_value := e.eval_expr(args[2]) or { return none }
4062 e.append_builder_string(mut items, e.value_string(first_value))
4063 e.append_builder_string(mut items, e.value_string(second_value))
4064 }
4065 'write_rune' {
4066 if args.len < 2 {
4067 return none
4068 }
4069 rune_value := e.eval_expr(args[1]) or { return none }
4070 e.append_builder_rune(mut items, e.value_as_int(rune_value) or { return none })
4071 }
4072 'write_repeated_rune' {
4073 if args.len < 3 {
4074 return none
4075 }
4076 rune_value := e.eval_expr(args[1]) or { return none }
4077 count_value := e.eval_expr(args[2]) or { return none }
4078 r := e.value_as_int(rune_value) or { return none }
4079 count := int(e.value_as_int(count_value) or { return none })
4080 for _ in 0 .. count {
4081 e.append_builder_rune(mut items, r)
4082 }
4083 }
4084 'write_byte', 'write_u8' {
4085 if args.len < 2 {
4086 return none
4087 }
4088 byte_value := e.eval_expr(args[1]) or { return none }
4089 items << (e.value_as_int(byte_value) or { return none })
4090 }
4091 'writeln' {
4092 if args.len < 2 {
4093 return none
4094 }
4095 value := e.eval_expr(args[1]) or { return none }
4096 e.append_builder_string(mut items, e.value_string(value))
4097 items << i64(`\n`)
4098 }
4099 'writeln2' {
4100 if args.len < 3 {
4101 return none
4102 }
4103 first_value := e.eval_expr(args[1]) or { return none }
4104 second_value := e.eval_expr(args[2]) or { return none }
4105 e.append_builder_string(mut items, e.value_string(first_value))
4106 items << i64(`\n`)
4107 e.append_builder_string(mut items, e.value_string(second_value))
4108 items << i64(`\n`)
4109 }
4110 else {}
4111 }
4112
4113 e.update_target(target_expr, ArrayValue{
4114 values: items
4115 }) or { return none }
4116 return void_value()
4117 }
4118 else {
4119 return none
4120 }
4121 }
4122}
4123
4124fn builder_target_expr(expr ast.Expr) ?ast.Expr {
4125 match expr {
4126 ast.CastExpr {
4127 return builder_target_expr(expr.expr)
4128 }
4129 ast.Ident {
4130 return expr
4131 }
4132 ast.ModifierExpr {
4133 return builder_target_expr(expr.expr)
4134 }
4135 ast.ParenExpr {
4136 return builder_target_expr(expr.expr)
4137 }
4138 ast.SelectorExpr {
4139 return expr
4140 }
4141 ast.PrefixExpr {
4142 if expr.op == .amp {
4143 return builder_target_expr(expr.expr)
4144 }
4145 }
4146 else {}
4147 }
4148
4149 return none
4150}
4151
4152fn receiver_method_type_candidates(receiver Value) []string {
4153 return match receiver {
4154 StructValue {
4155 struct_field_lookup_candidates(receiver.type_name)
4156 }
4157 TypeValue {
4158 struct_field_lookup_candidates(receiver.name)
4159 }
4160 else {
4161 []string{}
4162 }
4163 }
4164}
4165
4166fn (e &Eval) resolve_method_target(receiver Value, method_name string) ?MaybeFunctionTarget {
4167 candidates := receiver_method_type_candidates(receiver)
4168 if candidates.len == 0 {
4169 return none
4170 }
4171 for module_name, functions in e.functions {
4172 for candidate in candidates {
4173 key := '${candidate}__${method_name}'
4174 if key in functions {
4175 return MaybeFunctionTarget{
4176 found: true
4177 module_name: module_name
4178 fn_name: key
4179 }
4180 }
4181 }
4182 }
4183 return none
4184}
4185
4186fn (e &Eval) append_builder_string(mut items []Value, s string) {
4187 for b in s.bytes() {
4188 items << i64(b)
4189 }
4190}
4191
4192fn (e &Eval) append_builder_rune(mut items []Value, r i64) {
4193 e.append_builder_string(mut items, rune(r).str())
4194}
4195
4196fn (e &Eval) builder_array_to_string(receiver ArrayValue) string {
4197 mut bytes := []u8{cap: receiver.values.len}
4198 for item in receiver.values {
4199 bytes << u8(e.value_as_int(item) or { 0 })
4200 }
4201 return bytes.bytestr()
4202}
4203
4204fn (e &Eval) builder_slice_string(receiver ArrayValue, start_pos int, n int) string {
4205 if start_pos < 0 || n <= 0 || start_pos >= receiver.values.len {
4206 return ''
4207 }
4208 end := if start_pos + n > receiver.values.len {
4209 receiver.values.len
4210 } else {
4211 start_pos + n
4212 }
4213 return e.builder_array_to_string(ArrayValue{
4214 values: receiver.values[start_pos..end].clone()
4215 })
4216}
4217
4218fn (e &Eval) builder_tail_string(receiver ArrayValue, n int) string {
4219 if n <= 0 || n > receiver.values.len {
4220 return ''
4221 }
4222 return e.builder_array_to_string(ArrayValue{
4223 values: receiver.values[receiver.values.len - n..].clone()
4224 })
4225}
4226
4227fn (mut e Eval) eval_if_value(expr ast.IfExpr) !Value {
4228 should_run := if expr.cond is ast.EmptyExpr {
4229 true
4230 } else {
4231 e.value_as_bool(e.eval_expr(expr.cond)!)!
4232 }
4233 if should_run {
4234 return e.eval_block_value(expr.stmts)
4235 }
4236 if expr.else_expr is ast.IfExpr {
4237 return e.eval_if_value(expr.else_expr)
4238 }
4239 if expr.else_expr is ast.EmptyExpr {
4240 return void_value()
4241 }
4242 return e.eval_expr(expr.else_expr)
4243}
4244
4245fn (e &Eval) resolve_mangled_function_target(name string) ?MaybeFunctionTarget {
4246 for module_name, functions in e.functions {
4247 prefix := e.mangled_module_name(module_name) + '__'
4248 if !name.starts_with(prefix) {
4249 continue
4250 }
4251 fn_name := name[prefix.len..]
4252 if fn_name in functions {
4253 return MaybeFunctionTarget{
4254 found: true
4255 module_name: module_name
4256 fn_name: fn_name
4257 }
4258 }
4259 }
4260 return none
4261}
4262
4263fn (mut e Eval) eval_block_value(stmts []ast.Stmt) !Value {
4264 e.open_scope()
4265 defer {
4266 e.close_scope() or {}
4267 }
4268 if stmts.len == 0 {
4269 return void_value()
4270 }
4271 for i, stmt in stmts {
4272 is_last := i == stmts.len - 1
4273 if is_last && stmt is ast.ExprStmt {
4274 if stmt.expr is ast.IfExpr {
4275 return e.eval_if_value(stmt.expr)
4276 }
4277 return e.eval_expr(stmt.expr)
4278 }
4279 signal := e.exec_stmt(stmt)!
4280 if signal.kind != .normal {
4281 return error('v2.eval: control flow inside expression block is not supported yet')
4282 }
4283 }
4284 return void_value()
4285}
4286
4287fn (mut e Eval) eval_index_expr(expr ast.IndexExpr) !Value {
4288 container := e.eval_expr(expr.lhs)!
4289 if expr.expr is ast.RangeExpr {
4290 range_value := e.eval_expr(expr.expr)! as RangeValue
4291 start := int(range_value.start)
4292 end := int(range_value.end) + if range_value.inclusive { 1 } else { 0 }
4293 match container {
4294 ArrayValue {
4295 return ArrayValue{
4296 values: container.values[start..end]
4297 }
4298 }
4299 string {
4300 s := container[start..end]
4301 return s
4302 }
4303 else {
4304 return error('v2.eval: slicing is only supported for arrays and strings')
4305 }
4306 }
4307 }
4308 index_value := e.eval_expr(expr.expr)!
4309 match container {
4310 ArrayValue {
4311 index := int(e.value_as_int(index_value)!)
4312 if index < 0 || index >= container.values.len {
4313 return error('v2.eval: array index out of bounds')
4314 }
4315 return container.values[index]
4316 }
4317 MapValue {
4318 return e.map_get_or_default(container, index_value)
4319 }
4320 string {
4321 index := int(e.value_as_int(index_value)!)
4322 if index < 0 || index >= container.len {
4323 return error('v2.eval: string index out of bounds')
4324 }
4325 return i64(container[index])
4326 }
4327 else {
4328 return error('v2.eval: unsupported index target `${e.runtime_type_name(container)}`')
4329 }
4330 }
4331}
4332
4333fn (mut e Eval) eval_infix_expr(expr ast.InfixExpr) !Value {
4334 if expr.op == .and {
4335 left := e.value_as_bool(e.eval_expr(expr.lhs)!)!
4336 if !left {
4337 return Value(false)
4338 }
4339 return e.value_as_bool(e.eval_expr(expr.rhs)!)!
4340 }
4341 if expr.op == .logical_or {
4342 left := e.value_as_bool(e.eval_expr(expr.lhs)!)!
4343 if left {
4344 return Value(true)
4345 }
4346 return e.value_as_bool(e.eval_expr(expr.rhs)!)!
4347 }
4348 left := e.eval_expr(expr.lhs)!
4349 right := e.eval_expr(expr.rhs)!
4350 return e.apply_infix(expr.op, left, right)
4351}
4352
4353fn (mut e Eval) apply_infix(op token.Token, left Value, right Value) !Value {
4354 match op {
4355 .plus {
4356 if left is string || right is string {
4357 return e.value_string(left) + e.value_string(right)
4358 }
4359 if left is f64 || right is f64 {
4360 return e.value_as_f64(left)! + e.value_as_f64(right)!
4361 }
4362 return e.value_as_int(left)! + e.value_as_int(right)!
4363 }
4364 .minus {
4365 if left is f64 || right is f64 {
4366 return e.value_as_f64(left)! - e.value_as_f64(right)!
4367 }
4368 return e.value_as_int(left)! - e.value_as_int(right)!
4369 }
4370 .mul {
4371 if left is f64 || right is f64 {
4372 return e.value_as_f64(left)! * e.value_as_f64(right)!
4373 }
4374 return e.value_as_int(left)! * e.value_as_int(right)!
4375 }
4376 .div {
4377 if left is f64 || right is f64 {
4378 return e.value_as_f64(left)! / e.value_as_f64(right)!
4379 }
4380 return e.value_as_int(left)! / e.value_as_int(right)!
4381 }
4382 .mod {
4383 return e.value_as_int(left)! % e.value_as_int(right)!
4384 }
4385 .eq {
4386 return e.value_eq(left, right)
4387 }
4388 .ne {
4389 return !e.value_eq(left, right)
4390 }
4391 .lt {
4392 return e.compare_values(left, right) < 0
4393 }
4394 .le {
4395 return e.compare_values(left, right) <= 0
4396 }
4397 .gt {
4398 return e.compare_values(left, right) > 0
4399 }
4400 .ge {
4401 return e.compare_values(left, right) >= 0
4402 }
4403 .key_is {
4404 return e.value_is_type(left, right)
4405 }
4406 .not_is {
4407 return !e.value_is_type(left, right)
4408 }
4409 .amp {
4410 return e.value_as_int(left)! & e.value_as_int(right)!
4411 }
4412 .pipe {
4413 return e.value_as_int(left)! | e.value_as_int(right)!
4414 }
4415 .xor {
4416 return e.value_as_int(left)! ^ e.value_as_int(right)!
4417 }
4418 .left_shift {
4419 return i64(u64(e.value_as_int(left)!) << u64(e.value_as_int(right)!))
4420 }
4421 .right_shift {
4422 return e.value_as_int(left)! >> e.value_as_int(right)!
4423 }
4424 .right_shift_unsigned {
4425 return i64(u64(e.value_as_int(left)!) >> u64(e.value_as_int(right)!))
4426 }
4427 .key_in {
4428 match right {
4429 ArrayValue {
4430 for item in right.values {
4431 if e.value_eq(left, item) {
4432 return true
4433 }
4434 }
4435 return false
4436 }
4437 string {
4438 return right.contains(e.value_string(left))
4439 }
4440 MapValue {
4441 return e.map_contains_key(right, left)
4442 }
4443 else {
4444 return error('v2.eval: unsupported `in` rhs `${e.runtime_type_name(right)}`')
4445 }
4446 }
4447 }
4448 .not_in {
4449 in_result := e.apply_infix(.key_in, left, right)!
4450 return !e.value_as_bool(in_result)!
4451 }
4452 else {
4453 return error('v2.eval: unsupported infix operator `${op}`')
4454 }
4455 }
4456}
4457
4458fn (e &Eval) value_is_type(value Value, rhs Value) bool {
4459 target_name := match rhs {
4460 TypeValue { rhs.name }
4461 string { rhs }
4462 else { e.runtime_type_name(rhs) }
4463 }
4464
4465 if value is StructValue && e.unwrap_sumtype_value(value, target_name) != none {
4466 return true
4467 }
4468 return e.value_matches_type_name(value, target_name)
4469}
4470
4471fn (e &Eval) compare_values(left Value, right Value) int {
4472 if left is string || right is string {
4473 ls := e.value_string(left)
4474 rs := e.value_string(right)
4475 if ls < rs {
4476 return -1
4477 }
4478 if ls > rs {
4479 return 1
4480 }
4481 return 0
4482 }
4483 if left is f64 || right is f64 {
4484 lf := e.value_as_f64(left) or { 0.0 }
4485 rf := e.value_as_f64(right) or { 0.0 }
4486 if lf < rf {
4487 return -1
4488 }
4489 if lf > rf {
4490 return 1
4491 }
4492 return 0
4493 }
4494 li := e.value_as_int(left) or { 0 }
4495 ri := e.value_as_int(right) or { 0 }
4496 if li < ri {
4497 return -1
4498 }
4499 if li > ri {
4500 return 1
4501 }
4502 return 0
4503}
4504
4505fn (e &Eval) value_eq(left Value, right Value) bool {
4506 match left {
4507 bool {
4508 return right is bool && left == right
4509 }
4510 i64 {
4511 if right is i64 {
4512 return left == right
4513 }
4514 if right is f64 {
4515 return f64(left) == value_f64_payload(right)
4516 }
4517 return false
4518 }
4519 f64 {
4520 left_f := value_f64_payload(left)
4521 if right is f64 {
4522 return left_f == value_f64_payload(right)
4523 }
4524 if right is i64 {
4525 return left_f == f64(right)
4526 }
4527 return false
4528 }
4529 string {
4530 return right is string && left == right
4531 }
4532 ArrayValue {
4533 if right !is ArrayValue {
4534 return false
4535 }
4536 right_array := right as ArrayValue
4537 if left.values.len != right_array.values.len {
4538 return false
4539 }
4540 for i, item in left.values {
4541 if !e.value_eq(item, right_array.values[i]) {
4542 return false
4543 }
4544 }
4545 return true
4546 }
4547 MapValue {
4548 if right !is MapValue {
4549 return false
4550 }
4551 right_map := right as MapValue
4552 if left.entries.len != right_map.entries.len {
4553 return false
4554 }
4555 for entry in left.entries {
4556 right_value, found := e.map_lookup(right_map, entry.key)
4557 if !found || !e.value_eq(entry.value, right_value) {
4558 return false
4559 }
4560 }
4561 return true
4562 }
4563 StructValue {
4564 if right !is StructValue {
4565 return false
4566 }
4567 right_struct := right as StructValue
4568 if left.type_name != right_struct.type_name
4569 || left.fields.len != right_struct.fields.len {
4570 return false
4571 }
4572 for key, value in left.fields {
4573 right_value := right_struct.fields[key] or { return false }
4574 if !e.value_eq(value, right_value) {
4575 return false
4576 }
4577 }
4578 return true
4579 }
4580 FlagsValue {
4581 return right is FlagsValue
4582 }
4583 ModuleValue {
4584 return right is ModuleValue && left.name == right.name
4585 }
4586 TypeValue {
4587 return right is TypeValue && left.name == right.name
4588 }
4589 VoidValue {
4590 return right is VoidValue
4591 }
4592 TupleValue {
4593 if right !is TupleValue {
4594 return false
4595 }
4596 right_tuple := right as TupleValue
4597 if left.values.len != right_tuple.values.len {
4598 return false
4599 }
4600 for i, item in left.values {
4601 if !e.value_eq(item, right_tuple.values[i]) {
4602 return false
4603 }
4604 }
4605 return true
4606 }
4607 RangeValue {
4608 return right is RangeValue && left.start == right.start && left.end == right.end
4609 && left.inclusive == right.inclusive
4610 }
4611 }
4612}
4613
4614fn (mut e Eval) eval_keyword_operator(expr ast.KeywordOperator) !Value {
4615 match expr.op {
4616 .key_isreftype {
4617 if expr.exprs.len == 0 {
4618 return error('v2.eval: isreftype expects one argument')
4619 }
4620 if e.is_type_expr(expr.exprs[0]) {
4621 return e.is_ref_type_name(e.type_expr_name(expr.exprs[0]))
4622 }
4623 value := e.eval_expr(expr.exprs[0])!
4624 return e.is_ref_type_name(e.runtime_type_name(value))
4625 }
4626 .key_sizeof {
4627 if expr.exprs.len == 0 {
4628 return error('v2.eval: sizeof expects one argument')
4629 }
4630 if e.is_type_expr(expr.exprs[0]) {
4631 return e.sizeof_type_name(e.type_expr_name(expr.exprs[0]))
4632 }
4633 value := e.eval_expr(expr.exprs[0])!
4634 return e.sizeof_type_name(e.runtime_type_name(value))
4635 }
4636 .key_typeof {
4637 if expr.exprs.len == 0 {
4638 return error('v2.eval: typeof expects one argument')
4639 }
4640 value := e.eval_expr(expr.exprs[0])!
4641 return TypeValue{
4642 name: e.runtime_type_name(value)
4643 }
4644 }
4645 else {
4646 return error('v2.eval: unsupported keyword operator `${expr.op}`')
4647 }
4648 }
4649}
4650
4651fn (mut e Eval) eval_postfix_expr(expr ast.PostfixExpr) !Value {
4652 if !can_update_target(expr.expr) {
4653 return error('v2.eval: postfix update expects an assignable target')
4654 }
4655 current := e.eval_expr(expr.expr)!
4656 current_i64 := e.value_as_int(current)!
4657 updated := if expr.op == .inc { current_i64 + 1 } else { current_i64 - 1 }
4658 e.update_target(expr.expr, updated)!
4659 return updated
4660}
4661
4662fn (mut e Eval) eval_prefix_expr(expr ast.PrefixExpr) !Value {
4663 value := e.eval_expr(expr.expr)!
4664 match expr.op {
4665 .not {
4666 return !e.value_as_bool(value)!
4667 }
4668 .amp, .mul {
4669 return value
4670 }
4671 .bit_not {
4672 return ~e.value_as_int(value)!
4673 }
4674 .minus {
4675 if value is f64 {
4676 f := -value_f64_payload(value)
4677 return f
4678 }
4679 return -e.value_as_int(value)!
4680 }
4681 .plus {
4682 return value
4683 }
4684 else {
4685 return error('v2.eval: unsupported prefix operator `${expr.op}`')
4686 }
4687 }
4688}
4689
4690fn (mut e Eval) eval_selector_expr(expr ast.SelectorExpr) !Value {
4691 if expr.lhs is ast.EmptyExpr {
4692 const_result := e.lookup_const(e.current_module_name(), expr.rhs.name)
4693 if const_result.found {
4694 return const_result.value
4695 }
4696 return error('v2.eval: enum shorthand `${expr.rhs.name}` is not supported yet')
4697 }
4698 left := e.eval_expr(expr.lhs)!
4699 if expr.rhs.name == '_tag' {
4700 if tag := e.contextual_sumtype_tag(expr.lhs, left) {
4701 return i64(tag)
4702 }
4703 }
4704 if expr.rhs.name == '_data' {
4705 if left !is StructValue || '_data' !in (left as StructValue).fields {
4706 if _ := e.contextual_sumtype_tag(expr.lhs, left) {
4707 return left
4708 }
4709 }
4710 }
4711 match left {
4712 ModuleValue {
4713 prop := e.module_property(left.name, expr.rhs.name)
4714 if prop.found {
4715 return prop.value
4716 }
4717 if e.has_type_name(left.name, expr.rhs.name) {
4718 return TypeValue{
4719 name: '${left.name}.${expr.rhs.name}'
4720 }
4721 }
4722 if expr.rhs.name.contains('__') {
4723 short_name := expr.rhs.name.all_after_last('__')
4724 if short_name != '' {
4725 if e.has_type_name(left.name, short_name) {
4726 return TypeValue{
4727 name: '${left.name}.${short_name}'
4728 }
4729 }
4730 const_result := e.lookup_const(left.name, short_name)
4731 if const_result.found {
4732 return const_result.value
4733 }
4734 }
4735 module_prefix := e.mangled_module_name(left.name) + '__'
4736 if expr.rhs.name.starts_with(module_prefix) {
4737 normalized_name := expr.rhs.name[module_prefix.len..]
4738 if e.has_type_name(left.name, normalized_name) {
4739 return TypeValue{
4740 name: '${left.name}.${normalized_name}'
4741 }
4742 }
4743 }
4744 }
4745 const_result := e.lookup_const(left.name, expr.rhs.name)
4746 if const_result.found {
4747 return const_result.value
4748 }
4749 return error('v2.eval: unknown module selector `${left.name}.${expr.rhs.name}`')
4750 }
4751 ArrayValue {
4752 if expr.rhs.name == 'len' {
4753 return i64(left.values.len)
4754 }
4755 if expr.rhs.name == 'flags' {
4756 return FlagsValue{}
4757 }
4758 if expr.rhs.name == 'str' {
4759 return e.value_string(left)
4760 }
4761 }
4762 MapValue {
4763 if expr.rhs.name == 'len' {
4764 return i64(left.entries.len)
4765 }
4766 if expr.rhs.name == 'str' {
4767 return e.value_string(left)
4768 }
4769 }
4770 StructValue {
4771 if expr.rhs.name == 'mtx' {
4772 return StructValue{
4773 type_name: 'sync__RwMutex'
4774 fields: map[string]Value{}
4775 }
4776 }
4777 if expr.rhs.name == '_tag' {
4778 if tag := e.inferred_sumtype_tag(left) {
4779 return i64(tag)
4780 }
4781 }
4782 if expr.rhs.name == '_data' && '_data' !in left.fields {
4783 if _ := e.inferred_sumtype_tag(left) {
4784 return left
4785 }
4786 }
4787 if variant_value := e.sumtype_variant_field_value(left, expr.rhs.name) {
4788 return variant_value
4789 }
4790 if expr.rhs.name in left.fields {
4791 field_value := left.fields[expr.rhs.name] or {
4792 return error('v2.eval: unknown struct field `${expr.rhs.name}` on `${left.type_name}` fields `${left.fields.keys()}` in `${e.current_function_label()}` stack `${e.call_stack_trace()}`')
4793 }
4794 if left.type_name.ends_with('._data') && expr.rhs.name.starts_with('_')
4795 && is_semantically_empty_value(field_value) {
4796 if zero_payload := e.zero_value_for_sumtype_data_field(left.type_name,
4797 expr.rhs.name)
4798 {
4799 return zero_payload
4800 }
4801 }
4802 return field_value
4803 }
4804 if zero_payload := e.zero_value_for_sumtype_data_field(left.type_name, expr.rhs.name) {
4805 return zero_payload
4806 }
4807 if embedded_value := e.lookup_embedded_struct_field_value(left, expr.rhs.name, 0) {
4808 return embedded_value
4809 }
4810 if field_type := e.lookup_struct_field_type(left.type_name, expr.rhs.name) {
4811 return e.zero_value_for_type_expr(field_type)
4812 }
4813 return error('v2.eval: unknown struct field `${expr.rhs.name}` on `${left.type_name}` fields `${left.fields.keys()}` in `${e.current_function_label()}` stack `${e.call_stack_trace()}`')
4814 }
4815 string {
4816 if expr.rhs.name == 'len' {
4817 return i64(left.len)
4818 }
4819 if expr.rhs.name == 'str' {
4820 return left
4821 }
4822 }
4823 i64 {
4824 if expr.rhs.name == 'str' {
4825 return e.value_string(left)
4826 }
4827 if expr.rhs.name == '_tag' || expr.rhs.name == '_data' {
4828 return Value(left)
4829 }
4830 }
4831 f64 {
4832 if expr.rhs.name == 'str' {
4833 return e.value_string(left)
4834 }
4835 }
4836 bool {
4837 if expr.rhs.name == 'str' {
4838 return e.value_string(left)
4839 }
4840 }
4841 TypeValue {
4842 if expr.rhs.name == '_tag' {
4843 if tag := e.inferred_sumtype_tag(left) {
4844 return i64(tag)
4845 }
4846 }
4847 if expr.rhs.name == '_data' {
4848 if _ := e.inferred_sumtype_tag(left) {
4849 return left
4850 }
4851 }
4852 module_name := e.type_value_module_name(left)
4853 if module_name != '' {
4854 const_result := e.lookup_const(module_name, expr.rhs.name)
4855 if const_result.found {
4856 return const_result.value
4857 }
4858 }
4859 if expr.rhs.name == 'name' {
4860 s := left.name
4861 v := Value(s)
4862 return v
4863 }
4864 }
4865 else {}
4866 }
4867
4868 return error('v2.eval: unsupported selector `${expr.rhs.name}` on `${e.runtime_type_name(left)}` from `${expr.lhs.type_name()}` `${expr.lhs.name()}` in `${e.current_function_label()}`')
4869}
4870
4871fn (e &Eval) type_value_module_name(value TypeValue) string {
4872 if !value.name.contains('.') {
4873 return ''
4874 }
4875 return value.name.all_before_last('.')
4876}
4877
4878fn struct_field_lookup_candidates(type_name string) []string {
4879 mut candidates := []string{}
4880 mut trimmed := type_name.trim_left('&').trim_right('*')
4881 if trimmed == '' {
4882 return candidates
4883 }
4884 add_type_name_alias(mut candidates, trimmed)
4885 if trimmed.contains('__') {
4886 add_type_name_alias(mut candidates, trimmed.replace('__', '.'))
4887 add_type_name_alias(mut candidates, trimmed.all_after_last('__'))
4888 }
4889 if trimmed.contains('.') {
4890 add_type_name_alias(mut candidates, trimmed.all_after_last('.'))
4891 }
4892 return candidates
4893}
4894
4895fn (e &Eval) qualify_type_name(module_name string, type_name string) string {
4896 if module_name == '' || type_name == '' {
4897 return type_name
4898 }
4899 if type_name.starts_with('[]') {
4900 return '[]' + e.qualify_type_name(module_name, type_name[2..])
4901 }
4902 if type_name.starts_with('?') || type_name.starts_with('!') {
4903 return type_name[..1] + e.qualify_type_name(module_name, type_name[1..])
4904 }
4905 if type_name.starts_with('&') {
4906 return '&' + e.qualify_type_name(module_name, type_name[1..])
4907 }
4908 if type_name.starts_with('chan ') {
4909 return 'chan ' + e.qualify_type_name(module_name, type_name[5..])
4910 }
4911 if type_name.starts_with('thread ') {
4912 return 'thread ' + e.qualify_type_name(module_name, type_name[7..])
4913 }
4914 if type_name.starts_with('map[') {
4915 inner := type_name[4..]
4916 if bracket_idx := inner.index(']') {
4917 key_name := inner[..bracket_idx]
4918 value_name := inner[bracket_idx + 1..]
4919 return 'map[${e.qualify_type_name(module_name, key_name)}]${e.qualify_type_name(module_name,
4920 value_name)}'
4921 }
4922 }
4923 if (type_name.starts_with('[') && type_name.contains(']'))
4924 || type_name.contains('.') || type_name.contains('__')
4925 || e.is_builtin_type_name(type_name) || type_name in ['nil', 'none'] {
4926 return type_name
4927 }
4928 if e.has_type_name(module_name, type_name) {
4929 return '${module_name}.${type_name}'
4930 }
4931 return type_name
4932}
4933
4934fn (e &Eval) qualify_type_expr(module_name string, expr ast.Expr) ast.Expr {
4935 return match expr {
4936 ast.GenericArgs {
4937 ast.Expr(ast.GenericArgs{
4938 lhs: e.qualify_type_expr(module_name, expr.lhs)
4939 args: expr.args.map(e.qualify_type_expr(module_name, it))
4940 pos: expr.pos
4941 })
4942 }
4943 ast.Ident {
4944 qualified_name := e.qualify_type_name(module_name, expr.name)
4945 if qualified_name == expr.name {
4946 ast.Expr(expr)
4947 } else {
4948 parts := qualified_name.split('.')
4949 if parts.len == 2 {
4950 ast.Expr(ast.SelectorExpr{
4951 lhs: ast.Expr(ast.Ident{
4952 name: parts[0]
4953 })
4954 rhs: ast.Ident{
4955 name: parts[1]
4956 }
4957 })
4958 } else {
4959 ast.Expr(expr)
4960 }
4961 }
4962 }
4963 ast.ModifierExpr {
4964 ast.Expr(ast.ModifierExpr{
4965 kind: expr.kind
4966 expr: e.qualify_type_expr(module_name, expr.expr)
4967 })
4968 }
4969 ast.ParenExpr {
4970 ast.Expr(ast.ParenExpr{
4971 expr: e.qualify_type_expr(module_name, expr.expr)
4972 })
4973 }
4974 ast.Type {
4975 match expr {
4976 ast.ArrayFixedType {
4977 ast.Expr(ast.Type(ast.ArrayFixedType{
4978 len: expr.len
4979 elem_type: e.qualify_type_expr(module_name, expr.elem_type)
4980 }))
4981 }
4982 ast.ArrayType {
4983 ast.Expr(ast.Type(ast.ArrayType{
4984 elem_type: e.qualify_type_expr(module_name, expr.elem_type)
4985 }))
4986 }
4987 ast.ChannelType {
4988 ast.Expr(ast.Type(ast.ChannelType{
4989 cap: expr.cap
4990 elem_type: e.qualify_type_expr(module_name, expr.elem_type)
4991 }))
4992 }
4993 ast.GenericType {
4994 ast.Expr(ast.Type(ast.GenericType{
4995 name: e.qualify_type_expr(module_name, expr.name)
4996 params: expr.params.map(e.qualify_type_expr(module_name, it))
4997 }))
4998 }
4999 ast.MapType {
5000 ast.Expr(ast.Type(ast.MapType{
5001 key_type: e.qualify_type_expr(module_name, expr.key_type)
5002 value_type: e.qualify_type_expr(module_name, expr.value_type)
5003 }))
5004 }
5005 ast.OptionType {
5006 ast.Expr(ast.Type(ast.OptionType{
5007 base_type: e.qualify_type_expr(module_name, expr.base_type)
5008 }))
5009 }
5010 ast.ResultType {
5011 ast.Expr(ast.Type(ast.ResultType{
5012 base_type: e.qualify_type_expr(module_name, expr.base_type)
5013 }))
5014 }
5015 ast.ThreadType {
5016 ast.Expr(ast.Type(ast.ThreadType{
5017 elem_type: e.qualify_type_expr(module_name, expr.elem_type)
5018 }))
5019 }
5020 ast.TupleType {
5021 ast.Expr(ast.Type(ast.TupleType{
5022 types: expr.types.map(e.qualify_type_expr(module_name, it))
5023 }))
5024 }
5025 else {
5026 expr
5027 }
5028 }
5029 }
5030 else {
5031 expr
5032 }
5033 }
5034}
5035
5036fn (e &Eval) lookup_struct_embed_types(type_name string) []string {
5037 for candidate in struct_field_lookup_candidates(type_name) {
5038 mut module_name := ''
5039 mut short_type_name := candidate
5040 if candidate.contains('.') {
5041 module_name = candidate.all_before_last('.')
5042 short_type_name = candidate.all_after_last('.')
5043 }
5044 if module_name != '' {
5045 if module_embeds := e.struct_embeds[module_name] {
5046 if embed_names := module_embeds[short_type_name] {
5047 return embed_names.map(e.qualify_type_name(module_name, it))
5048 }
5049 }
5050 continue
5051 }
5052 current_module := e.current_module_name()
5053 if module_embeds := e.struct_embeds[current_module] {
5054 if embed_names := module_embeds[short_type_name] {
5055 return embed_names.map(e.qualify_type_name(current_module, it))
5056 }
5057 }
5058 for mod_name, module_embeds in e.struct_embeds {
5059 if embed_names := module_embeds[short_type_name] {
5060 return embed_names.map(e.qualify_type_name(mod_name, it))
5061 }
5062 }
5063 }
5064 return []string{}
5065}
5066
5067fn (e &Eval) lookup_struct_field_type(type_name string, field_name string) ?ast.Expr {
5068 return e.lookup_struct_field_type_with_depth(type_name, field_name, 0)
5069}
5070
5071fn (e &Eval) lookup_struct_field_type_with_depth(type_name string, field_name string, depth int) ?ast.Expr {
5072 if depth > 16 {
5073 return none
5074 }
5075 for candidate in struct_field_lookup_candidates(type_name) {
5076 mut module_name := ''
5077 mut short_type_name := candidate
5078 if candidate.contains('.') {
5079 module_name = candidate.all_before_last('.')
5080 short_type_name = candidate.all_after_last('.')
5081 }
5082 if module_name != '' {
5083 if module_fields := e.struct_field_types[module_name] {
5084 if type_fields := module_fields[short_type_name] {
5085 if field_name in type_fields {
5086 return e.qualify_type_expr(module_name, type_fields[field_name] or {
5087 return none
5088 })
5089 }
5090 }
5091 }
5092 for embedded_type in e.lookup_struct_embed_types(candidate) {
5093 if embedded_field_type := e.lookup_struct_field_type_with_depth(embedded_type,
5094 field_name, depth + 1)
5095 {
5096 return embedded_field_type
5097 }
5098 }
5099 continue
5100 }
5101 current_module := e.current_module_name()
5102 if module_fields := e.struct_field_types[current_module] {
5103 if type_fields := module_fields[short_type_name] {
5104 if field_name in type_fields {
5105 return e.qualify_type_expr(current_module, type_fields[field_name] or {
5106 return none
5107 })
5108 }
5109 }
5110 }
5111 for mod_name, module_fields in e.struct_field_types {
5112 if type_fields := module_fields[short_type_name] {
5113 if field_name in type_fields {
5114 return e.qualify_type_expr(mod_name, type_fields[field_name] or { return none })
5115 }
5116 }
5117 }
5118 for embedded_type in e.lookup_struct_embed_types(candidate) {
5119 if embedded_field_type := e.lookup_struct_field_type_with_depth(embedded_type,
5120 field_name, depth + 1)
5121 {
5122 return embedded_field_type
5123 }
5124 }
5125 }
5126 return none
5127}
5128
5129fn (e &Eval) lookup_embedded_struct_field_value(value StructValue, field_name string, depth int) ?Value {
5130 if depth > 16 {
5131 return none
5132 }
5133 for embedded_type in e.lookup_struct_embed_types(value.type_name) {
5134 for embedded_alias in struct_field_lookup_candidates(embedded_type) {
5135 if embedded_value := value.fields[embedded_alias] {
5136 if embedded_value is StructValue {
5137 embedded_struct := embedded_value as StructValue
5138 if field_name in embedded_struct.fields {
5139 return embedded_struct.fields[field_name] or { return none }
5140 }
5141 if nested_value := e.lookup_embedded_struct_field_value(embedded_struct,
5142 field_name, depth + 1)
5143 {
5144 return nested_value
5145 }
5146 }
5147 }
5148 }
5149 }
5150 return none
5151}
5152
5153fn (e &Eval) zero_struct_value(type_name string) StructValue {
5154 if info := e.sum_type_info(type_name) {
5155 return e.build_sumtype_wrapper(type_name, info, 0, void_value())
5156 }
5157 mut fields := map[string]Value{}
5158 mut module_name := ''
5159 mut short_type_name := type_name
5160 if type_name.contains('.') {
5161 module_name = type_name.all_before_last('.')
5162 short_type_name = type_name.all_after_last('.')
5163 }
5164 if module_name != '' {
5165 if module_fields := e.struct_field_types[module_name] {
5166 if type_fields := module_fields[short_type_name] {
5167 for field_name, field_type in type_fields {
5168 fields[field_name] = e.zero_value_for_type_expr(e.qualify_type_expr(module_name,
5169 field_type))
5170 }
5171 }
5172 }
5173 } else if module_fields := e.struct_field_types[e.current_module_name()] {
5174 if type_fields := module_fields[short_type_name] {
5175 for field_name, field_type in type_fields {
5176 fields[field_name] = e.zero_value_for_type_expr(e.qualify_type_expr(e.current_module_name(),
5177 field_type))
5178 }
5179 }
5180 }
5181 return StructValue{
5182 type_name: type_name
5183 fields: fields
5184 }
5185}
5186
5187fn (mut e Eval) eval_string_inter(expr ast.StringInterLiteral) !Value {
5188 mut out := ''
5189 for i, part in expr.values {
5190 mut decoded := decode_string_literal(part)
5191 if part in ['"', "'"] && (i == 0 || i == expr.values.len - 1) {
5192 decoded = ''
5193 }
5194 out += decoded
5195 if i < expr.inters.len {
5196 inter := expr.inters[i]
5197 out += e.value_string(e.eval_expr(inter.expr)!)
5198 }
5199 }
5200 return out
5201}
5202
5203fn decode_string_literal(raw string) string {
5204 mut s := raw
5205 if s.len >= 2 && ((s[0] == `"` && s[s.len - 1] == `"`) || (s[0] == `'` && s[s.len - 1] == `'`)) {
5206 s = s[1..s.len - 1]
5207 }
5208 return s.replace('\\n', '\n').replace('\\r', '\r').replace('\\t', '\t').replace('\\0', '\0').replace('\\"',
5209 '"').replace("\\'", "'").replace('\\`', '`').replace('\\\\', '\\').replace('\\$', '$')
5210}
5211
5212fn (mut e Eval) eval_unsafe_expr(expr ast.UnsafeExpr) !Value {
5213 if expr.stmts.len == 0 {
5214 return void_value()
5215 }
5216 e.open_scope()
5217 defer {
5218 e.close_scope() or {}
5219 }
5220 for i, stmt in expr.stmts {
5221 is_last := i == expr.stmts.len - 1
5222 if is_last && stmt is ast.ExprStmt {
5223 return e.eval_expr(stmt.expr)
5224 }
5225 signal := e.exec_stmt(stmt)!
5226 if signal.kind != .normal {
5227 return error('v2.eval: control flow inside unsafe expression is not supported')
5228 }
5229 }
5230 return void_value()
5231}
5232
5233fn (mut e Eval) call_value_method(receiver Value, method_name string, args []Value) !Value {
5234 if method_name == 'str' && args.len == 0 {
5235 return e.value_string(receiver)
5236 }
5237 match receiver {
5238 string {
5239 return e.call_string_method(receiver, method_name, args)
5240 }
5241 ArrayValue {
5242 return e.call_array_method(receiver, method_name, args)
5243 }
5244 FlagsValue {
5245 return e.call_flags_method(method_name, args)
5246 }
5247 MapValue {
5248 if method_name == 'str' && args.len == 0 {
5249 return e.value_string(receiver)
5250 }
5251 }
5252 i64 {
5253 if args.len == 0 && receiver >= 0 && receiver <= 255 {
5254 if byte_value := eval_byte_method_value(u8(receiver), method_name) {
5255 return byte_value
5256 }
5257 }
5258 if args.len == 0 && method_name != 'str' {
5259 // Token enum values are stored as ints in eval, so enum helpers need a narrow cast here.
5260 if token_value := eval_token_method_value(unsafe { token.Token(int(receiver)) },
5261 method_name)
5262 {
5263 return token_value
5264 }
5265 }
5266 if method_name == 'str' && args.len == 0 {
5267 return e.value_string(receiver)
5268 }
5269 }
5270 f64, bool {
5271 if method_name == 'str' && args.len == 0 {
5272 return e.value_string(receiver)
5273 }
5274 }
5275 else {}
5276 }
5277
5278 return error('v2.eval: unsupported method `${method_name}` on `${e.runtime_type_name(receiver)}`')
5279}
5280
5281fn (mut e Eval) call_string_method(receiver string, method_name string, args []Value) !Value {
5282 match method_name {
5283 'all_after' {
5284 return receiver.all_after(e.expect_string_arg(args, 0)!)
5285 }
5286 'all_after_last' {
5287 return receiver.all_after_last(e.expect_string_arg(args, 0)!)
5288 }
5289 'all_before' {
5290 return receiver.all_before(e.expect_string_arg(args, 0)!)
5291 }
5292 'all_before_last' {
5293 return receiver.all_before_last(e.expect_string_arg(args, 0)!)
5294 }
5295 'contains' {
5296 return receiver.contains(e.expect_string_arg(args, 0)!)
5297 }
5298 'bytes', 'vbytes' {
5299 mut values := []Value{cap: receiver.len}
5300 for b in receiver.bytes() {
5301 values << i64(b)
5302 }
5303 return ArrayValue{
5304 values: values
5305 }
5306 }
5307 'clone' {
5308 return receiver.clone()
5309 }
5310 'ends_with' {
5311 return receiver.ends_with(e.expect_string_arg(args, 0)!)
5312 }
5313 'ge' {
5314 return receiver >= e.expect_string_arg(args, 0)!
5315 }
5316 'gt' {
5317 return receiver > e.expect_string_arg(args, 0)!
5318 }
5319 'int' {
5320 return i64(receiver.int())
5321 }
5322 'index' {
5323 idx := receiver.index(e.expect_string_arg(args, 0)!) or { return wrap_option_none() }
5324 return wrap_option_ok(i64(idx))
5325 }
5326 'i64' {
5327 return receiver.i64()
5328 }
5329 'last_index' {
5330 idx := receiver.last_index(e.expect_string_arg(args, 0)!) or {
5331 return wrap_option_none()
5332 }
5333 return wrap_option_ok(i64(idx))
5334 }
5335 'le' {
5336 return receiver <= e.expect_string_arg(args, 0)!
5337 }
5338 'lt' {
5339 return receiver < e.expect_string_arg(args, 0)!
5340 }
5341 'ne' {
5342 return receiver != e.expect_string_arg(args, 0)!
5343 }
5344 'plus' {
5345 return receiver + e.expect_string_arg(args, 0)!
5346 }
5347 'plus_two' {
5348 return receiver + e.expect_string_arg(args, 0)! + e.expect_string_arg(args, 1)!
5349 }
5350 'repeat' {
5351 return receiver.repeat(int(e.value_as_int(args[0])!))
5352 }
5353 'replace' {
5354 return receiver.replace(e.expect_string_arg(args, 0)!, e.expect_string_arg(args, 1)!)
5355 }
5356 'split' {
5357 return ArrayValue{
5358 values: receiver.split(e.expect_string_arg(args, 0)!).map(Value(it))
5359 }
5360 }
5361 'starts_with' {
5362 return receiver.starts_with(e.expect_string_arg(args, 0)!)
5363 }
5364 'substr', 'substr_unsafe' {
5365 start := int(e.value_as_int(args[0])!)
5366 end := int(e.value_as_int(args[1])!)
5367 if start < 0 || end < start || end > receiver.len {
5368 return ''
5369 }
5370 substr := receiver[start..end]
5371 return substr
5372 }
5373 'substr_with_check' {
5374 start := int(e.value_as_int(args[0])!)
5375 end := int(e.value_as_int(args[1])!)
5376 if start < 0 || end < start || end > receiver.len {
5377 return wrap_result_err('substring out of bounds')
5378 }
5379 substr := receiver[start..end]
5380 return wrap_result_ok(substr)
5381 }
5382 'to_lower' {
5383 return receiver.to_lower()
5384 }
5385 'to_upper' {
5386 return receiver.to_upper()
5387 }
5388 'trim' {
5389 return receiver.trim(e.expect_string_arg(args, 0)!)
5390 }
5391 'trim_right' {
5392 return receiver.trim_right(e.expect_string_arg(args, 0)!)
5393 }
5394 'trim_space' {
5395 return receiver.trim_space()
5396 }
5397 else {
5398 return error('v2.eval: unsupported string method `${method_name}`')
5399 }
5400 }
5401}
5402
5403fn (e &Eval) call_flags_method(method_name string, args []Value) !Value {
5404 _ = args
5405 return match method_name {
5406 'set', 'clear' { void_value() }
5407 'has' { Value(false) }
5408 else { error('v2.eval: unsupported flags method `${method_name}`') }
5409 }
5410}
5411
5412fn (mut e Eval) call_array_method(receiver ArrayValue, method_name string, args []Value) !Value {
5413 match method_name {
5414 'has' {
5415 return e.array_has(receiver, safe_arg(args, 0))
5416 }
5417 'clone' {
5418 return ArrayValue{
5419 elem_type_name: receiver.elem_type_name
5420 values: receiver.values.clone()
5421 }
5422 }
5423 'contains' {
5424 return e.array_contains(receiver, safe_arg(args, 0))
5425 }
5426 'first' {
5427 return e.array_first_value(receiver)
5428 }
5429 'index' {
5430 return e.array_index(receiver, safe_arg(args, 0), false)
5431 }
5432 'join' {
5433 sep := e.expect_string_arg(args, 0)!
5434 return receiver.values.map(e.value_string(it)).join(sep)
5435 }
5436 'last' {
5437 return e.array_last_value(receiver)
5438 }
5439 'last_index' {
5440 return e.array_index(receiver, safe_arg(args, 0), true)
5441 }
5442 'str' {
5443 return e.value_string(receiver)
5444 }
5445 else {
5446 return error('v2.eval: unsupported array method `${method_name}`')
5447 }
5448 }
5449}
5450
5451fn (e &Eval) map_lookup(receiver MapValue, key Value) (Value, bool) {
5452 for entry in receiver.entries {
5453 if e.value_eq(entry.key, key) {
5454 return entry.value, true
5455 }
5456 }
5457 return receiver.default_value, false
5458}
5459
5460fn (e &Eval) map_get_or_default(receiver MapValue, key Value) Value {
5461 value, found := e.map_lookup(receiver, key)
5462 if found {
5463 return value
5464 }
5465 return receiver.default_value
5466}
5467
5468fn (e &Eval) map_contains_key(receiver MapValue, key Value) bool {
5469 _, found := e.map_lookup(receiver, key)
5470 return found
5471}
5472
5473fn (e &Eval) map_set_value(receiver MapValue, key Value, value Value) MapValue {
5474 default_value := if receiver.default_value is VoidValue {
5475 e.zero_value_like(value)
5476 } else {
5477 receiver.default_value
5478 }
5479 mut entries := receiver.entries.clone()
5480 for i, entry in entries {
5481 if e.value_eq(entry.key, key) {
5482 entries[i] = MapEntry{
5483 key: key
5484 value: value
5485 }
5486 return MapValue{
5487 default_value: default_value
5488 entries: entries
5489 }
5490 }
5491 }
5492 entries << MapEntry{
5493 key: key
5494 value: value
5495 }
5496 return MapValue{
5497 default_value: default_value
5498 entries: entries
5499 }
5500}
5501
5502fn (e &Eval) map_delete_value(receiver MapValue, key Value) MapValue {
5503 mut entries := []MapEntry{cap: receiver.entries.len}
5504 for entry in receiver.entries {
5505 if e.value_eq(entry.key, key) {
5506 continue
5507 }
5508 entries << entry
5509 }
5510 return MapValue{
5511 default_value: receiver.default_value
5512 entries: entries
5513 }
5514}
5515
5516fn (e &Eval) map_keys(receiver MapValue) ArrayValue {
5517 mut keys := []Value{cap: receiver.entries.len}
5518 for entry in receiver.entries {
5519 keys << entry.key
5520 }
5521 return ArrayValue{
5522 elem_type_name: e.infer_array_elem_type(keys)
5523 values: keys
5524 }
5525}
5526
5527fn (e &Eval) map_values(receiver MapValue) ArrayValue {
5528 mut values := []Value{cap: receiver.entries.len}
5529 for entry in receiver.entries {
5530 values << entry.value
5531 }
5532 elem_type_name := if receiver.default_value is VoidValue {
5533 e.infer_array_elem_type(values)
5534 } else {
5535 e.runtime_type_name(receiver.default_value)
5536 }
5537 return ArrayValue{
5538 elem_type_name: elem_type_name
5539 values: values
5540 }
5541}
5542
5543fn (e &Eval) map_clone(receiver MapValue) MapValue {
5544 return MapValue{
5545 default_value: receiver.default_value
5546 entries: receiver.entries.clone()
5547 }
5548}
5549
5550fn (e &Eval) map_clear(receiver MapValue) MapValue {
5551 return MapValue{
5552 default_value: receiver.default_value
5553 entries: []MapEntry{}
5554 }
5555}
5556
5557fn (e &Eval) zero_value_like(value Value) Value {
5558 return match value {
5559 ArrayValue {
5560 ArrayValue{}
5561 }
5562 FlagsValue {
5563 FlagsValue{}
5564 }
5565 MapValue {
5566 MapValue{
5567 default_value: e.zero_value_like(value.default_value)
5568 }
5569 }
5570 StructValue {
5571 e.zero_struct_value(value.type_name)
5572 }
5573 TupleValue {
5574 TupleValue{}
5575 }
5576 VoidValue {
5577 void_value()
5578 }
5579 bool {
5580 false
5581 }
5582 f64 {
5583 f64(0.0)
5584 }
5585 i64 {
5586 i64(0)
5587 }
5588 string {
5589 ''
5590 }
5591 else {
5592 void_value()
5593 }
5594 }
5595}
5596
5597fn (e &Eval) zero_value_for_type_expr(expr ast.Expr) Value {
5598 match expr {
5599 ast.GenericArgs {
5600 if expr.lhs.name() == 'map' && expr.args.len == 2 {
5601 return MapValue{
5602 default_value: e.zero_value_for_type_expr(expr.args[1])
5603 }
5604 }
5605 return StructValue{
5606 type_name: generic_args_name(expr)
5607 fields: map[string]Value{}
5608 }
5609 }
5610 ast.Ident {
5611 if expr.name == 'bool' {
5612 return false
5613 }
5614 if expr.name in ['byte', 'char', 'i8', 'i16', 'i32', 'int', 'i64', 'isize', 'rune',
5615 'u8', 'u16', 'u32', 'u64', 'usize'] {
5616 return i64(0)
5617 }
5618 if expr.name in ['f32', 'f64'] {
5619 return f64(0.0)
5620 }
5621 if expr.name == 'string' {
5622 return ''
5623 }
5624 type_name := if e.has_type_name(e.current_module_name(), expr.name) {
5625 '${e.current_module_name()}.${expr.name}'
5626 } else {
5627 expr.name
5628 }
5629 return e.zero_struct_value(type_name)
5630 }
5631 ast.SelectorExpr {
5632 return e.zero_struct_value(expr.name())
5633 }
5634 ast.Type {
5635 return match expr {
5636 ast.ArrayFixedType, ast.ArrayType {
5637 ArrayValue{}
5638 }
5639 ast.MapType {
5640 MapValue{
5641 default_value: e.zero_value_for_type_expr(expr.value_type)
5642 }
5643 }
5644 ast.OptionType, ast.ResultType, ast.NilType, ast.NoneType {
5645 void_value()
5646 }
5647 ast.TupleType {
5648 TupleValue{
5649 values: expr.types.map(e.zero_value_for_type_expr(it))
5650 }
5651 }
5652 else {
5653 e.zero_struct_value(e.type_node_name(expr))
5654 }
5655 }
5656 }
5657 else {
5658 return void_value()
5659 }
5660 }
5661}
5662
5663fn (e &Eval) array_contains(receiver ArrayValue, needle Value) bool {
5664 for item in receiver.values {
5665 if e.value_eq(item, needle) {
5666 return true
5667 }
5668 }
5669 return false
5670}
5671
5672fn (e &Eval) array_has(receiver ArrayValue, needle Value) bool {
5673 if e.array_contains(receiver, needle) {
5674 return true
5675 }
5676 if needle is string {
5677 for item in receiver.values {
5678 if item is StructValue {
5679 if name_value := item.fields['name'] {
5680 if e.value_string(name_value) == needle {
5681 return true
5682 }
5683 }
5684 }
5685 }
5686 }
5687 return false
5688}
5689
5690fn (e &Eval) array_index(receiver ArrayValue, needle Value, reverse bool) i64 {
5691 if reverse {
5692 for i := receiver.values.len - 1; i >= 0; i-- {
5693 if e.value_eq(receiver.values[i], needle) {
5694 return i64(i)
5695 }
5696 }
5697 return -1
5698 }
5699 for i, item in receiver.values {
5700 if e.value_eq(item, needle) {
5701 return i64(i)
5702 }
5703 }
5704 return -1
5705}
5706
5707fn (e &Eval) array_first_value(receiver ArrayValue) !Value {
5708 if receiver.values.len == 0 {
5709 return error('v2.eval: array.first on empty array')
5710 }
5711 return receiver.values[0]
5712}
5713
5714fn (e &Eval) array_last_value(receiver ArrayValue) !Value {
5715 if receiver.values.len == 0 {
5716 return error('v2.eval: array.last on empty array')
5717 }
5718 return receiver.values[receiver.values.len - 1]
5719}
5720
5721fn (e &Eval) module_property(module_name string, field_name string) MaybeValue {
5722 if module_name == 'os' && field_name == 'args' {
5723 return MaybeValue{
5724 found: true
5725 value: ArrayValue{
5726 values: e.program_args().map(Value(it))
5727 }
5728 }
5729 }
5730 return MaybeValue{}
5731}
5732
5733fn (e &Eval) program_args() []string {
5734 if e.prefs.eval_runtime_args.len > 0 {
5735 return e.prefs.eval_runtime_args
5736 }
5737 return os.args
5738}
5739
5740fn (e &Eval) is_type_expr(expr ast.Expr) bool {
5741 match expr {
5742 ast.Ident {
5743 return e.is_builtin_type_name(expr.name)
5744 || e.has_type_name(e.current_module_name(), expr.name)
5745 || e.resolve_mangled_type_value(expr.name) != none || e.is_sum_type_name(expr.name)
5746 }
5747 ast.Type {
5748 return true
5749 }
5750 ast.GenericArgs {
5751 return true
5752 }
5753 else {
5754 return false
5755 }
5756 }
5757}
5758
5759fn generic_args_name(expr ast.GenericArgs) string {
5760 mut parts := []string{cap: expr.args.len}
5761 for arg in expr.args {
5762 parts << arg.name()
5763 }
5764 return '${expr.lhs.name()}[${parts.join(',')}]'
5765}
5766
5767fn (e &Eval) type_expr_name(expr ast.Expr) string {
5768 return match expr {
5769 ast.GenericArgs {
5770 generic_args_name(expr)
5771 }
5772 ast.Ident {
5773 expr.name
5774 }
5775 ast.ModifierExpr {
5776 e.type_expr_name(expr.expr)
5777 }
5778 ast.ParenExpr {
5779 e.type_expr_name(expr.expr)
5780 }
5781 ast.SelectorExpr {
5782 expr.name()
5783 }
5784 ast.Type {
5785 e.type_node_name(expr)
5786 }
5787 else {
5788 expr.name()
5789 }
5790 }
5791}
5792
5793fn (e &Eval) type_node_name(typ ast.Type) string {
5794 return match typ {
5795 ast.AnonStructType {
5796 'struct'
5797 }
5798 ast.ArrayFixedType {
5799 '[${typ.len.name()}]${e.type_expr_name(typ.elem_type)}'
5800 }
5801 ast.ArrayType {
5802 '[]${e.type_expr_name(typ.elem_type)}'
5803 }
5804 ast.ChannelType {
5805 'chan ${e.type_expr_name(typ.elem_type)}'
5806 }
5807 ast.FnType {
5808 'fn'
5809 }
5810 ast.GenericType {
5811 '${typ.name.name()}[${typ.params.name_list()}]'
5812 }
5813 ast.MapType {
5814 'map[${e.type_expr_name(typ.key_type)}]${e.type_expr_name(typ.value_type)}'
5815 }
5816 ast.NilType {
5817 'nil'
5818 }
5819 ast.NoneType {
5820 'none'
5821 }
5822 ast.OptionType {
5823 '?${e.type_expr_name(typ.base_type)}'
5824 }
5825 ast.PointerType {
5826 if typ.lifetime != '' {
5827 '&^${typ.lifetime} ${e.type_expr_name(typ.base_type)}'
5828 } else {
5829 '&${e.type_expr_name(typ.base_type)}'
5830 }
5831 }
5832 ast.ResultType {
5833 '!${e.type_expr_name(typ.base_type)}'
5834 }
5835 ast.ThreadType {
5836 if typ.elem_type is ast.EmptyExpr {
5837 'thread'
5838 } else {
5839 'thread ${e.type_expr_name(typ.elem_type)}'
5840 }
5841 }
5842 ast.TupleType {
5843 '(' + typ.types.map(e.type_expr_name(it)).join(',') + ')'
5844 }
5845 }
5846}
5847
5848fn (e &Eval) is_builtin_type_name(name string) bool {
5849 return name in ['bool', 'byte', 'char', 'f32', 'f64', 'i8', 'i16', 'i32', 'int', 'i64', 'isize',
5850 'rune', 'string', 'u8', 'u16', 'u32', 'u64', 'usize', 'voidptr', 'byteptr']
5851}
5852
5853fn (e &Eval) is_ref_type_name(name string) bool {
5854 trimmed := name.trim_space()
5855 if trimmed == '' {
5856 return false
5857 }
5858 if trimmed.starts_with('&') || trimmed.starts_with('[]') || trimmed.starts_with('map[')
5859 || trimmed.starts_with('fn') || trimmed.starts_with('thread ')
5860 || trimmed in ['array', 'map', 'module', 'range', 'tuple', 'type', 'void'] {
5861 return true
5862 }
5863 if trimmed.starts_with('?') || trimmed.starts_with('!') {
5864 return e.is_ref_type_name(trimmed[1..])
5865 }
5866 if e.is_builtin_type_name(trimmed) {
5867 return false
5868 }
5869 return trimmed.contains('.')
5870}
5871
5872fn (e &Eval) sizeof_type_name(name string) i64 {
5873 trimmed := name.trim_space()
5874 if trimmed == '' {
5875 return 0
5876 }
5877 if trimmed.starts_with('?') || trimmed.starts_with('!') {
5878 return e.sizeof_type_name(trimmed[1..])
5879 }
5880 if trimmed.starts_with('&') || trimmed.ends_with('*') || trimmed == 'voidptr'
5881 || trimmed == 'byteptr' || trimmed.starts_with('fn') {
5882 return 8
5883 }
5884 if trimmed.starts_with('[]') || trimmed == 'array' || trimmed.ends_with('Builder')
5885 || trimmed.ends_with('.Builder') {
5886 return 24
5887 }
5888 if trimmed.starts_with('map[') || trimmed == 'map' {
5889 return 32
5890 }
5891 if trimmed.starts_with('chan ') || trimmed.starts_with('thread ') {
5892 return 8
5893 }
5894 return match trimmed {
5895 'bool', 'byte', 'char', 'i8', 'u8' {
5896 1
5897 }
5898 'i16', 'u16' {
5899 2
5900 }
5901 'f32', 'i32', 'int', 'rune', 'u32' {
5902 4
5903 }
5904 'f64', 'i64', 'isize', 'u64', 'usize' {
5905 8
5906 }
5907 'string' {
5908 16
5909 }
5910 'flags' {
5911 4
5912 }
5913 'module', 'range', 'tuple', 'type', 'void' {
5914 8
5915 }
5916 else {
5917 if trimmed.contains('.') || trimmed == 'struct' {
5918 8
5919 } else {
5920 0
5921 }
5922 }
5923 }
5924}
5925
5926fn (e &Eval) cast_value(value Value, type_name string) !Value {
5927 if info := e.sum_type_info(type_name) {
5928 if e.is_existing_sumtype_wrapper(value, type_name) {
5929 return value
5930 }
5931 if value is StructValue {
5932 if inferred := e.infer_bare_sumtype_variant(info, value) {
5933 payload := StructValue{
5934 type_name: inferred.variant_name
5935 fields: value.fields.clone()
5936 }
5937 return e.build_sumtype_wrapper(type_name, info, inferred.tag, payload)
5938 }
5939 }
5940 if nested := e.infer_nested_sumtype_variant(info, value) {
5941 return e.build_sumtype_wrapper(type_name, info, nested.tag, nested.payload)
5942 }
5943 if tag := e.sumtype_tag_from_value(info, value) {
5944 return e.build_sumtype_wrapper(type_name, info, tag, value)
5945 }
5946 }
5947 match type_name {
5948 'bool' {
5949 return e.value_as_bool(value)!
5950 }
5951 'byte', 'char', 'i8', 'i16', 'int', 'i64', 'rune', 'u8', 'u16', 'u32', 'u64' {
5952 return e.value_as_int(value)!
5953 }
5954 'f32', 'f64' {
5955 return e.value_as_f64(value)!
5956 }
5957 'string' {
5958 return e.value_string(value)
5959 }
5960 else {
5961 if value is StructValue {
5962 if payload := e.unwrap_sumtype_value(value, type_name) {
5963 return payload
5964 }
5965 return StructValue{
5966 type_name: type_name
5967 fields: value.fields.clone()
5968 }
5969 }
5970 return value
5971 }
5972 }
5973}
5974
5975fn (e &Eval) type_name_matches(actual string, expected string) bool {
5976 if actual == expected {
5977 return true
5978 }
5979 mut actual_module := ''
5980 if actual.contains('.') {
5981 actual_module = actual.all_before_last('.')
5982 }
5983 for alias in e.type_name_aliases(actual_module, actual) {
5984 if alias == expected {
5985 return true
5986 }
5987 }
5988 mut expected_module := ''
5989 if expected.contains('.') {
5990 expected_module = expected.all_before_last('.')
5991 }
5992 for alias in e.type_name_aliases(expected_module, expected) {
5993 if alias == actual {
5994 return true
5995 }
5996 }
5997 return false
5998}
5999
6000fn (e &Eval) value_matches_type_name(value Value, target_name string) bool {
6001 match value {
6002 ArrayValue {
6003 return target_name == 'array' || target_name.starts_with('[]')
6004 }
6005 FlagsValue {
6006 return target_name == 'flags'
6007 }
6008 MapValue {
6009 return target_name == 'map' || target_name.starts_with('map[')
6010 }
6011 ModuleValue {
6012 return target_name == 'module'
6013 }
6014 RangeValue {
6015 return target_name == 'range'
6016 }
6017 StructValue {
6018 return e.type_name_matches(value.type_name, target_name)
6019 }
6020 TupleValue {
6021 return target_name == 'tuple'
6022 }
6023 TypeValue {
6024 return target_name == 'type' || value.name == target_name
6025 }
6026 VoidValue {
6027 return target_name in ['none', 'nil', 'void']
6028 }
6029 bool {
6030 return target_name == 'bool'
6031 }
6032 f64 {
6033 return target_name in ['f32', 'f64']
6034 }
6035 i64 {
6036 return target_name in ['byte', 'char', 'i8', 'i16', 'i32', 'int', 'i64', 'isize', 'rune',
6037 'u8', 'u16', 'u32', 'u64', 'usize']
6038 }
6039 string {
6040 return target_name == 'string'
6041 }
6042 }
6043}
6044
6045fn (e &Eval) expect_string_arg(args []Value, index int) !string {
6046 if index >= args.len {
6047 return error('v2.eval: missing argument ${index}')
6048 }
6049 value := args[index]
6050 if value is string {
6051 return value
6052 }
6053 return e.value_string(value)
6054}
6055
6056fn (e &Eval) value_to_string_array(value Value) ![]string {
6057 if value is ArrayValue {
6058 vals := value.values
6059 return vals.map(e.value_string(it))
6060 }
6061 return error('v2.eval: expected []string-compatible value')
6062}
6063
6064fn (e &Eval) value_to_byte_array(value Value) ![]u8 {
6065 if value !is ArrayValue {
6066 return error('v2.eval: expected []u8-compatible value')
6067 }
6068 array_value := value as ArrayValue
6069 mut bytes := []u8{cap: array_value.values.len}
6070 for item in array_value.values {
6071 bytes << u8(e.value_as_int(item)!)
6072 }
6073 return bytes
6074}
6075
6076fn (e &Eval) array_args_to_strings(args []Value) []string {
6077 mut out := []string{}
6078 for arg in args {
6079 if arg is ArrayValue {
6080 for item in arg.values {
6081 out << e.value_string(item)
6082 }
6083 continue
6084 }
6085 out << e.value_string(arg)
6086 }
6087 return out
6088}
6089
6090fn (e &Eval) value_as_bool(value Value) !bool {
6091 return match value {
6092 bool { value }
6093 i64 { value != 0 }
6094 f64 { value_f64_payload(value) != 0.0 }
6095 string { value.len > 0 }
6096 ArrayValue { value.values.len > 0 }
6097 FlagsValue { false }
6098 MapValue { value.entries.len > 0 }
6099 StructValue { value.fields.len > 0 }
6100 VoidValue { false }
6101 else { return error('v2.eval: `${e.runtime_type_name(value)}` can not be used as bool') }
6102 }
6103}
6104
6105fn (e &Eval) value_as_int(value Value) !i64 {
6106 return match value {
6107 i64 {
6108 value
6109 }
6110 f64 {
6111 i64(value_f64_payload(value))
6112 }
6113 bool {
6114 if value {
6115 i64(1)
6116 } else {
6117 i64(0)
6118 }
6119 }
6120 string {
6121 strconv.parse_int(value, 0, 64)!
6122 }
6123 FlagsValue {
6124 i64(0)
6125 }
6126 else {
6127 return error('v2.eval: `${e.runtime_type_name(value)}` can not be used as int in `${e.current_function_label()}` stack `${e.call_stack_trace()}`')
6128 }
6129 }
6130}
6131
6132fn (e &Eval) value_as_f64(value Value) !f64 {
6133 return match value {
6134 f64 {
6135 value_f64_payload(value)
6136 }
6137 i64 {
6138 f64(value)
6139 }
6140 bool {
6141 if value {
6142 1.0
6143 } else {
6144 0.0
6145 }
6146 }
6147 string {
6148 strconv.atof64(value)!
6149 }
6150 else {
6151 return error('v2.eval: `${e.runtime_type_name(value)}` can not be used as float')
6152 }
6153 }
6154}
6155
6156fn (e &Eval) map_entry_string(entry MapEntry) string {
6157 key_text := if entry.key is string {
6158 "'${entry.key}'"
6159 } else {
6160 e.value_string(entry.key)
6161 }
6162 return '${key_text}: ${e.value_string(entry.value)}'
6163}
6164
6165fn (e &Eval) value_string(value Value) string {
6166 return match value {
6167 ArrayValue {
6168 vals := value.values
6169 '[' + vals.map(e.value_string(it)).join(', ') + ']'
6170 }
6171 FlagsValue {
6172 'flags'
6173 }
6174 MapValue {
6175 '{' + value.entries.map(e.map_entry_string(it)).join(', ') + '}'
6176 }
6177 ModuleValue {
6178 value.name
6179 }
6180 RangeValue {
6181 rs := value.start
6182 re := value.end
6183 sep := if value.inclusive { '...' } else { '..' }
6184 '${rs}${sep}${re}'
6185 }
6186 StructValue {
6187 keys := value.fields.keys()
6188
6189 '${value.type_name}{' + keys.map('${it}: ${e.value_string(value.fields[it] or {
6190 void_value()
6191 })}').join(', ') + '}'
6192 }
6193 TupleValue {
6194 vals := value.values
6195 '(' + vals.map(e.value_string(it)).join(', ') + ')'
6196 }
6197 TypeValue {
6198 value.name
6199 }
6200 VoidValue {
6201 ''
6202 }
6203 bool, i64, string {
6204 value.str()
6205 }
6206 f64 {
6207 value_f64_payload(value).str()
6208 }
6209 }
6210}
6211
6212fn (e &Eval) runtime_type_name(value Value) string {
6213 return match value {
6214 ArrayValue { 'array' }
6215 FlagsValue { 'flags' }
6216 MapValue { 'map' }
6217 ModuleValue { 'module' }
6218 RangeValue { 'range' }
6219 StructValue { value.type_name }
6220 TupleValue { 'tuple' }
6221 TypeValue { 'type' }
6222 VoidValue { 'void' }
6223 bool { 'bool' }
6224 f64 { 'f64' }
6225 i64 { 'int' }
6226 string { 'string' }
6227 }
6228}
6229
6230fn (mut e Eval) write_stdout(s string) {
6231 if e.capture_output {
6232 e.stdout_data += s
6233 } else {
6234 print(s)
6235 }
6236}
6237
6238fn (mut e Eval) write_stderr(s string) {
6239 if e.capture_output {
6240 e.stderr_data += s
6241 } else {
6242 eprint(s)
6243 }
6244}
6245