use std::str::FromStr;
use crate::ast::{RelationOp, ArithmeticOp, Expression, UnaryOp, Member, Literal};
grammar;
pub Expression: Box<Expression> = {
<left:Expression> <op:ArithmeticOp> <right:Primary> => Expression::Arithmetic{<>}.into(),
<left:Expression> <op:RelationOp> <right:Primary> => Expression::Relation{<>}.into(),
<condition:Expression> "?" <left:Primary> ":" <right:Primary> => Expression::Ternary{<>}.into(),
<left:Expression> "||" <right:Primary> => Expression::Or{<>}.into(),
<left:Expression> "&&" <right:Primary> => Expression::And{<>}.into(),
<op:UnaryOp> <right:Primary> => Expression::Unary{<>}.into(),
Member,
};
pub Member: Box<Expression> = {
Primary,
<primary:Member> "." <identifier:Ident> => Expression::Member{primary, member: Member::Attribute{identifier}}.into(),
<primary:Member> "." <identifier:Ident> "(" <arguments:CommaSeparated<Expression>> ")" => Expression::Member{primary, member: Member::Function{identifier, arguments}}.into(),
<primary:Member> "[" <expression:Expression> "]" => Expression::Member{primary, member: Member::Index{expression}}.into(),
<primary:Member> "{" <fields:CommaSeparated<FieldInits>> "}" => Expression::Member{primary, member: Member::Fields{fields}}.into(),
}
pub Primary: Box<Expression> = {
"."? <Ident> => Expression::Ident(<>).into(),
Literal => Expression::Literal(<>).into(),
"[" <members:CommaSeparated<Expression>> "]" => Expression::List{<>}.into(),
"{" <fields:CommaSeparated<MapInits>> "}" => Expression::Map{<>}.into(),
"(" <Expression> ")"
}
pub FieldInits: (String, Box<Expression>) = {
<Ident> ":" <Expression>
}
pub MapInits: (Box<Expression>, Box<Expression>) = {
<Expression> ":" <Expression>
}
CommaSeparated<T>: Vec<T> = {
<v:(<T> ",")*> <e:T?> => match e {
None => v,
Some(e) => {
let mut v = v;
v.push(e);
v
}
}
};
ArithmeticOp: ArithmeticOp = { // (3)
"+" => ArithmeticOp::Add,
"-" => ArithmeticOp::Subtract,
"*" => ArithmeticOp::Multiply,
"/" => ArithmeticOp::Divide,
"%" => ArithmeticOp::Modulus,
};
UnaryOp: UnaryOp = {
"!" => UnaryOp::Not,
"!!" => UnaryOp::DoubleNot,
"-" => UnaryOp::Minus,
"--" => UnaryOp::DoubleMinus,
}
RelationOp: RelationOp = {
"<" => RelationOp::LessThan,
"<=" => RelationOp::LessThanEq,
">" => RelationOp::GreaterThan,
">=" => RelationOp::GreaterThanEq,
"==" => RelationOp::Equals,
"!=" => RelationOp::NotEquals,
"in" => RelationOp::In
}
Literal: Literal = {
r"[0-9]+" => Literal::Int(<>.parse().unwrap()),
r"[0-9]+ [uU]" => Literal::UInt(<>.parse().unwrap()),
};
Num: i32 = {
r"[0-9]+" => i32::from_str(<>).unwrap()
};
Ident: String = {
r"[_a-zA-Z][_a-zA-Z0-9]*" => String::from(<>)
}