use crate::ast::*; use std::rc::Rc; peg::parser! { pub grammar schala_parser() for str { pub rule program() -> AST = n:(statement() ** delimiter() ) { AST { id: Default::default(), statements: n.into() } } rule delimiter() = ";" / "\n" rule statement() -> Statement = expr:expression() { Statement { id: Default::default(), location: Default::default(), kind: StatementKind::Expression(expr) } } pub rule expression() -> Expression = kind:expression_kind() { Expression { id: Default::default(), type_anno: None, kind: kind } } rule expression_kind() -> ExpressionKind = primary() rule primary() -> ExpressionKind = float_literal() / nat_literal() / bool_literal() / string_literal() / paren_expr() rule paren_expr() -> ExpressionKind = "(" exprs:(expression() ** ",") ")" { let mut exprs = exprs; match exprs.len() { 1 => exprs.pop().unwrap().kind, _ => ExpressionKind::TupleLiteral(exprs), } } //TODO string escapes, prefixes rule string_literal() -> ExpressionKind = "\"" items:$([^ '"' ]*) "\"" { ExpressionKind::StringLiteral(Rc::new(items.to_string())) } rule bool_literal() -> ExpressionKind = "true" { ExpressionKind::BoolLiteral(true) } / "false" { ExpressionKind::BoolLiteral(false) } rule nat_literal() -> ExpressionKind = bin_literal() / hex_literal() / unmarked_literal() rule unmarked_literal() -> ExpressionKind = digits:digits() { ExpressionKind::NatLiteral(digits.parse().unwrap()) } rule bin_literal() -> ExpressionKind = "0b" digits:bin_digits() { ExpressionKind::NatLiteral(parse_binary(digits)) } rule hex_literal() -> ExpressionKind = "0x" digits:hex_digits() { ExpressionKind::NatLiteral(parse_hex(digits)) } rule float_literal() -> ExpressionKind = ds:$( digits() "." digits()? / "." digits() ) { ExpressionKind::FloatLiteral(ds.parse().unwrap()) } rule digits() -> &'input str = $((digit_group() "_"*)+) rule bin_digits() -> &'input str = $((bin_digit_group() "_"*)+) rule hex_digits() -> &'input str = $((hex_digit_group() "_"*)+) rule digit_group() -> &'input str = $(['0'..='9']+) rule bin_digit_group() -> &'input str = $(['0' | '1']+) rule hex_digit_group() -> &'input str = $(['0'..='9' | 'a'..='f' | 'A'..='F']+) } } fn parse_binary(digits: &str/*, tok: Token*/) -> /*ParseResult*/ u64 { let mut result: u64 = 0; let mut multiplier = 1; for d in digits.chars().rev() { match d { '1' => result += multiplier, '0' => (), '_' => continue, _ => unreachable!() } multiplier = match multiplier.checked_mul(2) { Some(m) => m, None => /*return ParseError::new_with_token("This binary expression will overflow", tok),*/ panic!(), } } //Ok(result) result } //TODO fix these two functions fn parse_hex(digits: &str) -> u64 { let mut result: u64 = 0; let mut multiplier: u64 = 1; for d in digits.chars().rev() { if d == '_' { continue; } match d.to_digit(16) { Some(n) => result += n as u64 * multiplier, None => panic!(), } multiplier = match multiplier.checked_mul(16) { Some(m) => m, None => panic!() } } result } #[cfg(test)] mod test { use super::*; use pretty_assertions::assert_eq; #[test] fn new_parser() { let parsed = schala_parser::expression("4"); assert_eq!(parsed.unwrap(), Expression { id: Default::default(), type_anno: None, kind: ExpressionKind::NatLiteral(4) }); let parsed = schala_parser::program("56.1"); if let Err(ref err) = parsed { println!("{}", err); } assert_eq!(parsed.unwrap(), AST { id: Default::default(), statements: vec![ Statement { id: Default::default(), location: Default::default(), kind: StatementKind::Expression(Expression { id: Default::default(), type_anno: None, kind: ExpressionKind::FloatLiteral(56.1) }) } ].into() }); let parsed = schala_parser::program("1;2\n5\n(1.1,false)"); if let Err(ref err) = parsed { println!("{}", err); } assert_eq!(parsed.unwrap(), AST { id: Default::default(), statements: vec![ Statement { id: Default::default(), location: Default::default(), kind: StatementKind::Expression(Expression { id: Default::default(), type_anno: None, kind: ExpressionKind::NatLiteral(1) }) }, Statement { id: Default::default(), location: Default::default(), kind: StatementKind::Expression(Expression { id: Default::default(), type_anno: None, kind: ExpressionKind::NatLiteral(2) }) }, Statement { id: Default::default(), location: Default::default(), kind: StatementKind::Expression(Expression { id: Default::default(), type_anno: None, kind: ExpressionKind::NatLiteral(5) }) }, Statement { id: Default::default(), location: Default::default(), kind: StatementKind::Expression(Expression { id: Default::default(), type_anno: None, kind: ExpressionKind::TupleLiteral(vec![Expression{ id: Default::default(), type_anno: None, kind: ExpressionKind::FloatLiteral(1.1), }, Expression { id: Default::default(), type_anno: None, kind: ExpressionKind::BoolLiteral(false), }] ) }) } ].into() }); /* let parsed = schala_parser::expression("quincy"); println!("{:?}", parsed.unwrap_err()); assert_eq!(1, 2); */ } }