Continue experimenting with context and scopes

This commit is contained in:
Jeff 2024-07-06 02:41:43 -04:00
parent e84e022eed
commit dd72faf7c8
8 changed files with 154 additions and 40 deletions

View File

@ -150,27 +150,28 @@ impl AbstractNode for FunctionCall {
}; };
if let ValueInner::Function(function) = value.inner().as_ref() { if let ValueInner::Function(function) = value.inner().as_ref() {
if let (Some(type_parameters), Some(type_arguments)) = let type_arguments = if let Some(type_arguments) = self.type_arguments {
(function.type_parameters(), self.type_arguments) let mut types = Vec::with_capacity(type_arguments.len());
{
for (identifier, constructor) in
type_parameters.into_iter().zip(type_arguments.into_iter())
{
let r#type = constructor.construct(context)?;
context.set_type(identifier.clone(), r#type, function_position)?; for constructor in type_arguments {
types.push(constructor.construct(context)?)
} }
}
if let (Some(parameters), Some(arguments)) = Some(types)
(function.value_parameters(), self.value_arguments) } else {
{ None
for ((identifier, _), expression) in };
parameters.into_iter().zip(arguments.into_iter()) let value_arguments = if let Some(value_arguments) = self.value_arguments {
{ let mut values = Vec::with_capacity(value_arguments.len());
for expression in value_arguments {
let position = expression.position(); let position = expression.position();
let evaluation = expression.evaluate(context, manage_memory, scope)?; let evaluation = (expression.evaluate(context, manage_memory, scope)?).ok_or(
let value = if let Some(Evaluation::Return(value)) = evaluation { RuntimeError::ValidationFailure(ValidationError::ExpectedValueStatement(
position,
)),
)?;
let value = if let Evaluation::Return(value) = evaluation {
value value
} else { } else {
return Err(RuntimeError::ValidationFailure( return Err(RuntimeError::ValidationFailure(
@ -178,11 +179,17 @@ impl AbstractNode for FunctionCall {
)); ));
}; };
context.set_value(identifier.clone(), value, function_position)?; values.push(value);
} }
}
return function.clone().call(context, manage_memory, scope); Some(values)
} else {
None
};
return function
.clone()
.call(Some(context), type_arguments, value_arguments);
} }
if let ValueInner::BuiltInFunction(function) = value.inner().as_ref() { if let ValueInner::BuiltInFunction(function) = value.inner().as_ref() {

View File

@ -1,5 +1,5 @@
use std::{ use std::{
fmt::Display, fmt::{self, Display, Formatter},
fs::read_to_string, fs::read_to_string,
path::Path, path::Path,
sync::{Arc, RwLock}, sync::{Arc, RwLock},
@ -93,8 +93,8 @@ impl AbstractNode for Use {
} }
impl Display for Use { impl Display for Use {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
todo!() write!(f, "use {}", self.path)
} }
} }

View File

@ -218,7 +218,7 @@ impl AbstractNode for ValueNode {
fields: expressions, fields: expressions,
} = self } = self
{ {
if !context.contains(&name.node)? { if !context.contains(&name.node, scope)? {
return Err(ValidationError::VariableNotFound { return Err(ValidationError::VariableNotFound {
identifier: name.node.clone(), identifier: name.node.clone(),
position: name.position, position: name.position,

View File

@ -1,20 +1,24 @@
use std::{ use std::{
cmp::Ordering,
collections::HashMap, collections::HashMap,
fmt::Debug, fmt::Debug,
sync::{Arc, RwLock}, sync::{Arc, RwLock},
}; };
use log::trace;
use rand::random;
use crate::{ use crate::{
abstract_tree::{SourcePosition, Type}, abstract_tree::{SourcePosition, Type},
error::{PoisonError, ValidationError}, error::{PoisonError, ValidationError},
identifier::Identifier, identifier::Identifier,
standard_library::core_context, standard_library::core_context,
value::ValueInner,
Value, Value,
}; };
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Context { pub struct Context {
id: u32,
variables: Arc<RwLock<HashMap<Identifier, (VariableData, UsageData, SourcePosition)>>>, variables: Arc<RwLock<HashMap<Identifier, (VariableData, UsageData, SourcePosition)>>>,
is_clean: Arc<RwLock<bool>>, is_clean: Arc<RwLock<bool>>,
} }
@ -22,6 +26,7 @@ pub struct Context {
impl Context { impl Context {
pub fn new() -> Self { pub fn new() -> Self {
Context { Context {
id: random(),
variables: Arc::new(RwLock::new(HashMap::new())), variables: Arc::new(RwLock::new(HashMap::new())),
is_clean: Arc::new(RwLock::new(true)), is_clean: Arc::new(RwLock::new(true)),
} }
@ -37,11 +42,29 @@ impl Context {
let variables = other.variables.read()?.clone(); let variables = other.variables.read()?.clone();
Ok(Context { Ok(Context {
id: random(),
variables: Arc::new(RwLock::new(variables)), variables: Arc::new(RwLock::new(variables)),
is_clean: Arc::new(RwLock::new(true)), is_clean: Arc::new(RwLock::new(true)),
}) })
} }
pub fn inherit_variables_from(&self, other: &Context) -> Result<(), PoisonError> {
let (get_self_variables, get_other_variables) =
(self.variables.try_write(), other.variables.try_read());
if let (Ok(mut self_variables), Ok(other_variables)) =
(get_self_variables, get_other_variables)
{
self_variables.extend(other_variables.iter().map(|(identifier, data)| {
trace!("Inheriting {identifier}");
(identifier.clone(), data.clone())
}));
}
Ok(())
}
pub fn contains( pub fn contains(
&self, &self,
identifier: &Identifier, identifier: &Identifier,
@ -55,6 +78,8 @@ impl Context {
if scope.0 >= variable_scope.0 && scope.1 <= variable_scope.1 { if scope.0 >= variable_scope.0 && scope.1 <= variable_scope.1 {
return Ok(true); return Ok(true);
} }
} else {
trace!("Denying access to {identifier}, out of scope")
} }
Ok(false) Ok(false)
@ -194,6 +219,26 @@ impl Default for Context {
} }
} }
impl Eq for Context {}
impl PartialEq for Context {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl PartialOrd for Context {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Context {
fn cmp(&self, other: &Self) -> Ordering {
self.id.cmp(&other.id)
}
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum VariableData { pub enum VariableData {
Type(Type), Type(Type),

View File

@ -1,14 +1,12 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
hash::{Hash, Hasher}, hash::Hash,
sync::{Arc, OnceLock, RwLock}, sync::{Arc, OnceLock, RwLock},
}; };
use serde::{de::Visitor, Deserialize, Serialize}; use serde::{de::Visitor, Deserialize, Serialize};
use crate::abstract_tree::SourcePosition;
static IDENTIFIER_CACHE: OnceLock<RwLock<HashMap<String, Identifier>>> = OnceLock::new(); static IDENTIFIER_CACHE: OnceLock<RwLock<HashMap<String, Identifier>>> = OnceLock::new();
fn identifier_cache<'a>() -> &'a RwLock<HashMap<String, Identifier>> { fn identifier_cache<'a>() -> &'a RwLock<HashMap<String, Identifier>> {
@ -19,7 +17,7 @@ fn identifier_cache<'a>() -> &'a RwLock<HashMap<String, Identifier>> {
pub struct Identifier(Arc<String>); pub struct Identifier(Arc<String>);
impl Identifier { impl Identifier {
pub fn new(text: &str, scope: Option<SourcePosition>) -> Self { pub fn new(text: &str) -> Self {
let cache = identifier_cache(); let cache = identifier_cache();
if let Some(identifier) = cache.read().unwrap().get(text).cloned() { if let Some(identifier) = cache.read().unwrap().get(text).cloned() {
@ -40,7 +38,7 @@ impl Identifier {
impl From<&str> for Identifier { impl From<&str> for Identifier {
fn from(text: &str) -> Self { fn from(text: &str) -> Self {
Identifier::new(text, None) Identifier::new(text)
} }
} }
@ -88,7 +86,7 @@ impl<'de> Visitor<'de> for IdentifierVisitor {
where where
E: serde::de::Error, E: serde::de::Error,
{ {
Ok(Identifier::new(v, None)) Ok(Identifier::new(v))
} }
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E> fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>

View File

@ -7,6 +7,7 @@ use std::{
}; };
use chumsky::container::Container; use chumsky::container::Container;
use log::{debug, trace};
use serde::{ use serde::{
de::Visitor, de::Visitor,
ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeTuple}, ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeTuple},
@ -15,7 +16,8 @@ use serde::{
use crate::{ use crate::{
abstract_tree::{ abstract_tree::{
AbstractNode, Block, BuiltInFunction, Evaluation, SourcePosition, Type, WithPosition, AbstractNode, Block, BuiltInFunction, Evaluation, SourcePosition, Type, TypeConstructor,
WithPosition,
}, },
context::Context, context::Context,
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
@ -80,12 +82,12 @@ impl Value {
return_type: Option<Type>, return_type: Option<Type>,
body: Block, body: Block,
) -> Self { ) -> Self {
Value(Arc::new(ValueInner::Function(Function { Value(Arc::new(ValueInner::Function(Function::new(
type_parameters, type_parameters,
value_parameters, value_parameters,
return_type, return_type,
body, body,
}))) ))))
} }
pub fn structure(name: WithPosition<Identifier>, fields: Vec<(Identifier, Value)>) -> Self { pub fn structure(name: WithPosition<Identifier>, fields: Vec<(Identifier, Value)>) -> Self {
@ -741,12 +743,13 @@ impl Ord for ValueInner {
} }
} }
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug)]
pub struct Function { pub struct Function {
type_parameters: Option<Vec<Identifier>>, type_parameters: Option<Vec<Identifier>>,
value_parameters: Option<Vec<(Identifier, Type)>>, value_parameters: Option<Vec<(Identifier, Type)>>,
return_type: Option<Type>, return_type: Option<Type>,
body: Block, body: Block,
context: Context,
} }
impl Function { impl Function {
@ -761,6 +764,7 @@ impl Function {
value_parameters, value_parameters,
return_type, return_type,
body, body,
context: Context::new(),
} }
} }
@ -778,12 +782,68 @@ impl Function {
pub fn call( pub fn call(
self, self,
context: &Context, outer_context: Option<&Context>,
manage_memory: bool, type_arguments: Option<Vec<Type>>,
scope: SourcePosition, value_arguments: Option<Vec<Value>>,
) -> Result<Option<Evaluation>, RuntimeError> { ) -> Result<Option<Evaluation>, RuntimeError> {
trace!("Setting function call variables");
if let Some(outer_context) = outer_context {
if &self.context == outer_context {
log::debug!("Recursion detected");
}
self.context.inherit_variables_from(outer_context)?;
}
if let (Some(type_parameters), Some(type_arguments)) =
(self.type_parameters, type_arguments)
{
for (identifier, r#type) in type_parameters.into_iter().zip(type_arguments.into_iter())
{
self.context
.set_type(identifier.clone(), r#type, SourcePosition(0, usize::MAX))?;
}
}
if let (Some(value_parameters), Some(value_arguments)) =
(self.value_parameters, value_arguments)
{
for ((identifier, _), value) in value_parameters
.into_iter()
.zip(value_arguments.into_iter())
{
self.context
.set_value(identifier.clone(), value, SourcePosition(0, usize::MAX))?;
}
}
debug!("Calling function");
self.body self.body
.define_and_validate(context, manage_memory, scope)?; .evaluate(&self.context, false, SourcePosition(0, usize::MAX))
self.body.evaluate(context, manage_memory, scope) }
}
impl Eq for Function {}
impl PartialEq for Function {
fn eq(&self, other: &Self) -> bool {
self.type_parameters == other.type_parameters
&& self.value_parameters == other.value_parameters
&& self.return_type == other.return_type
&& self.body == other.body
}
}
impl PartialOrd for Function {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Function {
fn cmp(&self, other: &Self) -> Ordering {
todo!()
} }
} }

View File

@ -1,3 +1,5 @@
use std.io
count = 1 count = 1
while count <= 15 { while count <= 15 {

View File

@ -1,3 +1,5 @@
use std.io
io.write_line("Hello, world!") io.write_line("Hello, world!")
io.write_line("Enter your name...") io.write_line("Enter your name...")