Skip to main content

lemon_tree/
lib.rs

1//! Famous [Lemon Parser Generator](https://www.hwaci.com/sw/lemon/), designed as library that builds your parser transparently during cargo build.
2//! To describe parser rules you add annotation attributes to rust functions, structs and enums.
3//!
4//! You can find usage examples [here](https://github.com/jeremiah-shaulov/lemon-tree).
5//!
6//! Let's say we want to create Lemon parser like this:
7//!
8//! ```ignore
9//! %token_type {f64}
10//! %left PLUS
11//!
12//! Unit ::= Expr(expr).
13//! Expr ::= VALUE(value).
14//! Expr ::= Expr(a) PLUS Expr(b).
15//! ```
16//!
17//! We want that Unit and Expr will be represented by the following types in rust:
18//!
19//! ```ignore
20//! struct Unit
21//! {	expr: Expr,
22//! }
23//!
24//! struct Expr
25//! {	value: f64,
26//! }
27//! ```
28//!
29//! Every symbol except the start symbol we need to annotate with `#[derive(LemonTreeNode)]`, and the start symbol with `#[derive(LemonTree)]`.
30//! Parser rules that return this symbol we put into `#[lem()]` annotation attributes.
31//! All `#[derive(LemonTreeNode)]`, `#[derive(LemonTree)]` and `#[lem_fn()]` attributes that describe single Lemon parser must be contained in single rust file,
32//! and the `#[derive(LemonTree)]` must come the last.
33//!
34//! ```ignore
35//! #[derive(LemonTreeNode)]
36//! #[lem("VALUE(value)")]
37//! pub struct Expr
38//! {	value: f64,
39//! }
40//!
41//! #[derive(LemonTree)]
42//! #[lem("Expr(expr)")]
43//! pub struct Unit
44//! {	expr: Expr,
45//! }
46//! ```
47//!
48//! The `#[lem()]` attribute can appear multiple times, and each attribute can contain multiple rules, like `#[lem("A(value)", "B(value)")]`.
49//!
50//! Each rule will produce code that creates new struct instance. Aliases given in parentheses will be assigned to struct fields.
51//! If a struct has more fields than appear in expression, the remaining fields will be set to `Default::default()`, so they need to implement `std::default::Default` trait.
52//! Existing fields will be assigned like this: `Type {field: value.into()}`. So field type in struct can be the type of value, or compatible with it.
53//!
54//! In example above, there's one Lemon rule, that doesn't return the final result, but needs to perform some calculation.
55//! We expect that rule `Expr ::= Expr(a) PLUS Expr(b)` will produce type `Expr {value: a.value + b.value}`.
56//! We can implement this rule as rust function:
57//!
58//! ```ignore
59//! #[lem_fn("Expr(a) PLUS Expr(b)")]
60//! pub fn expr_1(a: Expr, b: Expr) -> Expr
61//! {	Expr {value: a.value + b.value}
62//! }
63//! ```
64//!
65//! So `#[lem_fn()]` attribute creates parser rule, whose action is module-global function call.
66//! The return type of such function will be the left-hand side symbol in Lemon rule, like `Expr ::= Expr(a) PLUS Expr(b)`.
67//!
68//! To specify Lemon parser directives, like `%token_type {f64}`, need to use `#[lem_opt()]` attributes near start symbol, like `#[lem_opt(token_type="f64")]`.
69//!
70//! Here is complete example:
71//!
72//! ```
73//! use lemon_tree::{lem_fn, LemonTree, LemonTreeNode};
74//!
75//! #[derive(LemonTreeNode, Debug)]
76//! #[lem("VALUE(value)")]
77//! pub struct Expr
78//! {	value: f64,
79//! }
80//!
81//! #[lem_fn("Expr(a) PLUS Expr(b)")]
82//! pub fn expr_1(a: Expr, b: Expr) -> Expr
83//! {	Expr {value: a.value + b.value}
84//! }
85//!
86//! #[derive(LemonTree, Debug)]
87//! #[lem("Expr(expr)")]
88//! #[lem_opt(token_type="f64", left="PLUS")]
89//! pub struct Unit
90//! {	expr: Expr,
91//! }
92//!
93//! fn main()
94//! {	let mut parser = Unit::get_parser(());
95//! 	parser.add_token(<Unit as LemonTree>::Token::VALUE, 10.0).unwrap();
96//! 	parser.add_token(<Unit as LemonTree>::Token::PLUS, 0.0).unwrap();
97//! 	parser.add_token(<Unit as LemonTree>::Token::VALUE, 20.0).unwrap();
98//! 	let result = parser.end().unwrap();
99//! 	assert_eq!(result.expr.value, 30.0);
100//! 	println!("Result: {:?}", result);
101//! }
102//! ```
103//!
104//! Enums can be used as symbol types as well. With enums need to put `#[lem()]` parser rules near enum variants.
105//! Example:
106//!
107//! ```
108//! use lemon_tree::{lem_fn, LemonTree, LemonTreeNode};
109//!
110//! #[derive(LemonTreeNode, Debug, PartialEq)]
111//! pub enum Expr
112//! {	#[lem("VALUE(0)")]
113//! 	Value(f64),
114//!
115//! 	#[lem("Expr(0) PLUS Expr(1)")]
116//! 	Plus(Box<Expr>, Box<Expr>), // the generated action will look like: Expr::Plus(arg_0.into(), arg_1.into())
117//! }
118//!
119//! #[derive(LemonTree, Debug, PartialEq)]
120//! #[lem("Expr(expr)")]
121//! #[lem_opt(token_type="f64", left="PLUS")]
122//! pub struct Unit
123//! {	expr: Expr,
124//! }
125//!
126//! fn main()
127//! {	let mut parser = Unit::get_parser(());
128//! 	parser.add_token(<Unit as LemonTree>::Token::VALUE, 10.0).unwrap();
129//! 	parser.add_token(<Unit as LemonTree>::Token::PLUS, 0.0).unwrap();
130//! 	parser.add_token(<Unit as LemonTree>::Token::VALUE, 20.0).unwrap();
131//! 	let result = parser.end().unwrap();
132//! 	assert_eq!
133//! 	(	result,
134//! 		Unit
135//! 		{	expr: Expr::Plus
136//! 			(	Box::new(Expr::Value(10.0)),
137//! 				Box::new(Expr::Value(20.0)),
138//! 			)
139//! 		}
140//! 	);
141//! 	println!("Result: {:?}", result);
142//! }
143//! ```
144//!
145//! Notice, that in `Expr::Plus` action, `Expr` object magically converted to `Box<Expr>`, because `Box<T>` implements `From<T>`, so `into()` can be used to convert.
146//!
147//! What if we want to do more complex conversion? Actually we can convert anything to anything, if we manually implement an `Into<T>` trait.
148//! Example:
149//!
150//! ```
151//! use lemon_tree::{lem_fn, LemonTree, LemonTreeNode};
152//!
153//! #[derive(LemonTreeNode, Debug, PartialEq)]
154//! pub enum Expr
155//! {	#[lem("VALUE(0)")]
156//! 	Value(f64),
157//!
158//! 	#[lem("Expr(0) PLUS Expr(1)")]
159//! 	Plus(String, String),
160//! }
161//!
162//! impl Into<String> for Expr
163//! {	fn into(self) -> String
164//! 	{	match self
165//! 		{	Expr::Value(v) => format!("{}", v),
166//! 			Expr::Plus(a, b) => format!("{} + {}", a, b),
167//! 		}
168//! 	}
169//! }
170//!
171//! #[derive(LemonTree, Debug, PartialEq)]
172//! #[lem("Expr(expr)")]
173//! #[lem_opt(token_type="f64", left="PLUS")]
174//! pub struct Unit
175//! {	expr: Expr,
176//! }
177//!
178//! fn main()
179//! {	let mut parser = Unit::get_parser(());
180//! 	parser.add_token(<Unit as LemonTree>::Token::VALUE, 10.0).unwrap();
181//! 	parser.add_token(<Unit as LemonTree>::Token::PLUS, 0.0).unwrap();
182//! 	parser.add_token(<Unit as LemonTree>::Token::VALUE, 20.0).unwrap();
183//! 	let result = parser.end().unwrap();
184//! 	assert_eq!
185//! 	(	result,
186//! 		Unit
187//! 		{	expr: Expr::Plus("10".to_string(), "20".to_string())
188//! 		}
189//! 	);
190//! 	println!("Result: {:?}", result);
191//! }
192//! ```
193//!
194
195pub use lemon_tree_derive::{lem_fn, LemonTree, LemonTreeNode};
196
197/// Parser "start symbol" can be represented as a struct or enum. You need to annotate it with `#[derive(LemonTree)]`, and implementation of this trait will be generated.
198///
199/// The implementation contains 2 associated types:
200/// * Parser - the parser, that will accept tokens, and finally return the start symbol.
201/// * Token - enum with token names. All the terminal symbols (tokens) that appear in your grammar (in #[lem()] and #[lem_fn()] attributes) will become variants in this enum.
202///
203/// If you annotate a struct like this:
204///
205/// ```ignore
206/// #[derive(LemonTree)]
207/// struct Unit
208/// {
209/// }
210/// ```
211///
212/// And you have terminal symbols `HELLO` and `WORLD`, then you can:
213///
214/// ```ignore
215/// let mut parser = Unit::get_parser(()); // where () is initializer for %extra_argument
216/// // the type of parser is <Unit as LemonTree>::Parser
217/// parser.add_token(<Unit as LemonTree>::Token::HELLO, ()).unwrap();
218/// parser.add_token(<Unit as LemonTree>::Token::WORLD, ()).unwrap();
219/// let resulting_unit = parser.end().unwrap(); // returns Unit
220/// ```
221pub trait LemonTree
222{   type Parser;
223	type Token;
224}
225
226/// For nonterminal symbols, except start symbol.
227pub trait LemonTreeNode
228{
229}