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 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() {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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),
|
||||||
|
@ -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>
|
||||||
|
@ -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!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std.io
|
||||||
|
|
||||||
count = 1
|
count = 1
|
||||||
|
|
||||||
while count <= 15 {
|
while count <= 15 {
|
||||||
|
@ -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...")
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user