Continue experimenting with context and scopes
This commit is contained in:
parent
e84e022eed
commit
dd72faf7c8
@ -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() {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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>
|
||||
|
@ -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!()
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std.io
|
||||
|
||||
count = 1
|
||||
|
||||
while count <= 15 {
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std.io
|
||||
|
||||
io.write_line("Hello, world!")
|
||||
io.write_line("Enter your name...")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user