|
1 | 1 | // The Rust Target for emit-portable. Renders the same language-agnostic ParserIR as |
2 | 2 | // tsTarget/goTarget into a self-contained Rust program (no external crates — the lexer is |
3 | 3 | // regex-free, so it compiles with rustc alone, no Cargo/network). Its CST JSON is checked |
4 | | -// byte-for-byte against the interpreter, so `emitPortableParser(grammar, rustTarget)` is a |
| 4 | +// byte-for-byte against the interpreter, so `emitParser(grammar, rustTarget)` is a |
5 | 5 | // real, verified Rust parser derived from the same grammar definition. |
6 | 6 | // |
7 | 7 | // Rust ownership note: a CST node is OWNED (moved), unlike the TS/Go pointer trees. In the |
|
11 | 11 | // returns it. Sub-sequence combinators (star/opt/sep) take non-capturing fn pointers |
12 | 12 | // `fn(&mut Parser, &mut Vec<Cst>) -> bool`, threading the parser + kids as params (so nothing |
13 | 13 | // is captured, sidestepping the borrow checker). |
14 | | -import type { ParserIR, RdRule, PrattRule, Step, Bracket, CharRange, LexTok, Target, TplCfg } from './emit-portable.ts'; |
15 | | -import type { TokenPattern } from './types.ts'; |
| 14 | +import type { ParserIR, RdRule, PrattRule, Step, Bracket, CharRange, LexTok, TplCfg } from './emit-portable.ts'; |
| 15 | +import { portableIR } from './emit-portable.ts'; |
| 16 | +import type { Target } from './emit.ts'; |
| 17 | +import type { TokenPattern, CstGrammar } from './types.ts'; |
16 | 18 |
|
17 | 19 | const J = (v: unknown) => JSON.stringify(v); |
18 | 20 | const rangeCond = (v: string, rs: CharRange[]) => |
@@ -312,7 +314,11 @@ ${r.nudSeqs.map((seq) => ` { let save = self.pos; let mut kids: Vec<Cst> |
312 | 314 | export const rustTarget: Target = { |
313 | 315 | name: 'rust', |
314 | 316 | ext: 'rs', |
315 | | - render(ir: ParserIR): string { |
| 317 | + emitLexer(grammar: CstGrammar): string { |
| 318 | + return lexer(portableIR(grammar)); |
| 319 | + }, |
| 320 | + emitParser(grammar: CstGrammar, lexerSrc: string | null): string { |
| 321 | + const ir = portableIR(grammar); |
316 | 322 | const ruleFns = ir.rules.map((r) => (r.kind === 'pratt' ? prattRule(r, ir.tpl) : rdRule(r))).join('\n\n'); |
317 | 323 | const matchTemplate = ir.tpl ? ` fn match_template(&mut self) -> Option<Cst> { |
318 | 324 | let t = self.peek()?; |
@@ -350,7 +356,7 @@ impl Cst { |
350 | 356 | // offset/end inferred from first/last child (children non-empty). |
351 | 357 | fn node(rule: &'static str, kids: Vec<Cst>) -> Cst { let o = kids[0].offset; let e = kids[kids.len() - 1].end; Cst::node(rule, kids, o, e) } |
352 | 358 |
|
353 | | -${lexer(ir)} |
| 359 | +${lexerSrc ?? ''} |
354 | 360 |
|
355 | 361 | struct Parser<'a> { toks: Vec<Tok<'a>>, pos: usize, capped: bool, suppress_next: Vec<&'static str>, src: &'a str } |
356 | 362 | impl<'a> Parser<'a> { |
|
0 commit comments