diff --git a/schala-lang/language/src/parsing/new.rs b/schala-lang/language/src/parsing/new.rs index d1dd07f..135fe89 100644 --- a/schala-lang/language/src/parsing/new.rs +++ b/schala-lang/language/src/parsing/new.rs @@ -1,7 +1,9 @@ use crate::ast::*; +use std::rc::Rc; + peg::parser! { - grammar schala_parser() for str { + pub grammar schala_parser() for str { pub rule program() -> AST = n:(statement() ** delimiter() ) { AST { id: Default::default(), statements: n.into() } } @@ -20,25 +22,94 @@ peg::parser! { primary() rule primary() -> ExpressionKind = - float_literal() / nat_literal() + 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 = - ("0x" / "0b")? digits:digits() { ExpressionKind::NatLiteral(digits.parse().unwrap()) } + 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 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() { @@ -60,6 +131,50 @@ mod test { ].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()); diff --git a/schala-lang/language/src/parsing/test.rs b/schala-lang/language/src/parsing/test.rs index 2d201a4..9d6ec99 100644 --- a/schala-lang/language/src/parsing/test.rs +++ b/schala-lang/language/src/parsing/test.rs @@ -8,6 +8,7 @@ use pretty_assertions::assert_eq; use super::{tokenize, ParseResult, Parser}; use crate::{ast::*, tokenizing::Location}; +use super::new::schala_parser; fn rc(s: &str) -> Rc { Rc::new(s.to_owned()) @@ -121,6 +122,12 @@ macro_rules! assert_expr { }; } +macro_rules! assert_expr2 { + ($input:expr, $correct:expr) => { + assert_eq!(schala_parser::expression($input).unwrap(), $correct); + }; +} + macro_rules! assert_fail_expr { ($input:expr, $failure:expr) => { let mut parser = make_parser($input); @@ -132,16 +139,16 @@ macro_rules! assert_fail_expr { fn basic_literals() { use ExpressionKind::*; - assert_expr!(".2", expr(FloatLiteral(0.2))); - assert_expr!("8.1", expr(FloatLiteral(8.1))); - assert_expr!("0b010", expr(NatLiteral(2))); - assert_expr!("0b0_1_0", expr(NatLiteral(2))); - assert_expr!("0xff", expr(NatLiteral(255))); - assert_expr!("0x032f", expr(NatLiteral(815))); - assert_expr!("0xf_f_", expr(NatLiteral(255))); - assert_expr!("false", expr(BoolLiteral(false))); - assert_expr!("true", expr(BoolLiteral(true))); - assert_expr!(r#""hello""#, expr(StringLiteral(rc("hello")))); + assert_expr2!(".2", expr(FloatLiteral(0.2))); + assert_expr2!("8.1", expr(FloatLiteral(8.1))); + assert_expr2!("0b010", expr(NatLiteral(2))); + assert_expr2!("0b0_1_0", expr(NatLiteral(2))); + assert_expr2!("0xff", expr(NatLiteral(255))); + assert_expr2!("0x032f", expr(NatLiteral(815))); + assert_expr2!("0xf_f_", expr(NatLiteral(255))); + assert_expr2!("false", expr(BoolLiteral(false))); + assert_expr2!("true", expr(BoolLiteral(true))); + assert_expr2!(r#""hello""#, expr(StringLiteral(rc("hello")))); } #[test]