Skip to main content

Parse

Struct Parse 

Source
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>

Source

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"]);
Source

pub fn source(&self) -> &'a str

The source text that was parsed. Spans in the tree and the diagnostics are byte offsets into it.

Source

pub fn language(&self) -> &'a Language

The language that parsed the source, for looking kinds up and naming them.

Source

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"));
Source

pub fn has_errors(&self) -> bool

Whether any diagnostic is an error (rather than a warning or a note a capability pass added).

Source

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());
Source

pub fn into_tree(self) -> Node<Kind>

Takes the tree, dropping the diagnostics and the borrows.

Source

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",
);

Trait Implementations§

Source§

impl<'a> Clone for Parse<'a>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<'a> Debug for Parse<'a>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'a> Freeze for Parse<'a>

§

impl<'a> RefUnwindSafe for Parse<'a>

§

impl<'a> Send for Parse<'a>

§

impl<'a> Sync for Parse<'a>

§

impl<'a> Unpin for Parse<'a>

§

impl<'a> UnsafeUnpin for Parse<'a>

§

impl<'a> UnwindSafe for Parse<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.