summaryrefslogtreecommitdiffstats
path: root/crates/rebel-parse/src/grammar/recipe.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/rebel-parse/src/grammar/recipe.rs')
-rw-r--r--crates/rebel-parse/src/grammar/recipe.rs220
1 files changed, 113 insertions, 107 deletions
diff --git a/crates/rebel-parse/src/grammar/recipe.rs b/crates/rebel-parse/src/grammar/recipe.rs
index 5ae6b8b..d1deba4 100644
--- a/crates/rebel-parse/src/grammar/recipe.rs
+++ b/crates/rebel-parse/src/grammar/recipe.rs
@@ -1,156 +1,162 @@
-use crate::ast::*;
+use crate::ast::{self, Expr};
+use crate::token::*;
pub use rules::*;
peg::parser! {
- pub grammar rules() for str {
- use OpBinary::*;
- use OpUnary::*;
+ pub grammar rules<'a>() for [Token<'a>] {
+ use ast::OpBinary::*;
+ use ast::OpUnary::*;
- pub rule recipe() -> Recipe<'input>
- = _ recipe:recipe_stmt()* { recipe }
+ pub rule recipe() -> ast::Recipe<'a>
+ = recipe:recipe_stmt()* { recipe }
- pub rule recipe_stmt() -> RecipeStmt<'input>
- = stmt:body_stmt() {
- RecipeStmt::BodyStmt(stmt)
+ pub rule recipe_stmt() -> ast::RecipeStmt<'a>
+ = keyword_fetch() name:ident() p('{') body:body() p('}') {
+ ast::RecipeStmt::Fetch { name, body: Vec::new() }
}
- / "fetch" __ name:ident() _ "{" _ body:body() _ "}" _ {
- RecipeStmt::Fetch { name, body }
+ / keyword_task() name:ident() p('(') args:argtypes() p(')') p('{') body:body() p('}') {
+ ast::RecipeStmt::Task { name, args, body }
}
- / "task" __ name:ident() _ "(" _ args:argtypes() _ ")" _ "{" _ body:body() _ "}" _ {
- RecipeStmt::Task { name, args, body }
+ / stmt:body_stmt() {
+ ast::RecipeStmt::BodyStmt(stmt)
}
- pub rule body() -> Body<'input>
- = recipe:body_stmt()* { recipe }
+ pub rule body() -> ast::Body<'a>
+ = body:body_stmt()* { body }
- pub rule body_stmt() -> BodyStmt<'input>
- = left:typed_expr() _ op:assign_op() _ right:expr() _ ";" _ {
- BodyStmt::assign(left, op, right)
+ pub rule body_stmt() -> ast::BodyStmt<'a>
+ = left:typed_expr() op:assign_op() right:expr() p(';') {
+ ast::BodyStmt::assign(left, op, right)
}
- rule assign_op() -> Option<OpBinary>
- = "+=" { Some(Add) }
- / "-=" { Some(Sub) }
- / "*=" { Some(Mul) }
- / "/=" { Some(Div) }
- / "%=" { Some(Rem) }
- / "=" { None }
+ rule assign_op() -> Option<ast::OpBinary>
+ = p2('+', '=') { Some(Add) }
+ / p2('-', '=') { Some(Sub) }
+ / p2('*', '=') { Some(Mul) }
+ / p2('/', '=') { Some(Div) }
+ / p2('%', '=') { Some(Rem) }
+ / p('=') { None }
- rule typed_expr() -> TypedExpr<'input>
- = expr:expr() typ:tagged(<_ ":" _>, <typ()>)? { TypedExpr { expr, typ } }
+ rule typed_expr() -> ast::TypedExpr<'a>
+ = expr:expr() typ:tagged(<p(':')>, <expr()>)? { ast::TypedExpr { expr, typ } }
-
- rule typ() -> Path<'input>
- = path()
-
- pub rule expr() -> Expr<'input> = precedence! {
- left:(@) _ "||" _ right:@ { Expr::binary(left, Or, right) }
+ pub rule expr() -> Expr<'a> = precedence! {
+ left:(@) p2('|', '|') right:@ { Expr::binary(left, Or, right) }
--
- left:(@) _ "&&" _ right:@ { Expr::binary(left, And, right) }
+ left:(@) p2('&', '&') right:@ { Expr::binary(left, And, right) }
--
- left:(@) _ "==" _ right:@ { Expr::binary(left, Eq, right) }
- left:(@) _ "!=" _ right:@ { Expr::binary(left, Ne, right) }
- left:(@) _ "<" _ right:@ { Expr::binary(left, Lt, right) }
- left:(@) _ ">" _ right:@ { Expr::binary(left, Gt, right) }
- left:(@) _ "<=" _ right:@ { Expr::binary(left, Le, right) }
- left:(@) _ ">=" _ right:@ { Expr::binary(left, Ge, right) }
+ left:(@) p2('=', '=') right:@ { Expr::binary(left, Eq, right) }
+ left:(@) p2('!', '=') right:@ { Expr::binary(left, Ne, right) }
+ left:(@) p('<') right:@ { Expr::binary(left, Lt, right) }
+ left:(@) p('>') right:@ { Expr::binary(left, Gt, right) }
+ left:(@) p2('<', '=') right:@ { Expr::binary(left, Le, right) }
+ left:(@) p2('>', '=') right:@ { Expr::binary(left, Ge, right) }
--
- left:(@) _ "+" _ right:@ { Expr::binary(left, Add, right) }
- left:(@) _ "-" _ right:@ { Expr::binary(left, Sub, right) }
+ left:(@) p('+') right:@ { Expr::binary(left, Add, right) }
+ left:(@) p('-') right:@ { Expr::binary(left, Sub, right) }
--
- left:(@) _ "*" _ right:@ { Expr::binary(left, Mul, right) }
- left:(@) _ "/" _ right:@ { Expr::binary(left, Div, right) }
- left:(@) _ "%" _ right:@ { Expr::binary(left, Rem, right) }
+ left:(@) p('*') right:@ { Expr::binary(left, Mul, right) }
+ left:(@) p('/') right:@ { Expr::binary(left, Div, right) }
+ left:(@) p('%') right:@ { Expr::binary(left, Rem, right) }
--
- "-" _ expr:@ { Expr::unary(Neg, expr) }
- "!" _ expr:@ { Expr::unary(Not, expr) }
+ p('-') expr:@ { Expr::unary(Neg, expr) }
+ p('!') expr:@ { Expr::unary(Not, expr) }
--
- expr:@ _ "(" _ args:args() _ ")" { Expr::apply(expr, args) }
- expr:@ _ "[" _ index:expr() _ "]" { Expr::index(expr, index) }
+ expr:@ p('(') args:args() p(')') { Expr::apply(expr, args) }
+ expr:@ p('[') index:expr() p(']') { Expr::index(expr, index) }
--
- expr:@ _ "." _ field:field() { Expr::field(expr, field) }
+ expr:@ p('.') field:field() { Expr::field(expr, field) }
--
- "(" _ e:expr() _ ")" { Expr::paren(e) }
+ p('(') e:expr() p(')') { Expr::paren(e) }
e:atom() { e }
}
- rule atom() -> Expr<'input>
+ rule atom() -> Expr<'a>
= lit:literal() { Expr::Literal(lit) }
/ path:path() { Expr::Path(path) }
- rule args() -> Vec<Arg<'input>>
- = args:delimited(<arg()>, <_ "," _>) { args }
+ rule args() -> Vec<ast::Arg<'a>>
+ = args:delimited(<arg()>, <p(',')>) { args }
- rule arg() -> Arg<'input>
- = expr:expr() { Arg { expr } }
+ rule arg() -> ast::Arg<'a>
+ = expr:expr() { ast::Arg { expr } }
- rule argtypes() -> Vec<ArgType<'input>>
- = args:delimited(<argtype()>, <_ "," _>) { args }
+ rule argtypes() -> Vec<ast::ArgType<'a>>
+ = args:delimited(<argtype()>, <p(',')>) { args }
- rule argtype() -> ArgType<'input>
- = expr:typed_expr() { ArgType { expr } }
+ rule argtype() -> ast::ArgType<'a>
+ = name:ident() p(':') typ:expr() { ast::ArgType { name, typ } }
- rule literal() -> Literal<'input>
- = "true" { Literal::Boolean(true) }
- / "false" { Literal::Boolean(false) }
- / "0x" s:$((['0'..='9' | 'a'..='f' | 'A'..='F']+) ++ "_") { ?
- Literal::integer(s, 16)
+ rule literal() -> ast::Literal<'a>
+ = keyword_true() { ast::Literal::Boolean(true) }
+ / keyword_false() { ast::Literal::Boolean(false) }
+ / [Token::Literal(Literal { content, kind: LiteralKind::Number })] { ?
+ ast::Literal::number(content)
+ }
+ / [Token::Literal(Literal { content, kind: LiteralKind::String })] {
+ ast::Literal::String(content)
+ }
+ / [Token::Literal(Literal { content, kind: LiteralKind::RawString })] {
+ ast::Literal::RawString(content)
}
- / "0o" s:$((['0'..='7']+) ++ "_") { ?
- Literal::integer(s, 8)
+ / [Token::Literal(Literal { content, kind: LiteralKind::ScriptString })] {
+ ast::Literal::ScriptString(content)
}
- / "0b" s:$((['0'..='1']+) ++ "_") { ?
- Literal::integer(s, 2)
+ / p('(') p(')') { ast::Literal::Unit }
+ / p('(') elements:(expr() ** p(',')) p(',')? p(')') {
+ ast::Literal::Tuple(elements)
}
- / s:$((['0'..='9']+) ++ "_") { ?
- Literal::integer(s, 10)
+ / p('[') elements:delimited(<expr()>, <p(',')>) p(']') {
+ ast::Literal::Array(elements)
}
- / "\"" s:$(string_char()*) "\"" { Literal::String(s) }
- / "r\"" s:$([^'"']*) "\"" { Literal::RawString(s) }
- / "```" newline() s:$((!"```" [_])+) "```" { Literal::ScriptString(s) }
- / "(" _ ")" { Literal::Unit }
- / "(" _ elements:(expr() ** (_ "," _)) (_ ",")? _ ")" { Literal::Tuple(elements) }
- / "[" _ elements:delimited(<expr()>, <_ "," _>) _ "]" { Literal::Array(elements) }
- / "{" _ entries:delimited(<map_entry()>, <_ "," _>) _ "}" { Literal::Map(entries) }
-
- rule map_entry() -> MapEntry<'input>
- = left:typed_expr() _ "=" _ right:expr() {
- MapEntry { left, right }
+ / p('{') entries:delimited(<map_entry()>, <p(',')>) p('}') {
+ ast::Literal::Map(entries)
}
- rule string_char()
- = [^'"' | '\\']
- / "\\" [_]
+ rule map_entry() -> ast::MapEntry<'a>
+ = key:field() p('=') value:expr() {
+ ast::MapEntry { key: key.name, value }
+ }
+
+ rule path() -> ast::Path<'a>
+ = components:ident() ++ p2(':', ':') { ast::Path { components } }
+
+ rule field() -> ast::Ident<'a>
+ = ident()
+ / [Token::Literal(Literal {content, kind: LiteralKind::Number} )] {
+ ast::Ident { name: content }
+ }
- rule path() -> Path<'input>
- = components:ident() ++ (_ "::" _) { Path { components } }
+ rule p_(ch: char)
+ = [Token::Punct(Punct(c, Spacing::Joint)) if c == ch] {}
- rule field() -> Ident<'input>
- = name:$(
- ['a'..='z' | 'A' ..='Z' | '0'..='9' | '_']*
- ) { Ident { name } }
+ rule p(ch: char) -> ()
+ = [Token::Punct(Punct(c, _)) if c == ch] {}
- rule ident() -> Ident<'input>
- = name:$(
- ['a'..='z' | 'A' ..='Z' | '_' ]
- ['a'..='z' | 'A' ..='Z' | '0'..='9' | '_']*
- ) { Ident { name } }
+ rule p2(ch1: char, ch2: char)
+ = p_(ch1) p(ch2)
- /// Mandatory whitespace
- rule __
- = ([' ' | '\t'] / quiet!{newline()} / quiet!{comment()})+
+ rule ident() -> ast::Ident<'a>
+ = !keyword() [Token::Ident(Ident(name))] { ast::Ident { name } }
- /// Optional whitespace
- rule _
- = quiet!{__?}
+ rule keyword()
+ = keyword_true()
+ / keyword_false()
+ / keyword_fetch()
+ / keyword_task()
- rule comment()
- = "//" (!newline() [_])* (newline() / ![_])
- / "/*" (!"*/" [_])* "*/"
+ rule keyword_true()
+ = const_ident("true")
+ rule keyword_false()
+ = const_ident("false")
+ rule keyword_fetch()
+ = const_ident("fetch")
+ rule keyword_task()
+ = const_ident("task")
- rule newline()
- = ['\n' | '\r']
+ rule const_ident(keyword: &str)
+ = [Token::Ident(Ident(name)) if keyword == name]
rule delimited<T>(expr: rule<T>, delim: rule<()>) -> Vec<T>
= values:(expr() ++ delim()) delim()? { values }