xlang-syntax 0.0.4-alpha

The xlang parser and syntax utilities.
Documentation
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*;