pub struct Parse<'a> { /* private fields */ }Expand description
The result of Language::parse: a lossless syntax tree and the problems
found while building it.
Parsing never fails. Malformed input still yields a complete tree — missing
pieces are left out, unexpected tokens are wrapped in ERROR nodes — and a
Diagnostic for each problem, so an editor can highlight and navigate a
half-typed file and a compiler can report every syntax error in one pass.
The tree is lossless either way: it covers every byte of the source,
whitespace and comments included.
A Parse borrows the language and the source it was made from, so names,
text, and diagnostics can be resolved from it alone. It is also the unit
that capability passes run over; see Language::pipeline.
§Examples
use lang_forge::Language;
let lang = Language::from_lsf(
r#"
[language]
name = "pairs"
[rules]
file = "pair*"
pair = "IDENT '=' NUMBER ';'"
"#,
)?;
let parse = lang.parse("a = 1;\nb = ;\n");
assert!(parse.has_errors());
assert_eq!(parse.diagnostics()[0].message(), "expected a number, found `;`");
// Still a full tree, covering the whole source.
assert_eq!(parse.tree().text(parse.source()), Some("a = 1;\nb = ;\n"));
assert_eq!(parse.tree().child_nodes().count(), 2);Implementations§
Source§impl<'a> Parse<'a>
impl<'a> Parse<'a>
Sourcepub fn tree(&self) -> &Node<Kind>
pub fn tree(&self) -> &Node<Kind>
The root of the syntax tree: a node of the start rule’s kind that covers the whole source.
Walk it with the syntax_lang::Node API — children,
descendants, tokens — and slice
the source with Node::text. Every walk is iterative, so even very
deep trees are safe to traverse.
§Examples
use lang_forge::Language;
let lang = Language::from_lsf(
"[language]\nname = \"list\"\n[rules]\nlist = \"'[' (NUMBER (',' NUMBER)*)? ']'\"\n",
)?;
let parse = lang.parse("[1, 2, 3]");
let number = lang.kind("NUMBER").expect("built in");
let numbers: Vec<&str> = parse
.tree()
.tokens()
.filter(|t| *t.kind() == number)
.map(|t| &parse.source()[t.span().start().to_usize()..t.span().end().to_usize()])
.collect();
assert_eq!(numbers, ["1", "2", "3"]);Sourcepub fn source(&self) -> &'a str
pub fn source(&self) -> &'a str
The source text that was parsed. Spans in the tree and the diagnostics are byte offsets into it.
Sourcepub fn language(&self) -> &'a Language
pub fn language(&self) -> &'a Language
The language that parsed the source, for looking kinds up and naming them.
Sourcepub fn diagnostics(&self) -> &[Diagnostic]
pub fn diagnostics(&self) -> &[Diagnostic]
The problems found, in source order: lexical errors (unexpected
characters, unterminated strings and comments, malformed numbers),
syntax errors, and anything capability passes have reported.
Spans are byte offsets into source. Add the source to
a fresh SourceMap and
Renderer draws each one under the line at
fault.
§Examples
use lang_forge::Language;
use lang_forge::diag_lang::{Renderer, SourceMap};
let lang = Language::from_lsf(
"[language]\nname = \"calls\"\n[rules]\nfile = \"call*\"\ncall = \"IDENT '(' ')' ';'\"\n",
)?;
let source = "start();\nstop(;\n";
let parse = lang.parse(source);
let mut map = SourceMap::new();
map.add("main.calls", source).expect("fits");
let report = Renderer::new().render(&parse.diagnostics()[0], &map);
assert!(report.contains("expected `)`, found `;`"));
assert!(report.contains("main.calls:2:6"));Sourcepub fn has_errors(&self) -> bool
pub fn has_errors(&self) -> bool
Whether any diagnostic is an error (rather than a warning or a note a capability pass added).
Sourcepub fn report(&mut self, diagnostic: Diagnostic)
pub fn report(&mut self, diagnostic: Diagnostic)
Adds a diagnostic — the way a capability pass reports what it finds.
§Examples
use lang_forge::Language;
use lang_forge::diag_lang::{Diagnostic, Label, Severity};
let lang = Language::from_lsf("[language]\nname = \"n\"\n[rules]\nn = \"NUMBER\"\n")?;
let mut parse = lang.parse("42");
let span = parse.tree().span();
parse.report(Diagnostic::new(Severity::Warning, "the answer", Label::unlabelled(span)));
assert_eq!(parse.diagnostics().len(), 1);
assert!(!parse.has_errors());Sourcepub fn dump(&self) -> String
pub fn dump(&self) -> String
The tree as indented text, one node or token per line: each line is a kind name and a byte range, and each token also shows its text.
Meant for tests, snapshots, and debugging a grammar. The format is stable within a major version.
§Examples
use lang_forge::Language;
let lang = Language::from_lsf(
"[language]\nname = \"let\"\n[rules]\nstmt = \"'let' IDENT '=' NUMBER\"\n",
)?;
assert_eq!(
lang.parse("let x = 1").dump(),
"stmt@0..9\n \
let@0..3 \"let\"\n \
WHITESPACE@3..4 \" \"\n \
IDENT@4..5 \"x\"\n \
WHITESPACE@5..6 \" \"\n \
=@6..7 \"=\"\n \
WHITESPACE@7..8 \" \"\n \
NUMBER@8..9 \"1\"\n",
);