diff --git a/lib/edlang_parser/src/grammar.lalrpop b/lib/edlang_parser/src/grammar.lalrpop index 2d2c1bf62..061d31e26 100644 --- a/lib/edlang_parser/src/grammar.lalrpop +++ b/lib/edlang_parser/src/grammar.lalrpop @@ -25,10 +25,12 @@ extern { "pub" => Token::KeywordPub, "mut" => Token::KeywordMut, "use" => Token::KeywordUse, + "in" => Token::KeywordIn, + "extern" => Token::KeywordExtern, // literals "identifier" => Token::Identifier(), - "integer" => Token::Integer(), + "integer" => Token::Integer(), "string" => Token::String(), "boolean" => Token::Boolean(), @@ -50,6 +52,7 @@ extern { ">=" => Token::MoreThanEqSign, "<=" => Token::LessThanEqSign, "." => Token::Dot, + ".." => Token::TwoDots, // operators "+" => Token::OperatorAdd, @@ -111,9 +114,293 @@ PlusSeparated: Vec = { } }; +List: Vec = { + => vec![<>], + > => { + s.push(n); + s + }, +} + pub(crate) Ident: ast::Ident = { => ast::Ident { name, span: ast::Span::new(lo, hi), } } + +pub(crate) Type: ast::Type = { + => ast::Type { + name, + generics: vec![], + span: ast::Span::new(lo, hi), + }, + "<" > ">" => ast::Type { + name, + generics, + span: ast::Span::new(lo, hi), + }, +} + +pub(crate) PathExpr: ast::PathExpr = { + => ast::PathExpr { + first, + extra: extra.unwrap_or(vec![]), + span: ast::Span::new(lo, hi), + } +} + +pub PathSegments: Vec = { + => vec![<>], + => { + s.push(n); + s + }, +} + +pub(crate) PathSegment: ast::PathSegment = { + "." => ast::PathSegment::Field(<>), + "[" "]" => ast::PathSegment::Index { + value, + span: ast::Span::new(lo, hi), + }, +} + +pub(crate) Block: ast::Block = { + "{" > "}" => ast::Block { + body, + span: ast::Span::new(lo, hi), + } +} + +pub(crate) Statement: ast::Statement = { + => ast::Statement::If(<>), + => ast::Statement::While(<>), + => ast::Statement::For(<>), + ";" => ast::Statement::Let(<>), + ";" => ast::Statement::Assign(<>), + ";" => ast::Statement::FnCall(<>), + ";" => ast::Statement::Return(<>), +} + +pub(crate) FnCallExpr: ast::FnCallExpr = { + "(" > ")" => ast::FnCallExpr { + name, + params, + span: ast::Span::new(lo, hi), + } +} + +pub(crate) LetStmt: ast::LetStmt = { + "let" ":" "=" => ast::LetStmt { + is_mut: is_mut.is_some(), + name, + r#type: target_type, + value, + span: ast::Span::new(lo, hi), + }, +} + +pub(crate) AssignStmt: ast::AssignStmt = { + "=" => ast::AssignStmt { + name, + value, + span: ast::Span::new(lo, hi), + }, +} + +pub(crate) ReturnStmt: ast::ReturnStmt = { + "return" => ast::ReturnStmt { + value, + span: ast::Span::new(lo, hi), + }, +} + +pub(crate) WhileStmt: ast::WhileStmt = { + "while" => { + ast::WhileStmt { + condition, + block, + span: ast::Span::new(lo, hi), + } + } +} + +pub(crate) ForStmt: ast::ForStmt = { + "for" "in" => ast::ForStmt { + name, + from, + to: None, + block, + span: ast::Span::new(lo, hi), + }, + "for" "in" ".." => ast::ForStmt { + name, + from, + to: Some(to), + block, + span: ast::Span::new(lo, hi), + }, +} + +pub(crate) IfStmt: ast::IfStmt = { + "if" => { + ast::IfStmt { + condition, + then_block, + else_block, + span: ast::Span::new(lo, hi), + } + } +} + +pub(crate) Term: ast::Expression = { + => ast::Expression::Value(<>), + => ast::Expression::FnCall(<>), + "(" ")", +} + +pub(crate) Expression: ast::Expression = { + #[precedence(level="0")] + , + => ast::Expression::Unary( + op, + Box::new(rhs) + ), + // => ast::Expression::UnaryOp(op, Box::new(e)), + #[precedence(level="1")] #[assoc(side="left")] + => ast::Expression::Binary( + Box::new(lhs), + op, + Box::new(rhs) + ), + #[precedence(level="2")] #[assoc(side="left")] + => ast::Expression::Binary( + Box::new(lhs), + op, + Box::new(rhs) + ), + #[precedence(level="3")] #[assoc(side="left")] + => ast::Expression::Binary( + Box::new(lhs), + op, + Box::new(rhs) + ), +} + +pub BinaryFirstLvlOp: ast::BinaryOp = { + "==" => ast::BinaryOp::Compare(ast::CmpOp::Eq, ast::Span::new(hi, lo)), + "!=" => ast::BinaryOp::Compare(ast::CmpOp::NotEq, ast::Span::new(hi, lo)), + "<" => ast::BinaryOp::Compare(ast::CmpOp::Lt, ast::Span::new(hi, lo)), + ">" => ast::BinaryOp::Compare(ast::CmpOp::Gt, ast::Span::new(hi, lo)), + "<=" => ast::BinaryOp::Compare(ast::CmpOp::LtEq, ast::Span::new(hi, lo)), + ">=" => ast::BinaryOp::Compare(ast::CmpOp::GtEq, ast::Span::new(hi, lo)), + "&&" => ast::BinaryOp::Logic(ast::LogicOp::And, ast::Span::new(hi, lo)), + "||" => ast::BinaryOp::Logic(ast::LogicOp::Or, ast::Span::new(hi, lo)), +} + +pub BinarySecondLvlOp: ast::BinaryOp = { + "/" => ast::BinaryOp::Arith(ast::ArithOp::Div, ast::Span::new(hi, lo)), + "*" => ast::BinaryOp::Arith(ast::ArithOp::Mul, ast::Span::new(hi, lo)), + "%" => ast::BinaryOp::Arith(ast::ArithOp::Mod, ast::Span::new(hi, lo)), +} + +pub BinaryThirdLvlOp: ast::BinaryOp = { + "+" => ast::BinaryOp::Arith(ast::ArithOp::Add, ast::Span::new(hi, lo)), + "-" => ast::BinaryOp::Arith(ast::ArithOp::Sub, ast::Span::new(hi, lo)), + "&" => ast::BinaryOp::Bitwise(ast::BitwiseOp::And, ast::Span::new(hi, lo)), + "|" => ast::BinaryOp::Bitwise(ast::BitwiseOp::Or, ast::Span::new(hi, lo)), + "^" => ast::BinaryOp::Bitwise(ast::BitwiseOp::Xor, ast::Span::new(hi, lo)), +} + +pub UnaryOp: ast::UnaryOp = { + "-" => ast::UnaryOp::ArithNeg(ast::Span::new(hi, lo)), + "!" => ast::UnaryOp::LogicalNot(ast::Span::new(hi, lo)), + "~" => ast::UnaryOp::BitwiseNot(ast::Span::new(hi, lo)), +} + +pub(crate) ValueExpr: ast::ValueExpr = { + => ast::ValueExpr::Int { + value, + span: ast::Span::new(lo, hi), + }, + => ast::ValueExpr::Bool{ + value, + span: ast::Span::new(lo, hi), + }, + => ast::ValueExpr::Str{ + value, + span: ast::Span::new(lo, hi), + }, + => ast::ValueExpr::Path(<>), +} + +pub(crate) FnParam: ast::FnParam = { + ":" => ast::FnParam { + name, + arg_type, + span: ast::Span::new(lo, hi), + } +} + +pub(crate) Function: ast::Function = { + "fn" "(" > ")" + " )?> => ast::Function { + is_public: is_public.is_some(), + is_extern: is_extern.is_some(), + name, + params, + return_type, + body, + span: ast::Span::new(lo, hi), + } +} + +pub(crate) Constant: ast::Constant = { + "const" ":" "=" ";" => ast::Constant { + name, + r#type, + value, + span: ast::Span::new(lo, hi), + } +} + +pub(crate) StructField: ast::StructField = { + ":" => ast::StructField { + name, + r#type, + span: ast::Span::new(lo, hi), + } +} + +pub(crate) Struct: ast::Struct = { + "struct" > ">")?> "{" > "}" => ast::Struct { + name, + fields, + generics: generics.unwrap_or(vec![]), + span: ast::Span::new(lo, hi), + } +} + +pub(crate) Import: ast::Import = { + "use" > "}")?> ";" => ast::Import { + path, + symbols: symbols.unwrap_or(vec![]), + span: ast::Span::new(lo, hi), + } +} + +pub Module: ast::Module = { + "mod" "{" ?> > "}" => ast::Module { + name, + imports: imports.unwrap_or(vec![]), + contents, + span: ast::Span::new(lo, hi), + } +} + +pub(crate) ModuleStatement: ast::ModuleStatement = { + => ast::ModuleStatement::Function(<>), + => ast::ModuleStatement::Constant(<>), + => ast::ModuleStatement::Struct(<>), +} diff --git a/lib/edlang_parser/src/tokens.rs b/lib/edlang_parser/src/tokens.rs index 93a9bf573..781ed6bdb 100644 --- a/lib/edlang_parser/src/tokens.rs +++ b/lib/edlang_parser/src/tokens.rs @@ -51,14 +51,18 @@ pub enum Token { KeywordMut, #[token("use")] KeywordUse, + #[token("in")] + KeywordIn, + #[token("extern")] + KeywordExtern, // Modern way of allowing identifiers, read: https://unicode.org/reports/tr31/ #[regex(r"[\p{XID_Start}_]\p{XID_Continue}*", |lex| lex.slice().to_string())] Identifier(String), // Literals - #[regex(r"\d+", |lex| lex.slice().parse::().unwrap())] - Integer(u64), + #[regex(r"\d+", |lex| lex.slice().parse::().unwrap())] + Integer(u128), #[regex(r#""(?:[^"]|\\")*""#, |lex| lex.slice().to_string())] String(String), #[regex(r"(true|false)", |lex| lex.slice().parse::().unwrap())] @@ -88,6 +92,8 @@ pub enum Token { Coma, #[token(".")] Dot, + #[token("..")] + TwoDots, #[token("<")] LessThanSign, #[token(">")]