Add map parsing
This commit is contained in:
parent
7ee7a083ae
commit
32028acab2
@ -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))
|
||||||
}
|
}
|
||||||
|
@ -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())
|
||||||
|
@ -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);
|
||||||
|
130
src/parser.rs
130
src/parser.rs
@ -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!(
|
||||||
|
Loading…
Reference in New Issue
Block a user