diff --git a/README.md b/README.md index 4c44d5e..a54488c 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,8 @@ the driver uses `@source/compilation` to own loaded source buffers, copied paths AST `NodeId` values are compilation-wide, so declarations in different files cannot alias. spans carry their originating `diagnostics.SourceId`; `ast.source_files` exposes borrowed paths and text. `compilation.compile` resolves each package independently, checks the complete arena and lowers one independently owned IR module, selecting an entry only from the requested root package. interpreter diagnostics and generated native traps retain the originating filename and local line/byte-column. borrowed `ast.view` trees must be refreshed after builder mutation and must not be passed to `ast.deinit`. +AST nodes retain a compact 16-byte layout on the bootstrap target: a kind, three 32-bit payload words and one packed flag byte in existing padding. file-local, foreign-callable, variadic and opaque metadata therefore need neither per-node boolean fields nor another allocation. spans and variable-length payloads remain in parallel storage; cloning and replacement copy the flags with the node. + identifier interning is compilation-owned: initialize a `strpool.StringPool`, pass it to `lexer.scan` and `sema.resolve` before the diagnostic store, and release it after lowering. scanning interns identifier spellings once per pool; parsing preserves their IDs in compact AST storage, exposed through `ast.name_id`, while retaining source spans for diagnostics. name resolution keys scopes by those IDs and interns builtin names into the same pool, so identifier hashing and equality do not scan spelling bytes. IDs are meaningful only within their originating pool; independent compilations may assign the same numeric ID to different names. interning failures propagate as infrastructure errors rather than producing an invalid identifier ID. IR retains no pool dependency. resolver scopes use `@std/hashmap.AutoHashMap(K, V)`, which shares `init`, `put`, `get` and `deinit` with custom `HashMap` and `StringHashMap`. automatic keys support integers, booleans, enums, distinct types, fixed arrays and records recursively; record padding is ignored. slices, floating-point values, pointers, optionals and unions require explicit hashing and equality through `HashMap` (`StringHashMap` supplies content-based byte-string operations). keys and values are stored by value; referenced resources remain caller-owned. the builtin declaration count is inferred, and builtin ID storage derives its fixed stack-array length from that declaration array rather than repeating a count or initializer. diff --git a/source/ast/ast.hon b/source/ast/ast.hon index 89e81c6..46c8086 100644 --- a/source/ast/ast.hon +++ b/source/ast/ast.hon @@ -202,16 +202,19 @@ NodeData :: union { binary_operator BinaryOperator } +@hide:file file_local_flag u8 :: 1 +@hide:file foreign_type_flag u8 :: 2 +@hide:file variadic_flag u8 :: 4 +@hide:file opaque_flag u8 :: 8 + @hide:file Node :: struct { kind NodeKind + # use the padding before the payload words rather than enlarging every node. + flags u8 = 0 main NodeData = NodeData{ node_id = no_node } data0 NodeData = NodeData{ node_id = no_node } data1 NodeData = NodeData{ node_id = no_node } - file_local bool = false - foreign_type bool = false - variadic bool = false - is_opaque bool = false } @hide:file @@ -1114,35 +1117,39 @@ function_external proc(tree @Tree, id NodeId) bool { } set_file_local proc(builder @mut Builder, id NodeId) void { - builder.storage.nodes.items[usize(id)].file_local = true + node :: &builder.storage.nodes.items[usize(id)] + node.flags = node.flags | file_local_flag } file_local proc(tree @Tree, id NodeId) bool { - return get_node(&tree.storage, id).file_local + return (tree.storage.nodes.items[usize(id)].flags & file_local_flag) != 0 } set_callable_foreign proc(builder @mut Builder, id NodeId) void { - builder.storage.nodes.items[usize(id)].foreign_type = true + node :: &builder.storage.nodes.items[usize(id)] + node.flags = node.flags | foreign_type_flag } callable_foreign proc(tree @Tree, id NodeId) bool { - return function_external(tree, id) or get_node(&tree.storage, id).foreign_type + return function_external(tree, id) or (tree.storage.nodes.items[usize(id)].flags & foreign_type_flag) != 0 } set_callable_variadic proc(builder @mut Builder, id NodeId) void { - builder.storage.nodes.items[usize(id)].variadic = true + node :: &builder.storage.nodes.items[usize(id)] + node.flags = node.flags | variadic_flag } callable_variadic proc(tree @Tree, id NodeId) bool { - return get_node(&tree.storage, id).variadic + return (tree.storage.nodes.items[usize(id)].flags & variadic_flag) != 0 } set_record_opaque proc(builder @mut Builder, id NodeId) void { - builder.storage.nodes.items[usize(id)].is_opaque = true + node :: &builder.storage.nodes.items[usize(id)] + node.flags = node.flags | opaque_flag } record_opaque proc(tree @Tree, id NodeId) bool { - return get_node(&tree.storage, id).is_opaque + return (tree.storage.nodes.items[usize(id)].flags & opaque_flag) != 0 } function_generic proc(tree @Tree, id NodeId) bool {