%start Body %left '||' %left '&&' %left '<' '>' '<=' '>=' '==' '!=' %left '*' '/' %left '+' '-' %avoid_insert "NUM" "SYM" "STRING" "||" "&&" "<" ">" "<=" ">=" "!=" "==" "+" "-" "*" "/" "{" %% Body -> Result>: Body 'EOL' Stmt { flatten($1, $3) } | Body 'EOL' { $1 } | Stmt { Ok(vec![$1?]) } | { Ok(Vec::new()) } ; Stmt -> Result: Expr { Ok(Stmt::Expr($1?)) } | Assign { Ok(Stmt::Assign($1?)) } | Return { Ok(Stmt::Return($1?)) } ; Assign -> Result: LhsExpr '=' Expr { Ok(AssignStmt { lhs: $1?, rhs: $3? }) } ; LhsExpr -> Result: AccessExpr { let lhs = match $1? { Expr::Access(access) => LhsExpr::SetAttr(*access), Expr::Atom(Atom::Ident(local)) => LhsExpr::Name(local), _ => todo!("TODO : invalid syntax, raise error"), }; Ok(lhs) } ; Return -> Result: 'return' Expr { Ok(ReturnStmt { expr: Some($2?), }) } | 'return' { Ok(ReturnStmt { expr: None, }) } ; Expr -> Result: BinExpr { $1 }; BinExpr -> Result: UnExpr '||' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Or, $3?)) } | UnExpr '&&' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::And, $3?)) } | UnExpr '<' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Lt, $3?)) } | UnExpr '>' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Gt, $3?)) } | UnExpr '<=' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Le, $3?)) } | UnExpr '>=' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Ge, $3?)) } | UnExpr '==' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Eq, $3?)) } | UnExpr '!=' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Neq, $3?)) } | UnExpr '*' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Times, $3?)) } | UnExpr '/' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Div, $3?)) } | UnExpr '+' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Plus, $3?)) } | UnExpr '-' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Plus, $3?)) } | UnExpr { $1 } ; UnExpr -> Result: '+' UnExpr { Ok(UnExpr::new_expr(UnOp::Plus, $2?)) } | '-' UnExpr { Ok(UnExpr::new_expr(UnOp::Minus, $2?)) } | CallIndexExpr { $1 } ; CallIndexExpr -> Result: IndexExpr { $1 } | CallExpr { $1 } | AccessExpr { $1 } ; CallExpr -> Result: CallIndexExpr '(' FunArgs ')' { Ok(CallExpr::new_expr($1?, $3?)) } ; FunArgs -> Result>: FunArgsTail { $1 } | { Ok(Vec::new()) } ; FunArgsTail -> Result>: FunArgsTail ',' Expr { flatten($1, $3) } | Expr { Ok(vec![$1?]) } ; IndexExpr -> Result: CallIndexExpr '[' Expr ']' { Ok(IndexExpr::new_expr($1?, $3?)) } ; AccessExpr -> Result: FunExpr { $1 } | CallIndexExpr '.' Ident { Ok(AccessExpr::new_expr($1?, $3?)) } ; FunExpr -> Result: AtomExpr { $1 } | 'fn' '(' FunParams ')' '{' Body '}' { Ok(FunExpr::new_expr($3?, $6?)) } ; FunParams -> Result>: FunParamsTail { $1 } | { Ok(Vec::new()) } ; FunParamsTail -> Result>: FunParamsTail ',' Ident { flatten($1, $3) } | Ident { Ok(vec![$1?]) } ; AtomExpr -> Result: Atom { $1.map(Expr::Atom) } | '(' Expr ')' { $2 } ; Atom -> Result: Ident { Ok(Atom::Ident($1?)) } | 'SYM' { let v = $1.map_err(|_| ())?; let sym = &$lexer.span_str(v.span())[1..]; Ok(Atom::Sym(sym.to_string())) } | 'NUM' { let v = $1.map_err(|_| ())?; let num_text = &$lexer.span_str(v.span()); Ok(Atom::Num(num_text.parse().unwrap())) } | 'STRING' { let v = $1.map_err(|_| ())?; let string = &$lexer.span_str(v.span())[1..]; Ok(Atom::String(parse_string(string))) } ; Ident -> Result: 'IDENT' { let v = $1.map_err(|_| ())?; let ident = $lexer.span_str(v.span()).to_string(); Ok(ident) } ; %% use crate::syn::ast::*; type Result = std::result::Result; fn flatten(head: Result>, tail: Result) -> Result> { let mut head = head?; let tail = tail?; head.push(tail); Ok(head) } fn parse_string(input: &str) -> String { let mut s = String::new(); let input = &input[..input.bytes().len() - 1]; let mut chars = input.chars(); while let Some(c) = chars.next() { if c == '\\' { let next = chars.next().unwrap(); let c = match next { '\\' => '\\', '\'' => '\'', '"' => '"', 'n' => '\n', 't' => '\t', _ => unreachable!(), }; s.push(c); } else { s.push(c); } } s }