use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::rc::Rc;
use pax_manifest::{escape_identifier, ComponentTemplate, TemplateNodeId, TreeLocation, TypeId};
use pax_manifest::{
get_primitive_type_table, ComponentDefinition, ControlFlowRepeatPredicateDefinition,
ControlFlowRepeatSourceDefinition, ControlFlowSettingsDefinition, LiteralBlockDefinition,
LocationInfo, PropertyDefinition, SettingElement, SettingsBlockElement, TemplateNodeDefinition,
Token, TokenType, TypeDefinition, TypeTable, ValueDefinition,
};
extern crate pest;
use pest::iterators::{Pair, Pairs};
use pest::{Parser, Span};
use pest_derive::Parser;
use pest::pratt_parser::{Assoc, Op, PrattParser};
#[derive(Parser)]
#[grammar = "pax.pest"]
pub struct PaxParser;
pub fn run_pratt_parser(input_paxel: &str) -> (String, Vec<String>) {
let pratt = PrattParser::new()
.op(Op::infix(Rule::xo_tern_then, Assoc::Left)
| Op::infix(Rule::xo_tern_else, Assoc::Right))
.op(Op::infix(Rule::xo_bool_and, Assoc::Left) | Op::infix(Rule::xo_bool_or, Assoc::Left))
.op(Op::infix(Rule::xo_add, Assoc::Left) | Op::infix(Rule::xo_sub, Assoc::Left))
.op(Op::infix(Rule::xo_mul, Assoc::Left) | Op::infix(Rule::xo_div, Assoc::Left))
.op(Op::infix(Rule::xo_mod, Assoc::Left))
.op(Op::infix(Rule::xo_exp, Assoc::Right))
.op(Op::prefix(Rule::xo_neg))
.op(Op::infix(Rule::xo_rel_eq, Assoc::Left)
| Op::infix(Rule::xo_rel_neq, Assoc::Left)
| Op::infix(Rule::xo_rel_lt, Assoc::Left)
| Op::infix(Rule::xo_rel_lte, Assoc::Left)
| Op::infix(Rule::xo_rel_gt, Assoc::Left)
| Op::infix(Rule::xo_rel_gte, Assoc::Left))
.op(Op::prefix(Rule::xo_bool_not));
let pairs = PaxParser::parse(Rule::expression_body, input_paxel)
.expect(&format!("unsuccessful pratt parse {}", &input_paxel));
let symbolic_ids = Rc::new(RefCell::new(vec![]));
let output = recurse_pratt_parse_to_string(pairs, &pratt, Rc::clone(&symbolic_ids));
(output, symbolic_ids.take())
}
fn convert_symbolic_binding_from_paxel_to_ril(xo_symbol: Pair<Rule>) -> String {
let mut pairs = xo_symbol.clone().into_inner();
let maybe_this_or_self = pairs.next().unwrap().as_str();
let self_or_this_removed = if maybe_this_or_self == "this" || maybe_this_or_self == "self" {
let mut output = "".to_string();
pairs.for_each(|pair| output += &*(".".to_owned() + pair.as_str()));
output.replacen(".", "", 1)
} else {
xo_symbol.as_str().to_string()
};
escape_identifier(self_or_this_removed)
}
fn recurse_pratt_parse_to_string<'a>(
expression: Pairs<Rule>,
pratt_parser: &PrattParser<Rule>,
symbolic_ids: Rc<RefCell<Vec<String>>>,
) -> String {
pratt_parser
.map_primary(move |primary| match primary.as_rule() {
Rule::expression_grouped => {
let mut inner = primary.into_inner();
let exp_bod = recurse_pratt_parse_to_string(inner.next().unwrap().into_inner(), pratt_parser, Rc::clone(&symbolic_ids));
if let Some(literal_number_unit) = inner.next() {
let unit = literal_number_unit.as_str();
if unit == "px" {
format!("Size::Pixels({}.into())", exp_bod)
} else if unit == "%" {
format!("Percent({}.into())", exp_bod)
} else if unit == "deg" {
format!("Rotation::Degrees({}.into())", exp_bod)
} else if unit == "rad" {
format!("Rotation::Radians({}.into())", exp_bod)
} else {
unreachable!()
}
} else {
exp_bod
}
},
Rule::xo_enum_or_function_call => {
if !primary.as_str().contains("(") {
primary.as_str().to_string()
} else {
let mut pairs = primary.into_inner();
let mut output = "".to_string();
let mut next_pair = pairs.next().unwrap();
while let Rule::identifier = next_pair.as_rule() {
output = output + next_pair.as_str();
next_pair = pairs.next().unwrap();
if let Rule::identifier = next_pair.as_rule() {
output = output + "::";
}
};
let mut expression_body_pairs = next_pair.into_inner();
output = output + "(";
while let Some(next_pair) = expression_body_pairs.next() {
output = output + "(" + &recurse_pratt_parse_to_string(next_pair.into_inner(), pratt_parser, Rc::clone(&symbolic_ids)) + ").into(),"
}
output = output + ")";
output
}
},
Rule::xo_range => {
let mut pairs = primary.into_inner();
let op0 = pairs.next().unwrap();
let op0_out = match op0.as_rule() {
Rule::xo_literal => {
op0.as_str().to_string()
},
Rule::xo_symbol => {
symbolic_ids.borrow_mut().push(op0.as_str().to_string());
format!("{}.to_int()",convert_symbolic_binding_from_paxel_to_ril(op0))
},
_ => unimplemented!("")
};
let op1 = pairs.next().unwrap();
let op1_out = op1.as_str().to_string();
let op2 = pairs.next().unwrap();
let op2_out = match op2.as_rule() {
Rule::xo_literal => {
op2.as_str().to_string()
},
Rule::xo_symbol => {
symbolic_ids.borrow_mut().push(op2.as_str().to_string());
format!("{}.to_int()",convert_symbolic_binding_from_paxel_to_ril(op2))
},
_ => unimplemented!("")
};
format!("({} as isize){}({} as isize)", &op0_out, &op1_out, &op2_out)
},
Rule::xo_literal => {
let literal_kind = primary.into_inner().next().unwrap();
match literal_kind.as_rule() {
Rule::literal_number_with_unit => {
let mut inner = literal_kind.into_inner();
let value = inner.next().unwrap().as_str();
let unit = inner.next().unwrap().as_str();
if unit == "px" {
format!("Size::Pixels({}.into())", value)
} else if unit == "%" {
format!("Percent({}.into())", value)
} else if unit == "deg" {
format!("Rotation::Degrees({}.into())", value)
} else if unit == "rad" {
format!("Rotation::Radians({}.into())", value)
} else {
unreachable!()
}
},
Rule::literal_number => {
let mut inner = literal_kind.into_inner();
let value = inner.next().unwrap().as_str();
format!("Numeric::from({})", value)
},
Rule::string => {
format!("StringBox::from({})",literal_kind.as_str().to_string())
},
Rule::literal_color => {
let mut inner = literal_kind.into_inner();
let next_pair = inner.next().unwrap();
if let Rule::literal_color_const = next_pair.as_rule() {
format!("Color::{}", next_pair.as_str())
} else {
let func = next_pair.as_str().split("(").next().unwrap().to_string();
let mut accum = "".to_string();
let mut inner = next_pair.into_inner();
while let Some(next_pair) = inner.next() {
let literal_representation = next_pair.into_inner();
accum = accum + &recurse_pratt_parse_to_string(literal_representation, pratt_parser, Rc::clone(&symbolic_ids)) + ".into(),"
}
format!("Color::{}({})", &func, &accum )
}
},
_ => {
literal_kind.as_str().to_string()
}
}
},
Rule::xo_color_space_func => {
let mut inner = primary.clone().into_inner();
let func = primary.as_str().split("(").next().unwrap().to_string();
let mut accum = "".to_string();
while let Some(next_pair) = inner.next() {
let literal_representation = next_pair.into_inner();
accum = accum + &recurse_pratt_parse_to_string(literal_representation, pratt_parser, Rc::clone(&symbolic_ids)) + ".into(),"
}
format!("Color::{}({})", &func, &accum )
},
Rule::xo_object => {
let mut output : String = "".to_string();
let mut inner = primary.into_inner();
let maybe_identifier = inner.next().unwrap();
let rule = maybe_identifier.as_rule();
fn handle_xoskvp<'a>(xoskvp: Pair<Rule>, pratt_parser: &PrattParser<Rule>, symbolic_ids: Rc<RefCell<Vec<String>>>) -> String {
let mut inner_kvp = xoskvp.into_inner();
let settings_key = inner_kvp.next().unwrap().as_str().to_string();
let expression_body = inner_kvp.next().unwrap().into_inner();
let ril = recurse_pratt_parse_to_string(expression_body, pratt_parser, Rc::clone(&symbolic_ids));
format!("{}: {},\n",settings_key, ril)
}
if let Rule::identifier = rule {
unimplemented!("Explicit struct type declarations are not yet supported. Instead of `SomeType {{ ... }}`, try using simply `{{ ... }}`.");
} else {
let ril = handle_xoskvp(maybe_identifier, pratt_parser, Rc::clone(&symbolic_ids));
output += &ril;
}
let mut remaining_kvps = inner.into_iter();
while let Some(xoskkvp) = remaining_kvps.next() {
let ril = handle_xoskvp(xoskkvp, pratt_parser, Rc::clone(&symbolic_ids));
output += &ril;
}
output
},
Rule::xo_symbol => {
symbolic_ids.borrow_mut().push(primary.as_str().to_string());
format!("{}",convert_symbolic_binding_from_paxel_to_ril(primary))
},
Rule::xo_tuple => {
let mut tuple = primary.into_inner();
let exp0 = tuple.next().unwrap();
let exp1 = tuple.next().unwrap();
let exp0 = recurse_pratt_parse_to_string( exp0.into_inner(), pratt_parser, Rc::clone(&symbolic_ids));
let exp1 = recurse_pratt_parse_to_string( exp1.into_inner(), pratt_parser, Rc::clone(&symbolic_ids));
format!("({}.into(),{}.into())", exp0, exp1)
},
Rule::xo_list => {
let mut list = primary.into_inner();
let mut vec = Vec::new();
while let Some(item) = list.next() {
let item_str = recurse_pratt_parse_to_string(item.into_inner(), pratt_parser, Rc::clone(&symbolic_ids));
vec.push(item_str);
}
format!("vec![{}]", vec.join(","))
},
Rule::expression_body => {
recurse_pratt_parse_to_string(primary.into_inner(), pratt_parser, Rc::clone(&symbolic_ids))
},
_ => unreachable!("{}",primary.as_str()),
})
.map_prefix(|op, rhs| match op.as_rule() {
Rule::xo_neg => format!("(-{})", rhs),
Rule::xo_bool_not => format!("(!{})", rhs),
_ => unreachable!(),
})
.map_infix(|lhs, op, rhs| match op.as_rule() {
Rule::xo_add => {format!("({}+{})", lhs, rhs)},
Rule::xo_bool_and => {format!("({}&&{})", lhs, rhs)},
Rule::xo_bool_or => {format!("({}||{})", lhs, rhs)},
Rule::xo_div => {format!("({}/{})", lhs, rhs)},
Rule::xo_exp => {format!("(({}).pow({}))", lhs, rhs)},
Rule::xo_mod => {format!("({}%{})", lhs, rhs)},
Rule::xo_mul => {format!("({}*{})", lhs, rhs)},
Rule::xo_rel_eq => {format!("({}=={})", lhs, rhs)},
Rule::xo_rel_gt => {format!("({}>{})", lhs, rhs)},
Rule::xo_rel_gte => {format!("({}>={})", lhs, rhs)},
Rule::xo_rel_lt => {format!("({}<{})", lhs, rhs)},
Rule::xo_rel_lte => {format!("({}<={})", lhs, rhs)},
Rule::xo_rel_neq => {format!("({}!={})", lhs, rhs)},
Rule::xo_sub => {format!("({}-{})", lhs, rhs)},
Rule::xo_tern_then => {format!("if {} {{ {} }}", lhs, rhs)},
Rule::xo_tern_else => {format!("{} else {{ {} }}", lhs, rhs)},
_ => unreachable!(),
})
.parse(expression)
}
pub fn parse_template_from_component_definition_string(
ctx: &mut TemplateNodeParseContext,
pax: &str,
) {
let pax_component_definition = PaxParser::parse(Rule::pax_component_definition, pax)
.expect(&format!("unsuccessful parse from {}", &pax)) .next()
.unwrap(); pax_component_definition
.into_inner()
.for_each(|pair| match pair.as_rule() {
Rule::root_tag_pair => {
recurse_visit_tag_pairs_for_template(
ctx,
pair.into_inner().next().unwrap(),
pax,
TreeLocation::Root,
);
}
_ => {}
});
}
pub struct TemplateNodeParseContext {
pub template: ComponentTemplate,
pub pascal_identifier_to_type_id_map: HashMap<String, TypeId>,
}
fn recurse_visit_tag_pairs_for_template(
ctx: &mut TemplateNodeParseContext,
any_tag_pair: Pair<Rule>,
pax: &str,
location: TreeLocation,
) {
match any_tag_pair.as_rule() {
Rule::matched_tag => {
let matched_tag = any_tag_pair;
let mut open_tag = matched_tag
.clone()
.into_inner()
.next()
.unwrap()
.into_inner();
let pascal_identifier = open_tag.next().unwrap().as_str();
let template_node = TemplateNodeDefinition {
type_id: TypeId::build_singleton(
&ctx.pascal_identifier_to_type_id_map
.get(pascal_identifier)
.expect(&format!("Template key not found {}", &pascal_identifier))
.to_string(),
Some(&pascal_identifier.to_string()),
),
settings: parse_inline_attribute_from_final_pairs_of_tag(open_tag, pax),
raw_comment_string: None,
control_flow_settings: None,
};
let id = match location {
TreeLocation::Root => ctx.template.add_root_node_back(template_node),
TreeLocation::Parent(id) => ctx.template.add_child_back(id, template_node),
};
let prospective_inner_nodes = matched_tag.into_inner().nth(1).unwrap();
match prospective_inner_nodes.as_rule() {
Rule::inner_nodes => {
let inner_nodes = prospective_inner_nodes;
inner_nodes.into_inner().for_each(|sub_tag_pair| {
recurse_visit_tag_pairs_for_template(
ctx,
sub_tag_pair,
pax,
TreeLocation::Parent(id.clone().get_template_node_id()),
);
})
}
_ => {
panic!("wrong prospective inner nodes (or nth)")
}
}
}
Rule::self_closing_tag => {
let mut tag_pairs = any_tag_pair.into_inner();
let pascal_identifier = tag_pairs.next().unwrap().as_str();
let type_id = if let Some(type_id) =
ctx.pascal_identifier_to_type_id_map.get(pascal_identifier)
{
type_id.clone()
} else {
TypeId::build_blank_component(pascal_identifier)
};
let template_node = TemplateNodeDefinition {
type_id,
settings: parse_inline_attribute_from_final_pairs_of_tag(tag_pairs, pax),
raw_comment_string: None,
control_flow_settings: None,
};
let _ = match location {
TreeLocation::Root => ctx.template.add_root_node_back(template_node),
TreeLocation::Parent(id) => ctx.template.add_child_back(id, template_node),
};
}
Rule::statement_control_flow => {
let any_tag_pair = any_tag_pair.into_inner().next().unwrap();
let _template_node_definition = match any_tag_pair.as_rule() {
Rule::statement_if => {
let mut statement_if = any_tag_pair.into_inner();
let expression_body = statement_if.next().unwrap();
let expression_body_location = span_to_location(&expression_body.as_span());
let expression_body_token = Token::new(
expression_body.as_str().to_string(),
TokenType::IfExpression,
expression_body_location,
pax,
);
let template_node = TemplateNodeDefinition {
control_flow_settings: Some(ControlFlowSettingsDefinition {
condition_expression_paxel: Some(expression_body_token),
condition_expression_info: None, slot_index_expression_paxel: None,
slot_index_expression_info: None,
repeat_predicate_definition: None,
repeat_source_definition: None,
}),
type_id: TypeId::build_if(),
settings: None,
raw_comment_string: None,
};
let id = match location {
TreeLocation::Root => ctx.template.add_root_node_back(template_node),
TreeLocation::Parent(id) => ctx.template.add_child_back(id, template_node),
};
let prospective_inner_nodes = statement_if.next();
if let Some(inner_nodes) = prospective_inner_nodes {
inner_nodes.into_inner().for_each(|sub_tag_pair| {
recurse_visit_tag_pairs_for_template(
ctx,
sub_tag_pair,
pax,
TreeLocation::Parent(id.clone().get_template_node_id()),
);
})
}
}
Rule::statement_for => {
let mut cfavd = ControlFlowSettingsDefinition::default();
let mut for_statement = any_tag_pair.clone().into_inner();
let mut predicate_declaration = for_statement.next().unwrap().into_inner();
let source = for_statement.next().unwrap();
let prospective_inner_nodes = for_statement.next();
if predicate_declaration.clone().count() > 1 {
let elem = predicate_declaration.next().unwrap();
let elem_location = span_to_location(&elem.as_span());
let elem_token = Token::new(
elem.as_str().to_string(),
TokenType::ForPredicate,
elem_location,
pax,
);
let index = predicate_declaration.next().unwrap();
let index_location = span_to_location(&index.as_span());
let index_token = Token::new(
index.as_str().to_string(),
TokenType::ForPredicate,
index_location,
pax,
);
cfavd.repeat_predicate_definition =
Some(ControlFlowRepeatPredicateDefinition::ElemIdIndexId(
elem_token,
index_token,
));
} else {
let elem = predicate_declaration.next().unwrap();
let predicate_declaration_location = span_to_location(&elem.as_span());
let predicate_declaration_token = Token::new(
elem.as_str().to_string(),
TokenType::ForPredicate,
predicate_declaration_location,
pax,
);
cfavd.repeat_predicate_definition =
Some(ControlFlowRepeatPredicateDefinition::ElemId(
predicate_declaration_token,
));
}
let inner_source = source.into_inner().next().unwrap();
let inner_source_location = span_to_location(&inner_source.as_span());
let mut inner_source_token = Token::new(
inner_source.as_str().to_string(),
TokenType::ForSource,
inner_source_location,
pax,
);
let repeat_source_definition = match inner_source.as_rule() {
Rule::xo_range => {
let mut inner = inner_source.into_inner();
let left = inner.next().unwrap();
inner.next();
let right = inner.next().unwrap();
let mut range_symbolic_bindings = vec![];
if matches!(left.as_rule(), Rule::xo_symbol) {
let inner_source_location = span_to_location(&left.as_span());
let left_range_token = Token::new(
convert_symbolic_binding_from_paxel_to_ril(left),
TokenType::ForSource,
inner_source_location,
pax,
);
range_symbolic_bindings.push(left_range_token);
}
if matches!(right.as_rule(), Rule::xo_symbol) {
let inner_source_location = span_to_location(&right.as_span());
let left_range_token = Token::new(
convert_symbolic_binding_from_paxel_to_ril(right),
TokenType::ForSource,
inner_source_location,
pax,
);
range_symbolic_bindings.push(left_range_token);
}
ControlFlowRepeatSourceDefinition {
range_expression_paxel: Some(inner_source_token),
range_symbolic_bindings,
expression_info: None, symbolic_binding: None,
}
}
Rule::xo_symbol => {
inner_source_token.token_value =
convert_symbolic_binding_from_paxel_to_ril(inner_source);
ControlFlowRepeatSourceDefinition {
range_expression_paxel: None,
range_symbolic_bindings: vec![],
expression_info: None,
symbolic_binding: Some(inner_source_token),
}
}
_ => {
unreachable!()
}
};
cfavd.repeat_source_definition = Some(repeat_source_definition);
let template_node = TemplateNodeDefinition {
type_id: TypeId::build_repeat(),
control_flow_settings: Some(cfavd),
settings: None,
raw_comment_string: None,
};
let id = match location {
TreeLocation::Root => ctx.template.add_root_node_back(template_node),
TreeLocation::Parent(id) => ctx.template.add_child_back(id, template_node),
};
if let Some(inner_nodes) = prospective_inner_nodes {
inner_nodes.into_inner().for_each(|sub_tag_pair| {
recurse_visit_tag_pairs_for_template(
ctx,
sub_tag_pair,
pax,
TreeLocation::Parent(id.clone().get_template_node_id()),
);
})
}
}
Rule::statement_slot => {
let mut statement_slot = any_tag_pair.into_inner();
let expression_body = statement_slot.next().unwrap();
let expression_body_location = span_to_location(&expression_body.as_span());
let expression_body_token = Token::new(
expression_body.as_str().to_string(),
TokenType::SlotExpression,
expression_body_location,
pax,
);
let prospective_inner_nodes = statement_slot.next();
let template_node = TemplateNodeDefinition {
control_flow_settings: Some(ControlFlowSettingsDefinition {
condition_expression_paxel: None,
condition_expression_info: None,
slot_index_expression_paxel: Some(expression_body_token),
slot_index_expression_info: None, repeat_predicate_definition: None,
repeat_source_definition: None,
}),
type_id: TypeId::build_slot(),
settings: None,
raw_comment_string: None,
};
let id = match location {
TreeLocation::Root => ctx.template.add_root_node_back(template_node),
TreeLocation::Parent(id) => ctx.template.add_child_back(id, template_node),
};
if let Some(inner_nodes) = prospective_inner_nodes {
inner_nodes.into_inner().for_each(|sub_tag_pair| {
recurse_visit_tag_pairs_for_template(
ctx,
sub_tag_pair,
pax,
TreeLocation::Parent(id.clone().get_template_node_id()),
);
})
}
}
_ => {
unreachable!("Parsing error: {:?}", any_tag_pair.as_rule());
}
};
}
Rule::comment => {
let template_node = TemplateNodeDefinition {
control_flow_settings: None,
type_id: TypeId::build_comment(),
settings: None,
raw_comment_string: Some(any_tag_pair.as_str().to_string()),
};
let _ = match location {
TreeLocation::Root => ctx.template.add_root_node_back(template_node),
TreeLocation::Parent(id) => ctx.template.add_child_back(id, template_node),
};
}
Rule::node_inner_content => {
unimplemented!("Inner content not yet supported");
}
_ => {
unreachable!("Parsing error: {:?}", any_tag_pair.as_rule());
}
}
}
fn parse_literal_function(literal_function_full: Pair<Rule>, pax: &str) -> Token {
let literal_function = literal_function_full.clone().into_inner().next().unwrap();
let location_info = span_to_location(&literal_function.as_span());
let literal_function_token = Token::new_with_raw_value(
literal_function.as_str().to_string(),
literal_function_full.as_str().to_string().replace(",", ""),
TokenType::Handler,
location_info,
pax,
);
literal_function_token
}
fn parse_event_id(event_id_full: Pair<Rule>, pax: &str) -> Token {
let event_id = event_id_full.clone().into_inner().next().unwrap();
let event_id_location = span_to_location(&event_id.as_span());
let event_id_token = Token::new_with_raw_value(
event_id.as_str().to_string(),
event_id_full.as_str().to_string(),
TokenType::EventId,
event_id_location,
pax,
);
event_id_token
}
fn parse_inline_attribute_from_final_pairs_of_tag(
final_pairs_of_tag: Pairs<Rule>,
pax: &str,
) -> Option<Vec<SettingElement>> {
let vec: Vec<SettingElement> = final_pairs_of_tag
.map(|attribute_key_value_pair| {
match attribute_key_value_pair
.clone()
.into_inner()
.next()
.unwrap()
.as_rule()
{
Rule::attribute_event_binding => {
let mut kv = attribute_key_value_pair.into_inner();
let mut attribute_event_binding = kv.next().unwrap().into_inner();
let event_id_token =
parse_event_id(attribute_event_binding.next().unwrap(), pax);
let literal_function_token =
parse_literal_function(attribute_event_binding.next().unwrap(), pax);
SettingElement::Setting(
event_id_token,
ValueDefinition::EventBindingTarget(literal_function_token),
)
}
Rule::id_binding => {
let mut kv = attribute_key_value_pair
.into_inner()
.next()
.unwrap()
.into_inner();
let id_binding_key = kv.next().unwrap();
let id_binding_key_location = span_to_location(&id_binding_key.as_span());
let id_binding_key_token = Token::new(
id_binding_key.as_str().to_string(),
TokenType::SettingKey,
id_binding_key_location,
pax,
);
let id_binding_value = kv.next().unwrap();
let id_binding_value_location = span_to_location(&id_binding_value.as_span());
let id_binding_value_token = Token::new(
id_binding_value.as_str().to_string(),
TokenType::LiteralValue,
id_binding_value_location,
pax,
);
SettingElement::Setting(
id_binding_key_token,
ValueDefinition::LiteralValue(id_binding_value_token),
)
}
_ => {
let mut kv = attribute_key_value_pair.into_inner();
let key = kv.next().unwrap();
let key_location = span_to_location(&key.as_span());
let key_token = Token::new(
key.as_str().to_string(),
TokenType::SettingKey,
key_location,
pax,
);
let raw_value = kv.peek().unwrap().as_str();
let value = kv.next().unwrap().into_inner().next().unwrap();
let location_info = span_to_location(&value.as_span());
let value_definition = match value.as_rule() {
Rule::literal_value => {
let (output_string, _) =
crate::parsing::run_pratt_parser(value.as_str());
let literal_value_token = Token::new_with_raw_value(
output_string,
raw_value.to_string(),
TokenType::LiteralValue,
location_info,
pax,
);
ValueDefinition::LiteralValue(literal_value_token)
}
Rule::literal_object => ValueDefinition::Block(
derive_value_definition_from_literal_object_pair(value, pax),
),
Rule::expression_body => {
let expression_token = Token::new_with_raw_value(
value.as_str().to_string(),
raw_value.to_string(),
TokenType::Expression,
location_info,
pax,
);
ValueDefinition::Expression(expression_token, None)
}
Rule::identifier => {
let identifier_token = Token::new(
value.as_str().to_string(),
TokenType::Identifier,
location_info,
pax,
);
ValueDefinition::Identifier(identifier_token, None)
}
_ => {
unreachable!("Parsing error 3342638857230: {:?}", value.as_rule());
}
};
SettingElement::Setting(key_token, value_definition)
}
}
})
.collect();
if vec.len() > 0 {
Some(vec)
} else {
None
}
}
fn derive_value_definition_from_literal_object_pair(
literal_object: Pair<Rule>,
pax: &str,
) -> LiteralBlockDefinition {
let mut literal_object_pairs = literal_object.into_inner();
if let None = literal_object_pairs.peek() {
return LiteralBlockDefinition {
explicit_type_pascal_identifier: None,
elements: vec![],
};
}
let explicit_type_pascal_identifier = match literal_object_pairs.peek().unwrap().as_rule() {
Rule::pascal_identifier => {
let raw_value = literal_object_pairs.next().unwrap();
let raw_value_location = span_to_location(&raw_value.as_span());
let token = Token::new(
raw_value.as_str().to_string(),
TokenType::PascalIdentifier,
raw_value_location,
pax,
);
Some(token)
}
_ => None,
};
LiteralBlockDefinition {
explicit_type_pascal_identifier,
elements: literal_object_pairs
.map(|settings_key_value_pair| {
match settings_key_value_pair.as_rule() {
Rule::settings_key_value_pair => {
let mut pairs = settings_key_value_pair.into_inner();
let setting_key = pairs.next().unwrap().into_inner().next().unwrap();
let setting_key_location = span_to_location(&setting_key.as_span());
let setting_key_token = Token::new(
setting_key.as_str().to_string(),
TokenType::SettingKey,
setting_key_location,
pax,
);
let raw_value = pairs.peek().unwrap().as_str();
let value = pairs.next().unwrap().into_inner().next().unwrap();
let location_info = span_to_location(&value.as_span());
let setting_value_definition = match value.as_rule() {
Rule::literal_value => {
let (output_string, _) =
crate::parsing::run_pratt_parser(value.as_str());
let token = Token::new_with_raw_value(
output_string,
raw_value.to_string(),
TokenType::LiteralValue,
location_info,
pax,
);
ValueDefinition::LiteralValue(token)
}
Rule::literal_object => {
ValueDefinition::Block(
derive_value_definition_from_literal_object_pair(value, pax),
)
}
Rule::expression_body => {
let token = Token::new_with_raw_value(
value.as_str().to_string(),
raw_value.to_string(),
TokenType::Expression,
location_info,
pax,
);
ValueDefinition::Expression(token, None)
}
_ => {
unreachable!("Parsing error 231453468: {:?}", value.as_rule());
}
};
SettingElement::Setting(setting_key_token, setting_value_definition)
}
Rule::comment => {
let comment = settings_key_value_pair.as_str().to_string();
SettingElement::Comment(comment)
}
_ => {
unreachable!(
"Parsing error 2314314145: {:?}",
settings_key_value_pair.as_rule()
);
}
}
})
.collect(),
}
}
pub fn parse_settings_from_component_definition_string(pax: &str) -> Vec<SettingsBlockElement> {
let pax_component_definition = PaxParser::parse(Rule::pax_component_definition, pax)
.expect(&format!("unsuccessful parse from {}", &pax)) .next()
.unwrap(); let mut settings: Vec<SettingsBlockElement> = vec![];
pax_component_definition
.into_inner()
.for_each(|top_level_pair| {
match top_level_pair.as_rule() {
Rule::settings_block_declaration => {
top_level_pair
.into_inner()
.for_each(|top_level_settings_block_entity| {
match top_level_settings_block_entity.as_rule() {
Rule::settings_event_binding => {
let mut settings_event_binding_pairs =
top_level_settings_block_entity.into_inner();
let event_id_token = parse_event_id(
settings_event_binding_pairs.next().unwrap(),
pax,
);
let literal_function_token = parse_literal_function(
settings_event_binding_pairs.next().unwrap(),
pax,
);
let handler_element: SettingsBlockElement =
SettingsBlockElement::Handler(
event_id_token,
vec![literal_function_token],
);
settings.push(handler_element);
}
Rule::selector_block => {
let mut selector_block_pairs =
top_level_settings_block_entity.into_inner();
let raw_selector = selector_block_pairs.next().unwrap();
let raw_value_location =
span_to_location(&raw_selector.as_span());
let selector: String = raw_selector
.as_str()
.chars()
.filter(|c| !c.is_whitespace())
.collect();
let token = Token::new(
selector,
TokenType::Selector,
raw_value_location,
pax,
);
let literal_object = selector_block_pairs.next().unwrap();
settings.push(SettingsBlockElement::SelectorBlock(
token,
derive_value_definition_from_literal_object_pair(
literal_object,
pax,
),
));
}
Rule::comment => {
let comment =
top_level_settings_block_entity.as_str().to_string();
settings.push(SettingsBlockElement::Comment(comment));
}
_ => {
unreachable!(
"Parsing error: {:?}",
top_level_settings_block_entity.as_rule()
);
}
}
});
}
_ => {}
}
});
settings
}
pub struct ParsingContext {
pub visited_type_ids: HashSet<TypeId>,
pub main_component_type_id: TypeId,
pub component_definitions: HashMap<TypeId, ComponentDefinition>,
pub template_map: HashMap<String, TypeId>,
pub template_node_definitions: ComponentTemplate,
pub type_table: TypeTable,
pub import_paths: HashSet<String>,
}
impl Default for ParsingContext {
fn default() -> Self {
Self {
main_component_type_id: TypeId::default(),
visited_type_ids: HashSet::new(),
component_definitions: HashMap::new(),
template_map: HashMap::new(),
type_table: get_primitive_type_table(),
template_node_definitions: ComponentTemplate::default(),
import_paths: HashSet::new(),
}
}
}
#[derive(Debug)]
pub struct ParsingError {
pub error_name: String,
pub error_message: String,
pub matched_string: String,
pub start: (usize, usize),
pub end: (usize, usize),
}
pub fn extract_errors(pairs: pest::iterators::Pairs<Rule>) -> Vec<ParsingError> {
let mut errors = vec![];
for pair in pairs {
let error = match pair.as_rule() {
Rule::block_level_error => Some((
format!("{:?}", pair.as_rule()),
"Unexpected template structure encountered.".to_string(),
)),
Rule::attribute_key_value_pair_error => Some((
format!("{:?}", pair.as_rule()),
"Attribute key-value pair is malformed.".to_string(),
)),
Rule::inner_tag_error => Some((
format!("{:?}", pair.as_rule()),
"Inner tag doesn't match any expected format.".to_string(),
)),
Rule::selector_block_error => Some((
format!("{:?}", pair.as_rule()),
"Selector block structure is not well-defined.".to_string(),
)),
Rule::expression_body_error => Some((
format!("{:?}", pair.as_rule()),
"Expression inside curly braces is not well defined.".to_string(),
)),
Rule::open_tag_error => Some((
format!("{:?}", pair.as_rule()),
"Open tag is malformed".to_string(),
)),
Rule::tag_error => Some((
format!("{:?}", pair.as_rule()),
"Tag structure is unexpected.".to_string(),
)),
_ => None,
};
if let Some((error_name, error_message)) = error {
let span = pair.as_span();
let ((line_start, start_col), (line_end, end_col)) =
(pair.line_col(), span.end_pos().line_col());
let error = ParsingError {
error_name,
error_message,
matched_string: span.as_str().to_string(),
start: (line_start, start_col),
end: (line_end, end_col),
};
errors.push(error);
}
errors.extend(extract_errors(pair.into_inner()));
}
errors
}
pub fn assemble_component_definition(
mut ctx: ParsingContext,
pax: &str,
is_main_component: bool,
template_map: HashMap<String, TypeId>,
module_path: &str,
self_type_id: TypeId,
component_source_file_path: &str,
) -> (ParsingContext, ComponentDefinition) {
let _ast = PaxParser::parse(Rule::pax_component_definition, pax)
.expect(&format!("unsuccessful parse from {}", &pax)) .next()
.unwrap(); let errors = extract_errors(_ast.clone().into_inner());
if !errors.is_empty() {
let mut error_messages = String::new();
for error in &errors {
let msg = format!(
"error: {}\n --> {}:{}\n |\n{} | {}\n |{}\n\n",
error.error_message,
error.start.0,
error.start.1,
error.start.0,
error.matched_string,
"^".repeat(error.matched_string.len())
);
error_messages.push_str(&msg);
}
panic!("{}", error_messages);
}
if is_main_component {
ctx.main_component_type_id = self_type_id.clone();
}
let mut tpc = TemplateNodeParseContext {
pascal_identifier_to_type_id_map: template_map,
template: ComponentTemplate::new(
self_type_id.clone(),
Some(component_source_file_path.to_owned()),
),
};
parse_template_from_component_definition_string(&mut tpc, pax);
let modified_module_path = if module_path.starts_with("parser") {
module_path.replacen("parser", "crate", 1)
} else {
module_path.to_string()
};
ctx.template_node_definitions = tpc.template.clone();
let settings = parse_settings_from_component_definition_string(pax);
let new_def = ComponentDefinition {
is_primitive: false,
is_struct_only_component: false,
is_main_component,
primitive_instance_import_path: None,
type_id: self_type_id,
template: Some(tpc.template),
settings: Some(settings),
module_path: modified_module_path,
};
(ctx, new_def)
}
pub fn clean_module_path(module_path: &str) -> String {
if module_path.starts_with("parser") {
module_path.replacen("parser", "crate", 1)
} else {
module_path.to_string()
}
}
pub fn assemble_struct_only_component_definition(
ctx: ParsingContext,
module_path: &str,
self_type_id: TypeId,
) -> (ParsingContext, ComponentDefinition) {
let modified_module_path = clean_module_path(module_path);
let new_def = ComponentDefinition {
type_id: self_type_id,
is_main_component: false,
is_primitive: false,
is_struct_only_component: true,
module_path: modified_module_path,
primitive_instance_import_path: None,
template: None,
settings: None,
};
(ctx, new_def)
}
pub fn assemble_primitive_definition(
module_path: &str,
primitive_instance_import_path: String,
self_type_id: TypeId,
) -> ComponentDefinition {
let modified_module_path = clean_module_path(module_path);
ComponentDefinition {
is_primitive: true,
is_struct_only_component: false,
primitive_instance_import_path: Some(primitive_instance_import_path),
is_main_component: false,
type_id: self_type_id,
template: None,
settings: None,
module_path: modified_module_path,
}
}
pub fn assemble_type_definition(
mut ctx: ParsingContext,
property_definitions: Vec<PropertyDefinition>,
inner_iterable_type_id: Option<TypeId>,
self_type_id: TypeId,
) -> (ParsingContext, TypeDefinition) {
let new_def = TypeDefinition {
type_id: self_type_id.clone(),
inner_iterable_type_id,
property_definitions,
};
ctx.type_table.insert(self_type_id, new_def.clone());
(ctx, new_def)
}
fn span_to_location(span: &Span) -> LocationInfo {
let start = (
span.start_pos().line_col().0 - 1,
span.start_pos().line_col().1 - 1,
);
let end = (
span.end_pos().line_col().0 - 1,
span.end_pos().line_col().1 - 1,
);
LocationInfo {
start_line_col: start,
end_line_col: end,
}
}
pub trait Reflectable {
fn parse_to_manifest(mut ctx: ParsingContext) -> (ParsingContext, Vec<PropertyDefinition>) {
let type_id = Self::get_type_id();
let td = TypeDefinition {
type_id: type_id.clone(),
inner_iterable_type_id: None,
property_definitions: vec![],
};
if !ctx.type_table.contains_key(&type_id) {
ctx.type_table.insert(type_id, td);
}
(ctx, vec![])
}
fn get_import_path() -> String {
Self::get_self_pascal_identifier()
}
fn get_self_pascal_identifier() -> String;
fn get_type_id() -> TypeId;
fn get_iterable_type_id() -> Option<TypeId> {
None
}
}
impl Reflectable for usize {
fn get_self_pascal_identifier() -> String {
"usize".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_primitive(&Self::get_self_pascal_identifier())
}
}
impl Reflectable for isize {
fn get_self_pascal_identifier() -> String {
"isize".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_primitive(&Self::get_self_pascal_identifier())
}
}
impl Reflectable for i128 {
fn get_self_pascal_identifier() -> String {
"i128".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_primitive(&Self::get_self_pascal_identifier())
}
}
impl Reflectable for u128 {
fn get_self_pascal_identifier() -> String {
"u128".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_primitive(&Self::get_self_pascal_identifier())
}
}
impl Reflectable for i64 {
fn get_self_pascal_identifier() -> String {
"i64".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_primitive(&Self::get_self_pascal_identifier())
}
}
impl Reflectable for u64 {
fn get_self_pascal_identifier() -> String {
"u64".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_primitive(&Self::get_self_pascal_identifier())
}
}
impl Reflectable for i32 {
fn get_self_pascal_identifier() -> String {
"i32".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_primitive(&Self::get_self_pascal_identifier())
}
}
impl Reflectable for u32 {
fn get_self_pascal_identifier() -> String {
"u32".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_primitive(&Self::get_self_pascal_identifier())
}
}
impl Reflectable for i8 {
fn get_self_pascal_identifier() -> String {
"i8".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_primitive(&Self::get_self_pascal_identifier())
}
}
impl Reflectable for u8 {
fn get_self_pascal_identifier() -> String {
"u8".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_primitive(&Self::get_self_pascal_identifier())
}
}
impl Reflectable for f64 {
fn get_self_pascal_identifier() -> String {
"f64".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_primitive(&&Self::get_self_pascal_identifier())
}
}
impl Reflectable for f32 {
fn get_self_pascal_identifier() -> String {
"f32".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_primitive(&Self::get_self_pascal_identifier())
}
}
impl Reflectable for bool {
fn get_self_pascal_identifier() -> String {
"bool".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_primitive(&Self::get_self_pascal_identifier())
}
}
impl Reflectable for std::string::String {
fn get_import_path() -> String {
"std::string::String".to_string()
}
fn get_self_pascal_identifier() -> String {
"String".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_singleton(
&Self::get_import_path(),
Some(&Self::get_self_pascal_identifier()),
)
}
}
impl<T> Reflectable for std::rc::Rc<T> {
fn get_import_path() -> String {
"std::rc::Rc".to_string()
}
fn get_self_pascal_identifier() -> String {
"Rc".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_singleton(
&Self::get_import_path(),
Some(&Self::get_self_pascal_identifier()),
)
}
}
impl<T: Reflectable> Reflectable for std::option::Option<T> {
fn parse_to_manifest(mut ctx: ParsingContext) -> (ParsingContext, Vec<PropertyDefinition>) {
let type_id = Self::get_type_id();
let td = TypeDefinition {
type_id: type_id.clone(),
inner_iterable_type_id: None,
property_definitions: vec![],
};
if !ctx.type_table.contains_key(&type_id) {
ctx.type_table.insert(type_id, td);
}
let (ctx, _) = T::parse_to_manifest(ctx);
(ctx, vec![]) }
fn get_import_path() -> String {
"std::option::Option".to_string()
}
fn get_self_pascal_identifier() -> String {
"Option".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_option(&format!("{}{}", "{PREFIX}", &T::get_type_id()))
}
}
impl Reflectable for TypeId {
fn get_import_path() -> String {
"pax_manifest::TypeId".to_string()
}
fn get_self_pascal_identifier() -> String {
"TypeId".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_singleton(
&Self::get_import_path(),
Some(&Self::get_self_pascal_identifier()),
)
}
}
impl Reflectable for TemplateNodeId {
fn get_import_path() -> String {
"pax_manifest::TemplateNodeId".to_string()
}
fn get_self_pascal_identifier() -> String {
"TemplateNodeId".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_singleton(
&Self::get_import_path(),
Some(&Self::get_self_pascal_identifier()),
)
}
}
impl Reflectable for pax_runtime::api::Size {
fn get_import_path() -> String {
"pax_engine::api::Size".to_string()
}
fn get_self_pascal_identifier() -> String {
"Size".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_singleton(
&Self::get_import_path(),
Some(&Self::get_self_pascal_identifier()),
)
}
}
impl Reflectable for pax_runtime::api::Color {
fn get_import_path() -> String {
"pax_engine::api::Color".to_string()
}
fn get_self_pascal_identifier() -> String {
"Color".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_singleton(
&Self::get_import_path(),
Some(&Self::get_self_pascal_identifier()),
)
}
}
impl Reflectable for pax_runtime::api::ColorChannel {
fn get_import_path() -> String {
"pax_engine::api::ColorChannel".to_string()
}
fn get_self_pascal_identifier() -> String {
"ColorChannel".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_singleton(
&Self::get_import_path(),
Some(&Self::get_self_pascal_identifier()),
)
}
}
impl Reflectable for pax_runtime::api::Rotation {
fn get_import_path() -> String {
"pax_engine::api::Rotation".to_string()
}
fn get_self_pascal_identifier() -> String {
"Rotation".to_string()
}
fn get_type_id() -> TypeId {
let type_id = TypeId::build_singleton(
&Self::get_import_path(),
Some(&Self::get_self_pascal_identifier()),
);
type_id
}
}
impl Reflectable for pax_runtime::api::Numeric {
fn get_import_path() -> String {
"pax_engine::api::Numeric".to_string()
}
fn get_self_pascal_identifier() -> String {
"Numeric".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_singleton(
&Self::get_import_path(),
Some(&Self::get_self_pascal_identifier()),
)
}
}
impl Reflectable for kurbo::Point {
fn get_import_path() -> String {
"kurbo::Point".to_string()
}
fn get_self_pascal_identifier() -> String {
"Point".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_singleton(
&Self::get_import_path(),
Some(&Self::get_self_pascal_identifier()),
)
}
}
impl Reflectable for pax_runtime::api::Transform2D {
fn get_import_path() -> String {
"pax_engine::api::Transform2D".to_string()
}
fn get_self_pascal_identifier() -> String {
"Transform2D".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_singleton(
&Self::get_import_path(),
Some(&Self::get_self_pascal_identifier()),
)
}
}
impl Reflectable for pax_runtime::api::StringBox {
fn get_import_path() -> String {
"pax_engine::api::StringBox".to_string()
}
fn get_self_pascal_identifier() -> String {
"StringBox".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_singleton(
&Self::get_import_path(),
Some(&Self::get_self_pascal_identifier()),
)
}
}
impl<T: Reflectable> Reflectable for std::vec::Vec<T> {
fn parse_to_manifest(mut ctx: ParsingContext) -> (ParsingContext, Vec<PropertyDefinition>) {
let type_id = Self::get_type_id();
let td = TypeDefinition {
type_id: type_id.clone(),
inner_iterable_type_id: Self::get_iterable_type_id(),
property_definitions: vec![],
};
if !ctx.type_table.contains_key(&type_id) {
ctx.type_table.insert(type_id, td);
}
T::parse_to_manifest(ctx)
}
fn get_import_path() -> String {
"std::vec::Vec".to_string()
}
fn get_self_pascal_identifier() -> String {
"Vec".to_string()
}
fn get_type_id() -> TypeId {
TypeId::build_vector(&format!(
"{}{}",
"{PREFIX}",
&Self::get_iterable_type_id().unwrap()
))
}
fn get_iterable_type_id() -> Option<TypeId> {
Some(T::get_type_id())
}
}