use crate::my_parser::{Expr, Special};
grammar;
pub Main: Expr = {
<s: State> <b: MainBody> => Expr::MultipleExpr{ e1: Box::new(s), e2: Box::new(b) },
<i: Interface> <b: MainBody> => Expr::MultipleExpr{ e1: Box::new(i), e2: Box::new(b) },
<i: Interface> <s: State> <b: MainBody> =>
Expr::MultipleExpr{
e1: Box::new(
Expr::MultipleExpr{
e1: Box::new(i),
e2: Box::new(s)
}
),
e2: Box::new(b)
},
<b: MainBody> => b,
};
pub State: Expr = {
STATE COLON <ids: MultipleIds> => Expr::State{ body: Box::new(ids) }
};
pub MultipleIds: Expr = {
<id: Id> SEMI_COLON => Expr::String(id.to_string()),
<id: Id> <c: Comment> SEMI_COLON => Expr::MultipleExprNoNewLine{e1: Box::new(Expr::String(id.to_string())), e2: Box::new(c)},
<id1: Id> SEMI_COLON <m: MultipleIds>=> Expr::MultipleExpr{e1: Box::new(Expr::String(id1.to_string())), e2:
Box::new(m)},
<id1: Id> <c: Comment> SEMI_COLON <m: MultipleIds> => Expr::MultipleExpr{
e1:Box::new(Expr::MultipleExprNoNewLine{e1: Box::new(Expr::String(id1.to_string())), e2: Box::new(c)}),
e2: Box::new(m)},
}
pub Interface: Expr = {
INTERFACE COLON <r: Requests> <i: Indications> => Expr::Interface{ reqs: Box::new(r), indics: Box::new(i) },
INTERFACE COLON <r: Requests> => Expr::Interface{ reqs: Box::new(r), indics: Box::new(Expr::Empty) },
INTERFACE COLON <i: Indications> => Expr::Interface{ reqs: Box::new(Expr::Empty), indics: Box::new(i) },
};
pub Requests: Expr = {
REQUESTS COLON <r: MultiMethodCall> => Expr::Requests{ requests: Box::new(r) }
};
pub Indications: Expr = {
INDICATIONS COLON <i: MultiMethodCall> => Expr::Indications{ indications: Box::new(i) }
};
pub ProcedureCall: Expr = {
CALL <s: Id> OPEN_PAR CLOSE_PAR => Expr::ProcedureCall{ name: s.to_string() },
CALL <s: Id> OPEN_PAR <args: CallingArgs> CLOSE_PAR => Expr::ProcedureCallWithArgs{ name: s.to_string(), args: Box::new
(args) }
}
pub MainBody: Expr = {
<e: Init> => e,
<e: TopLevel> => e,
<e1: Init> <e2:TopLevel> => Expr::MultipleExpr{ e1: Box::new(e1), e2: Box::new(e2) }
};
pub Init: Expr = {
UPON INIT DO COLON <body: MultiBody> => Expr::Init{ body: Box::new(body)},
UPON INIT OPEN_PAR <args: DefiningArgs> CLOSE_PAR DO COLON <e: MultiBody> =>
Expr::InitWithArgs{ args, body: Box::new(e) }
};
pub TopLevel: Expr = {
<b: BasicStatements> => b,
<b: BasicStatements> <e: TopLevel> => Expr::MultipleExpr{ e1: Box::new(b), e2: Box::new(e) }
};
pub BasicStatements: Expr = {
<e: Method> => e,
<e: Timer> => e,
<e: CrashWithArgs> => e,
<e: Procedure> => e,
};
pub Method: Expr = {
SimpleMethod,
ComplexMethod,
SimpleEvent,
ComplexEvent
};
// METHODS
pub SimpleMethod: Expr = {
UPON <id: Id> DO COLON <e: MultiBody> => Expr::Method{ name: id.to_string(), body: Box::new(e) }
};
pub ComplexMethod: Expr = {
UPON <id: Id> OPEN_PAR <args: DefiningArgs> CLOSE_PAR DO COLON <e: MultiBody> => Expr::MethodWithArgs{ name: id
.to_string(), args, body: Box::new(e) }
};
pub SimpleEvent: Expr = {
UPON EVENT <id: Id> DO COLON <e: MultiBody> => Expr::Event{ name: id.to_string(), body: Box::new(e) }
};
pub ComplexEvent: Expr = {
UPON EVENT <id: Id> OPEN_PAR <args: DefiningArgs> CLOSE_PAR DO COLON <e: MultiBody> =>
Expr::EventWithArgs{ name: id.to_string(), args, body: Box::new(e) }
};
pub Trigger: Expr = {
TRIGGER <m: MethodCall> => Expr::Trigger{ method: Box::new(m) },
}
// TIMERS
pub Timer: Expr = {
UPON TIMER <id: Id> DO COLON <e: MultiBody> =>
Expr::Timer{ name: id.to_string(), body: Box::new(e) },
UPON TIMER <id: Id> OPEN_PAR <args: DefiningArgs> CLOSE_PAR DO COLON <e: MultiBody> =>
Expr::TimerWithArgs{ name: id.to_string(), args, body: Box::new(e) }
};
pub SetupTimer: Expr = {
SETUP TIMER <id: Id> OPEN_PAR <args: CallingArgs> CLOSE_PAR =>
Expr::SetupTimer{ name: id.to_string(), args: Box::new(args) },
SETUP PERIODIC TIMER <id: Id> OPEN_PAR <args: CallingArgs> CLOSE_PAR =>
Expr::SetupPeriodicTimer{ name: id.to_string(), args: Box::new(args) }
};
pub CancelTimer: Expr = {
CANCEL TIMER <id: Id> =>
Expr::CancelTimer{ name: id.to_string() },
CANCEL PERIODIC TIMER <id: Id> OPEN_PAR <args: CallingArgs> CLOSE_PAR =>
Expr::CancelTimerWithArgs{ name: id.to_string(), args: Box::new(args) }
};
// CRASHES
pub CrashWithArgs: Expr = {
UPON CRASH OPEN_PAR <args: DefiningArgs> CLOSE_PAR DO COLON <body: MultiBody> =>
Expr::CrashWithArgs{ args, body: Box::new(body)}
};
// PROCEDURES
pub Procedure: Expr = {
PROCEDURE <id: Id> COLON <body: MultiBody> =>
Expr::Procedure{ name: id.to_string(), body: Box::new(body) },
PROCEDURE <id: Id> OPEN_PAR <args: DefiningArgs> CLOSE_PAR COLON <body: MultiBody> =>
Expr::ProcedureWithArgs{ name: id.to_string(), args, body: Box::new(body) },
};
// BODY
pub MultiBody: Expr = {
<e: Body> => e,
<e1: Body> <e2: MultiBody> => Expr::MultipleExpr{ e1: Box::new(e1), e2: Box::new(e2) }
};
pub Body: Expr = {
<e: Conditional> => e,
<e: ForEach> => e,
<e: BodyLine> => e,
};
pub BodyLine: Expr = {
<e: Comment> SEMI_COLON => e,
<e: BodyLineSimple> SEMI_COLON => e,
<e: BodyLineWithComment> SEMI_COLON => e,
};
pub BodyLineSimple: Expr = {
<e: Assign> => e,
<e: Trigger> => e,
<e: MethodCall> => e,
<e: ProcedureCall> => e,
<e: SetupTimer> => e,
<e: CancelTimer> => e,
<e: Control> => e,
};
pub BodyLineWithComment: Expr = {
<e: BodyLineSimple> <c: Comment> => Expr::LineWithComment{e: Box::new(e), c: Box::new(c)}
};
pub Comment: Expr = {
DOUBLE_FORWARD_SLASH <e: CommentContent> => Expr::Comment{string: e},
};
pub MultiString: Vec<String> = {
<s: STRING> => vec![s.to_string()],
<s: STRING> <mut ss: MultiString> => { let mut res = vec![s.to_string()]; res.append(&mut ss); res }
};
pub MultiMethodCall: Expr = {
<m: MethodCall> => m,
<m: MethodCall> <ms: MultiMethodCall> => Expr::MultipleExpr{ e1: Box::new(m), e2: Box::new(ms) },
};
pub MethodCall: Expr = {
<s: Id> OPEN_PAR CLOSE_PAR => Expr::MethodCall{ name: s.to_string() },
<s: Id> OPEN_PAR <args: CallingArgs> CLOSE_PAR => Expr::MethodCallWithArgs{ name: s.to_string(), args: Box::new
(args) }
};
pub ForEach: Expr = {
FOREACH <condition: SingleLineMultiTerm> COLON <body: MultiBody> END =>
Expr::ForEach{ condition: Box::new(condition), body: Box::new(body) }
};
pub Control: Expr = {
RETURN => Expr::Return{},
BREAK => Expr::Break{},
CONTINUE => Expr::Continue{},
};
pub DefiningArgs: Vec<String> = {
<a: Id> => vec![a.to_string()],
<a: Id> COMMA <mut args: DefiningArgs> => { let mut res = vec![a.to_string()]; res.append(&mut args); res }
};
pub CallingArgs: Expr = {
Expression,
<e1: Expression> COMMA <e2: CallingArgs> => Expr::CallingArgs{e1: Box::new(e1), e2: Box::new(e2)}
};
pub Assign: Expr = {
<a: Assignable> EQ <e: Expression> => Expr::Assign{ name: Box::new(a), value: Box::new(e) },
};
// CONDITIONALS
pub Conditional: Expr = {
<e: If> END => e,
<e: IfComposed> <next_conditional: NextConditional> END =>
Expr::MultipleExprNoNewLine{e1: Box::new(e), e2: Box::new(next_conditional)},
};
// If expression
pub If: Expr = {
IF <condition: SingleLineMultiTerm> COLON <body: MultiBody> =>
Expr::If{ condition: Box::new(condition), body: Box::new(body) },
};
// If expression followed by either an ElseIf or an Else
pub IfComposed: Expr = {
IF <condition: SingleLineMultiTerm> COLON <body: MultiBody> =>
Expr::IfComposed{ condition: Box::new(condition), if_body: Box::new(body) },
};
// Else if expression
pub ElseIf: Expr = {
ELIF <condition: SingleLineMultiTerm> COLON <else_if_body: MultiBody> =>
Expr::ElseIf{ condition: Box::new(condition), else_if_body: Box::new(else_if_body) }
};
// Else if expression with else after
pub ElseIfComposed: Expr = {
ELIF <condition: SingleLineMultiTerm> COLON <else_if_body: MultiBody> =>
Expr::ElseIfComposed{ condition: Box::new(condition), else_if_body: Box::new(else_if_body) }
};
// Else expression
pub Else: Expr = {
ELSE COLON <else_body: MultiBody> => Expr::Else{else_body: Box::new(else_body)}
};
// After an If expression it can either be a single ElseIf or Else (SimpleNextConditional)
// or an ElseIf composed (followed by other ElseIfs or Else)
pub NextConditional: Expr = {
<e: SimpleNextConditional> => e,
<e: ComposedNextConditionals> => e,
};
// Check NextConditional comment
pub SimpleNextConditional: Expr = {
<e: ElseIf> => e,
<e: Else> => e
};
// Check NextConditional comment
pub ComposedNextConditionals: Expr = {
<else_if: ElseIfComposed> <next_conditional: NextConditional> => Expr::MultipleExprNoNewLine{e1: Box::new(else_if), e2: Box::new(next_conditional)}
};
// Multiple terminal tokens in more than one line
pub MultiLineMultiTerm: Expr = {
<e: Term> => e,
<e1: Term> <e2: MultiLineMultiTerm> => Expr::MultiLineMultipleTerm { t1: Box::new(e1), t2: Box::new(e2) }
};
// Multiple terminal tokens in the same line with a speace between them
pub SingleLineMultiTerm: Expr = {
<e: Term> => e,
<e1: Term> <e2: SingleLineMultiTerm> => Expr::SingleLineMultipleTerm { t1: Box::new(e1), t2: Box::new(e2) }
};
// Multiple terminal tokens in the same line without space between them
pub SingleLineMultiTermNoSpace: Expr = {
<e: Term> => e,
<e1: Term> <e2: SingleLineMultiTermNoSpace> => Expr::SingleLineMultipleTermNoSpace { t1: Box::new(e1), t2: Box::new(e2) }
};
// Basic terminal token, can be either a string or a special
pub Term: Expr = {
<e: Expression> => e
};
pub Assignable: Expr = {
<va: VecAccess> => va,
<sa: StructAccess> => sa,
<id: Id> => Expr::String(id.to_string()),
}
pub Expression: Expr = {
<o: Operation> => o,
<v: VecAccess> => v,
<s: Set> => s,
<sa: StructAccess> => sa,
<m: MethodCall> => m,
<id: Id> => Expr::String(id.to_string()),
UNDEFINED => Expr::Undefined{},
CARDINALITY <e:Expression> => Expr::Cardinality{e: Box::new(e)},
NOT OPEN_PAR <e: Expression> CLOSE_PAR => Expr::Negate{e: Box::new(e)},
};
pub Operation: Expr = {
<e1: VecAccess> <op: OperatorWithSpace> <e2: Expression> => Expr::Operation{e1: Box::new(e1), op, e2: Box::new
(e2)},
<e1: Set> <op: OperatorWithSpace> <e2: Expression> => Expr::Operation{e1: Box::new(e1), op, e2: Box::new
(e2)},
<e1: StructAccess> <op: OperatorWithSpace> <e2: Expression> => Expr::Operation{e1: Box::new(e1), op, e2: Box::new
(e2)},
<e1: MethodCall> <op: OperatorWithSpace> <e2: Expression> => Expr::Operation{e1: Box::new(e1), op, e2: Box::new
(e2)},
<e1: Id> <op: OperatorWithSpace> <e2: Expression> => Expr::Operation{e1: Box::new(Expr::String(e1.to_string())), op, e2:
Box::new(e2)},
};
pub VecAccess: Expr = {
<e1: StructAccess> OPEN_BRA <e2: Expression> CLOSE_BRA => Expr::Access{l: Box::new(e1), r: Box::new(e2)},
<e1: Id> OPEN_BRA <e2: Expression> CLOSE_BRA => Expr::Access{l: Box::new(Expr::String(e1.to_string())),
r: Box::new(e2)},
<e1: MethodCall> OPEN_BRA <e2: Expression> CLOSE_BRA => Expr::Access{l: Box::new(e1), r: Box::new(e2)},
};
pub Set: Expr = {
OPEN_CURLY_BRA <e: CallingArgs> CLOSE_CURLY_BRA => Expr::Set{e: Box::new(e)},
OPEN_CURLY_BRA CLOSE_CURLY_BRA => Expr::EmptySet{},
};
pub StructAccessible: Expr = {
<s: Set> => s,
<s: Id> => Expr::String(s),
<v: VecAccess> => v,
};
pub StructAccess: Expr = {
<s1: StructAccessible> DOT <s2: Id> => Expr::StructAccess{
t1: Box::new(s1),
t2: Box::new(Expr::String(s2))
},
};
pub OperatorWithSpace: Special = {
PLUS => Special::Plus,
MINUS => Special::Minus,
IN => Special::In,
NOT_IN => Special::NotIn,
EXISTS => Special::Exists,
NOT_EXISTS => Special::NotExists,
SET_MINUS => Special::SetMinus,
UNION => Special::Union,
INTERSECT => Special::Intersect,
AND => Special::And,
COMP_EQ => Special::CompEq,
LESS_THAN => Special::LessThan,
LESS_EQ_THAN => Special::LessEqThan,
GREATER_THAN => Special::GreaterThan,
GREATER_EQ_THAN => Special::GreaterEqThan,
DIFF_THAN => Special::Diff,
TIMES => Special::Times,
DIVISION => Special::Division
}
pub Id: String = {
<s: STRING> UNDERSCORE <id: Id> => format!("{}\\_{}", s, id),
<s: STRING> => s.to_string()
};
pub CommentContent: String = {
<t: CommentToken> => t.to_string(),
<t: CommentToken> <c: CommentContent> => format!("{} {}", t, c)
}
pub CommentToken: String = {
<s: NOT> => s.to_string(),
<s: DIFF_THAN> => s.to_string(),
<s: LESS_THAN> => s.to_string(),
<s: LESS_EQ_THAN> => s.to_string(),
<s: GREATER_THAN> => s.to_string(),
<s: GREATER_EQ_THAN> => s.to_string(),
<s: CARDINALITY> => s.to_string(),
<s: EQ> => s.to_string(),
<s: COMP_EQ> => s.to_string(),
<s: AND> => s.to_string(),
<s: UPON> => s.to_string(),
<s: EVENT> => s.to_string(),
<s: DO> => s.to_string(),
<s: COLON> => s.to_string(),
<s: COMMA> => s.to_string(),
<s: OPEN_PAR> => s.to_string(),
<s: CLOSE_PAR> => s.to_string(),
<s: OPEN_BRA> => s.to_string(),
<s: CLOSE_BRA> => s.to_string(),
<s: OPEN_CURLY_BRA> => s.to_string(),
<s: CLOSE_CURLY_BRA> => s.to_string(),
<s: PLUS> => s.to_string(),
<s: MINUS> => s.to_string(),
<s: TIMES> => s.to_string(),
<s: DIVISION> => s.to_string(),
<s: STATE> => s.to_string(),
<s: INTERFACE> => s.to_string(),
<s: REQUESTS> => s.to_string(),
<s: INDICATIONS> => s.to_string(),
<s: TRIGGER> => s.to_string(),
<s: BEGIN> => s.to_string(),
<s: END> => s.to_string(),
<s: IF> => s.to_string(),
<s: ELSE> => s.to_string(),
<s: ELIF> => s.to_string(),
<s: THEN> => s.to_string(),
<s: IN> => s.to_string(),
<s: EXISTS> => s.to_string(),
<s: INIT> => s.to_string(),
<s: TIMER> => s.to_string(),
<s: CRASH> => s.to_string(),
<s: PROCEDURE> => s.to_string(),
<s: CALL> => s.to_string(),
<s: SETUP> => s.to_string(),
<s: PERIODIC> => s.to_string(),
<s: CANCEL> => s.to_string(),
<s: FOREACH> => s.to_string(),
<s: SET_MINUS> => s.to_string(),
<s: NOT_IN> => s.to_string(),
<s: NOT_EXISTS> => s.to_string(),
<s: UNION> => s.to_string(),
<s: INTERSECT> => s.to_string(),
<s: UNDEFINED> => s.to_string(),
<s: DOT> => s.to_string(),
<s: CONTINUE> => s.to_string(),
<s: RETURN> => s.to_string(),
<s: BREAK> => s.to_string(),
<s: UNDERSCORE> => s.to_string(),
<s: STRING> => s.to_string(),
};
match {
"!" => NOT,
"!=" => DIFF_THAN,
"<" => LESS_THAN,
"<=" => LESS_EQ_THAN,
">" => GREATER_THAN,
">=" => GREATER_EQ_THAN,
"#" => CARDINALITY,
"=" => EQ,
"==" => COMP_EQ,
"and" => AND,
"upon" => UPON,
"event" => EVENT,
"do" => DO,
":" => COLON,
"," => COMMA,
"(" => OPEN_PAR,
")" => CLOSE_PAR,
"[" => OPEN_BRA,
"]" => CLOSE_BRA,
"{" => OPEN_CURLY_BRA,
"}" => CLOSE_CURLY_BRA,
"+" => PLUS,
"-" => MINUS,
"*" => TIMES,
"/" => DIVISION,
"//" => DOUBLE_FORWARD_SLASH,
"state" => STATE,
"interface" => INTERFACE,
"requests" => REQUESTS,
"indications" => INDICATIONS,
"trigger" => TRIGGER,
"begin" => BEGIN,
"end" => END,
"if" => IF,
"else" => ELSE,
"elif" => ELIF,
"then" => THEN,
"in" => IN,
"exists" => EXISTS,
"init" => INIT,
"timer" => TIMER,
"crash" => CRASH,
"procedure" => PROCEDURE,
"call" => CALL,
"setup" => SETUP,
"periodic" => PERIODIC,
"cancel" => CANCEL,
"foreach" => FOREACH,
"\\" => SET_MINUS,
"!in" => NOT_IN,
";" => SEMI_COLON,
"!exists" => NOT_EXISTS,
"unite" => UNION,
"intersect" => INTERSECT,
"undefined" => UNDEFINED,
"." => DOT,
"continue" => CONTINUE,
"return" => RETURN,
"break" => BREAK,
"_" => UNDERSCORE,
r"[a-zA-Z0-9]+" => STRING,
}