use crate::SourceCode; use crate::ast::*; use arcstr::Substr; use peg::{Parse, ParseElem, ParseLiteral, ParseSlice}; pub use peg::{error::*, str::LineCol}; impl Parse for SourceCode { type PositionRepr = LineCol; #[inline] fn start<'input>(&'input self) -> usize { self.text.as_str().start() } #[inline] fn is_eof<'input>(&'input self, p: usize) -> bool { self.text.as_str().is_eof(p) } #[inline] fn position_repr<'input>(&'input self, p: usize) -> Self::PositionRepr { self.text.as_str().position_repr(p) } } impl<'input> ParseElem<'input> for SourceCode { type Element = char; #[inline] fn parse_elem(&'input self, pos: usize) -> peg::RuleResult { self.text.as_str().parse_elem(pos) } } impl ParseLiteral for SourceCode { #[inline] fn parse_string_literal(&self, pos: usize, literal: &str) -> peg::RuleResult<()> { self.text.as_str().parse_string_literal(pos, literal) } } impl<'input> ParseSlice<'input> for SourceCode { type Slice = Substr; #[inline] fn parse_slice(&'input self, p1: usize, p2: usize) -> Self::Slice { self.text.substr(p1..p2) } } peg::parser! { grammar leaf_parser() for SourceCode { // #### ATOMS #### rule number() -> Number = text:$(['0'..='9']+) r#type:ident()? { Number { text, r#type } } / "0x" text:$(['0'..='9'|'a'..='f'|'A'..'F']+) r#type:ident()? { Number { text, r#type } } / "0b" text:$(['0'|'1']+) r#type:ident()? { Number { text, r#type } } rule ident() -> Ident = text:$(['_'|'a'..='z'|'A'..='Z']['_'|'a'..='z'|'A'..='Z'|'0'..='9']*) { Ident(text) } rule string() -> Substr = str:$("\"" char()* "\"") { str } rule char() -> char = normal() rule normal() -> char = [^'\\'|'"'] // ### EXPRESSIONS #### rule expr() -> Expr = precedence! { lhs:(@) __ op:$("as") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Cast(op), rhs })) } -- lhs:@ __ op:$("=") __ rhs:expr() { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Assign(op), rhs })) } lhs:(@) __ op:$(".") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Dot(op), rhs })) } lhs:(@) "(" __ args:(expr() ** ("," __)) __ ")" { Expr::Call { func: Box::new(lhs), args } } value:(@) "[" __ index:expr() __ "]" { Expr::Index(Box::new(IndexingExpr { value, index })) } r#type:(@) _ "{" __ values:name_value_pairs() __ "}" { Expr::Struct(Box::new(StructCtor { r#type, values })) } -- lhs:(@) __ op:$("+") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Add(op), rhs })) } lhs:(@) __ op:$("-") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Sub(op), rhs })) } -- lhs:(@) __ op:$("*") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Mul(op), rhs })) } lhs:(@) __ op:$("/") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Div(op), rhs })) } lhs:(@) __ op:$("%") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Mod(op), rhs })) } -- lhs:(@) __ op:$("..") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Range(op), rhs })) } -- lhs:(@) __ op:$("==") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Eq(op), rhs })) } lhs:(@) __ op:$("!=") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Ne(op), rhs })) } lhs:(@) __ op:$("<") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Lt(op), rhs })) } lhs:(@) __ op:$(">") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Gt(op), rhs })) } lhs:(@) __ op:$("<=") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Le(op), rhs })) } lhs:(@) __ op:$(">=") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Ge(op), rhs })) } -- block:block() { Expr::Block(block)} for_loop:for_loop() { Expr::For(Box::new(for_loop))} while_loop:while_loop() { Expr::While(Box::new(while_loop))} func:func() { Expr::Func(Box::new(func))} var_decl:var_decl() { Expr::VarDecl(Box::new(var_decl)) } const_decl:const_decl() { Expr::ConstDecl(Box::new(const_decl)) } "(" __ tuple:(expr() **<2,> ("," __)) __ ")" { Expr::Tuple(tuple) } "[" __ list:(expr() ** ("," __)) __ "]" { Expr::List(list) } "(" __ v:expr() __ ")" { v } "*" __ m:"mut"? __ v:expr() { Expr::Type(Box::new(Type::Ptr { base:v, mutable: m.is_some() })) } v:string() { Expr::String(v) } v:number() { Expr::Number(v) } v:ident() { Expr::Ident(v) } } rule block() -> Block = "{" __ exprs:(i:expr() statement_separator() {i})* __ "}" { Block(exprs) } rule func() -> Function = s:position!() t:$"fn" __ "(" __ args:name_value_pairs() __ ")" __ ret:("->" __ e:expr() {e})? __ block:block()? e:position!() { Function { args, ret, block, text: t.parent().substr(s..e), } } rule name_value_pair() -> NameValuePair = name:ident() __ ":" __ r#type:expr() { NameValuePair { name, r#type } } rule name_value_pairs() -> Vec = v:(name_value_pair() ** ("," __)) { v } rule import() -> Import = "import" _ expr:expr() { Import(expr) } rule name_pattern() -> NamePattern = "(" __ tuple:(ident() ** ("," __)) __ ")" { NamePattern::Tuple(tuple) } / "[" __ slice:(ident() ** ("," __)) __ "]" { NamePattern::List(slice) } / ident:ident() { NamePattern::Single(ident) } rule const_decl() -> ConstDecl = names:name_pattern() _? ":" r#type:(_ t:expr() _ {t})? ":" _ value:expr() { ConstDecl { names, r#type, value } } rule var_decl() -> VarDecl = names:name_pattern() _? ":" r#type:(_ t:expr() _ {t})? "=" _ value:expr() { VarDecl { names, r#type, value } } rule for_loop() -> For = "for" _ names:name_pattern() _ "in" _ value:expr() _ block:block() { For { names, value, block } } rule while_loop() -> While = "while" _ value:expr() _ block:block() { While { value, block } } pub rule compilation_unit() -> CompilationUnit = __ imports:(i:import() statement_separator() {i})* __ decls:(d:const_decl() statement_separator() {d})* __ { CompilationUnit { imports, decls } } // #### MISC #### rule _ = quiet! { [' '|'\t']+ } rule __ = quiet! { [' '|'\t'|'\n']* } rule statement_separator() = quiet! { [';'|'\n'] __ } } } pub use leaf_parser::compilation_unit;