| 1 | module flat |
| 2 | |
| 3 | import v3.token |
| 4 | |
| 5 | // NodeId aliases node id values used by flat. |
| 6 | pub type NodeId = int |
| 7 | |
| 8 | pub const empty_node = NodeId(-1) |
| 9 | |
| 10 | const empty_node_value = Node{} |
| 11 | |
| 12 | // NodeKind lists node kind values used by flat. |
| 13 | pub enum NodeKind { |
| 14 | empty |
| 15 | // expressions |
| 16 | int_literal |
| 17 | float_literal |
| 18 | bool_literal |
| 19 | char_literal |
| 20 | string_literal |
| 21 | string_interp |
| 22 | ident |
| 23 | infix |
| 24 | prefix |
| 25 | postfix |
| 26 | paren |
| 27 | call |
| 28 | selector |
| 29 | index |
| 30 | if_expr |
| 31 | struct_init |
| 32 | field_init |
| 33 | array_literal |
| 34 | array_init |
| 35 | map_init |
| 36 | fn_literal |
| 37 | or_expr |
| 38 | cast_expr |
| 39 | as_expr |
| 40 | enum_val |
| 41 | assoc |
| 42 | range |
| 43 | nil_literal |
| 44 | none_expr |
| 45 | spawn_expr |
| 46 | lock_expr |
| 47 | lambda_expr |
| 48 | sizeof_expr |
| 49 | typeof_expr |
| 50 | dump_expr |
| 51 | offsetof_expr |
| 52 | is_expr |
| 53 | in_expr |
| 54 | // statements |
| 55 | expr_stmt |
| 56 | assign |
| 57 | decl_assign |
| 58 | selector_assign |
| 59 | index_assign |
| 60 | return_stmt |
| 61 | block |
| 62 | for_stmt |
| 63 | for_in_stmt |
| 64 | break_stmt |
| 65 | continue_stmt |
| 66 | match_stmt |
| 67 | match_branch |
| 68 | defer_stmt |
| 69 | assert_stmt |
| 70 | goto_stmt |
| 71 | label_stmt |
| 72 | select_stmt |
| 73 | select_branch |
| 74 | comptime_if |
| 75 | comptime_for |
| 76 | asm_stmt |
| 77 | // declarations |
| 78 | fn_decl |
| 79 | struct_decl |
| 80 | field_decl |
| 81 | global_decl |
| 82 | const_decl |
| 83 | const_field |
| 84 | enum_decl |
| 85 | enum_field |
| 86 | type_decl |
| 87 | interface_decl |
| 88 | interface_field |
| 89 | import_decl |
| 90 | module_decl |
| 91 | directive |
| 92 | param |
| 93 | c_fn_decl |
| 94 | // top-level |
| 95 | file |
| 96 | sql_expr |
| 97 | } |
| 98 | |
| 99 | // Op lists op values used by flat. |
| 100 | pub enum Op { |
| 101 | none |
| 102 | plus |
| 103 | minus |
| 104 | mul |
| 105 | div |
| 106 | mod |
| 107 | eq |
| 108 | ne |
| 109 | lt |
| 110 | gt |
| 111 | le |
| 112 | ge |
| 113 | amp |
| 114 | pipe |
| 115 | xor |
| 116 | left_shift |
| 117 | right_shift |
| 118 | right_shift_unsigned |
| 119 | logical_and |
| 120 | logical_or |
| 121 | not |
| 122 | bit_not |
| 123 | assign |
| 124 | plus_assign |
| 125 | minus_assign |
| 126 | mul_assign |
| 127 | div_assign |
| 128 | mod_assign |
| 129 | amp_assign |
| 130 | pipe_assign |
| 131 | xor_assign |
| 132 | left_shift_assign |
| 133 | right_shift_assign |
| 134 | right_shift_unsigned_assign |
| 135 | inc |
| 136 | dec |
| 137 | dot |
| 138 | arrow |
| 139 | } |
| 140 | |
| 141 | // Node represents node data used by flat. |
| 142 | pub struct Node { |
| 143 | pub mut: |
| 144 | value string |
| 145 | typ string |
| 146 | generic_params []string |
| 147 | kind_id int |
| 148 | pub: |
| 149 | pos token.Pos |
| 150 | children_start i32 |
| 151 | children_count i16 |
| 152 | kind NodeKind |
| 153 | op Op |
| 154 | } |
| 155 | |
| 156 | // FlatAst represents flat ast data used by flat. |
| 157 | @[heap] |
| 158 | pub struct FlatAst { |
| 159 | pub mut: |
| 160 | nodes []Node |
| 161 | children []NodeId |
| 162 | user_code_start int |
| 163 | disabled_fns map[string]bool |
| 164 | export_fn_names map[string]string |
| 165 | } |
| 166 | |
| 167 | // new creates a FlatAst value for flat. |
| 168 | pub fn FlatAst.new() FlatAst { |
| 169 | return FlatAst{ |
| 170 | nodes: []Node{cap: 256} |
| 171 | children: []NodeId{cap: 512} |
| 172 | disabled_fns: map[string]bool{} |
| 173 | export_fn_names: map[string]string{} |
| 174 | } |
| 175 | } |
| 176 | |
| 177 | // add updates add state for FlatAst. |
| 178 | pub fn (mut a FlatAst) add(kind NodeKind) NodeId { |
| 179 | id := NodeId(a.nodes.len) |
| 180 | a.nodes << Node{ |
| 181 | kind: kind |
| 182 | kind_id: int(kind) |
| 183 | } |
| 184 | return id |
| 185 | } |
| 186 | |
| 187 | // add_id updates add id state for FlatAst. |
| 188 | pub fn (mut a FlatAst) add_id(kind_id int) NodeId { |
| 189 | id := NodeId(a.nodes.len) |
| 190 | a.nodes << Node{ |
| 191 | kind: node_kind_from_id(kind_id) |
| 192 | kind_id: kind_id |
| 193 | } |
| 194 | return id |
| 195 | } |
| 196 | |
| 197 | // node_kind_from_id converts node kind from id data for flat. |
| 198 | @[inline] |
| 199 | pub fn node_kind_from_id(id int) NodeKind { |
| 200 | return unsafe { NodeKind(id) } |
| 201 | } |
| 202 | |
| 203 | // add_val updates add val state for FlatAst. |
| 204 | pub fn (mut a FlatAst) add_val(kind NodeKind, value string) NodeId { |
| 205 | id := NodeId(a.nodes.len) |
| 206 | a.nodes << Node{ |
| 207 | kind: kind |
| 208 | kind_id: int(kind) |
| 209 | value: value |
| 210 | } |
| 211 | return id |
| 212 | } |
| 213 | |
| 214 | // add_val_id updates add val id state for FlatAst. |
| 215 | pub fn (mut a FlatAst) add_val_id(kind_id int, value string) NodeId { |
| 216 | id := NodeId(a.nodes.len) |
| 217 | a.nodes << Node{ |
| 218 | kind: node_kind_from_id(kind_id) |
| 219 | kind_id: kind_id |
| 220 | value: value |
| 221 | } |
| 222 | return id |
| 223 | } |
| 224 | |
| 225 | // with_shifted_children returns a copy of the node whose children_start is moved |
| 226 | // by `shift`. children_start lives in the immutable section of Node, so callers |
| 227 | // that relocate a node's children block (e.g. the parallel-transform merge) build |
| 228 | // a fresh node instead of mutating in place. |
| 229 | pub fn (n Node) with_shifted_children(shift i32) Node { |
| 230 | return Node{ |
| 231 | value: n.value |
| 232 | typ: n.typ |
| 233 | generic_params: n.generic_params |
| 234 | kind_id: n.kind_id |
| 235 | pos: n.pos |
| 236 | children_start: n.children_start + shift |
| 237 | children_count: n.children_count |
| 238 | kind: n.kind |
| 239 | op: n.op |
| 240 | } |
| 241 | } |
| 242 | |
| 243 | // add_node updates add node state for FlatAst. |
| 244 | pub fn (mut a FlatAst) add_node(node Node) NodeId { |
| 245 | id := NodeId(a.nodes.len) |
| 246 | mut n := node |
| 247 | if n.kind_id == 0 && int(n.kind) != 0 { |
| 248 | n.kind_id = int(n.kind) |
| 249 | } |
| 250 | a.nodes << n |
| 251 | return id |
| 252 | } |
| 253 | |
| 254 | // child_count converts a dynamic child count to Node's compact storage type. |
| 255 | pub fn child_count(count int) i16 { |
| 256 | if count > 32767 { |
| 257 | panic('flat node has too many children') |
| 258 | } |
| 259 | return i16(count) |
| 260 | } |
| 261 | |
| 262 | // begin_children supports begin children handling for FlatAst. |
| 263 | pub fn (mut a FlatAst) begin_children() int { |
| 264 | return a.children.len |
| 265 | } |
| 266 | |
| 267 | // add_child updates add child state for FlatAst. |
| 268 | pub fn (mut a FlatAst) add_child(id NodeId) { |
| 269 | a.children << id |
| 270 | } |
| 271 | |
| 272 | // child supports child handling for FlatAst. |
| 273 | pub fn (a &FlatAst) child(node &Node, index int) NodeId { |
| 274 | child_index := node.children_start + index |
| 275 | if index < 0 || index >= node.children_count || child_index < 0 || child_index >= a.children.len { |
| 276 | return empty_node |
| 277 | } |
| 278 | return a.children[child_index] |
| 279 | } |
| 280 | |
| 281 | // child_node supports child node handling for FlatAst. |
| 282 | pub fn (a &FlatAst) child_node(node &Node, index int) &Node { |
| 283 | id := a.child(node, index) |
| 284 | if int(id) < 0 || int(id) >= a.nodes.len { |
| 285 | return &empty_node_value |
| 286 | } |
| 287 | return &a.nodes[int(id)] |
| 288 | } |
| 289 | |
| 290 | // node supports node handling for FlatAst. |
| 291 | pub fn (a &FlatAst) node(id NodeId) &Node { |
| 292 | if int(id) < 0 || int(id) >= a.nodes.len { |
| 293 | return &empty_node_value |
| 294 | } |
| 295 | return &a.nodes[int(id)] |
| 296 | } |
| 297 | |
| 298 | // children_of supports children of handling for FlatAst. |
| 299 | pub fn (a &FlatAst) children_of(node &Node) []NodeId { |
| 300 | if node.children_count == 0 { |
| 301 | return [] |
| 302 | } |
| 303 | if node.children_start < 0 || node.children_start >= a.children.len { |
| 304 | return [] |
| 305 | } |
| 306 | if node.children_start + node.children_count > a.children.len { |
| 307 | return a.children[node.children_start..] |
| 308 | } |
| 309 | return a.children[node.children_start..node.children_start + node.children_count] |
| 310 | } |
| 311 | |
| 312 | // print_tree updates print tree state for FlatAst. |
| 313 | pub fn (a &FlatAst) print_tree(id NodeId, indent int) { |
| 314 | node := a.nodes[int(id)] |
| 315 | mut prefix := '' |
| 316 | for _ in 0 .. indent { |
| 317 | prefix += ' ' |
| 318 | } |
| 319 | mut info := '${node.kind}' |
| 320 | if node.value.len > 0 { |
| 321 | info += ' "${node.value}"' |
| 322 | } |
| 323 | if node.op != .none { |
| 324 | info += ' op=${node.op}' |
| 325 | } |
| 326 | if node.typ.len > 0 { |
| 327 | info += ' typ=${node.typ}' |
| 328 | } |
| 329 | println('${prefix}${info}') |
| 330 | for i in 0 .. node.children_count { |
| 331 | child_id := a.children[node.children_start + i] |
| 332 | if int(child_id) >= 0 { |
| 333 | a.print_tree(child_id, indent + 1) |
| 334 | } |
| 335 | } |
| 336 | } |
| 337 | |