compiler: Publish fully initialized immutable AST nodes
68c2ad5710e00522babd4db2653ae28feb828c2a54fb3504142096a930a02c7c
1 parent
6f1f12f2
lib/std/lang/ast.rad
+2 -2
| 918 | 918 | else => return false, |
|
| 919 | 919 | } |
|
| 920 | 920 | } |
|
| 921 | 921 | ||
| 922 | 922 | /// Allocate a new AST node from the arena with the given span and value. |
|
| 923 | - | export unsafe fn allocNode(arena: &mut NodeArena, span: Span, value: NodeValue) -> *mut Node { |
|
| 923 | + | export unsafe fn allocNode(arena: &mut NodeArena, span: Span, value: NodeValue) -> *Node { |
|
| 924 | 924 | let p = try! alloc::alloc(&mut arena.arena, @sizeOf(Node), @alignOf(Node)); |
|
| 925 | 925 | let node = p as *mut Node; |
|
| 926 | 926 | let nodeId = arena.nextId; |
|
| 927 | 927 | set arena.nextId = nodeId + 1; |
|
| 928 | 928 |
| 930 | 930 | ||
| 931 | 931 | return node; |
|
| 932 | 932 | } |
|
| 933 | 933 | ||
| 934 | 934 | /// Allocate a synthetic AST node with a zero-length span. |
|
| 935 | - | export unsafe fn synthNode(arena: &mut NodeArena, value: NodeValue) -> *mut Node { |
|
| 935 | + | export unsafe fn synthNode(arena: &mut NodeArena, value: NodeValue) -> *Node { |
|
| 936 | 936 | return allocNode(arena, Span { offset: 0, length: 0 }, value); |
|
| 937 | 937 | } |
|
| 938 | 938 | ||
| 939 | 939 | /// Synthetic module with a single function in it. |
|
| 940 | 940 | record SynthFnMod: Copy { |
lib/std/lang/parser.rad
+9 -22
| 1086 | 1086 | return expr; |
|
| 1087 | 1087 | } |
|
| 1088 | 1088 | return branch; |
|
| 1089 | 1089 | } |
|
| 1090 | 1090 | ||
| 1091 | - | /// Allocate a new node from the parser's arena. |
|
| 1092 | - | unsafe fn node 'pool (p: &mut Parser 'pool, value: ast::NodeValue) -> *mut ast::Node { |
|
| 1091 | + | /// Allocate a node with its span set from the most recently consumed token. |
|
| 1092 | + | unsafe fn node 'pool (p: &mut Parser 'pool, value: ast::NodeValue) -> *ast::Node { |
|
| 1093 | + | let start = p.previous.offset; |
|
| 1094 | + | let end = start + p.previous.source.len; |
|
| 1093 | 1095 | let span = ast::Span { |
|
| 1094 | - | offset: p.previous.offset, |
|
| 1095 | - | length: p.previous.source.len, |
|
| 1096 | + | offset: start, |
|
| 1097 | + | length: end - start if end >= start else 0, |
|
| 1096 | 1098 | }; |
|
| 1097 | - | let n = ast::allocNode(p.arena, span, value); |
|
| 1098 | - | finishSpan(p, n); |
|
| 1099 | - | ||
| 1100 | - | return n; |
|
| 1101 | - | } |
|
| 1102 | - | ||
| 1103 | - | /// Update the span of `node` using the most recently consumed token. |
|
| 1104 | - | fn finishSpan 'pool (p: &mut Parser 'pool, node: &mut ast::Node) { |
|
| 1105 | - | let start: u32 = node.span.offset; |
|
| 1106 | - | let mut end: u32 = p.previous.offset + p.previous.source.len; |
|
| 1107 | - | ||
| 1108 | - | if end >= start { |
|
| 1109 | - | set node.span.length = end - start; |
|
| 1110 | - | } else { |
|
| 1111 | - | set node.span.length = 0; |
|
| 1112 | - | } |
|
| 1099 | + | return ast::allocNode(p.arena, span, value); |
|
| 1113 | 1100 | } |
|
| 1114 | 1101 | ||
| 1115 | 1102 | /// Save parser state for speculative parsing. |
|
| 1116 | 1103 | fn saveState 'pool (p: &Parser 'pool) -> SavedState { |
|
| 1117 | 1104 | return SavedState { |
| 2445 | 2432 | ident: binding.name, type: binding.type, value, alignment: binding.alignment, mutable, |
|
| 2446 | 2433 | })); |
|
| 2447 | 2434 | } |
|
| 2448 | 2435 | ||
| 2449 | 2436 | /// Parse a module from source text using the provided arena for node storage. |
|
| 2450 | - | export unsafe fn parse(sourceLoc: scanner::SourceLoc, input: *[u8], arena: &mut ast::NodeArena, pool: &mut strings::Pool) -> *mut ast::Node |
|
| 2437 | + | export unsafe fn parse(sourceLoc: scanner::SourceLoc, input: *[u8], arena: &mut ast::NodeArena, pool: &mut strings::Pool) -> *ast::Node |
|
| 2451 | 2438 | throws (ParseError) |
|
| 2452 | 2439 | { |
|
| 2453 | 2440 | let poolRef: 'pool = &mut *pool, arenaRef = &mut *arena in { |
|
| 2454 | 2441 | let mut p = mkParser(sourceLoc, input, arenaRef, poolRef); |
|
| 2455 | 2442 | return try parseModule(&mut p) catch { |
| 2461 | 2448 | ||
| 2462 | 2449 | /// Parse a complete module into a block of top-level statements. |
|
| 2463 | 2450 | /// |
|
| 2464 | 2451 | /// This is the main entry point for parsing an entire Radiance source file. |
|
| 2465 | 2452 | /// The parser must already be initialized with source code. |
|
| 2466 | - | export unsafe fn parseModule 'pool (p: &mut Parser 'pool) -> *mut ast::Node |
|
| 2453 | + | export unsafe fn parseModule 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 2467 | 2454 | throws (ParseError) |
|
| 2468 | 2455 | { |
|
| 2469 | 2456 | advance(p); // Set the parser up with a first token. |
|
| 2470 | 2457 | ||
| 2471 | 2458 | let statements = try parseStmtsUntil(p, scanner::TokenKind::Eof, 512); |
lib/std/lang/parser/tests.rad
+19 -0
| 8 | 8 | use std::lang::sexpr; |
|
| 9 | 9 | use std::lang::ast::printer; |
|
| 10 | 10 | use std::lang::scanner; |
|
| 11 | 11 | use std::lang::strings; |
|
| 12 | 12 | ||
| 13 | + | /// Allocated nodes publish immutable pointers with stable metadata and edges. |
|
| 14 | + | @test unsafe fn testAstNodePublication() throws (testing::TestError) { |
|
| 15 | + | static STORAGE: [u8; 4096] = [0; 4096]; |
|
| 16 | + | let mut arena = ast::nodeArena(&mut STORAGE[..]); |
|
| 17 | + | let allocate: unsafe fn(&mut ast::NodeArena, ast::Span, ast::NodeValue) -> *ast::Node = ast::allocNode; |
|
| 18 | + | let synthesize: unsafe fn(&mut ast::NodeArena, ast::NodeValue) -> *ast::Node = ast::synthNode; |
|
| 19 | + | let leaf = allocate(&mut arena, ast::Span { offset: 9, length: 4 }, ast::NodeValue::Bool(true)); |
|
| 20 | + | let root = synthesize(&mut arena, ast::NodeValue::ExprStmt(leaf)); |
|
| 21 | + | assert leaf.id == 0; |
|
| 22 | + | assert leaf.span.offset == 9; |
|
| 23 | + | assert leaf.span.length == 4; |
|
| 24 | + | assert root.id == 1; |
|
| 25 | + | assert root.span.offset == 0; |
|
| 26 | + | assert root.span.length == 0; |
|
| 27 | + | let case ast::NodeValue::ExprStmt(child) = root.value else throw testing::TestError::Failed; |
|
| 28 | + | assert child == leaf; |
|
| 29 | + | assert arena.nextId == 2; |
|
| 30 | + | } |
|
| 31 | + | ||
| 13 | 32 | /// Unified arena size. |
|
| 14 | 33 | constant ARENA_SIZE: u32 = 2097152; |
|
| 15 | 34 | /// Unified arena storage for all AST allocations. |
|
| 16 | 35 | static ARENA_STORAGE: [u8; ARENA_SIZE] = [0; ARENA_SIZE]; |
|
| 17 | 36 | /// String pool. |