Implement structure parsing

This commit is contained in:
Jeff 2024-03-19 18:31:52 -04:00
parent 16d443d8a6
commit bcc89f2c7d
10 changed files with 153 additions and 47 deletions

View File

@ -65,7 +65,7 @@ impl AbstractTree for FunctionCall {
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedFunction {
actual: value.r#type(),
actual: value.r#type(context)?,
position: self.function.position,
},
));

View File

@ -63,8 +63,8 @@ impl AbstractTree for IfElse {
}
}
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
let action = self.if_expression.node.run(_context)?;
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
let action = self.if_expression.node.run(context)?;
let value = if let Action::Return(value) = action {
value
} else {
@ -75,16 +75,16 @@ impl AbstractTree for IfElse {
if let ValueInner::Boolean(if_boolean) = value.inner().as_ref() {
if *if_boolean {
self.if_block.run(_context)
self.if_block.run(context)
} else if let Some(else_statement) = self.else_block {
else_statement.run(_context)
else_statement.run(context)
} else {
Ok(Action::None)
}
} else {
Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedBoolean {
actual: value.r#type(),
actual: value.r#type(context)?,
position: self.if_expression.position,
},
))

View File

@ -68,8 +68,8 @@ impl AbstractTree for ListIndex {
}
}
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
let left_action = self.left.node.run(_context)?;
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
let left_action = self.left.node.run(context)?;
let left_value = if let Action::Return(value) = left_action {
value
} else {
@ -77,7 +77,7 @@ impl AbstractTree for ListIndex {
ValidationError::InterpreterExpectedReturn(self.left.position),
));
};
let right_action = self.right.node.run(_context)?;
let right_action = self.right.node.run(context)?;
let right_value = if let Action::Return(value) = right_action {
value
} else {
@ -97,9 +97,9 @@ impl AbstractTree for ListIndex {
} else {
Err(RuntimeError::ValidationFailure(
ValidationError::CannotIndexWith {
collection_type: left_value.r#type(),
collection_type: left_value.r#type(context)?,
collection_position: self.left.position,
index_type: right_value.r#type(),
index_type: right_value.r#type(context)?,
index_position: self.right.position,
},
))

View File

@ -83,10 +83,10 @@ impl AbstractTree for Logic {
}
}
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
let run_and_expect_value =
|expression: WithPosition<Expression>| -> Result<Value, RuntimeError> {
let action = expression.node.run(_context)?;
let action = expression.node.run(context)?;
let value = if let Action::Return(value) = action {
value
} else {
@ -100,7 +100,7 @@ impl AbstractTree for Logic {
let run_and_expect_boolean =
|expression: WithPosition<Expression>| -> Result<bool, RuntimeError> {
let action = expression.node.run(_context)?;
let action = expression.node.run(context)?;
let value = if let Action::Return(value) = action {
value
} else {
@ -114,7 +114,7 @@ impl AbstractTree for Logic {
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedBoolean {
actual: value.r#type(),
actual: value.r#type(context)?,
position: expression.position,
},
));

View File

@ -19,15 +19,15 @@ impl MapIndex {
}
impl AbstractTree for MapIndex {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
let left_type = self.left.node.expected_type(_context)?;
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
let left_type = self.left.node.expected_type(context)?;
if let (
Expression::Identifier(collection_identifier),
Expression::Identifier(index_identifier),
) = (&self.left.node, &self.right.node)
{
let collection = if let Some(collection) = _context.get_value(collection_identifier)? {
let collection = if let Some(collection) = context.get_value(collection_identifier)? {
collection
} else {
return Err(ValidationError::VariableNotFound(
@ -37,7 +37,7 @@ impl AbstractTree for MapIndex {
if let ValueInner::Map(map) = collection.inner().as_ref() {
return if let Some(value) = map.get(index_identifier) {
Ok(value.r#type())
Ok(value.r#type(context)?)
} else {
Err(ValidationError::PropertyNotFound {
identifier: index_identifier.clone(),
@ -56,9 +56,9 @@ impl AbstractTree for MapIndex {
.find_map(|(property, type_option, expression)| {
if property == identifier {
if let Some(r#type) = type_option {
Some(r#type.node.expected_type(_context))
Some(r#type.node.expected_type(context))
} else {
Some(expression.node.expected_type(_context))
Some(expression.node.expected_type(context))
}
} else {
None
@ -74,7 +74,7 @@ impl AbstractTree for MapIndex {
Err(ValidationError::CannotIndexWith {
collection_type: left_type,
collection_position: self.left.position,
index_type: self.right.node.expected_type(_context)?,
index_type: self.right.node.expected_type(context)?,
index_position: self.right.position,
})
}
@ -100,8 +100,8 @@ impl AbstractTree for MapIndex {
}
}
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
let action = self.left.node.run(_context)?;
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
let action = self.left.node.run(context)?;
let collection = if let Action::Return(value) = action {
value
} else {
@ -122,9 +122,9 @@ impl AbstractTree for MapIndex {
} else {
Err(RuntimeError::ValidationFailure(
ValidationError::CannotIndexWith {
collection_type: collection.r#type(),
collection_type: collection.r#type(context)?,
collection_position: self.left.position,
index_type: self.right.node.expected_type(_context)?,
index_type: self.right.node.expected_type(context)?,
index_position: self.right.position,
},
))

View File

@ -25,7 +25,7 @@ pub enum ValueNode {
String(String),
Structure {
name: Identifier,
fields: Vec<(Identifier, Type)>,
fields: Vec<(Identifier, WithPosition<Expression>)>,
},
Function {
parameters: Vec<(Identifier, WithPosition<Type>)>,
@ -244,14 +244,6 @@ impl Ord for ValueNode {
fields: right_fields,
},
) => todo!(),
(
Structure { name, fields },
Function {
parameters,
return_type,
body,
},
) => todo!(),
(Structure { name, fields }, _) => todo!(),
}
}

View File

@ -5,7 +5,7 @@ use std::{
use crate::{
abstract_tree::{Identifier, Type},
error::RwLockPoisonError,
error::{RwLockPoisonError, ValidationError},
value::{BUILT_IN_FUNCTIONS, BUILT_IN_MODULES},
Value,
};
@ -72,11 +72,11 @@ impl Context {
}
}
pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, RwLockPoisonError> {
pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, ValidationError> {
if let Some(value_data) = self.inner.read()?.get(identifier) {
let r#type = match value_data {
ValueData::Type(r#type) => r#type.clone(),
ValueData::Value(value) => value.r#type(),
ValueData::Value(value) => value.r#type(self)?,
};
return Ok(Some(r#type.clone()));

View File

@ -291,6 +291,12 @@ impl From<RwLockPoisonError> for ValidationError {
}
}
impl<T> From<PoisonError<T>> for ValidationError {
fn from(_: PoisonError<T>) -> Self {
ValidationError::RwLockPoison(RwLockPoisonError)
}
}
#[derive(Debug, PartialEq)]
pub struct RwLockPoisonError;

View File

@ -336,7 +336,30 @@ pub fn parser<'src>() -> impl Parser<
),
));
let structure_field = identifier
.clone()
.then_ignore(just(Token::Operator(Operator::Assign)))
.then(positioned_expression.clone());
let structure_instance = identifier
.clone()
.then(
structure_field
.separated_by(just(Token::Control(Control::Comma)))
.allow_trailing()
.collect()
.delimited_by(
just(Token::Control(Control::CurlyOpen)),
just(Token::Control(Control::CurlyClose)),
),
)
.map_with(|(name, fields), state| {
Expression::Value(ValueNode::Structure { name, fields })
.with_position(state.span())
});
choice((
structure_instance,
range,
logic_math_indexes_and_function_calls,
function,
@ -417,12 +440,12 @@ pub fn parser<'src>() -> impl Parser<
.with_position(state.span())
});
let structure_field = identifier.clone().then(type_specification.clone());
let structure_field_definition = identifier.clone().then(type_specification.clone());
let structure_definition = just(Token::Keyword("struct"))
.ignore_then(identifier.clone())
.then(
structure_field
structure_field_definition
.separated_by(just(Token::Control(Control::Comma)))
.allow_trailing()
.collect()
@ -458,6 +481,37 @@ mod tests {
use super::*;
#[test]
fn structure_instance() {
assert_eq!(
parse(
&lex("
Foo {
bar = 42,
baz = 'hiya',
}
")
.unwrap()
)
.unwrap()[0]
.node,
Statement::Expression(Expression::Value(ValueNode::Structure {
name: Identifier::new("Foo"),
fields: vec![
(
Identifier::new("bar"),
Expression::Value(ValueNode::Integer(42)).with_position((57, 59))
),
(
Identifier::new("baz"),
Expression::Value(ValueNode::String("hiya".to_string()))
.with_position((91, 97))
),
]
}))
)
}
#[test]
fn structure_definition() {
assert_eq!(

View File

@ -15,7 +15,7 @@ use stanza::{
};
use crate::{
abstract_tree::{AbstractTree, Action, Block, Identifier, Type, WithPosition},
abstract_tree::{AbstractTree, Action, Block, Expression, Identifier, Type, WithPosition},
context::Context,
error::{RuntimeError, ValidationError},
};
@ -74,8 +74,8 @@ impl Value {
Value(Arc::new(ValueInner::Function(Function::BuiltIn(function))))
}
pub fn r#type(&self) -> Type {
match self.0.as_ref() {
pub fn r#type(&self, context: &Context) -> Result<Type, ValidationError> {
let r#type = match self.0.as_ref() {
ValueInner::Boolean(_) => Type::Boolean,
ValueInner::Float(_) => Type::Float,
ValueInner::Integer(_) => Type::Integer,
@ -83,7 +83,7 @@ impl Value {
let mut types = Vec::with_capacity(values.len());
for value in values {
types.push(value.r#type());
types.push(value.r#type(context)?);
}
Type::ListExact(types)
@ -102,7 +102,29 @@ impl Value {
},
Function::BuiltIn(built_in_function) => built_in_function.r#type(),
},
}
ValueInner::Structure {
name,
fields: expressions,
} => {
let mut fields = Vec::with_capacity(expressions.len());
for (identifier, expression) in expressions {
let r#type = expression
.node
.expected_type(context)?
.with_position(expression.position);
fields.push((identifier.clone(), r#type));
}
Type::Structure {
name: name.clone(),
fields,
}
}
};
Ok(r#type)
}
pub fn as_boolean(&self) -> Option<bool> {
@ -176,6 +198,7 @@ impl Display for Value {
ValueInner::Function(Function::BuiltIn(built_in_function)) => {
write!(f, "{built_in_function}")
}
ValueInner::Structure { name, fields } => todo!(),
}
}
}
@ -204,6 +227,10 @@ pub enum ValueInner {
Map(BTreeMap<Identifier, Value>),
Range(Range<i64>),
String(String),
Structure {
name: Identifier,
fields: Vec<(Identifier, WithPosition<Expression>)>,
},
}
impl Eq for ValueInner {}
@ -243,6 +270,25 @@ impl Ord for ValueInner {
(String(_), _) => Ordering::Greater,
(Function(left), Function(right)) => left.cmp(right),
(Function(_), _) => Ordering::Greater,
(
Structure {
name: left_name,
fields: left_fields,
},
Structure {
name: right_name,
fields: right_fields,
},
) => {
let name_cmp = left_name.cmp(right_name);
if name_cmp.is_eq() {
left_fields.cmp(right_fields)
} else {
name_cmp
}
}
(Structure { .. }, _) => Ordering::Greater,
}
}
}
@ -347,7 +393,7 @@ impl BuiltInFunction {
}
}
pub fn call(&self, arguments: Vec<Value>, _context: &Context) -> Result<Action, RuntimeError> {
pub fn call(&self, arguments: Vec<Value>, context: &Context) -> Result<Action, RuntimeError> {
match self {
BuiltInFunction::IntParse => {
let string = arguments.get(0).unwrap();
@ -359,10 +405,18 @@ impl BuiltInFunction {
// Ok(Action::Return(Value::integer(integer)))
} else {
let mut actual = Vec::with_capacity(arguments.len());
for value in arguments {
let r#type = value.r#type(context)?;
actual.push(r#type);
}
Err(RuntimeError::ValidationFailure(
ValidationError::WrongArguments {
expected: vec![Type::String],
actual: arguments.iter().map(|value| value.r#type()).collect(),
actual,
},
))
}