use ast::*;
use sindra::Node;
use sindra::float::float_ext;
use sindra::int::int_ext;
use sindra::string::{match_str_ext, convert_string};
use regex::Regex;
#[pub]
program -> Node<Program>
= b:block { Node::new(Program(b)) }
#[pub]
block -> Node<Block>
= vec:(ws stmt:statement ws { stmt })* { Node::new(Block(vec)) }
#[pub]
statement -> Node<Statement>
= declare_statement
/ assign_statement
/ fn_define_statement
/ return_statement
/ break_statement
/ print_statement
/ expr:expression ws ";"? ws { Node::new(Statement::Expression(expr)) }
fn_define_statement -> Node<Statement>
= kw_fn fn_ident:identifier ws '(' vec:(ws params:parameters { params }) ')' ws "->" ws
ret_type:identifier ws "{" body:block "}" {
Node::new(Statement::FnDefine(FunctionDef { name: fn_ident,
ret_type: ret_type, params: vec, body: body }))
}
parameters -> Vec<Node<Parameter>>
= parameter_ws**","
parameter_ws -> Node<Parameter>
= ws p:parameter ws { p }
parameter -> Node<Parameter>
= ident:identifier ws ":" ws ty:identifier { Node::new(Parameter { name: ident.clone(),
ty: ty.clone() }) }
declare_statement -> Node<Statement>
= kw_let ident:identifier ws "=" expr:expression_ws (";" ws)? {
Node::new(Statement::Declare(ident, expr))
}
assign_statement -> Node<Statement>
= ident:identifier ws "=" expr:expression ws (";" ws)? {
Node::new(Statement::Assign(ident, expr))
}
return_statement -> Node<Statement>
= kw_return ws expr:expression ws (";" ws)? {
Node::new(Statement::Return(expr))
}
break_statement -> Node<Statement>
= kw_break ws expr:expression ws (";" ws)? {
Node::new(Statement::Break(expr))
}
print_statement -> Node<Statement>
= kw_print exprs:expressions (";" ws)? {
Node::new(Statement::Print(exprs))
}
expressions -> Vec<Node<Expression>>
= expression_ws**","
keyword<k> = k !@"\p{XID_Continue}"@ ws
kw_let = keyword<"let">
kw_fn = keyword<"fn">
kw_global = keyword<"set">
kw_if = keyword<"if">
kw_else = keyword<"else">
kw_true = keyword<"true">
kw_false = keyword<"false">
kw_iterate = keyword<"iterate">
kw_over = keyword<"over">
kw_return = keyword<"return">
kw_break = keyword<"break">
kw_print = keyword<"print">
kw = kw_let / kw_global / kw_fn / kw_if / kw_else / kw_true / kw_false / kw_iterate / kw_over
/ kw_return / kw_break / kw_print;
type -> Node<Identifier>
= primitive_type / identifier
primitive_type -> Node<Identifier>
= 'real' { Node::new(Identifier("real".to_string())) }
/ 'int' { Node::new(Identifier("int".to_string())) }
/ 'complex' { Node::new(Identifier("complex".to_string())) }
/ 'bool' { Node::new(Identifier("bool".to_string())) }
#[pub]
arith_expression -> Node<Expression>
= infix_arith
/ signed_or_unsigned_primary
expression_ws -> Node<Expression>
= ws e:expression ws { e }
#[pub]
expression -> Node<Expression>
= i:identifier ws "(" pl:arg_list ")" {
Node::new(Expression::FnCall { name: i, args: pl })
}
/ "{" ws b:block ws "}" { Node::new(Expression::Block(b)) }
/ arith_expression
/ lit:literal { Node::new(Expression::Literal(lit)) }
/ ifelse
/ loop
arg_list -> Vec<Node<Expression>>
= expression_ws**","
atom -> Node<Expression>
= ws n:num ws { Node::new(Expression::Literal(n)) }
/ ws i:identifier ws { Node::new(Expression::Identifier(i)) }
/ ws g:grouped_arith ws { g }
conjugated_atom -> Node<Expression>
= a:atom ws "`" {
Node::new(Expression::Postfix { op: PostfixOp::Conjugate, left: Box::new(a) })
}
imaginary_atom -> Node<Expression>
= a:atom ws "i" {
Node::new(Expression::Postfix { op: PostfixOp::Imaginary, left: Box::new(a) })
}
primary -> Node<Expression>
= ws c:conjugated_atom ws { c }
/ ws i:imaginary_atom ws { i }
/ ws a:atom ws { a }
signed_primary -> Node<Expression>
= ws "+" p:primary {
Node::new(Expression::Prefix { op: PrefixOp::UnaryPlus, right: Box::new(p) })
}
/ ws "-" p:primary {
Node::new(Expression::Prefix { op: PrefixOp::UnaryMinus, right: Box::new(p) })
}
signed_or_unsigned_primary -> Node<Expression>
= primary
/ signed_primary
grouped_arith -> Node<Expression>
= "(" expr:arith_expression ")" { expr }
infix_arith -> Node<Expression> = #infix<signed_or_unsigned_primary> {
#L l "==" r {
Node::new(Expression::Infix { op: InfixOp::Comparison(CompareOp::Equal),
left: Box::new(l), right: Box::new(r) })
}
l "!=" r {
Node::new(Expression::Infix { op: InfixOp::Comparison(CompareOp::NotEqual),
left: Box::new(l), right: Box::new(r) })
}
#L l "<=" r {
Node::new(Expression::Infix { op: InfixOp::Comparison(CompareOp::LessThanEqual),
left: Box::new(l), right: Box::new(r) })
}
l ">=" r {
Node::new(Expression::Infix { op: InfixOp::Comparison(CompareOp::GreaterThanEqual),
left: Box::new(l), right: Box::new(r) })
}
#L l "<" r {
Node::new(Expression::Infix { op: InfixOp::Comparison(CompareOp::LessThan),
left: Box::new(l), right: Box::new(r) })
}
l ">" r {
Node::new(Expression::Infix { op: InfixOp::Comparison(CompareOp::GreaterThan),
left: Box::new(l), right: Box::new(r) })
}
#L l "+" r {
Node::new(Expression::Infix { op: InfixOp::Add, left: Box::new(l), right: Box::new(r) })
}
l "-" r {
Node::new(Expression::Infix { op: InfixOp::Subtract, left: Box::new(l), right: Box::new(r) })
}
#L l "*" r {
Node::new(Expression::Infix { op: InfixOp::Multiply, left: Box::new(l), right: Box::new(r) })
}
l "/" r {
Node::new(Expression::Infix { op: InfixOp::Divide, left: Box::new(l), right: Box::new(r) })
}
#R l "^" r {
Node::new(Expression::Infix { op: InfixOp::Power, left: Box::new(l), right: Box::new(r) })
}
}
ifelse -> Node<Expression>
= ws kw_if ws cond:expression ws ifb:paren_block ws kw_else ws elseb:paren_block ws {
Node::new(Expression::IfElse {
cond: Box::new(cond),
if_block: ifb,
else_block: Some(elseb)
})
}
/ ws kw_if ws cond:expression ws ifb:paren_block ws {
Node::new(Expression::IfElse {
cond: Box::new(cond),
if_block: ifb,
else_block: None
})
}
paren_block -> Node<Block>
= "{" ws b:block ws "}" { b }
loop -> Node<Expression>
= interval
interval -> Node<Expression>
= ws kw_iterate ws kw_over ws int:set_interval ws body:paren_block ws {
Node::new(Expression::Loop {
variant: None,
set: int,
body: body,
})
}
/ ws kw_iterate ws i:identifier ws "=" ws int:set_interval ws body:paren_block ws {
Node::new(Expression::Loop {
variant: Some(i),
set: int,
body: body,
})
}
set_interval -> Node<Set>
= "[" ws start:expression ws "," ws end:expression ws ")" {
Node::new(Set::Interval {
start: Box::new(start),
end: Box::new(end),
end_inclusive: false,
step: Box::new(Node::new(Expression::Literal(Node::new(Literal::Int(1)))))
})
}
/ "[" ws start:expression ws ".." ws step:expression ".." end:expression ws ")" {
Node::new(Set::Interval {
start: Box::new(start),
end: Box::new(end),
end_inclusive: false,
step: Box::new(Node::new(Expression::Literal(Node::new(Literal::Int(1)))))
})
}
/ "[" ws start:expression ws "," ws end:expression ws "]" {
Node::new(Set::Interval {
start: Box::new(start),
end: Box::new(end),
end_inclusive: true,
step: Box::new(Node::new(Expression::Literal(Node::new(Literal::Int(1)))))
})
}
/ "[" ws start:expression ws ".." ws step:expression ".." end:expression ws "]" {
Node::new(Set::Interval {
start: Box::new(start),
end: Box::new(end),
end_inclusive: true,
step: Box::new(Node::new(Expression::Literal(Node::new(Literal::Int(1)))))
})
}
ws = #quiet<(ws_char / eol / comment)*>
eol
= "\n"
/ "\r\n"
/ "\r"
/ "\u{2028}"
/ "\u{2029}"
eol_char = [\n\r\u{2028}\u{2029}]
ws_char
= [ \t\u{00A0}\u{FEFF}\u{1680}\u{180E}\u{2000}-\u{200A}\u{202F}\u{205F}\u{3000}]
comment
= comment_single_line
/ comment_multi_line
comment_single_line
= "//" (!eol_char .)*
comment_multi_line
= "/*" (!"*/" .)* "*/"
#[pub]
literal -> Node<Literal>
= num
/ string
/ boolean
num -> Node<Literal>
= f:#ext<float> { Node::new(Literal::Float(f)) }
/ i:#ext<int> { Node::new(Literal::Int(i)) }
str -> String
= s:#ext<match_str> {? convert_string(s) }
string -> Node<Literal>
= s:str { Node::new(Literal::String(s)) }
truefalse -> bool
= "true" { true }
/ "false" { false }
boolean -> Node<Literal>
= b:truefalse { Node::new(Literal::Boolean(b)) }
identifier -> Node<Identifier>
= !kw s:@"\p{XID_Start}\p{XID_Continue}*"@ {
Node::new(Identifier(s.get(0).unwrap().as_str().to_string()))
}