v / vlib / v2 / ast / ast.v
1092 lines · 979 sloc · 16.16 KB · 14e53cdc34a9cff1905b50dc10512efc80ed9bcd
Raw
1// Copyright (c) 2020-2024 Joe Conigliaro. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module ast
5
6import v2.token
7
8pub const empty_expr = Expr(EmptyExpr(0))
9pub const empty_stmt = Stmt(EmptyStmt(0))
10
11type EmptyExpr = u8
12type EmptyStmt = u8
13
14pub type Expr = ArrayInitExpr
15 | AsCastExpr
16 | AssocExpr
17 | BasicLiteral
18 | CallExpr
19 | CallOrCastExpr
20 | CastExpr
21 | ComptimeExpr
22 | EmptyExpr
23 | FieldInit
24 | FnLiteral
25 | GenericArgOrIndexExpr
26 | GenericArgs
27 | Ident
28 | IfExpr
29 | IfGuardExpr
30 | IndexExpr
31 | InfixExpr
32 | InitExpr
33 | Keyword
34 | KeywordOperator
35 | LambdaExpr
36 | LifetimeExpr
37 | LockExpr
38 | MapInitExpr
39 | MatchExpr
40 | ModifierExpr
41 | OrExpr
42 | ParenExpr
43 | PostfixExpr
44 | PrefixExpr
45 | RangeExpr
46 | SelectExpr
47 | SelectorExpr
48 | SqlExpr
49 | StringInterLiteral
50 | StringLiteral
51 | Tuple
52 | Type
53 | UnsafeExpr
54
55// TODO: decide if this going to be done like this (FieldInit)
56
57pub type Stmt = AsmStmt
58 | AssertStmt
59 | AssignStmt
60 | BlockStmt
61 | ComptimeStmt
62 | ConstDecl
63 | DeferStmt
64 | Directive
65 | EmptyStmt
66 | EnumDecl
67 | ExprStmt
68 | FlowControlStmt
69 | FnDecl
70 | ForInStmt
71 | ForStmt
72 | GlobalDecl
73 | ImportStmt
74 | InterfaceDecl
75 | LabelStmt
76 | ModuleStmt
77 | ReturnStmt
78 | StructDecl
79 | TypeDecl
80 | []Attribute
81
82// pub type Decl = ConstDecl | EnumDecl | FnDecl | GlobalDecl
83// | InterfaceDecl | StructDecl | TypeDecl
84
85// TODO: (re)implement nested sumtype like TS (was removed from v)
86// currently need to cast to type in parser.type. Should I leave like
87// this or add these directly to Expr until nesting is implemented?
88pub type Type = AnonStructType
89 | ArrayFixedType
90 | ArrayType
91 | ChannelType
92 | FnType
93 | GenericType
94 | MapType
95 | NilType
96 | NoneType
97 | OptionType
98 | PointerType
99 | ResultType
100 | ThreadType
101 | TupleType
102
103pub fn (exprs []Expr) name_list() string {
104 mut out := ''
105 for i := 0; i < exprs.len; i++ {
106 out = out + exprs[i].name()
107 if i < exprs.len - 1 {
108 out = out + ','
109 }
110 }
111 return out
112}
113
114pub fn (t Type) name() string {
115 return match t {
116 GenericType {
117 '${t.name.name()}[${t.params.name_list()}]'
118 }
119 else {
120 'Type'
121 }
122 }
123}
124
125// TODO: fix this, should be only what is needed
126pub fn (expr Expr) name() string {
127 return match expr {
128 AsCastExpr {
129 '${expr.expr.name()} as ${expr.typ.name()}'
130 }
131 BasicLiteral {
132 expr.value
133 }
134 CallExpr {
135 // TODO:
136 '${expr.lhs.name()}()'
137 }
138 CallOrCastExpr {
139 '${expr.lhs.name()}(${expr.expr.name()})'
140 }
141 EmptyExpr {
142 // TODO:
143 'EmptyExpr'
144 }
145 GenericArgs {
146 '${expr.lhs.name()}[${expr.args.name_list()}]'
147 }
148 Ident {
149 expr.name
150 }
151 IndexExpr {
152 '${expr.lhs.name()}[${expr.expr.name()}]'
153 }
154 InfixExpr {
155 '${expr.lhs.name()} ${expr.op} ${expr.rhs.name()}'
156 }
157 Keyword {
158 expr.tok.str()
159 }
160 LifetimeExpr {
161 '^' + expr.name
162 }
163 ModifierExpr {
164 '${expr.kind} ${expr.expr.name()}'
165 }
166 ParenExpr {
167 '(${expr.expr.name()})'
168 }
169 PrefixExpr {
170 '${expr.op}${expr.expr.name()}'
171 }
172 SelectorExpr {
173 expr.lhs.name() + '.' + expr.rhs.name
174 }
175 StringLiteral {
176 "'${expr.value}'"
177 }
178 Type {
179 'Type'
180 }
181 UnsafeExpr {
182 // TODO:
183 'UnsafeExpr'
184 }
185 else {
186 'Expr'
187 }
188 }
189}
190
191pub fn (expr Expr) pos() token.Pos {
192 return match expr {
193 AsCastExpr {
194 expr.pos
195 }
196 ArrayInitExpr {
197 expr.pos
198 }
199 AssocExpr {
200 expr.pos
201 }
202 BasicLiteral {
203 expr.pos
204 }
205 CallExpr {
206 expr.pos
207 }
208 CallOrCastExpr {
209 expr.pos
210 }
211 CastExpr {
212 expr.pos
213 }
214 ComptimeExpr {
215 expr.pos
216 }
217 FnLiteral {
218 expr.pos
219 }
220 GenericArgOrIndexExpr {
221 expr.pos
222 }
223 GenericArgs {
224 expr.pos
225 }
226 Ident {
227 expr.pos
228 }
229 IfExpr {
230 expr.pos
231 }
232 IfGuardExpr {
233 expr.pos
234 }
235 IndexExpr {
236 expr.pos
237 }
238 InfixExpr {
239 expr.pos
240 }
241 InitExpr {
242 expr.pos
243 }
244 KeywordOperator {
245 expr.pos
246 }
247 LifetimeExpr {
248 expr.pos
249 }
250 LambdaExpr {
251 expr.pos
252 }
253 LockExpr {
254 expr.pos
255 }
256 MapInitExpr {
257 expr.pos
258 }
259 MatchExpr {
260 expr.pos
261 }
262 ModifierExpr {
263 expr.pos
264 }
265 OrExpr {
266 expr.pos
267 }
268 ParenExpr {
269 expr.pos
270 }
271 PostfixExpr {
272 expr.pos
273 }
274 PrefixExpr {
275 expr.pos
276 }
277 RangeExpr {
278 expr.pos
279 }
280 SelectExpr {
281 expr.pos
282 }
283 SelectorExpr {
284 expr.pos
285 }
286 SqlExpr {
287 expr.pos
288 }
289 StringInterLiteral {
290 expr.pos
291 }
292 StringLiteral {
293 expr.pos
294 }
295 Tuple {
296 expr.pos
297 }
298 UnsafeExpr {
299 expr.pos
300 }
301 else {
302 // Default for expressions without pos field (EmptyExpr, FieldInit, Keyword, Type)
303 token.Pos{}
304 }
305 }
306}
307
308// File (AST container)
309pub struct File {
310pub:
311 attributes []Attribute
312 mod string
313 name string
314 stmts []Stmt
315 imports []ImportStmt
316 selector_names map[int]string
317}
318
319pub enum Language {
320 v
321 c
322 js
323}
324
325pub fn (lang Language) str() string {
326 return match lang {
327 .v { 'V' }
328 .c { 'C' }
329 .js { 'JS' }
330 }
331}
332
333pub enum DeferMode {
334 scoped // default: defer to end of current scope
335 function // defer(fn): defer to end of function
336}
337
338// Expressions
339pub struct ArrayInitExpr {
340pub mut:
341 typ Expr = empty_expr
342 exprs []Expr
343 init Expr = empty_expr
344 cap Expr = empty_expr
345 len Expr = empty_expr
346 update_expr Expr = empty_expr // `a` in `[...a, 3, 4]`
347 pos token.Pos
348}
349
350pub struct AsCastExpr {
351pub:
352 expr Expr
353 typ Expr
354 pos token.Pos
355}
356
357pub struct AssocExpr {
358pub:
359 typ Expr
360 expr Expr
361 fields []FieldInit
362 pos token.Pos
363}
364
365pub struct BasicLiteral {
366pub:
367 kind token.Token
368 value string
369 pos token.Pos
370}
371
372pub struct CallExpr {
373pub mut:
374 lhs Expr
375pub:
376 args []Expr
377 pos token.Pos
378}
379
380pub struct CallOrCastExpr {
381pub mut:
382 lhs Expr
383 expr Expr
384pub:
385 pos token.Pos
386}
387
388pub struct CastExpr {
389pub mut:
390 typ Expr
391 expr Expr
392pub:
393 pos token.Pos
394}
395
396pub struct ComptimeExpr {
397pub:
398 expr Expr
399 pos token.Pos
400}
401
402pub struct FieldDecl {
403pub:
404 name string
405 typ Expr = empty_expr // can be empty as used for const (unless we use something else)
406 value Expr = empty_expr
407 attributes []Attribute
408 is_public bool
409 is_mut bool
410 is_module_mut bool
411 is_interface_method bool
412}
413
414pub struct FieldInit {
415pub:
416 name string
417pub mut:
418 value Expr
419}
420
421// anon fn / closure
422pub struct FnLiteral {
423pub:
424 typ FnType
425 captured_vars []Expr
426 stmts []Stmt
427 pos token.Pos
428}
429
430pub struct GenericArgs {
431pub:
432 lhs Expr
433 args []Expr // concrete types and lifetimes
434 pos token.Pos
435}
436
437pub struct GenericArgOrIndexExpr {
438pub:
439 lhs Expr
440 expr Expr
441 pos token.Pos
442}
443
444pub struct Ident {
445pub mut:
446 pos token.Pos
447 name string
448}
449
450pub struct IfExpr {
451pub mut:
452 cond Expr = empty_expr
453 else_expr Expr = empty_expr
454 stmts []Stmt
455 pos token.Pos
456}
457
458pub struct IfGuardExpr {
459pub:
460 stmt AssignStmt
461 pos token.Pos
462}
463
464pub struct InfixExpr {
465pub mut:
466 op token.Token
467 lhs Expr
468 rhs Expr
469 pos token.Pos
470}
471
472pub struct IndexExpr {
473pub mut:
474 lhs Expr
475 expr Expr
476 is_gated bool
477 pos token.Pos
478}
479
480pub struct InitExpr {
481pub mut:
482 typ Expr
483 fields []FieldInit
484 pos token.Pos
485}
486
487pub struct Keyword {
488pub:
489 tok token.Token
490}
491
492pub struct KeywordOperator {
493pub:
494 op token.Token
495 exprs []Expr
496 pos token.Pos
497}
498
499pub struct Tuple {
500pub:
501 exprs []Expr
502 pos token.Pos
503}
504
505pub struct LambdaExpr {
506pub:
507 args []Ident
508 expr Expr
509 pos token.Pos
510}
511
512pub struct LockExpr {
513pub:
514 lock_exprs []Expr
515 rlock_exprs []Expr
516 stmts []Stmt
517 pos token.Pos
518}
519
520pub struct MapInitExpr {
521pub:
522 typ Expr = empty_expr
523 keys []Expr
524 vals []Expr
525 pos token.Pos
526}
527
528pub struct MatchBranch {
529pub:
530 cond []Expr
531 stmts []Stmt
532 pos token.Pos
533}
534
535pub struct MatchExpr {
536pub:
537 expr Expr
538 branches []MatchBranch
539 pos token.Pos
540}
541
542// TODO: possibly merge modifiers into a bitfield where
543// multiple modifiers are used. this could also be used
544// for struct decl `mut:`, `pub mut:` etc. consider this
545// [flag]
546// pub enum Modifier {
547// .atomic
548// .global
549// .mutable
550// .public
551// .shared
552// .static
553// .volatile
554// }
555
556pub struct ModifierExpr {
557pub mut:
558 kind token.Token
559 expr Expr
560 pos token.Pos
561}
562
563// pub fn (expr ModifierExpr) unwrap() Expr {
564// return expr.expr
565// }
566
567pub struct OrExpr {
568pub:
569 expr Expr
570 stmts []Stmt
571 pos token.Pos
572}
573
574pub struct Parameter {
575pub mut:
576 name string
577 typ Expr
578 is_mut bool
579 pos token.Pos
580}
581
582pub struct LifetimeExpr {
583pub:
584 name string
585 pos token.Pos
586}
587
588// name_str returns the parameter name.
589pub fn (p Parameter) name_str() string {
590 return p.name
591}
592
593pub struct ParenExpr {
594pub:
595 expr Expr
596 pos token.Pos
597}
598
599pub struct PostfixExpr {
600pub:
601 op token.Token
602 expr Expr
603 pos token.Pos
604}
605
606pub struct PrefixExpr {
607pub mut:
608 op token.Token
609 expr Expr
610 pos token.Pos
611}
612
613pub struct RangeExpr {
614pub:
615 op token.Token // `..` exclusive | `...` inclusive
616 start Expr
617 end Expr
618 pos token.Pos
619}
620
621pub struct SelectExpr {
622pub:
623 pos token.Pos
624 stmt Stmt
625 stmts []Stmt
626 next Expr = empty_expr
627}
628
629pub struct SelectorExpr {
630pub mut:
631 lhs Expr
632 rhs Ident
633 pos token.Pos
634}
635
636pub fn (se SelectorExpr) leftmost() Expr {
637 if se.lhs is SelectorExpr {
638 return se.lhs.leftmost()
639 }
640 return se.lhs
641}
642
643// pub fn (expr Expr) str() string {
644// return 'Expr.str() - ${expr.type_name()}'
645// }
646
647pub fn (se SelectorExpr) name() string {
648 return se.lhs.name() + '.' + se.rhs.name
649}
650
651pub enum StringLiteralKind {
652 c
653 js
654 raw
655 v
656}
657
658pub fn (s StringLiteralKind) str() string {
659 return match s {
660 .c { 'c' }
661 .js { 'js' }
662 .raw { 'r' }
663 .v { 'v' }
664 }
665}
666
667// TODO: allow overriding this method in main v compiler
668// that is why this method was renamed from `from_string`
669@[direct_array_access]
670pub fn StringLiteralKind.from_string_tinyv(s string) StringLiteralKind {
671 match s[0] {
672 `c` {
673 return .c
674 }
675 `j` {
676 if s[1] == `s` {
677 return .js
678 }
679 }
680 `r` {
681 return .raw
682 }
683 else {}
684 }
685
686 return .v
687}
688
689// NOTE: I'm using two nodes StringLiteral & StringInterLiteral
690// to avoid the extra array allocations when not needed.
691pub struct StringLiteral {
692pub:
693 kind StringLiteralKind
694 value string
695 pos token.Pos
696}
697
698pub struct StringInterLiteral {
699pub:
700 kind StringLiteralKind
701 values []string
702 inters []StringInter
703 pos token.Pos
704}
705
706pub struct StringInter {
707pub:
708 format StringInterFormat
709 width int
710 precision int
711 expr Expr
712 // TEMP: prob removed once individual
713 // fields are set, precision etc
714 format_expr Expr = empty_expr
715 resolved_fmt string // resolved sprintf format specifier (e.g. '%d', '%s', '%lld'), set by transformer
716}
717
718pub enum StringInterFormat {
719 unformatted
720 binary
721 character
722 decimal
723 exponent
724 exponent_short
725 float
726 hex
727 octal
728 pointer_address
729 string
730}
731
732pub fn StringInterFormat.from_u8(c u8) StringInterFormat {
733 return match c {
734 `b` { .binary }
735 `c` { .character }
736 `d` { .decimal }
737 `e`, `E` { .exponent }
738 `g`, `G` { .exponent_short }
739 `f`, `F` { .float }
740 `x`, `X` { .hex }
741 `o` { .octal }
742 `p` { .pointer_address }
743 `s` { .string }
744 else { .unformatted }
745 }
746}
747
748pub fn (sif StringInterFormat) str() string {
749 return match sif {
750 .unformatted { '' }
751 .binary { 'b' }
752 .character { 'c' }
753 .decimal { 'd' }
754 .exponent { 'e' }
755 .exponent_short { 'g' }
756 .float { 'f' }
757 .hex { 'x' }
758 .octal { 'o' }
759 .pointer_address { 'p' }
760 .string { 's' }
761 }
762}
763
764pub struct SqlExpr {
765pub:
766 expr Expr
767 table_name string
768 is_count bool
769 is_create bool
770 pos token.Pos
771}
772
773pub struct UnsafeExpr {
774pub:
775 stmts []Stmt
776 pos token.Pos
777}
778
779// Statements
780pub struct AsmStmt {
781pub:
782 arch string
783}
784
785pub struct AssertStmt {
786pub:
787 expr Expr
788 extra Expr = empty_expr
789}
790
791pub struct AssignStmt {
792pub:
793 op token.Token
794 lhs []Expr
795 rhs []Expr
796 pos token.Pos
797}
798
799pub fn (attributes []Attribute) has(name string) bool {
800 for attribute in attributes {
801 if attribute.name == name {
802 return true
803 }
804 // Also check value when it's a simple identifier (e.g., @[flag])
805 if attribute.name == '' {
806 if attribute.value is Ident && attribute.value.name == name {
807 return true
808 }
809 }
810 }
811 return false
812}
813
814pub struct Attribute {
815pub:
816 name string
817 value Expr
818 comptime_cond Expr
819 pos token.Pos
820}
821
822pub struct BlockStmt {
823pub:
824 stmts []Stmt
825}
826
827pub struct ComptimeStmt {
828pub:
829 stmt Stmt
830}
831
832pub struct ConstDecl {
833pub:
834 is_public bool
835 fields []FieldInit
836}
837
838pub struct DeferStmt {
839pub:
840 mode DeferMode
841 stmts []Stmt
842}
843
844// #flag / #include
845pub struct Directive {
846pub:
847 name string
848 value string
849 ct_cond string // optional comptime condition e.g. 'linux', 'darwin' for `#include linux <pty.h>`
850}
851
852pub struct EnumDecl {
853pub:
854 attributes []Attribute
855 is_public bool
856 name string
857 as_type Expr = empty_expr
858 fields []FieldDecl
859}
860
861pub struct ExprStmt {
862pub mut:
863 expr Expr
864}
865
866pub struct FlowControlStmt {
867pub:
868 op token.Token
869 label string
870}
871
872// enum FnArributes {
873// method
874// static
875// }
876
877pub struct FnDecl {
878pub:
879 attributes []Attribute
880 is_public bool
881 is_method bool
882 is_static bool
883 receiver Parameter
884 language Language = .v
885 name string
886 typ FnType
887 stmts []Stmt
888 pos token.Pos
889}
890
891pub struct ForStmt {
892pub mut:
893 init Stmt = empty_stmt // initialization
894 cond Expr = empty_expr // condition
895 post Stmt = empty_stmt // post iteration (afterthought)
896 stmts []Stmt
897}
898
899// NOTE: used as the initializer for ForStmt
900pub struct ForInStmt {
901pub mut:
902 // key string
903 // value string
904 // value_is_mut bool
905 // expr Expr
906 // TODO:
907 key Expr = empty_expr
908 value Expr
909 expr Expr
910}
911
912pub struct GlobalDecl {
913pub:
914 attributes []Attribute
915 fields []FieldDecl
916 is_public bool
917}
918
919pub struct ImportStmt {
920pub:
921 name string
922 alias string
923 is_aliased bool
924 symbols []Expr
925}
926
927pub struct InterfaceDecl {
928pub:
929 is_public bool
930 attributes []Attribute
931 name string
932 generic_params []Expr
933 embedded []Expr
934 fields []FieldDecl
935}
936
937pub struct LabelStmt {
938pub:
939 name string
940 stmt Stmt = empty_stmt
941}
942
943pub struct ModuleStmt {
944pub:
945 name string
946}
947
948pub struct ReturnStmt {
949pub:
950 exprs []Expr
951}
952
953pub struct StructDecl {
954pub:
955 attributes []Attribute
956 is_public bool
957 is_union bool
958 implements []Expr
959 embedded []Expr
960 language Language = .v
961 name string
962 generic_params []Expr
963 fields []FieldDecl
964 pos token.Pos
965}
966
967pub struct TypeDecl {
968pub:
969 is_public bool
970 language Language
971 name string
972 generic_params []Expr
973 base_type Expr = empty_expr
974 variants []Expr
975}
976
977// Type Nodes
978pub struct ArrayType {
979pub:
980 elem_type Expr = empty_expr
981}
982
983pub struct ArrayFixedType {
984pub:
985 len Expr = empty_expr
986 elem_type Expr = empty_expr
987}
988
989pub struct ChannelType {
990pub:
991 // s255: cap defaults to empty_expr (like ThreadType/OptionType/etc.). The
992 // parser omits cap for a bare `chan T` (type.v: `ChannelType{elem_type: ...}`),
993 // which previously left it a zero-valued Expr (invalid sum-type tag, null
994 // payload). Encoding that via FlatBuilder.add_expr crashes the arm64 self-host
995 // — an exhaustive match on the unmatched tag falls into the first arm
996 // (ArrayInitExpr) and derefs the null payload (same class as s251).
997 cap Expr = empty_expr
998 elem_type Expr = empty_expr
999}
1000
1001pub struct ThreadType {
1002pub:
1003 elem_type Expr = empty_expr
1004}
1005
1006pub struct FnType {
1007pub:
1008 generic_params []Expr
1009 params []Parameter
1010pub mut:
1011 return_type Expr = empty_expr
1012}
1013
1014pub fn (ft &FnType) str() string {
1015 mut s := 'fn('
1016 for i := 0; i < ft.params.len; i++ {
1017 param := ft.params[i]
1018 s = s + param.name + param.typ.name()
1019 if i < ft.params.len - 1 {
1020 s = s + ', '
1021 }
1022 }
1023 if ft.return_type is EmptyExpr {
1024 s = s + ')'
1025 } else {
1026 s = s + ') ' + ft.return_type.name()
1027 }
1028 return s
1029}
1030
1031pub fn (ident &Ident) str() string {
1032 return ident.name.clone()
1033}
1034
1035// pub fn (expr Expr) str() string {
1036// return match expr {
1037// Ident {
1038// expr.name
1039// }
1040// SelectorExpr {
1041// expr.lhs.str() + '.' + expr.rhs.name
1042// }
1043// else {
1044// 'missing Expr.str() for ${expr.type_name()}'
1045// // expr.str()
1046// }
1047// }
1048// }
1049
1050pub struct AnonStructType {
1051pub:
1052 generic_params []Expr
1053 embedded []Expr
1054 fields []FieldDecl
1055}
1056
1057pub struct GenericType {
1058pub:
1059 name Expr = empty_expr
1060 params []Expr
1061}
1062
1063pub struct MapType {
1064pub:
1065 key_type Expr = empty_expr
1066 value_type Expr = empty_expr
1067}
1068
1069pub struct NilType {}
1070
1071pub struct NoneType {}
1072
1073pub struct OptionType {
1074pub:
1075 base_type Expr = empty_expr
1076}
1077
1078pub struct PointerType {
1079pub:
1080 base_type Expr = empty_expr
1081 lifetime string
1082}
1083
1084pub struct ResultType {
1085pub:
1086 base_type Expr = empty_expr
1087}
1088
1089pub struct TupleType {
1090pub:
1091 types []Expr
1092}
1093