peg::parser! { grammar syntax(source: &str) for [Token] { rule keyword(word: &str) -> Span = [Token { kind: TokenKind::Name, span } if &source[span.start..span.end] == word] { span } rule function_keyword() -> Span = quiet!{keyword("function")} / expected!("'function'") rule let_keyword() -> Span = quiet!{keyword("let")} / expected!("'let'") rule return_keyword() -> Span = quiet!{keyword("return")} / expected!("'return'") rule name() -> Name = span:quiet!{[Token { kind: TokenKind::Name, span }] { span }} { Name { text: source[span.start..span.end].into(), span } } / expected!("identifier") rule lparen() -> Span = quiet!{[Token { kind: TokenKind::LeftParen, span }] { span }} / expected!("'('") rule rparen() -> Span = quiet!{[Token { kind: TokenKind::RightParen, span }] { span }} / expected!("')'") rule lbrace() -> Span = quiet!{[Token { kind: TokenKind::LeftBrace, span }] { span }} / expected!("'{'") rule rbrace() -> Span = quiet!{[Token { kind: TokenKind::RightBrace, span }] { span }} / expected!("'}'") rule colon() = quiet!{[Token { kind: TokenKind::Colon, .. }]} / expected!("':'") rule comma() = quiet!{[Token { kind: TokenKind::Comma, .. }]} / expected!("','") rule equal() = quiet!{[Token { kind: TokenKind::Equal, .. }]} / expected!("'='") rule dot() -> Span = quiet!{[Token { kind: TokenKind::Dot, span }] { span }} / expected!("'.'") rule plus() = [Token { kind: TokenKind::Plus, .. }] rule minus() -> Span = [Token { kind: TokenKind::Minus, span }] { span } rule star() = [Token { kind: TokenKind::Star, .. }] rule slash() = [Token { kind: TokenKind::Slash, .. }] pub rule program() -> Program = declarations:declaration()+ { let span = declarations[0].span.through(declarations.last().unwrap().span); Program { declarations, span } } rule declaration() -> Decl = function:function() { Decl { span: function.span, kind: DeclKind::Function(function) } } pub rule interactive() -> InteractiveInput = statement:interactive_statement() { InteractiveInput { span: statement.span, statements: vec![statement] } } rule interactive_statement() -> Stmt = declaration:declaration() { Stmt { span: declaration.span, kind: StmtKind::Declaration(declaration) } } / binding:binding() { binding_statement(binding) } / assignment:assignment() { assignment } / expression:expression() { Stmt { span: expression.span, kind: StmtKind::Expression(expression) } } rule function() -> Function = start:function_keyword() name:name() lparen() parameters:(parameter() ** comma()) rparen() colon() return_type:name() body:block() { Function { span: start.through(body.span), name, parameters, return_type, body } } rule parameter() -> Parameter = name:name() colon() type_name:name() { Parameter { span: name.span.through(type_name.span), name, type_name } } rule block() -> Block = start:lbrace() locals:local_statement()* returned:return_statement() end:rbrace() { let mut statements = locals; statements.push(returned); Block { statements, span: start.through(end) } } rule local_statement() -> Stmt = binding:binding() { binding_statement(binding) } / assignment:assignment() { assignment } rule assignment() -> Stmt = name:name() equal() value:expression() { let span = name.span.through(value.span); Stmt { span, kind: StmtKind::Assignment(Assignment { name, value, span }) } } rule binding() -> Binding = start:let_keyword() name:name() equal() value:expression() { Binding { span: start.through(value.span), name, value } } rule return_statement() -> Stmt = start:return_keyword() value:expression() { let span = start.through(value.span); Stmt { span, kind: StmtKind::Return(ReturnStatement { value: Some(value), span }) } } pub rule expression() -> Expr = precedence! { left:(@) plus() right:@ { binary(left, BinaryOp::Add, right) } left:(@) minus() right:@ { binary(left, BinaryOp::Subtract, right) } -- left:(@) star() right:@ { binary(left, BinaryOp::Multiply, right) } left:(@) slash() right:@ { binary(left, BinaryOp::Divide, right) } -- start:minus() operand:@ { Expr { span: start.through(operand.span), kind: ExprKind::Unary { operation: UnaryOp::Negate, operand: Box::new(operand) } } } -- expression:postfix_expression() { expression } } rule postfix_expression() -> Expr = expression:primary() suffixes:suffix()* { suffixes.into_iter().fold(expression, postfix) } rule suffix() -> Suffix = dot() name:name() { Suffix::Member(name) } / lparen() arguments:(expression() ** comma()) end:rparen() { Suffix::Call(arguments, end) } rule primary() -> Expr = start:lparen() expression:expression() end:rparen() { Expr { span: start.through(end), ..expression } } / start:dot() name:name() { Expr { span: start.through(name.span), kind: ExprKind::Symbol(name) } } / [Token { kind: TokenKind::Number, span }] { Expr { span, kind: ExprKind::Number(source[span.start..span.end].into()) } } / [Token { kind: TokenKind::String, span }] { Expr { span, kind: ExprKind::String(decode_string(&source[span.start + 1..span.end - 1])) } } / name:name() { Expr { span: name.span, kind: ExprKind::Name(name.text) } } } }