Fix variable context bugs

This commit is contained in:
Jeff 2024-01-09 20:38:40 -05:00
parent d8850b2d3c
commit b7db177bd2
16 changed files with 78 additions and 96 deletions

View File

@ -47,7 +47,7 @@ impl AbstractTree for Assignment {
}; };
if let AssignmentOperator::Equal = operator { if let AssignmentOperator::Equal = operator {
context.set(variable_key, Value::none(), Some(variable_type))?; context.set_type(variable_key, variable_type)?;
} }
Ok(Assignment { Ok(Assignment {
@ -82,7 +82,9 @@ impl AbstractTree for Assignment {
} }
AssignmentOperator::PlusEqual => { AssignmentOperator::PlusEqual => {
if let Type::List(item_type) = type_definition.inner() { if let Type::List(item_type) = type_definition.inner() {
item_type.check(&actual_type)?; item_type.check(&actual_type).map_err(|error| {
error.at_source_position(source, self.syntax_position)
})?;
} else { } else {
type_definition type_definition
.inner() .inner()
@ -98,7 +100,9 @@ impl AbstractTree for Assignment {
match self.operator { match self.operator {
AssignmentOperator::Equal => { AssignmentOperator::Equal => {
if let Some(r#type) = established_type { if let Some(r#type) = established_type {
r#type.check(&actual_type)?; r#type.check(&actual_type).map_err(|error| {
error.at_source_position(source, self.syntax_position)
})?;
} }
} }
AssignmentOperator::PlusEqual => { AssignmentOperator::PlusEqual => {
@ -141,11 +145,7 @@ impl AbstractTree for Assignment {
AssignmentOperator::Equal => value, AssignmentOperator::Equal => value,
}; };
if let Some(type_defintion) = &self.type_definition { context.set(key.clone(), new_value)?;
context.set(key.clone(), new_value, Some(type_defintion.inner().clone()))?;
} else {
context.set(key.clone(), new_value, None)?;
}
Ok(Value::none()) Ok(Value::none())
} }

View File

@ -70,7 +70,6 @@ impl BuiltInValue {
.set( .set(
"read".to_string(), "read".to_string(),
Value::Function(Function::BuiltIn(BuiltInFunction::FsRead)), Value::Function(Function::BuiltIn(BuiltInFunction::FsRead)),
None,
) )
.unwrap(); .unwrap();
@ -83,7 +82,6 @@ impl BuiltInValue {
.set( .set(
BuiltInFunction::JsonParse.name().to_string(), BuiltInFunction::JsonParse.name().to_string(),
Value::Function(Function::BuiltIn(BuiltInFunction::JsonParse)), Value::Function(Function::BuiltIn(BuiltInFunction::JsonParse)),
None,
) )
.unwrap(); .unwrap();

View File

@ -57,7 +57,7 @@ impl AbstractTree for For {
values.par_iter().try_for_each(|value| { values.par_iter().try_for_each(|value| {
let iter_context = Map::clone_from(context)?; let iter_context = Map::clone_from(context)?;
iter_context.set(key.clone(), value.clone(), None)?; iter_context.set(key.clone(), value.clone())?;
self.block.run(source, &iter_context).map(|_value| ()) self.block.run(source, &iter_context).map(|_value| ())
})?; })?;
@ -65,7 +65,7 @@ impl AbstractTree for For {
let loop_context = Map::clone_from(context)?; let loop_context = Map::clone_from(context)?;
for value in values.iter() { for value in values.iter() {
loop_context.set(key.clone(), value.clone(), None)?; loop_context.set(key.clone(), value.clone())?;
self.block.run(source, &loop_context)?; self.block.run(source, &loop_context)?;
} }

View File

@ -54,7 +54,7 @@ impl AbstractTree for FunctionCall {
}) })
} }
fn check_type(&self, _source: &str, context: &Map) -> Result<()> { fn check_type(&self, source: &str, context: &Map) -> Result<()> {
let function_expression_type = self.function_expression.expected_type(context)?; let function_expression_type = self.function_expression.expected_type(context)?;
let parameter_types = match function_expression_type { let parameter_types = match function_expression_type {
@ -65,22 +65,25 @@ impl AbstractTree for FunctionCall {
_ => { _ => {
return Err(Error::TypeCheckExpectedFunction { return Err(Error::TypeCheckExpectedFunction {
actual: function_expression_type, actual: function_expression_type,
}) }
.at_source_position(source, self.syntax_position))
} }
}; };
for (index, expression) in self.arguments.iter().enumerate() {
if let Some(r#type) = parameter_types.get(index) {
r#type.check(&expression.expected_type(context)?)?;
}
}
if self.arguments.len() != parameter_types.len() { if self.arguments.len() != parameter_types.len() {
return Err(Error::ExpectedFunctionArgumentAmount { return Err(Error::ExpectedFunctionArgumentAmount {
expected: parameter_types.len(), expected: parameter_types.len(),
actual: self.arguments.len(), actual: self.arguments.len(),
} }
.at_source_position(_source, self.syntax_position)); .at_source_position(source, self.syntax_position));
}
for (index, expression) in self.arguments.iter().enumerate() {
if let Some(r#type) = parameter_types.get(index) {
r#type
.check(&expression.expected_type(context)?)
.map_err(|error| error.at_source_position(source, self.syntax_position))?;
}
} }
Ok(()) Ok(())
@ -116,10 +119,6 @@ impl AbstractTree for FunctionCall {
arguments.push(value); arguments.push(value);
} }
if let Some(name) = &name {
context.set(name.to_string(), value.clone(), None)?;
}
value.as_function()?.call(name, &arguments, source, context) value.as_function()?.call(name, &arguments, source, context)
} }

View File

@ -23,14 +23,13 @@ impl FunctionNode {
body: Block, body: Block,
r#type: Type, r#type: Type,
syntax_position: SyntaxPosition, syntax_position: SyntaxPosition,
context: Map,
) -> Self { ) -> Self {
Self { Self {
parameters, parameters,
body, body,
r#type, r#type,
syntax_position, syntax_position,
context, context: Map::new(),
} }
} }
@ -63,21 +62,20 @@ impl FunctionNode {
source: &str, source: &str,
outer_context: &Map, outer_context: &Map,
) -> Result<Value> { ) -> Result<Value> {
let parameter_argument_pairs = self.parameters.iter().zip(arguments.iter());
self.context.clone_complex_values_from(outer_context)?; self.context.clone_complex_values_from(outer_context)?;
let parameter_argument_pairs = self.parameters.iter().zip(arguments.iter());
for (identifier, value) in parameter_argument_pairs { for (identifier, value) in parameter_argument_pairs {
let key = identifier.inner().clone(); let key = identifier.inner().clone();
self.context.set(key, value.clone(), None)?; self.context.set(key, value.clone())?;
} }
if let Some(name) = name { if let Some(name) = name {
self.context.set( self.context.set(
name, name,
Value::Function(Function::ContextDefined(self.clone())), Value::Function(Function::ContextDefined(self.clone())),
None,
)?; )?;
} }
@ -111,41 +109,37 @@ impl AbstractTree for FunctionNode {
} }
} }
let return_type_node = node.child(child_count - 2).unwrap();
let return_type = TypeDefinition::from_syntax_node(source, return_type_node, context)?;
let function_context = Map::new(); let function_context = Map::new();
function_context.clone_complex_values_from(context)?; function_context.clone_complex_values_from(context)?;
for (parameter_name, parameter_type) in parameters.iter().zip(parameter_types.iter()) { for (identifier, r#type) in parameters.iter().zip(parameter_types.iter()) {
function_context.set( function_context.set_type(identifier.inner().clone(), r#type.clone())?;
parameter_name.inner().clone(),
Value::none(),
Some(parameter_type.clone()),
)?;
} }
let return_type_node = node.child(child_count - 2).unwrap();
let return_type = TypeDefinition::from_syntax_node(source, return_type_node, context)?;
let body_node = node.child(child_count - 1).unwrap(); let body_node = node.child(child_count - 1).unwrap();
let body = Block::from_syntax_node(source, body_node, &function_context)?; let body = Block::from_syntax_node(source, body_node, &function_context)?;
let r#type = Type::function(parameter_types, return_type.take_inner()); let r#type = Type::function(parameter_types, return_type.take_inner());
let syntax_position = node.range().into(); let syntax_position = node.range().into();
Ok(FunctionNode::new( Ok(FunctionNode {
parameters, parameters,
body, body,
r#type, r#type,
syntax_position, syntax_position,
function_context, context: function_context,
)) })
} }
fn check_type(&self, source: &str, _context: &Map) -> Result<()> { fn check_type(&self, source: &str, context: &Map) -> Result<()> {
self.context.clone_complex_values_from(context)?;
self.return_type() self.return_type()
.check(&self.body.expected_type(&self.context)?) .check(&self.body.expected_type(&self.context)?)
.map_err(|error| error.at_source_position(source, self.syntax_position))?; .map_err(|error| error.at_source_position(source, self.syntax_position))?;
self.body.check_type(source, &self.context)?; self.body.check_type(source, &self.context)?;
Ok(()) Ok(())

View File

@ -45,12 +45,8 @@ impl AbstractTree for Identifier {
} }
} }
fn check_type(&self, _source: &str, context: &Map) -> Result<()> { fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
if let Some(_) = context.variables()?.get(&self.0) { Ok(())
Ok(())
} else {
Err(Error::VariableIdentifierNotFound(self.0.clone()))
}
} }
fn expected_type(&self, context: &Map) -> Result<Type> { fn expected_type(&self, context: &Map) -> Result<Type> {

View File

@ -70,7 +70,7 @@ impl AbstractTree for IndexAssignment {
AssignmentOperator::Equal => value, AssignmentOperator::Equal => value,
}; };
index_context.set(index_key.clone(), new_value, None)?; index_context.set(index_key.clone(), new_value)?;
Ok(Value::none()) Ok(Value::none())
} }

