use crate::ast::*;
grammar;
// Macros
List<T, Delim>: Vec<T> = <mut items:(<T> Delim)*> <last_item:T?> => match last_item {
Some(item) => {
items.push(item);
items
},
_ => items,
};
// Literals
RawNone = "none";
RawBool = {"true", "false"};
RawDec = r"[0-9][0-9_]*";
RawHex = r"0[xX][0-9a-fA-F][0-9a-fA-F_]*";
RawBin = r"0[bB][01][01_]*";
RawOct = r"0[oO][0-7][0-7_]*";
RawFloat = r"[0-9][0-9_]*((\\.[0-9][0-9_]*)?[eE][-+]?[0-9][0-9_]*|\\.[0-9][0-9_]*)";
RawIdent = r"[_\p{XIDStart}]\p{XIDContinue}*";
RawAtom = r":\p{XIDContinue}*";
RawStr = r#""([^\\"]|\\.)*""#;
// Literal expressions
None: None = <start:@L> RawNone <end:@R> => None::new(start..end);
Bool: Bool<'input> = <start:@L> <value:RawBool> <end:@R> => Bool::new(start..end, value);
Num: Num<'input> = {
<start:@L> <value:RawDec> <end:@R> => Num::dec(start..end, value),
<start:@L> <value:RawHex> <end:@R> => Num::hex(start..end, value),
<start:@L> <value:RawBin> <end:@R> => Num::bin(start..end, value),
<start:@L> <value:RawOct> <end:@R> => Num::oct(start..end, value),
<start:@L> <value:RawFloat> <end:@R> => Num::float(start..end, value),
};
Ident: Ident<'input> = <start:@L> <value:RawIdent> <end:@R> => Ident::new(start..end, value);
Atom: Atom<'input> = <start:@L> <value:RawAtom> <end:@R> => Atom::new(start..end, value);
Str: Str<'input> = <start:@L> <value:RawStr> <end:@R> => Str::new(start..end, value);
// Expressions
pub Expr: Expr<'input> = OrExpr;
InlineFun: InlineFun<'input> = <start:@L> "fun" "(" <args:List<Ident, ",">> ")" <block:Block> <end:@R> => InlineFun::new(start..end, args, block);
ListLit: ListLit<'input> = <start:@L> "[" <items:List<Expr, ",">> "]" <end:@R> => ListLit::new(start..end, items);
MapPair: MapPair<'input> = {
<start:@L> <name:Ident> <end:@R> => MapPair::local(start..end, name),
<start:@L> <name:Ident> ":" <value:Expr> <end:@R> => MapPair::literal(start..end, name, Box::new(value)),
<start:@L> "[" <name:Expr> "]" ":" <value:Expr> <end:@R> => MapPair::evaluated(start..end, Box::new(name), Box::new(value)),
};
MapLit: MapLit<'input> = <start:@L> "#" "{" <items:List<MapPair, ",">> "}" <end:@R> => MapLit::new(start..end, items);
LitExpr: Expr<'input> = {
<expr:None> => Expr::None(expr),
<expr:Bool> => Expr::Bool(expr),
<expr:Num> => Expr::Num(expr),
<expr:Ident> => Expr::Ident(expr),
<expr:Atom> => Expr::Atom(expr),
<expr:Str> => Expr::Str(expr),
<expr:InlineFun> => Expr::InlineFun(expr),
<expr:ListLit> => Expr::ListLit(expr),
<expr:MapLit> => Expr::MapLit(expr),
"(" <Expr> ")",
};
AccessOp: BinaryOp = {
"." => BinaryOp::ObjIdx,
"::" => BinaryOp::StaticIdx,
};
AccessExpr: Expr<'input> = {
<LitExpr>,
<start:@L> <left:AccessExpr> <op:AccessOp> <right:LitExpr> <end:@R> => Expr::binary(start..end, left, op, right),
<start:@L> <left:AccessExpr> "[" <right:LitExpr> "]" <end:@R> => Expr::binary(start..end, left, BinaryOp::ExprIdx, right),
<start:@L> <fun:AccessExpr> "(" <args:List<Expr, ",">> ")" <end:@R> => Expr::call(start..end, fun, args),
<start:@L> <subject:AccessExpr> "." "deref" <end:@R> => Expr::unary(start..end, UnaryOp::Deref, subject),
<start:@L> <subject:AccessExpr> "." "cloned" <end:@R> => Expr::unary(start..end, UnaryOp::Cloned, subject),
<start:@L> <subject:AccessExpr> "." "new" <end:@R> => Expr::unary(start..end, UnaryOp::New, subject),
};
UnaryOp: UnaryOp = {
"+" => UnaryOp::Pos,
"-" => UnaryOp::Neg,
"!" => UnaryOp::Not,
"~" => UnaryOp::BitNot,
};
UnaryExpr: Expr<'input> = {
<AccessExpr>,
<start:@L> <op:UnaryOp> <subject:UnaryExpr> <end:@R> => Expr::unary(start..end, op, subject),
};
MulOp: BinaryOp = {
"*" => BinaryOp::Mul,
"/" => BinaryOp::Div,
"%" => BinaryOp::Mod,
};
MulExpr: Expr<'input> = {
<UnaryExpr>,
<start:@L> <left:MulExpr> <op:MulOp> <right:UnaryExpr> <end:@R> => Expr::binary(start..end, left, op, right),
};
AddOp: BinaryOp = {
"+" => BinaryOp::Add,
"-" => BinaryOp::Sub,
};
AddExpr: Expr<'input> = {
<MulExpr>,
<start:@L> <left:AddExpr> <op:AddOp> <right:MulExpr> <end:@R> => Expr::binary(start..end, left, op, right),
};
ShOp: BinaryOp = {
"<<" => BinaryOp::Shl,
">>" => BinaryOp::Shr,
};
ShExpr: Expr<'input> = {
<AddExpr>,
<start:@L> <left:ShExpr> <op:ShOp> <right:AddExpr> <end:@R> => Expr::binary(start..end, left, op, right),
};
BitAndExpr: Expr<'input> = {
<ShExpr>,
<start:@L> <left:BitAndExpr> "&" <right:ShExpr> <end:@R> => Expr::binary(start..end, left, BinaryOp::BitAnd, right),
};
BitXorExpr: Expr<'input> = {
<ShExpr>,
<start:@L> <left:BitXorExpr> "^" <right:BitAndExpr> <end:@R> => Expr::binary(start..end, left, BinaryOp::BitXor, right),
};
BitOrExpr: Expr<'input> = {
<BitXorExpr>,
<start:@L> <left:BitOrExpr> "|" <right:BitXorExpr> <end:@R> => Expr::binary(start..end, left, BinaryOp::BitOr, right),
};
CmpOp: BinaryOp = {
"==" => BinaryOp::Eq,
"!=" => BinaryOp::Neq,
"<" => BinaryOp::Lt,
">" => BinaryOp::Gt,
"<=" => BinaryOp::LtEq,
">=" => BinaryOp::GtEq,
};
CmpExpr: Expr<'input> = {
<BitOrExpr>,
<start:@L> <left:CmpExpr> <op:CmpOp> <right:BitOrExpr> <end:@R> => Expr::binary(start..end, left, op, right),
};
AndExpr: Expr<'input> = {
<CmpExpr>,
<start:@L> <left:AndExpr> "&&" <right:CmpExpr> <end:@R> => Expr::binary(start..end, left, BinaryOp::And, right),
};
OrExpr: Expr<'input> = {
<AndExpr>,
<start:@L> <left:OrExpr> "||" <right:AndExpr> <end:@R> => Expr::binary(start..end, left, BinaryOp::Or, right),
};
AssignOp: AssignOp = {
"=" => AssignOp::Assign,
"+=" => AssignOp::AssignAdd,
"-=" => AssignOp::AssignSub,
"*=" => AssignOp::AssignMul,
"/=" => AssignOp::AssignDiv,
"%=" => AssignOp::AssignMod,
"|=" => AssignOp::AssignBitOr,
"^=" => AssignOp::AssignBitXor,
"<<=" => AssignOp::AssignShl,
">>=" => AssignOp::AssignShr,
};
AssignExpr: Expr<'input> = <start:@L> <left:AccessExpr> <op:AssignOp> <right:Expr> <end:@R> => Expr::assign(start..end, left, op, right);
// Blocks
StmntExpr: Expr<'input> = {
<expr:Expr> ";" => expr,
<expr:AssignExpr> ";" => expr,
<expr:Var> ";" => Expr::Var(expr),
<expr:Break> ";" => Expr::Break(expr),
<expr:Continue> ";" => Expr::Continue(expr),
<expr:Return> ";" => Expr::Return(expr),
<expr:If> => Expr::If(expr),
<expr:Fun> => Expr::Fun(expr),
<expr:Struct> => Expr::Struct(expr),
<expr:While> => Expr::While(expr),
<expr:Block> => Expr::Block(expr),
};
Block: Block<'input> = <start:@L> "{" <actions:StmntExpr*> "}" <end:@R> => Block::new(start..end, actions);
// If statement
ElseIf: ElseIf<'input> = <start:@L> "else" "if" <cond:Expr> <block:Block> <end:@R> => ElseIf::new(start..end, Box::new(cond), block);
Else: Else<'input> = <start:@L> "else" <block:Block> <end:@R> => Else::new(start..end, block);
IfBranch: IfBranch<'input> = {
<branch:ElseIf> => IfBranch::ElseIf(branch),
<branch:Else> => IfBranch::Else(branch),
};
If: If<'input> = <start:@L> "if" <cond:Expr> <block:Block> <branches:IfBranch*> <end:@R> =>
If::new(start..end, Box::new(cond), block, branches);
// Function declarations
Fun: Fun<'input> = <start:@L> <publ:"publ"?> "fun" <name:Ident> "(" <args:List<Ident, ",">> ")" <block:Block> <end:@R> =>
Fun::new(start..end, publ != None, name, args, block);
// Struct declarations
StructProp: StructProp<'input> = <start:@L> <publ:"publ"?> <name:Ident> <end:@R> => StructProp::new(start..end, publ != None, name);
StructMember: StructMember<'input> = {
<member:StructProp> ";" => StructMember::Prop(member),
<member:Fun> => StructMember::Fun(member),
};
Struct: Struct<'input> = <start:@L> <publ:"publ"?> "struct" <name:Ident> "{" <members:StructMember*> "}" <end:@R> => Struct::new(start..end, publ != None, name, members);
VarDeco: VarDeco = {
<start:@L> "mut" <end:@R> => VarDeco::mut_(start..end),
<start:@L> "const" <end:@R> => VarDeco::const_(start..end),
};
Var: Var<'input> = <start:@L> <deco:VarDeco> <name:Ident> <value:("=" <Expr>)?> <end:@R> => Var::new(start..end, deco, name, Box::new(value));
While: While<'input> = <start:@L> <label:(<Ident> ":")?> "while" <cond:Expr> <block:Block> <end:@R> => While::new(start..end, label, Box::new(cond), block);
Break: Break<'input> = <start:@L> "break" <label:Ident?> <end:@R> => Break::new(start..end, label);
Continue: Continue<'input> = <start:@L> "continue" <label:Ident?> <end:@R> => Continue::new(start..end, label);
Return: Return<'input> = <start:@L> "return" <value:Expr?> <end:@R> => Return::new(start..end, Box::new(value));
pub Exprs: Vec<Expr<'input>> = StmntExpr*;