lemon-tree

Famous Lemon Parser Generator, designed as library that builds your parser transparently during cargo build. Uses attributes to describe parser rules.

This crate uses lemon-mint as backend.

Example

You can have several parsers in your project. Each parser must be completely described in one rust file, and #[derive(LemonTree)] (the start symbol) must appear the last in the file.

```rust extern crate lemon_tree;

use lemontree::{lemfn, LemonTree};

type Expr = f64; type Exprs = Vec;

[lemfn("NUM(value)")] pub fn expr1(value: f64) -> Expr {value}

[lemfn("MINUS Expr(a)")] pub fn expr2(a: Expr) -> Expr {-a}

[lemfn("PLUS Expr(a)")] pub fn expr3(a: Expr) -> Expr {a}

[lemfn("Expr(a) PLUS Expr(b)")] pub fn expr4(a: Expr, b: Expr) -> Expr {a + b}

[lemfn("Expr(a) MINUS Expr(b)")] pub fn expr5(a: Expr, b: Expr) -> Expr {a - b}

[lemfn("Expr(a) TIMES Expr(b)")] pub fn expr6(a: Expr, b: Expr) -> Expr {a * b}

[lemfn("Expr(a) DIVIDE Expr(b)")] pub fn expr7(a: Expr, b: Expr) -> Expr {a / b}

[lemfn("PAROPEN Expr(0) PARCLOSE")] pub fn expr8(a: Expr) -> Expr {a}

[lemfn("Expr(item)")] pub fn exprs1(item: Expr) -> Exprs {vec![item]}

[lemfn("Exprs(items) SEMICOLON Expr(item)")] pub fn exprs2(mut items: Exprs, item: Expr) -> Exprs {items.push(item); items}

[derive(LemonTree)]

[lemopt(tokentype="f64", left="PLUS MINUS", left="DIVIDE TIMES", trace=">>")]

[lem("Exprs(exprs) [SEMICOLON]")]

pub struct Program { exprs: Exprs, }

fn parse(parser: &mut ::Parser, mut input: &str) -> Exprs { loop { input = input.trimstart(); match input.bytes().next() { Some(c) => match c { b'+' => parser.addtoken(::Token::PLUS, 0.0).unwrap(), b'-' => parser.addtoken(::Token::MINUS, 0.0).unwrap(), b'*' => parser.addtoken(::Token::TIMES, 0.0).unwrap(), b'/' => parser.addtoken(::Token::DIVIDE, 0.0).unwrap(), b'(' => parser.addtoken(::Token::PAROPEN, 0.0).unwrap(), b')' => parser.addtoken(::Token::PARCLOSE, 0.0).unwrap(), b';' => parser.addtoken(::Token::SEMICOLON, 0.0).unwrap(), b'0' ..= b'9' | b'.' => { let pos = input.bytes().position(|c| !c.isasciidigit() && c!=b'.').unwrapor(input.len()); let value = input[.. pos].parse().unwrap(); parser.addtoken(::Token::NUM, value).unwrap(); input = &input[pos-1 ..]; } _ => panic!("Invalid token") } None => { return parser.end().unwrap().exprs; } } input = &input[1 ..]; } }

fn main() { let mut parser = Program::get_parser(());

assert_eq!(parse(&mut parser, "2 + 2 * 2; (2+2) * 2"), vec![6.0, 8.0]);
assert_eq!(parse(&mut parser, "2 * 2 + 2; (2*2) + 2"), vec![6.0, 6.0]);
assert_eq!(parse(&mut parser, "-1*30"), vec![-30.0]);
assert_eq!(parse(&mut parser, "0--1;"), vec![1.0]);
assert_eq!(parse(&mut parser, "(((0)))"), vec![0.0]);
assert_eq!(parse(&mut parser, "0.123 + 10"), vec![10.123]);
assert_eq!(parse(&mut parser, "0.123 / (1.0-1.0)"), vec![f64::INFINITY]);

} ```

This crate exports 3 symbols: lem_fn, LemonTree and LemonTreeNode.

Need to mark start symbol with #[derive(LemonTree)]. This automatic derive trait allows to set parser options with #[lem_opt()] attribute, and parser rules with #[lem()] attribute.

Symbols other than the start symbol can be declared with module-global functions annotated with #[lem_fn()] attribute. This attribute must be exported to the current namespace with use lemon_tree::lem_fn.

Another option is to use LemonTreeNode:

```rust use lemontree::{lemfn, LemonTree, LemonTreeNode};

[derive(LemonTreeNode, Debug, PartialEq)]

pub enum Expr { #[lem("NUM(0)")] Num(f64), #[lem("MINUS Expr(0)")] UnaryMinus(Box), #[lem("PLUS Expr(0)")] UnaryPlus(Box), #[lem("Expr(0) PLUS Expr(1)")] Plus(Box, Box), #[lem("Expr(0) MINUS Expr(1)")] Minus(Box, Box), #[lem("Expr(0) TIMES Expr(1)")] Times(Box, Box), #[lem("Expr(0) DIVIDE Expr(1)")] Divide(Box, Box), }

[lemfn("PAROPEN Expr(0) PARCLOSE")] pub fn exprfrom_par(a: Expr) -> Expr {a}

[derive(LemonTreeNode, Debug, PartialEq)]

pub enum Exprs { #[lem("Expr(0)")] Expr(Expr),

#[lem("Exprs(0) SEMICOLON Expr(1)")]
Exprs(Box<Exprs>, Expr),

}

[derive(LemonTree, Debug)]

[lemopt(tokentype="f64", left="PLUS MINUS", left="DIVIDE TIMES")]

[lem("Exprs(exprs) [SEMICOLON]")]

pub struct Program { exprs: Vec, flag: bool, }

fn parse(parser: &mut ::Parser, mut input: &str) -> Vec { loop { input = input.trimstart(); match input.bytes().next() { Some(c) => match c { b'+' => parser.addtoken(::Token::PLUS, 0.0).unwrap(), b'-' => parser.addtoken(::Token::MINUS, 0.0).unwrap(), b'*' => parser.addtoken(::Token::TIMES, 0.0).unwrap(), b'/' => parser.addtoken(::Token::DIVIDE, 0.0).unwrap(), b'(' => parser.addtoken(::Token::PAROPEN, 0.0).unwrap(), b')' => parser.addtoken(::Token::PARCLOSE, 0.0).unwrap(), b';' => parser.addtoken(::Token::SEMICOLON, 0.0).unwrap(), b'0' ..= b'9' | b'.' => { let pos = input.bytes().position(|c| !c.isasciidigit() && c!=b'.').unwrapor(input.len()); let value = input[.. pos].parse().unwrap(); parser.addtoken(::Token::NUM, value).unwrap(); input = &input[pos-1 ..]; } _ => panic!("Invalid token") } None => { return parser.end().unwrap().exprs; } } input = &input[1 ..]; } }

fn main() { use Expr::*; let mut parser = Program::get_parser(());

assert_eq!
(   parse(&mut parser, "2 + 2 * 2; (2+2) * 2"),
    vec!
    [   Times
        (   Box::new(Plus(Box::new(Num(2.0)), Box::new(Num(2.0)))),
            Box::new(Num(2.0))
        ),
        Plus
        (   Box::new(Num(2.0)),
            Box::new(Times(Box::new(Num(2.0)), Box::new(Num(2.0))))
        )
    ]
);

} ```

This allows to build syntax trees easily.