View File

@ -60,9 +60,9 @@ impl From<tree_sitter::Range> for SyntaxPosition {
SyntaxPosition { SyntaxPosition {
start_byte: range.start_byte, start_byte: range.start_byte,
end_byte: range.end_byte, end_byte: range.end_byte,
start_row: range.start_point.row, start_row: range.start_point.row + 1,
start_column: range.start_point.column, start_column: range.start_point.column,
end_row: range.end_point.row, end_row: range.end_point.row + 1,
end_column: range.end_point.column, end_column: range.end_point.column,
} }
} }

View File

@ -232,10 +232,10 @@ impl AbstractTree for ValueNode {
let map = Map::new(); let map = Map::new();
{ {
for (key, (statement, r#type)) in key_statement_pairs { for (key, (statement, _)) in key_statement_pairs {
let value = statement.run(source, context)?; let value = statement.run(source, context)?;
map.set(key.clone(), value, r#type.clone())?; map.set(key.clone(), value)?;
} }
} }

View File

@ -29,9 +29,9 @@ pub fn interpret(source: &str) -> Result<Value> {
/// # use dust_lang::*; /// # use dust_lang::*;
/// let context = Map::new(); /// let context = Map::new();
/// ///
/// context.set("one".into(), 1.into(), None); /// context.set("one".into(), 1.into());
/// context.set("two".into(), 2.into(), None); /// context.set("two".into(), 2.into());
/// context.set("three".into(), 3.into(), None); /// context.set("three".into(), 3.into());
/// ///
/// let dust_code = "four = 4 one + two + three + four"; /// let dust_code = "four = 4 one + two + three + four";
/// ///

View File

@ -64,7 +64,7 @@ fn main() {
if let Some(input) = args.input { if let Some(input) = args.input {
context context
.set("input".to_string(), Value::string(input), None) .set("input".to_string(), Value::string(input))
.unwrap(); .unwrap();
} }
@ -72,7 +72,7 @@ fn main() {
let file_contents = read_to_string(path).unwrap(); let file_contents = read_to_string(path).unwrap();
context context
.set("input".to_string(), Value::string(file_contents), None) .set("input".to_string(), Value::string(file_contents))
.unwrap(); .unwrap();
} }

View File

@ -64,13 +64,8 @@ impl Map {
Ok(self.variables.write()?) Ok(self.variables.write()?)
} }
pub fn set( pub fn set(&self, key: String, value: Value) -> Result<Option<(Value, Type)>> {
&self, let value_type = value.r#type();
key: String,
value: Value,
r#type: Option<Type>,
) -> Result<Option<(Value, Type)>> {
let value_type = r#type.unwrap_or(value.r#type());
let previous = self let previous = self
.variables .variables
.write()? .write()?
@ -79,6 +74,12 @@ impl Map {
Ok(previous) Ok(previous)
} }
pub fn set_type(&self, key: String, r#type: Type) -> Result<Option<(Value, Type)>> {
let previous = self.variables.write()?.insert(key, (Value::none(), r#type));
Ok(previous)
}
pub fn unset_all(&self) -> Result<()> { pub fn unset_all(&self) -> Result<()> {
for (_key, (value, r#_type)) in self.variables.write()?.iter_mut() { for (_key, (value, r#_type)) in self.variables.write()?.iter_mut() {
*value = Value::none(); *value = Value::none();
@ -182,7 +183,7 @@ impl<'de> Visitor<'de> for MapVisitor {
{ {
while let Some((key, value)) = access.next_entry::<String, Value>()? { while let Some((key, value)) = access.next_entry::<String, Value>()? {
map.set(key, value, None).unwrap(); map.set(key, value).unwrap();
} }
} }

View File

@ -844,7 +844,7 @@ impl<'de> Visitor<'de> for ValueVisitor {
let map = Map::new(); let map = Map::new();
while let Some((key, value)) = access.next_entry::<String, Value>()? { while let Some((key, value)) = access.next_entry::<String, Value>()? {
map.set(key, value, None).unwrap(); map.set(key, value).unwrap();
} }
Ok(Value::Map(map)) Ok(Value::Map(map))

View File

@ -58,10 +58,7 @@ fn function_context_does_not_capture_normal_values() {
), ),
Err(Error::VariableIdentifierNotFound("x".to_string())) Err(Error::VariableIdentifierNotFound("x".to_string()))
); );
}
#[test]
fn function_context_captures_functions() {
assert_eq!( assert_eq!(
interpret( interpret(
" "
@ -72,7 +69,10 @@ fn function_context_captures_functions() {
), ),
Ok(Value::Integer(2)) Ok(Value::Integer(2))
); );
}
#[test]
fn function_context_captures_functions() {
assert_eq!( assert_eq!(
interpret( interpret(
" "
@ -84,24 +84,23 @@ fn function_context_captures_functions() {
Ok(Value::Integer(2)) Ok(Value::Integer(2))
); );
assert_eq!( // assert_eq!(
interpret( // interpret(
" // "
foo = () <int> { bar() } // foo = () <int> { bar() }
foo() // foo()
bar = () <int> { 2 } // bar = () <int> { 2 }
" // "
), // ),
Ok(Value::Integer(2)) // Ok(Value::Integer(2))
); // );
} }
#[test] #[test]
fn function_context_captures_structure_definitions() { fn function_context_captures_structure_definitions() {
let map = Map::new(); let map = Map::new();
map.set("name".to_string(), Value::string("bob"), None) map.set("name".to_string(), Value::string("bob")).unwrap();
.unwrap();
assert_eq!( assert_eq!(
interpret( interpret(

View File

@ -13,7 +13,7 @@ fn simple_type_check() {
#[test] #[test]
fn argument_count_check() { fn argument_count_check() {
let source = " let source = "
foo = (x <int>) <bool> { foo = (x <int>) <int> {
x x
} }
foo() foo()
@ -21,7 +21,7 @@ fn argument_count_check() {
let result = interpret(&source); let result = interpret(&source);
assert_eq!( assert_eq!(
"Expected 1 arguments, but got 0. Occured at (4, 12) to (4, 17). Source: foo()", "Expected 1 arguments, but got 0. Occured at (5, 12) to (5, 17). Source: foo()",
result.unwrap_err().to_string() result.unwrap_err().to_string()
) )
} }

View File

@ -49,8 +49,8 @@ fn list() {
fn map() { fn map() {
let map = Map::new(); let map = Map::new();
map.set("x".to_string(), Value::Integer(1), None).unwrap(); map.set("x".to_string(), Value::Integer(1)).unwrap();
map.set("foo".to_string(), Value::string("bar".to_string()), None) map.set("foo".to_string(), Value::string("bar".to_string()))
.unwrap(); .unwrap();
assert_eq!(interpret("{ x = 1, foo = 'bar' }"), Ok(Value::Map(map))); assert_eq!(interpret("{ x = 1, foo = 'bar' }"), Ok(Value::Map(map)));
@ -60,14 +60,9 @@ fn map() {
fn map_types() { fn map_types() {
let map = Map::new(); let map = Map::new();
map.set("x".to_string(), Value::Integer(1), Some(Type::Integer)) map.set("x".to_string(), Value::Integer(1)).unwrap();
map.set("foo".to_string(), Value::string("bar".to_string()))
.unwrap(); .unwrap();
map.set(
"foo".to_string(),
Value::string("bar".to_string()),
Some(Type::String),
)
.unwrap();
assert_eq!( assert_eq!(
interpret("{ x <int> = 1, foo <str> = 'bar' }"), interpret("{ x <int> = 1, foo <str> = 'bar' }"),