Add map parsing

This commit is contained in:
Jeff 2024-03-07 16:13:15 -05:00
parent 7ee7a083ae
commit 32028acab2
4 changed files with 111 additions and 51 deletions

View File

@ -19,8 +19,8 @@ impl<'src> Index<'src> {
} }
impl<'src> AbstractTree for Index<'src> { impl<'src> AbstractTree for Index<'src> {
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
let left_type = self.left.expected_type(context)?; let left_type = self.left.expected_type(_context)?;
if let ( if let (
Expression::Value(ValueNode::List(expression_list)), Expression::Value(ValueNode::List(expression_list)),
@ -33,7 +33,7 @@ impl<'src> AbstractTree for Index<'src> {
return Ok(Type::None); return Ok(Type::None);
}; };
expression.expected_type(context) expression.expected_type(_context)
} else { } else {
Err(ValidationError::CannotIndex(left_type)) Err(ValidationError::CannotIndex(left_type))
} }

View File

@ -48,11 +48,11 @@ impl<'src> AbstractTree for Math<'src> {
} }
} }
fn run(self, context: &Context) -> Result<Value, RuntimeError> { fn run(self, _context: &Context) -> Result<Value, RuntimeError> {
match self { match self {
Math::Add(left, right) => { Math::Add(left, right) => {
let left_value = left.run(context)?; let left_value = left.run(_context)?;
let right_value = right.run(context)?; let right_value = right.run(_context)?;
if let (ValueInner::Integer(left), ValueInner::Integer(right)) = if let (ValueInner::Integer(left), ValueInner::Integer(right)) =
(left_value.inner().as_ref(), right_value.inner().as_ref()) (left_value.inner().as_ref(), right_value.inner().as_ref())
@ -65,8 +65,8 @@ impl<'src> AbstractTree for Math<'src> {
} }
} }
Math::Subtract(left, right) => { Math::Subtract(left, right) => {
let left_value = left.run(context)?; let left_value = left.run(_context)?;
let right_value = right.run(context)?; let right_value = right.run(_context)?;
if let (ValueInner::Integer(left), ValueInner::Integer(right)) = if let (ValueInner::Integer(left), ValueInner::Integer(right)) =
(left_value.inner().as_ref(), right_value.inner().as_ref()) (left_value.inner().as_ref(), right_value.inner().as_ref())
@ -79,8 +79,8 @@ impl<'src> AbstractTree for Math<'src> {
} }
} }
Math::Multiply(left, right) => { Math::Multiply(left, right) => {
let left_value = left.run(context)?; let left_value = left.run(_context)?;
let right_value = right.run(context)?; let right_value = right.run(_context)?;
if let (ValueInner::Integer(left), ValueInner::Integer(right)) = if let (ValueInner::Integer(left), ValueInner::Integer(right)) =
(left_value.inner().as_ref(), right_value.inner().as_ref()) (left_value.inner().as_ref(), right_value.inner().as_ref())
@ -93,8 +93,8 @@ impl<'src> AbstractTree for Math<'src> {
} }
} }
Math::Divide(left, right) => { Math::Divide(left, right) => {
let left_value = left.run(context)?; let left_value = left.run(_context)?;
let right_value = right.run(context)?; let right_value = right.run(_context)?;
if let (ValueInner::Integer(left), ValueInner::Integer(right)) = if let (ValueInner::Integer(left), ValueInner::Integer(right)) =
(left_value.inner().as_ref(), right_value.inner().as_ref()) (left_value.inner().as_ref(), right_value.inner().as_ref())
@ -107,8 +107,8 @@ impl<'src> AbstractTree for Math<'src> {
} }
} }
Math::Modulo(left, right) => { Math::Modulo(left, right) => {
let left_value = left.run(context)?; let left_value = left.run(_context)?;
let right_value = right.run(context)?; let right_value = right.run(_context)?;
if let (ValueInner::Integer(left), ValueInner::Integer(right)) = if let (ValueInner::Integer(left), ValueInner::Integer(right)) =
(left_value.inner().as_ref(), right_value.inner().as_ref()) (left_value.inner().as_ref(), right_value.inner().as_ref())

View File

@ -14,7 +14,7 @@ pub enum ValueNode<'src> {
Float(f64), Float(f64),
Integer(i64), Integer(i64),
List(Vec<Expression<'src>>), List(Vec<Expression<'src>>),
Map(Vec<(Identifier, Expression<'src>)>), Map(Vec<(Identifier, Option<Type>, Expression<'src>)>),
Range(Range<i64>), Range(Range<i64>),
String(&'src str), String(&'src str),
Enum(Identifier, Identifier), Enum(Identifier, Identifier),
@ -67,7 +67,7 @@ impl<'src> AbstractTree for ValueNode<'src> {
ValueNode::Map(property_list) => { ValueNode::Map(property_list) => {
let mut property_map = BTreeMap::new(); let mut property_map = BTreeMap::new();
for (identifier, expression) in property_list { for (identifier, _type, expression) in property_list {
let value = expression.run(_context)?; let value = expression.run(_context)?;
property_map.insert(identifier, value); property_map.insert(identifier, value);

View File

@ -47,6 +47,39 @@ pub fn parser<'src>() -> DustParser<'src> {
} }
}; };
let basic_type = choice((
just(Token::Keyword("bool")).to(Type::Boolean),
just(Token::Keyword("float")).to(Type::Float),
just(Token::Keyword("int")).to(Type::Integer),
just(Token::Keyword("range")).to(Type::Range),
just(Token::Keyword("str")).to(Type::String),
just(Token::Keyword("list")).to(Type::List),
));
let type_arguments = basic_type.clone().delimited_by(
just(Token::Control(Control::ParenOpen)),
just(Token::Control(Control::ParenClose)),
);
let type_specification = just(Token::Control(Control::Colon)).ignore_then(choice((
basic_type
.clone()
.separated_by(just(Token::Control(Control::Comma)))
.collect()
.delimited_by(
just(Token::Control(Control::SquareOpen)),
just(Token::Control(Control::SquareClose)),
)
.map(|types| Type::ListExact(types)),
just(Token::Keyword("list"))
.then(type_arguments)
.map(|(_, item_type)| Type::ListOf(Box::new(item_type))),
basic_type.clone(),
identifier
.clone()
.map(|identifier| Type::Custom(identifier)),
)));
let expression = recursive(|expression| { let expression = recursive(|expression| {
let basic_value = select! { let basic_value = select! {
Token::Boolean(boolean) => ValueNode::Boolean(boolean), Token::Boolean(boolean) => ValueNode::Boolean(boolean),
@ -74,6 +107,23 @@ pub fn parser<'src>() -> DustParser<'src> {
.map(|list| Expression::Value(ValueNode::List(list))) .map(|list| Expression::Value(ValueNode::List(list)))
.boxed(); .boxed();
let map_assignment = identifier
.clone()
.then(type_specification.clone().or_not())
.then_ignore(just(Token::Operator(Operator::Assign)))
.then(expression.clone())
.map(|((identifier, r#type), expression)| (identifier, r#type, expression));
let map = map_assignment
.separated_by(just(Token::Control(Control::Comma)).or_not())
.allow_trailing()
.collect()
.delimited_by(
just(Token::Control(Control::CurlyOpen)),
just(Token::Control(Control::CurlyClose)),
)
.map(|map_assigment_list| Expression::Value(ValueNode::Map(map_assigment_list)));
let r#enum = identifier let r#enum = identifier
.clone() .clone()
.then_ignore(just(Token::Control(Control::DoubleColon))) .then_ignore(just(Token::Control(Control::DoubleColon)))
@ -94,7 +144,7 @@ pub fn parser<'src>() -> DustParser<'src> {
use Operator::*; use Operator::*;
let logic_and_math = atom let logic_math_and_index = atom
.pratt(( .pratt((
prefix(2, just(Token::Operator(Not)), |expression| { prefix(2, just(Token::Operator(Not)), |expression| {
Expression::Logic(Box::new(Logic::Not(expression))) Expression::Logic(Box::new(Logic::Not(expression)))
@ -152,9 +202,10 @@ pub fn parser<'src>() -> DustParser<'src> {
choice(( choice((
r#enum, r#enum,
logic_and_math, logic_math_and_index,
identifier_expression, identifier_expression,
list, list,
map,
basic_value, basic_value,
)) ))
}); });
@ -164,39 +215,6 @@ pub fn parser<'src>() -> DustParser<'src> {
.map(|expression| Statement::Expression(expression)) .map(|expression| Statement::Expression(expression))
.boxed(); .boxed();
let basic_type = choice((
just(Token::Keyword("bool")).to(Type::Boolean),
just(Token::Keyword("float")).to(Type::Float),
just(Token::Keyword("int")).to(Type::Integer),
just(Token::Keyword("range")).to(Type::Range),
just(Token::Keyword("str")).to(Type::String),
just(Token::Keyword("list")).to(Type::List),
));
let type_arguments = basic_type.clone().delimited_by(
just(Token::Control(Control::ParenOpen)),
just(Token::Control(Control::ParenClose)),
);
let type_specification = just(Token::Control(Control::Colon)).ignore_then(choice((
basic_type
.clone()
.separated_by(just(Token::Control(Control::Comma)))
.collect()
.delimited_by(
just(Token::Control(Control::SquareOpen)),
just(Token::Control(Control::SquareClose)),
)
.map(|types| Type::ListExact(types)),
just(Token::Keyword("list"))
.then(type_arguments)
.map(|(_, item_type)| Type::ListOf(Box::new(item_type))),
basic_type.clone(),
identifier
.clone()
.map(|identifier| Type::Custom(identifier)),
)));
let assignment = identifier let assignment = identifier
.then(type_specification.clone().or_not()) .then(type_specification.clone().or_not())
.then_ignore(just(Token::Operator(Operator::Assign))) .then_ignore(just(Token::Operator(Operator::Assign)))
@ -245,6 +263,48 @@ mod tests {
use super::*; use super::*;
#[test]
fn map() {
assert_eq!(
parse(&lex("{ foo = 'bar' }").unwrap()).unwrap()[0].0,
Statement::Expression(Expression::Value(ValueNode::Map(vec![(
Identifier::new("foo"),
None,
Expression::Value(ValueNode::String("bar"))
)])))
);
assert_eq!(
parse(&lex("{ x = 1, y = 2, }").unwrap()).unwrap()[0].0,
Statement::Expression(Expression::Value(ValueNode::Map(vec![
(
Identifier::new("x"),
None,
Expression::Value(ValueNode::Integer(1))
),
(
Identifier::new("y"),
None,
Expression::Value(ValueNode::Integer(2))
),
])))
);
assert_eq!(
parse(&lex("{ x = 1 y = 2 }").unwrap()).unwrap()[0].0,
Statement::Expression(Expression::Value(ValueNode::Map(vec![
(
Identifier::new("x"),
None,
Expression::Value(ValueNode::Integer(1))
),
(
Identifier::new("y"),
None,
Expression::Value(ValueNode::Integer(2))
),
])))
);
}
#[test] #[test]
fn math() { fn math() {
assert_eq!( assert_eq!(