1
0

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 { } else {
return Err(RuntimeError::ValidationFailure( return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedFunction { ValidationError::ExpectedFunction {
actual: value.r#type(), actual: value.r#type(context)?,
position: self.function.position, position: self.function.position,
}, },
)); ));

View File

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

View File

@ -68,8 +68,8 @@ impl AbstractTree for ListIndex {
} }
} }
fn run(self, _context: &Context) -> Result<Action, RuntimeError> { fn run(self, context: &Context) -> Result<Action, RuntimeError> {
let left_action = self.left.node.run(_context)?; let left_action = self.left.node.run(context)?;
let left_value = if let Action::Return(value) = left_action { let left_value = if let Action::Return(value) = left_action {
value value
} else { } else {
@ -77,7 +77,7 @@ impl AbstractTree for ListIndex {
ValidationError::InterpreterExpectedReturn(self.left.position), 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 { let right_value = if let Action::Return(value) = right_action {
value value
} else { } else {
@ -97,9 +97,9 @@ impl AbstractTree for ListIndex {
} else { } else {
Err(RuntimeError::ValidationFailure( Err(RuntimeError::ValidationFailure(
ValidationError::CannotIndexWith { ValidationError::CannotIndexWith {
collection_type: left_value.r#type(), collection_type: left_value.r#type(context)?,
collection_position: self.left.position, collection_position: self.left.position,
index_type: right_value.r#type(), index_type: right_value.r#type(context)?,
index_position: self.right.position, 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 = let run_and_expect_value =
|expression: WithPosition<Expression>| -> Result<Value, RuntimeError> { |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 { let value = if let Action::Return(value) = action {
value value
} else { } else {
@ -100,7 +100,7 @@ impl AbstractTree for Logic {
let run_and_expect_boolean = let run_and_expect_boolean =
|expression: WithPosition<Expression>| -> Result<bool, RuntimeError> { |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 { let value = if let Action::Return(value) = action {
value value
} else { } else {
@ -114,7 +114,7 @@ impl AbstractTree for Logic {
} else { } else {
return Err(RuntimeError::ValidationFailure( return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedBoolean { ValidationError::ExpectedBoolean {
actual: value.r#type(), actual: value.r#type(context)?,
position: expression.position, position: expression.position,
}, },
)); ));

View File

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

View File

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

View File

@ -5,7 +5,7 @@ use std::{
use crate::{ use crate::{
abstract_tree::{Identifier, Type}, abstract_tree::{Identifier, Type},
error::RwLockPoisonError, error::{RwLockPoisonError, ValidationError},
value::{BUILT_IN_FUNCTIONS, BUILT_IN_MODULES}, value::{BUILT_IN_FUNCTIONS, BUILT_IN_MODULES},
Value, 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) { if let Some(value_data) = self.inner.read()?.get(identifier) {
let r#type = match value_data { let r#type = match value_data {
ValueData::Type(r#type) => r#type.clone(), 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())); 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)] #[derive(Debug, PartialEq)]
pub struct RwLockPoisonError; 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(( choice((
structure_instance,
range, range,
logic_math_indexes_and_function_calls, logic_math_indexes_and_function_calls,
function, function,
@ -417,12 +440,12 @@ pub fn parser<'src>() -> impl Parser<
.with_position(state.span()) .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")) let structure_definition = just(Token::Keyword("struct"))
.ignore_then(identifier.clone()) .ignore_then(identifier.clone())
.then( .then(
structure_field structure_field_definition
.separated_by(just(Token::Control(Control::Comma))) .separated_by(just(Token::Control(Control::Comma)))
.allow_trailing() .allow_trailing()
.collect() .collect()
@ -458,6 +481,37 @@ mod tests {
use super::*; 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] #[test]
fn structure_definition() { fn structure_definition() {
assert_eq!( assert_eq!(

View File

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