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 (Some(type_parameters), Some(type_arguments)) =
(function.type_parameters(), self.type_arguments)
{
for (identifier, constructor) in
type_parameters.into_iter().zip(type_arguments.into_iter())
{
let r#type = constructor.construct(context)?;
let type_arguments = if let Some(type_arguments) = self.type_arguments {
let mut types = Vec::with_capacity(type_arguments.len());
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)) =
(function.value_parameters(), self.value_arguments)
{
for ((identifier, _), expression) in
parameters.into_iter().zip(arguments.into_iter())
{
Some(types)
} else {
None
};
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 evaluation = expression.evaluate(context, manage_memory, scope)?;
let value = if let Some(Evaluation::Return(value)) = evaluation {
let evaluation = (expression.evaluate(context, manage_memory, scope)?).ok_or(
RuntimeError::ValidationFailure(ValidationError::ExpectedValueStatement(
position,
)),
)?;
let value = if let Evaluation::Return(value) = evaluation {
value
} else {
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() {

View File

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

View File

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

View File

@ -1,20 +1,24 @@
use std::{
cmp::Ordering,
collections::HashMap,
fmt::Debug,
sync::{Arc, RwLock},
};
use log::trace;
use rand::random;
use crate::{
abstract_tree::{SourcePosition, Type},
error::{PoisonError, ValidationError},
identifier::Identifier,
standard_library::core_context,
value::ValueInner,
Value,
};
#[derive(Clone, Debug)]
pub struct Context {
id: u32,
variables: Arc<RwLock<HashMap<Identifier, (VariableData, UsageData, SourcePosition)>>>,
is_clean: Arc<RwLock<bool>>,
}
@ -22,6 +26,7 @@ pub struct Context {
impl Context {
pub fn new() -> Self {
Context {
id: random(),
variables: Arc::new(RwLock::new(HashMap::new())),
is_clean: Arc::new(RwLock::new(true)),
}
@ -37,11 +42,29 @@ impl Context {
let variables = other.variables.read()?.clone();
Ok(Context {
id: random(),
variables: Arc::new(RwLock::new(variables)),
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(
&self,
identifier: &Identifier,
@ -55,6 +78,8 @@ impl Context {
if scope.0 >= variable_scope.0 && scope.1 <= variable_scope.1 {
return Ok(true);
}
} else {
trace!("Denying access to {identifier}, out of scope")
}
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)]
pub enum VariableData {
Type(Type),

View File

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

View File

@ -7,6 +7,7 @@ use std::{
};
use chumsky::container::Container;
use log::{debug, trace};
use serde::{
de::Visitor,
ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeTuple},
@ -15,7 +16,8 @@ use serde::{
use crate::{
abstract_tree::{
AbstractNode, Block, BuiltInFunction, Evaluation, SourcePosition, Type, WithPosition,
AbstractNode, Block, BuiltInFunction, Evaluation, SourcePosition, Type, TypeConstructor,
WithPosition,
},
context::Context,
error::{RuntimeError, ValidationError},
@ -80,12 +82,12 @@ impl Value {
return_type: Option<Type>,
body: Block,
) -> Self {
Value(Arc::new(ValueInner::Function(Function {
Value(Arc::new(ValueInner::Function(Function::new(
type_parameters,
value_parameters,
return_type,
body,
})))
))))
}
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 {
type_parameters: Option<Vec<Identifier>>,
value_parameters: Option<Vec<(Identifier, Type)>>,
return_type: Option<Type>,
body: Block,
context: Context,
}
impl Function {
@ -761,6 +764,7 @@ impl Function {
value_parameters,
return_type,
body,
context: Context::new(),
}
}
@ -778,12 +782,68 @@ impl Function {
pub fn call(
self,
context: &Context,
manage_memory: bool,
scope: SourcePosition,
outer_context: Option<&Context>,
type_arguments: Option<Vec<Type>>,
value_arguments: Option<Vec<Value>>,
) -> 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
.define_and_validate(context, manage_memory, scope)?;
self.body.evaluate(context, manage_memory, scope)
.evaluate(&self.context, false, SourcePosition(0, usize::MAX))
}
}
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
while count <= 15 {

View File

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