mirror of
https://github.com/tursodatabase/libsql.git
synced 2025-05-25 15:40:38 +00:00
124 lines
3.3 KiB
Plaintext
124 lines
3.3 KiB
Plaintext
%token_type { i32 }
|
|
|
|
// An extra argument to the constructor for the parser, which is available
|
|
// to all actions.
|
|
%extra_context {ctx: Context}
|
|
|
|
%left PLUS MINUS.
|
|
%left DIVIDE TIMES.
|
|
|
|
%include {
|
|
|
|
use log::{debug, error, log_enabled, Level, LevelFilter, Metadata, Record, SetLoggerError};
|
|
|
|
pub struct Context {
|
|
expr: Option<Expr>,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum Operator {
|
|
Add,
|
|
Substract,
|
|
Multiply,
|
|
Divide,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum Expr {
|
|
Number(i32),
|
|
Binary(Operator, Box<Expr>, Box<Expr>),
|
|
}
|
|
impl Expr {
|
|
fn binary(op: Operator, lhs: Expr, rhs: Expr) -> Expr {
|
|
Expr::Binary(op, Box::new(lhs), Box::new(rhs))
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
init_logger().unwrap();
|
|
|
|
let r = Context { expr: None };
|
|
let mut p = yyParser::new(r);
|
|
p.Parse(TokenType::INTEGER, Some(5));
|
|
p.Parse(TokenType::PLUS, None);
|
|
p.Parse(TokenType::INTEGER, Some(10));
|
|
p.Parse(TokenType::TIMES, None);
|
|
p.Parse(TokenType::INTEGER, Some(4));
|
|
p.Parse(TokenType::EOF, None);
|
|
p.ParseFinalize();
|
|
let s = format!("{:?}", p.ctx.expr);
|
|
assert_eq!(s, "Some(Binary(Add, Number(5), Binary(Multiply, Number(10), Number(4))))");
|
|
|
|
let r = Context { expr: None };
|
|
let mut p = yyParser::new(r);
|
|
p.Parse(TokenType::INTEGER, Some(15));
|
|
p.Parse(TokenType::DIVIDE, None);
|
|
p.Parse(TokenType::INTEGER, Some(5));
|
|
p.Parse(TokenType::EOF, None);
|
|
p.ParseFinalize();
|
|
let s = format!("{:?}", p.ctx.expr);
|
|
assert_eq!(s, "Some(Binary(Divide, Number(15), Number(5)))");
|
|
|
|
let r = Context { expr: None };
|
|
let mut p = yyParser::new(r);
|
|
p.Parse(TokenType::INTEGER, Some(50));
|
|
p.Parse(TokenType::PLUS, None);
|
|
p.Parse(TokenType::INTEGER, Some(125));
|
|
p.Parse(TokenType::EOF, None);
|
|
p.ParseFinalize();
|
|
let s = format!("{:?}", p.ctx.expr);
|
|
assert_eq!(s, "Some(Binary(Add, Number(50), Number(125)))");
|
|
|
|
let r = Context { expr: None };
|
|
let mut p = yyParser::new(r);
|
|
p.Parse(TokenType::INTEGER, Some(50));
|
|
p.Parse(TokenType::TIMES, None);
|
|
p.Parse(TokenType::INTEGER, Some(125));
|
|
p.Parse(TokenType::PLUS, None);
|
|
p.Parse(TokenType::INTEGER, Some(125));
|
|
p.Parse(TokenType::EOF, None);
|
|
p.ParseFinalize();
|
|
let s = format!("{:?}", p.ctx.expr);
|
|
assert_eq!(s, "Some(Binary(Add, Binary(Multiply, Number(50), Number(125)), Number(125)))");
|
|
}
|
|
|
|
static LOGGER: Logger = Logger;
|
|
struct Logger;
|
|
|
|
impl log::Log for Logger {
|
|
fn enabled(&self, metadata: &Metadata) -> bool {
|
|
metadata.level() <= Level::Debug
|
|
}
|
|
|
|
fn log(&self, record: &Record) {
|
|
if self.enabled(record.metadata()) {
|
|
eprintln!("{} - {}", record.level(), record.args());
|
|
}
|
|
}
|
|
|
|
fn flush(&self) {
|
|
}
|
|
}
|
|
|
|
fn init_logger() -> Result<(), SetLoggerError> {
|
|
log::set_logger(&LOGGER)?;
|
|
log::set_max_level(LevelFilter::Debug);
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
%syntax_error {
|
|
let _ = yymajor;
|
|
println!("near token {:?}: syntax error", yyminor);
|
|
}
|
|
|
|
program ::= expr(A). { self.ctx.expr = Some(A); }
|
|
|
|
%type expr { Expr }
|
|
expr(A) ::= expr(B) MINUS expr(C). { A = Expr::binary(Operator::Substract, B, C); }
|
|
expr(A) ::= expr(B) PLUS expr(C). { A = Expr::binary(Operator::Add, B, C); }
|
|
expr(A) ::= expr(B) TIMES expr(C). { A = Expr::binary(Operator::Multiply, B, C); }
|
|
expr(A) ::= expr(B) DIVIDE expr(C). { A = Expr::binary(Operator::Divide, B, C); }
|
|
|
|
expr(A) ::= INTEGER(B). { A = Expr::Number(B.unwrap()); }
|