use lalrpop_util::ErrorRecovery;
use crate::{
CesFile, CesFileBlock, CesName, ImmediateDef, CesImmediate, CesInstance,
PropBlock, PropValue, CapacitiesBlock, UnboundedBlock, WeightsBlock,
InhibitorsBlock, HoldersBlock, Rex, ThinArrowRule, FatArrowRule, Polynomial,
Node, BinOp, Literal, Token, AscesisError, AscesisErrorKind,
};
grammar<'input, 'env>(errors: &'env mut Vec<ErrorRecovery<usize, Token<'input>, AscesisError>>);
// ces_file = { immediate_def | template_def | context_block } ;
pub CesFile: CesFile = <CesFileBlock*> => <>.into();
pub CesFileBlock: CesFileBlock = {
<ImmediateDef> => <>.into(),
<PropBlock> => <>.into(),
<CapsBlock> => <>.into(),
<UnboundedBlock> => <>.into(),
<WeightsBlock> => <>.into(),
<InhibitBlock> => <>.into(),
<HoldBlock> => <>.into(),
! => {
errors.push(<>);
CesFileBlock::Bad(AscesisErrorKind::ParsingFailure.into())
},
};
// Structure definition, immediate form
// immediate_def = immediate_sig "{" { rex } "}" ;
pub ImmediateDef: ImmediateDef = {
<sig: ImmediateSig> "{" "}" =>
ImmediateDef::new(sig, Rex::new()),
<sig: ImmediateSig> "{" <rex: Rex> "}" =>
ImmediateDef::new(sig, rex),
};
// immediate_sig = "ces" identifier ;
ImmediateSig: CesName =
"ces" <Identifier> =>
CesName::from(<>);
// Structure definition, template form
// FIXME
// template_def = template_sig "{" { rex } "}" ;
// template_sig = "ces" identifier "(" { template_args } ")" ;
// template_args = arg_decl { "," arg_decl } [ "," ] ;
// arg_decl = identifier ":" ( "Node" | "CES" | "Size" | "String" ) ;
// Structure instantiation
// ces_immediate = identifier "(" ")" ;
pub CesImmediate: CesImmediate =
<name: Identifier> "(" ")" =>
CesImmediate::new(CesName::from(name));
// ces_instance = identifier "!" "(" { instance_args } ")" ;
pub CesInstance: CesInstance = {
<name: Identifier> "!" "(" ")" =>
CesInstance::new(CesName::from(name)),
<name: Identifier> "!" "(" <args: InstanceArgs> ")" =>
CesInstance::new(CesName::from(name)).with_args(args),
};
// instance_args = arg_value { "," arg_value } [ "," ] ;
InstanceArgs: Vec<String> = {
<head: ArgValue> <tail: CommaThenArgValue*> ","? => {
let mut tail = tail;
let mut result = vec![head];
result.append(&mut tail);
result
}
};
CommaThenArgValue: String = "," <ArgValue>;
// arg_value = identifier | size | string ;
ArgValue: String = <Identifier>;
// Context
// context_block = prop_block
// | caps_block
// | unbounded_block
// | weights_block
// | inhibit_block
// | hold_block ;
// prop_selector = "vis" | "sat" ;
PropSelector: String = {
"vis" => <>.into(),
"sat" => <>.into(),
};
// prop_block = prop_selector "{" { prop_list } "}" ;
pub PropBlock: PropBlock = {
<sel: PropSelector> "{" "}" =>
PropBlock::new().with_selector(sel),
<sel: PropSelector> "{" <blk: PropList> "}" =>
blk.with_selector(sel),
};
// prop_list = prop_field { "," prop_field } [ "," ] ;
PropList: PropBlock =
<head: PropField> <tail: CommaThenPropField*> ","? =>
head.with_more(tail);
CommaThenPropField: PropBlock = "," <PropField>;
// prop_field = identifier ":" prop_value ;
PropField: PropBlock =
<key: Identifier> ":" <value: PropValue> =>
PropBlock::new().with_prop(key, value);
// prop_value_array = prop_value { "," prop_value } [ "," ] ;
PropValueArray: PropValue =
<head: PropValue> <tail: CommaThenPropValue*> ","? =>
head.into_array_with_more(tail);
CommaThenPropValue: PropValue = "," <PropValue>;
// prop_value = name
// | size_list
// | node_list
// | "[" prop_value_array "]"
// | "{" prop_list "}" ;
PropValue: PropValue = {
<Name> =>? Ok(PropValue::new_name(<>)?),
<SizeList> =>? Ok(PropValue::new_size_list(<>)?),
<IdentifierList> =>? Ok(PropValue::new_node_list(<>)?),
"[" <PropValueArray> "]" => <>.into(),
"{" <PropList> "}" => <>.into(),
};
// caps_block = "caps" "{" { cap_list } "}" ;
pub CapsBlock: CapacitiesBlock = {
"caps" "{" "}" => CapacitiesBlock::new(),
"caps" "{" <head: CapField> <tail: CommaThenCapField*> ","? "}" =>
head.with_more(tail),
};
// cap_list = cap_field { "," cap_field } [ "," ] ;
CommaThenCapField: CapacitiesBlock = "," <CapField>;
// cap_field = size node_list ;
CapField: CapacitiesBlock =
<size: Size> <nodes: NodeList> =>
CapacitiesBlock::new().with_nodes(size, nodes).unwrap();
// unbounded_block = "unbounded" "{" { node_list } "}" ;
pub UnboundedBlock: UnboundedBlock = {
"unbounded" "{" "}" => UnboundedBlock::new(),
"unbounded" "{" <nodes: NodeList> "}" =>
UnboundedBlock::from_nodes(nodes).unwrap(),
};
// weights_block = "weights" "{" { weight_list } "}" ;
pub WeightsBlock: WeightsBlock = {
"weights" "{" "}" => WeightsBlock::new(),
"weights" "{" <head: WeightField> <tail: CommaThenWeightField*> ","? "}" =>
head.with_more(tail),
};
// weight_list = weight_field { "," weight_field } [ "," ] ;
CommaThenWeightField: WeightsBlock = "," <WeightField>;
// weight_field = size node_list ( "->" | "<-" ) node_list ;
WeightField: WeightsBlock = {
<size: Size> <pre_nodes: NodeList> "->" <post_set: NodeList> =>
WeightsBlock::new_effects(size, pre_nodes, post_set).unwrap(),
<size: Size> <post_nodes: NodeList> "<-" <pre_set: NodeList> =>
WeightsBlock::new_causes(size, post_nodes, pre_set).unwrap(),
};
// inhibit_block = "inhibit" "{" { inhibit_list } "}" ;
pub InhibitBlock: InhibitorsBlock = {
"inhibit" "{" "}" => InhibitorsBlock::new(),
"inhibit" "{" <head: InhibitField> <tail: CommaThenInhibitField*> ","? "}" =>
head.with_more(tail),
};
// inhibit_list = inhibit_field { "," inhibit_field } [ "," ] ;
CommaThenInhibitField: InhibitorsBlock = "," <InhibitField>;
// inhibit_field = node_list ( "->" | "<-" ) node_list ;
InhibitField: InhibitorsBlock = {
<pre_nodes: NodeList> "->" <post_set: NodeList> =>
InhibitorsBlock::new_effects(pre_nodes, post_set).unwrap(),
<post_nodes: NodeList> "<-" <pre_set: NodeList> =>
InhibitorsBlock::new_causes(post_nodes, pre_set).unwrap(),
};
// hold_block = "hold" "{" { hold_list } "}" ;
pub HoldBlock: HoldersBlock = {
"hold" "{" "}" => HoldersBlock::new(),
"hold" "{" <head: HoldField> <tail: CommaThenHoldField*> ","? "}" =>
head.with_more(tail),
};
// hold_list = hold_field { "," hold_field } [ "," ] ;
CommaThenHoldField: HoldersBlock = "," <HoldField>;
// hold_field = node_list ( "->" | "<-" ) node_list ;
HoldField: HoldersBlock = {
<pre_nodes: NodeList> "->" <post_set: NodeList> =>
HoldersBlock::new_effects(pre_nodes, post_set).unwrap(),
<post_nodes: NodeList> "<-" <pre_set: NodeList> =>
HoldersBlock::new_causes(post_nodes, pre_set).unwrap(),
};
// Rule expression
// rex = thin_arrow_rule
// | fat_arrow_rule
// | rex_term { [ "+" ] rex_term } ;
pub Rex: Rex = {
<ThinArrowRule> => <>.into(),
<FatArrowRule> => <>.into(),
<head: RexTerm> <tail: (<AddOp?> <RexTerm>)*> => head.with_more(tail),
};
// rex_term = ces_immediate | ces_instance | "{" rex "}" ;
RexTerm: Rex = {
<CesImmediate> => <>.into(),
<CesInstance> => <>.into(),
"{" <Rex> "}",
};
// Arrow rules
// thin_arrow_rule = e_rule | c_rule | ec_rule | ce_rule | fw_rule | bw_rule ;
// e_rule = node_list "->" polynomial ;
// c_rule = node_list "<-" polynomial ;
// ec_rule = node_list "->" polynomial "<-" polynomial ;
// ce_rule = node_list "<-" polynomial "->" polynomial ;
// fw_rule = "+" plain_polynomial "->" node_list "->" polynomial ;
// bw_rule = "+" plain_polynomial "<-" node_list "<-" polynomial ;
pub ThinArrowRule: ThinArrowRule = {
// effect-only rule
<nodes: Polynomial> "->" <effect: Polynomial> => {
ThinArrowRule::new().with_nodes(nodes).unwrap().with_effect(effect)
},
// cause-only rule
<nodes: Polynomial> "<-" <cause: Polynomial> => {
ThinArrowRule::new().with_nodes(nodes).unwrap().with_cause(cause)
},
// effect-then-cause rule
<nodes: Polynomial> "->" <effect: Polynomial> "<-" <cause: Polynomial> => {
ThinArrowRule::new().with_nodes(nodes).unwrap().with_cause(cause).with_effect(effect)
},
// cause-then-effect rule
<nodes: Polynomial> "<-" <cause: Polynomial> "->" <effect: Polynomial> => {
ThinArrowRule::new().with_nodes(nodes).unwrap().with_cause(cause).with_effect(effect)
},
// forward rule
<cause: Polynomial> "->" <nodes: Polynomial> "->" <effect: Polynomial> => {
ThinArrowRule::new().with_nodes(nodes).unwrap().with_cause(cause).with_effect(effect)
},
// backward rule
<effect: Polynomial> "<-" <nodes: Polynomial> "<-" <cause: Polynomial> => {
ThinArrowRule::new().with_nodes(nodes).unwrap().with_cause(cause).with_effect(effect)
},
};
// fat_arrow_rule = polynomial ( "=>" | "<=" | "<=>" ) polynomial { ( "=>" | "<=" | "<=>" ) polynomial } ;
pub FatArrowRule: FatArrowRule =
<head: Polynomial> <tail: (<FatOp> <Polynomial>)+> =>
FatArrowRule::from_parts(head, tail);
// Polynomial
// polynomial = [ [ polynomial ] "+" ] poly_term { poly_term } ;
pub Polynomial: Polynomial = {
AddOp? <head: PolyTerm> <tail: PolyTerm*> => head.with_product_multiplied(tail),
<head: Polynomial> AddOp <tail: PolyTerm+> => head.with_product_added(tail),
};
// poly_term = identifier | "(" polynomial ")" ;
#[inline]
PolyTerm: Polynomial = {
<Identifier> => Polynomial::from(Node::from(<>)),
"(" <Polynomial> ")",
};
NodeList: Polynomial = <Polynomial>;
// Operators
AddOp: BinOp = "+" => BinOp::Add;
ThinOp: BinOp = { "->" => BinOp::ThinTx, "<-" => BinOp::ThinRx };
FatOp: BinOp = { "=>" => BinOp::FatTx, "<=" => BinOp::FatRx, "<=>" => BinOp::FatDx };
// Identifiers
IdentifierList: Vec<String> = <Identifier+>;
Identifier: String = r"[A-Za-z_][A-Za-z0-9_-]*" => <>.to_owned();
// Literals
SizeList: Vec<Literal> = <Size+>;
FiniteSize: Literal = r"[0-9]+" => Literal::from_digits(<>).unwrap();
Omega: Literal = r"[Ωω]" => Literal::omega();
Theta: Literal = r"[Θθ]" => Literal::theta();
Size: Literal = { FiniteSize, Omega };
Name: Literal = r#""[^"]*""# => Literal::from_quoted_str(<>).unwrap();
extern {
type Location = usize;
type Error = AscesisError;
enum Token<'input> {
r"///.*\n" => Token::DocComment(<&'input str>),
r"[A-Za-z_][A-Za-z0-9_-]*" => Token::Identifier(<&'input str>),
r"[0-9]+" => Token::LiteralFiniteSize(<&'input str>),
r#""[^"]*""# => Token::LiteralName(<&'input str>),
r"[Ωω]" => Token::Omega,
r"[Θθ]" => Token::Theta,
";" => Token::Semicolon,
"," => Token::Comma,
":" => Token::Colon,
"{" => Token::OpenCurly,
"}" => Token::CloseCurly,
"(" => Token::OpenParen,
")" => Token::CloseParen,
"[" => Token::OpenBracket,
"]" => Token::CloseBracket,
"+" => Token::Add,
"->" => Token::ThinArrow,
"<-" => Token::ThinBackArrow,
"=>" => Token::FatArrow,
"<=" => Token::FatBackArrow,
"<=>" => Token::FatTwowayArrow,
"!" => Token::Bang,
"ces" => Token::Ces,
"vis" => Token::Vis,
"sat" => Token::Sat,
"caps" => Token::Caps,
"unbounded" => Token::Unbounded,
"weights" => Token::Weights,
"inhibit" => Token::Inhibit,
"hold" => Token::Hold,
}
}