Fix function contexts and recursion
This commit is contained in:
parent
7eecb7b070
commit
d2e0de0483
@ -13,9 +13,6 @@ pub struct FunctionCall {
|
|||||||
function_expression: FunctionExpression,
|
function_expression: FunctionExpression,
|
||||||
arguments: Vec<Expression>,
|
arguments: Vec<Expression>,
|
||||||
syntax_position: SourcePosition,
|
syntax_position: SourcePosition,
|
||||||
|
|
||||||
#[serde(skip)]
|
|
||||||
context: Context,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionCall {
|
impl FunctionCall {
|
||||||
@ -24,13 +21,11 @@ impl FunctionCall {
|
|||||||
function_expression: FunctionExpression,
|
function_expression: FunctionExpression,
|
||||||
arguments: Vec<Expression>,
|
arguments: Vec<Expression>,
|
||||||
syntax_position: SourcePosition,
|
syntax_position: SourcePosition,
|
||||||
context: Context,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
function_expression,
|
function_expression,
|
||||||
arguments,
|
arguments,
|
||||||
syntax_position,
|
syntax_position,
|
||||||
context,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,7 +53,6 @@ impl AbstractTree for FunctionCall {
|
|||||||
function_expression,
|
function_expression,
|
||||||
arguments,
|
arguments,
|
||||||
syntax_position: node.range().into(),
|
syntax_position: node.range().into(),
|
||||||
context: Context::new(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +137,6 @@ impl AbstractTree for FunctionCall {
|
|||||||
let value = match &self.function_expression {
|
let value = match &self.function_expression {
|
||||||
FunctionExpression::Identifier(identifier) => {
|
FunctionExpression::Identifier(identifier) => {
|
||||||
if let Some(value) = context.get_value(identifier)? {
|
if let Some(value) = context.get_value(identifier)? {
|
||||||
self.context.set_value(identifier.clone(), value.clone())?;
|
|
||||||
value.clone()
|
value.clone()
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::VariableIdentifierNotFound(identifier.clone()));
|
return Err(RuntimeError::VariableIdentifierNotFound(identifier.clone()));
|
||||||
@ -167,19 +160,25 @@ impl AbstractTree for FunctionCall {
|
|||||||
arguments.push(value);
|
arguments.push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
built_in_function.call(&arguments, source, &self.context)
|
built_in_function.call(&arguments, source, context)
|
||||||
}
|
}
|
||||||
Function::ContextDefined(function_node) => {
|
Function::ContextDefined(function_node) => {
|
||||||
|
let call_context = Context::with_variables_from(function_node.context())?;
|
||||||
|
|
||||||
|
call_context.inherit_from(context)?;
|
||||||
|
|
||||||
let parameter_expression_pairs =
|
let parameter_expression_pairs =
|
||||||
function_node.parameters().iter().zip(self.arguments.iter());
|
function_node.parameters().iter().zip(self.arguments.iter());
|
||||||
|
|
||||||
for (identifier, expression) in parameter_expression_pairs {
|
for (identifier, expression) in parameter_expression_pairs {
|
||||||
let value = expression.run(source, context)?;
|
let value = expression.run(source, context)?;
|
||||||
|
|
||||||
self.context.set_value(identifier.clone(), value)?;
|
call_context.set_value(identifier.clone(), value)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
function_node.call(source, &self.context)
|
println!("{}", call_context);
|
||||||
|
|
||||||
|
function_node.body().run(source, &call_context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,23 +14,12 @@ pub struct FunctionNode {
|
|||||||
body: Block,
|
body: Block,
|
||||||
r#type: Type,
|
r#type: Type,
|
||||||
syntax_position: SourcePosition,
|
syntax_position: SourcePosition,
|
||||||
|
|
||||||
|
#[serde(skip)]
|
||||||
|
context: Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionNode {
|
impl FunctionNode {
|
||||||
pub fn new(
|
|
||||||
parameters: Vec<Identifier>,
|
|
||||||
body: Block,
|
|
||||||
r#type: Type,
|
|
||||||
syntax_position: SourcePosition,
|
|
||||||
) -> Self {
|
|
||||||
FunctionNode {
|
|
||||||
parameters,
|
|
||||||
body,
|
|
||||||
r#type,
|
|
||||||
syntax_position,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parameters(&self) -> &Vec<Identifier> {
|
pub fn parameters(&self) -> &Vec<Identifier> {
|
||||||
&self.parameters
|
&self.parameters
|
||||||
}
|
}
|
||||||
@ -47,6 +36,10 @@ impl FunctionNode {
|
|||||||
&self.syntax_position
|
&self.syntax_position
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn context(&self) -> &Context {
|
||||||
|
&self.context
|
||||||
|
}
|
||||||
|
|
||||||
pub fn return_type(&self) -> &Type {
|
pub fn return_type(&self) -> &Type {
|
||||||
match &self.r#type {
|
match &self.r#type {
|
||||||
Type::Function {
|
Type::Function {
|
||||||
@ -56,12 +49,6 @@ impl FunctionNode {
|
|||||||
_ => &Type::None,
|
_ => &Type::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
|
||||||
let return_value = self.body.run(source, context)?;
|
|
||||||
|
|
||||||
Ok(return_value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for FunctionNode {
|
impl AbstractTree for FunctionNode {
|
||||||
@ -91,8 +78,10 @@ impl AbstractTree for FunctionNode {
|
|||||||
let return_type_node = node.child(child_count - 2).unwrap();
|
let return_type_node = node.child(child_count - 2).unwrap();
|
||||||
let return_type = TypeSpecification::from_syntax(return_type_node, source, context)?;
|
let return_type = TypeSpecification::from_syntax(return_type_node, source, context)?;
|
||||||
|
|
||||||
|
let function_context = Context::with_variables_from(context)?;
|
||||||
|
|
||||||
let body_node = node.child(child_count - 1).unwrap();
|
let body_node = node.child(child_count - 1).unwrap();
|
||||||
let body = Block::from_syntax(body_node, source, &context)?;
|
let body = Block::from_syntax(body_node, source, &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();
|
||||||
@ -102,6 +91,7 @@ impl AbstractTree for FunctionNode {
|
|||||||
body,
|
body,
|
||||||
r#type,
|
r#type,
|
||||||
syntax_position,
|
syntax_position,
|
||||||
|
context: function_context,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,19 +99,19 @@ impl AbstractTree for FunctionNode {
|
|||||||
Ok(self.r#type().clone())
|
Ok(self.r#type().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, source: &str, _context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, source: &str, context: &Context) -> Result<(), ValidationError> {
|
||||||
if let Type::Function {
|
if let Type::Function {
|
||||||
parameter_types,
|
parameter_types,
|
||||||
return_type,
|
return_type,
|
||||||
} = &self.r#type
|
} = &self.r#type
|
||||||
{
|
{
|
||||||
let validation_context = Context::new();
|
self.context.inherit_from(context)?;
|
||||||
|
|
||||||
for (parameter, r#type) in self.parameters.iter().zip(parameter_types.iter()) {
|
for (parameter, r#type) in self.parameters.iter().zip(parameter_types.iter()) {
|
||||||
validation_context.set_type(parameter.clone(), r#type.clone())?;
|
self.context.set_type(parameter.clone(), r#type.clone())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let actual = self.body.expected_type(&validation_context)?;
|
let actual = self.body.expected_type(&self.context)?;
|
||||||
|
|
||||||
if !return_type.accepts(&actual) {
|
if !return_type.accepts(&actual) {
|
||||||
return Err(ValidationError::TypeCheck {
|
return Err(ValidationError::TypeCheck {
|
||||||
@ -131,7 +121,7 @@ impl AbstractTree for FunctionNode {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.body.validate(source, &validation_context)?;
|
self.body.validate(source, &self.context)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@ -142,7 +132,9 @@ impl AbstractTree for FunctionNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, _context: &Context) -> Result<Value, RuntimeError> {
|
fn run(&self, _source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
||||||
|
self.context.inherit_from(context)?;
|
||||||
|
|
||||||
let self_as_value = Value::Function(Function::ContextDefined(self.clone()));
|
let self_as_value = Value::Function(Function::ContextDefined(self.clone()));
|
||||||
|
|
||||||
Ok(self_as_value)
|
Ok(self_as_value)
|
||||||
|
@ -59,8 +59,12 @@ impl AbstractTree for Identifier {
|
|||||||
Ok(Identifier::new(text))
|
Ok(Identifier::new(text))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, _source: &str, _context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> {
|
||||||
Ok(())
|
if let Some(_) = context.get_type(self)? {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ValidationError::VariableIdentifierNotFound(self.clone()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
|
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
|
fmt::Display,
|
||||||
sync::{Arc, RwLock, RwLockReadGuard},
|
sync::{Arc, RwLock, RwLockReadGuard},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -73,7 +74,7 @@ impl Context {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Modify a context to take on all of the key-value pairs of another.
|
/// Modify a context to take the functions and type definitions of another.
|
||||||
///
|
///
|
||||||
/// In the case of the conflict, the inherited value will override the previous
|
/// In the case of the conflict, the inherited value will override the previous
|
||||||
/// value.
|
/// value.
|
||||||
@ -96,11 +97,19 @@ impl Context {
|
|||||||
let mut self_variables = self.inner.write()?;
|
let mut self_variables = self.inner.write()?;
|
||||||
|
|
||||||
for (identifier, value_data) in other.inner.read()?.iter() {
|
for (identifier, value_data) in other.inner.read()?.iter() {
|
||||||
let existing_data = self_variables.get(identifier);
|
if let ValueData::Value { inner, .. } = value_data {
|
||||||
|
if inner.is_function() {
|
||||||
|
self_variables.insert(identifier.clone(), value_data.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(ValueData::Value { .. }) = existing_data {
|
if let ValueData::TypeHint { inner } = value_data {
|
||||||
continue;
|
if inner.is_function() {
|
||||||
} else {
|
self_variables.insert(identifier.clone(), value_data.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let ValueData::TypeDefinition(_) = value_data {
|
||||||
self_variables.insert(identifier.clone(), value_data.clone());
|
self_variables.insert(identifier.clone(), value_data.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,7 +129,6 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for built_in_value in all_built_in_values() {
|
for built_in_value in all_built_in_values() {
|
||||||
println!("{} {}", built_in_value.name(), identifier.inner());
|
|
||||||
if built_in_value.name() == identifier.inner().as_ref() {
|
if built_in_value.name() == identifier.inner().as_ref() {
|
||||||
return Ok(Some(built_in_value.get().clone()));
|
return Ok(Some(built_in_value.get().clone()));
|
||||||
}
|
}
|
||||||
@ -176,6 +184,8 @@ impl Context {
|
|||||||
|
|
||||||
/// Set a value to a key.
|
/// Set a value to a key.
|
||||||
pub fn set_value(&self, key: Identifier, value: Value) -> Result<(), RwLockError> {
|
pub fn set_value(&self, key: Identifier, value: Value) -> Result<(), RwLockError> {
|
||||||
|
log::info!("Setting value: {key} = {value}");
|
||||||
|
|
||||||
self.inner.write()?.insert(
|
self.inner.write()?.insert(
|
||||||
key,
|
key,
|
||||||
ValueData::Value {
|
ValueData::Value {
|
||||||
@ -192,6 +202,8 @@ impl Context {
|
|||||||
/// This allows the interpreter to check a value's type before the value
|
/// This allows the interpreter to check a value's type before the value
|
||||||
/// actually exists by predicting what the abstract tree will produce.
|
/// actually exists by predicting what the abstract tree will produce.
|
||||||
pub fn set_type(&self, key: Identifier, r#type: Type) -> Result<(), RwLockError> {
|
pub fn set_type(&self, key: Identifier, r#type: Type) -> Result<(), RwLockError> {
|
||||||
|
log::info!("Setting type: {key} <{}>", r#type);
|
||||||
|
|
||||||
self.inner
|
self.inner
|
||||||
.write()?
|
.write()?
|
||||||
.insert(key, ValueData::TypeHint { inner: r#type });
|
.insert(key, ValueData::TypeHint { inner: r#type });
|
||||||
@ -339,3 +351,15 @@ impl Ord for ValueData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Context {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
writeln!(f, "{{")?;
|
||||||
|
|
||||||
|
for (identifier, value_data) in self.inner.read().unwrap().iter() {
|
||||||
|
writeln!(f, "{identifier} {value_data:?}")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln!(f, "}}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,9 +5,9 @@ fn function_call() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpret(
|
interpret(
|
||||||
"
|
"
|
||||||
foobar = (message <str>) <str> { message }
|
foobar = (message <str>) <str> { message }
|
||||||
foobar('Hiya')
|
foobar('Hiya')
|
||||||
",
|
",
|
||||||
),
|
),
|
||||||
Ok(Value::string("Hiya".to_string()))
|
Ok(Value::string("Hiya".to_string()))
|
||||||
);
|
);
|
||||||
@ -18,9 +18,9 @@ fn call_empty_function() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpret(
|
interpret(
|
||||||
"
|
"
|
||||||
foobar = (message <str>) <none> {}
|
foobar = (message <str>) <none> {}
|
||||||
foobar('Hiya')
|
foobar('Hiya')
|
||||||
",
|
",
|
||||||
),
|
),
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
);
|
);
|
||||||
@ -96,7 +96,7 @@ fn function_context_captures_structure_definitions() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpret(
|
interpret(
|
||||||
"
|
"
|
||||||
User = struct {
|
struct User {
|
||||||
name <str>
|
name <str>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user