aquavm/crates/air-parser/src/lalrpop/aqua.lalrpop
2020-11-11 14:31:53 +03:00

94 lines
2.6 KiB
Plaintext

use crate::ast::*;
use crate::lalrpop::parser::InstructionError;
use lalrpop_util::ErrorRecovery;
use std::rc::Rc;
grammar<'err>(errors: &'err mut Vec<ErrorRecovery<usize, Token<'input>, InstructionError>>);
extern {
type Error = InstructionError;
}
pub Instr: Box<Instruction<'input>> = {
"(" "seq" <l:Instr> <r:Instr> ")" => Box::new(Instruction::Seq(Seq(l, r))),
"(" "par" <l:Instr> <r:Instr> ")" => Box::new(Instruction::Par(Par(l, r))),
"(" "xor" <l:Instr> <r:Instr> ")" => Box::new(Instruction::Xor(Xor(l, r))),
"(" "call" <p:PeerPart> <f:FPart> <args:Args> <output:Output?> ")" => {
let output = output.unwrap_or(CallOutput::None);
Box::new(Instruction::Call(Call{peer_part: p, function_part: f, args, output}))
},
"(" "fold" <iterable:Value> <iterator:Alphanumeric> <i:Instr> ")" => {
let instruction = Rc::new(*i);
Box::new(Instruction::Fold(Fold{ iterable, iterator, instruction }))
},
"(" "next" <i:Alphanumeric> ")" => Box::new(Instruction::Next(Next(i))),
"(" "null" ")" => Box::new(Instruction::Null(Null)),
! => { errors.push(<>); Box::new(Instruction::Error) },
}
Args: Vec<Value<'input>> = {
"[" <args:(<Arg>)*> "]" => args
}
FPart: FunctionPart<'input> = {
<f:Function> => FunctionPart::FuncName(f),
"(" <sid:ServiceId> <f:Function> ")" => FunctionPart::ServiceIdWithFuncName(sid, f),
}
PeerPart: PeerPart<'input> = {
<pid:PeerId> => PeerPart::PeerPk(pid),
"(" <pid:PeerId> <sid:ServiceId> ")" => PeerPart::PeerPkWithServiceId(pid, sid),
}
Output: CallOutput<'input> = {
<o:Alphanumeric> => CallOutput::Scalar(o),
<o:ACCUMULATOR> => CallOutput::Accumulator(&o[..o.len()-2]),
};
Function = Value;
PeerId = Value;
ServiceId = Value;
Arg = Value;
Value: Value<'input> = {
"\"" "\"" => Value::Literal(""), // TODO: signal absence somehow?
"\"" <v: Alphanumeric> "\"" => Value::Literal(v),
<v:Alphanumeric> => Value::Variable(v),
<v:JSON_PATH> => {
let mut path = v.splitn(2, ".");
let variable = path.next().expect("must contain dot");
let path = path.next().expect("contain component after dot");
Value::JsonPath { variable, path }
},
CURRENT_PEER_ID => Value::CurrentPeerId,
INIT_PEER_ID => Value::InitPeerId,
}
Alphanumeric = ALPHANUMERIC;
match {
r"[\w_-]+" => ALPHANUMERIC,
r"[\w_-]+\[\]" => ACCUMULATOR,
r#"[\w_-]+\.*\$([\w._-]*(\[[\w"]+\])*)+"# => JSON_PATH,
r#"%current_peer_id%"# => CURRENT_PEER_ID,
r#"%init_peer_id%"# => INIT_PEER_ID,
"seq",
"call",
"null",
"par",
"xor",
"fold",
"next",
} else {
_
}