Overhaul built-ins and identifiers
This commit is contained in:
parent
91e94a5adc
commit
c2ba519240
@ -54,14 +54,13 @@ impl AbstractTree for Assignment {
|
|||||||
|
|
||||||
fn validate(&self, source: &str, context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, source: &str, context: &Context) -> Result<(), ValidationError> {
|
||||||
if let AssignmentOperator::Equal = self.operator {
|
if let AssignmentOperator::Equal = self.operator {
|
||||||
let key = self.identifier.inner().clone();
|
|
||||||
let r#type = if let Some(definition) = &self.type_specification {
|
let r#type = if let Some(definition) = &self.type_specification {
|
||||||
definition.inner().clone()
|
definition.inner().clone()
|
||||||
} else {
|
} else {
|
||||||
self.statement.expected_type(context)?
|
self.statement.expected_type(context)?
|
||||||
};
|
};
|
||||||
|
|
||||||
context.set_type(key, r#type)?;
|
context.set_type(self.identifier.clone(), r#type)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(type_specification) = &self.type_specification {
|
if let Some(type_specification) = &self.type_specification {
|
||||||
@ -130,30 +129,33 @@ impl AbstractTree for Assignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
||||||
let key = self.identifier.inner();
|
|
||||||
let value = self.statement.run(source, context)?;
|
let value = self.statement.run(source, context)?;
|
||||||
|
|
||||||
let new_value = match self.operator {
|
let new_value = match self.operator {
|
||||||
AssignmentOperator::PlusEqual => {
|
AssignmentOperator::PlusEqual => {
|
||||||
if let Some(mut previous_value) = context.get_value(key)? {
|
if let Some(mut previous_value) = context.get_value(&self.identifier)? {
|
||||||
previous_value += value;
|
previous_value += value;
|
||||||
previous_value
|
previous_value
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::VariableIdentifierNotFound(key.clone()));
|
return Err(RuntimeError::VariableIdentifierNotFound(
|
||||||
|
self.identifier.clone(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssignmentOperator::MinusEqual => {
|
AssignmentOperator::MinusEqual => {
|
||||||
if let Some(mut previous_value) = context.get_value(key)? {
|
if let Some(mut previous_value) = context.get_value(&self.identifier)? {
|
||||||
previous_value -= value;
|
previous_value -= value;
|
||||||
previous_value
|
previous_value
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::VariableIdentifierNotFound(key.clone()));
|
return Err(RuntimeError::VariableIdentifierNotFound(
|
||||||
|
self.identifier.clone(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssignmentOperator::Equal => value,
|
AssignmentOperator::Equal => value,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.set_value(key.clone(), new_value)?;
|
context.set_value(self.identifier.clone(), new_value)?;
|
||||||
|
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,8 @@ impl EnumDefinition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn instantiate(&self, variant: String, content: Option<Value>) -> EnumInstance {
|
pub fn instantiate(&self, variant: Identifier, content: Option<Value>) -> EnumInstance {
|
||||||
EnumInstance::new(self.identifier.inner().clone(), variant, content)
|
EnumInstance::new(self.identifier.clone(), variant, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn identifier(&self) -> &Identifier {
|
pub fn identifier(&self) -> &Identifier {
|
||||||
@ -86,10 +86,7 @@ impl AbstractTree for EnumDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
fn run(&self, _source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
||||||
context.set_definition(
|
context.set_definition(self.identifier.clone(), TypeDefinition::Enum(self.clone()))?;
|
||||||
self.identifier.inner().clone(),
|
|
||||||
TypeDefinition::Enum(self.clone()),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ impl AbstractTree for For {
|
|||||||
position: self.source_position,
|
position: self.source_position,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
let key = self.item_id.inner().clone();
|
let key = self.item_id.clone();
|
||||||
|
|
||||||
self.context.inherit_from(context)?;
|
self.context.inherit_from(context)?;
|
||||||
self.context.set_type(key, item_type)?;
|
self.context.set_type(key, item_type)?;
|
||||||
@ -87,7 +87,7 @@ impl AbstractTree for For {
|
|||||||
self.context.inherit_from(context)?;
|
self.context.inherit_from(context)?;
|
||||||
|
|
||||||
let expression_run = self.collection.run(source, context)?;
|
let expression_run = self.collection.run(source, context)?;
|
||||||
let key = self.item_id.inner();
|
let key = &self.item_id;
|
||||||
|
|
||||||
if let Value::Range(range) = expression_run {
|
if let Value::Range(range) = expression_run {
|
||||||
if self.is_async {
|
if self.is_async {
|
||||||
|
@ -142,16 +142,11 @@ impl AbstractTree for FunctionCall {
|
|||||||
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
||||||
let value = match &self.function_expression {
|
let value = match &self.function_expression {
|
||||||
FunctionExpression::Identifier(identifier) => {
|
FunctionExpression::Identifier(identifier) => {
|
||||||
let key = identifier.inner();
|
if let Some(value) = context.get_value(identifier)? {
|
||||||
|
self.context.set_value(identifier.clone(), value.clone())?;
|
||||||
if let Some(value) = context.get_value(key)? {
|
|
||||||
self.context
|
|
||||||
.set_value(identifier.inner().clone(), value.clone())?;
|
|
||||||
value.clone()
|
value.clone()
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::VariableIdentifierNotFound(
|
return Err(RuntimeError::VariableIdentifierNotFound(identifier.clone()));
|
||||||
identifier.inner().clone(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FunctionExpression::FunctionCall(function_call) => {
|
FunctionExpression::FunctionCall(function_call) => {
|
||||||
@ -181,7 +176,7 @@ impl AbstractTree for FunctionCall {
|
|||||||
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.inner().clone(), value)?;
|
self.context.set_value(identifier.clone(), value)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
function_node.call(source, &self.context)
|
function_node.call(source, &self.context)
|
||||||
|
@ -118,7 +118,7 @@ impl AbstractTree for FunctionNode {
|
|||||||
let validation_context = Context::new();
|
let validation_context = Context::new();
|
||||||
|
|
||||||
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.inner().clone(), r#type.clone())?;
|
validation_context.set_type(parameter.clone(), r#type.clone())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let actual = self.body.expected_type(&validation_context)?;
|
let actual = self.body.expected_type(&validation_context)?;
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::{
|
||||||
|
fmt::{self, Display, Formatter},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{de::Visitor, Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
built_in_identifiers::all_built_in_identifiers,
|
||||||
error::{RuntimeError, SyntaxError, ValidationError},
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
AbstractTree, Context, Format, SyntaxNode, Type, Value,
|
AbstractTree, Context, Format, SyntaxNode, Type, Value,
|
||||||
};
|
};
|
||||||
@ -10,22 +14,30 @@ use crate::{
|
|||||||
/// A string by which a variable is known to a context.
|
/// A string by which a variable is known to a context.
|
||||||
///
|
///
|
||||||
/// Every variable is a key-value pair. An identifier holds the key part of that
|
/// Every variable is a key-value pair. An identifier holds the key part of that
|
||||||
/// pair. Its inner value can be used to retrieve a Value instance from a Map.
|
/// pair and can be used to retrieve a Value instance from a Map or Context.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||||
pub struct Identifier(String);
|
pub struct Identifier(Arc<String>);
|
||||||
|
|
||||||
impl Identifier {
|
impl Identifier {
|
||||||
pub fn new<T: Into<String>>(inner: T) -> Self {
|
pub fn new(key: &str) -> Self {
|
||||||
Identifier(inner.into())
|
for built_in_identifier in all_built_in_identifiers() {
|
||||||
|
let identifier = built_in_identifier.get();
|
||||||
|
|
||||||
|
if &key == identifier.inner().as_ref() {
|
||||||
|
return identifier.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Identifier(Arc::new(key.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_inner(self) -> String {
|
pub fn inner(&self) -> &Arc<String> {
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn inner(&self) -> &String {
|
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn contains(&self, string: &str) -> bool {
|
||||||
|
self.0.as_ref() == string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Identifier {
|
impl AbstractTree for Identifier {
|
||||||
@ -40,7 +52,7 @@ impl AbstractTree for Identifier {
|
|||||||
|
|
||||||
debug_assert!(!text.is_empty());
|
debug_assert!(!text.is_empty());
|
||||||
|
|
||||||
Ok(Identifier(text.to_string()))
|
Ok(Identifier::new(text))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, _source: &str, _context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, _source: &str, _context: &Context) -> Result<(), ValidationError> {
|
||||||
@ -48,7 +60,7 @@ impl AbstractTree for Identifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
|
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
|
||||||
if let Some(r#type) = context.get_type(&self.0)? {
|
if let Some(r#type) = context.get_type(self)? {
|
||||||
Ok(r#type)
|
Ok(r#type)
|
||||||
} else {
|
} else {
|
||||||
Err(ValidationError::VariableIdentifierNotFound(self.clone()))
|
Err(ValidationError::VariableIdentifierNotFound(self.clone()))
|
||||||
@ -56,10 +68,10 @@ impl AbstractTree for Identifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
fn run(&self, _source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
||||||
if let Some(value) = context.get_value(&self.0)? {
|
if let Some(value) = context.get_value(self)? {
|
||||||
Ok(value.clone())
|
Ok(value.clone())
|
||||||
} else {
|
} else {
|
||||||
Err(RuntimeError::VariableIdentifierNotFound(self.0.clone()))
|
Err(RuntimeError::VariableIdentifierNotFound(self.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,3 +87,38 @@ impl Display for Identifier {
|
|||||||
write!(f, "{}", self.0)
|
write!(f, "{}", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Serialize for Identifier {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_str(self.0.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Identifier {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_string(IdentifierVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IdentifierVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for IdentifierVisitor {
|
||||||
|
type Value = Identifier;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("valid UFT-8 sequence")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
Ok(Identifier(Arc::new(v)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,7 +2,8 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{RuntimeError, SyntaxError, ValidationError},
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
AbstractTree, Context, Format, IndexExpression, List, SourcePosition, SyntaxNode, Type, Value,
|
AbstractTree, Context, Format, Identifier, IndexExpression, SourcePosition, SyntaxNode, Type,
|
||||||
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Abstract representation of an index expression.
|
/// Abstract representation of an index expression.
|
||||||
@ -12,7 +13,6 @@ use crate::{
|
|||||||
pub struct Index {
|
pub struct Index {
|
||||||
pub collection: IndexExpression,
|
pub collection: IndexExpression,
|
||||||
pub index: IndexExpression,
|
pub index: IndexExpression,
|
||||||
pub index_end: Option<IndexExpression>,
|
|
||||||
source_position: SourcePosition,
|
source_position: SourcePosition,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,21 +26,9 @@ impl AbstractTree for Index {
|
|||||||
let index_node = node.child(2).unwrap();
|
let index_node = node.child(2).unwrap();
|
||||||
let index = IndexExpression::from_syntax(index_node, source, context)?;
|
let index = IndexExpression::from_syntax(index_node, source, context)?;
|
||||||
|
|
||||||
let index_end_node = node.child(4);
|
|
||||||
let index_end = if let Some(index_end_node) = index_end_node {
|
|
||||||
Some(IndexExpression::from_syntax(
|
|
||||||
index_end_node,
|
|
||||||
source,
|
|
||||||
context,
|
|
||||||
)?)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Index {
|
Ok(Index {
|
||||||
collection,
|
collection,
|
||||||
index,
|
index,
|
||||||
index_end,
|
|
||||||
source_position: SourcePosition::from(node.range()),
|
source_position: SourcePosition::from(node.range()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -58,10 +46,6 @@ impl AbstractTree for Index {
|
|||||||
self.collection.validate(_source, _context)?;
|
self.collection.validate(_source, _context)?;
|
||||||
self.index.validate(_source, _context)?;
|
self.index.validate(_source, _context)?;
|
||||||
|
|
||||||
if let Some(index_end) = &self.index_end {
|
|
||||||
index_end.validate(_source, _context)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,36 +55,28 @@ impl AbstractTree for Index {
|
|||||||
match value {
|
match value {
|
||||||
Value::List(list) => {
|
Value::List(list) => {
|
||||||
let index = self.index.run(source, context)?.as_integer()? as usize;
|
let index = self.index.run(source, context)?.as_integer()? as usize;
|
||||||
|
let item = list.items().get(index).cloned().unwrap_or_default();
|
||||||
let item = if let Some(index_end) = &self.index_end {
|
|
||||||
let index_end = index_end.run(source, context)?.as_integer()? as usize;
|
|
||||||
let sublist = list.items()[index..=index_end].to_vec();
|
|
||||||
|
|
||||||
Value::List(List::with_items(sublist))
|
|
||||||
} else {
|
|
||||||
list.items().get(index).cloned().unwrap_or_default()
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(item)
|
Ok(item)
|
||||||
}
|
}
|
||||||
Value::Map(map) => {
|
Value::Map(map) => {
|
||||||
let map = map.inner();
|
let map = map.inner();
|
||||||
|
|
||||||
let (key, value) = if let IndexExpression::Identifier(identifier) = &self.index {
|
let (identifier, value) =
|
||||||
let key = identifier.inner();
|
if let IndexExpression::Identifier(identifier) = &self.index {
|
||||||
let value = map.get(key).unwrap_or_default();
|
let value = map.get(identifier).unwrap_or_default();
|
||||||
|
|
||||||
(key.clone(), value)
|
(identifier.clone(), value)
|
||||||
} else {
|
} else {
|
||||||
let index_value = self.index.run(source, context)?;
|
let index_value = self.index.run(source, context)?;
|
||||||
let key = index_value.as_string()?;
|
let identifier = Identifier::new(index_value.as_string()?);
|
||||||
let value = map.get(key.as_str()).unwrap_or_default();
|
let value = map.get(&identifier).unwrap_or_default();
|
||||||
|
|
||||||
(key.clone(), value)
|
(identifier, value)
|
||||||
};
|
};
|
||||||
|
|
||||||
if value.is_none() {
|
if value.is_none() {
|
||||||
Err(RuntimeError::VariableIdentifierNotFound(key))
|
Err(RuntimeError::VariableIdentifierNotFound(identifier))
|
||||||
} else {
|
} else {
|
||||||
Ok(value.clone())
|
Ok(value.clone())
|
||||||
}
|
}
|
||||||
@ -121,10 +97,5 @@ impl Format for Index {
|
|||||||
self.collection.format(output, indent_level);
|
self.collection.format(output, indent_level);
|
||||||
output.push(':');
|
output.push(':');
|
||||||
self.index.format(output, indent_level);
|
self.index.format(output, indent_level);
|
||||||
|
|
||||||
if let Some(expression) = &self.index_end {
|
|
||||||
output.push_str("..");
|
|
||||||
expression.format(output, indent_level);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{RuntimeError, SyntaxError, ValidationError},
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
AbstractTree, AssignmentOperator, Context, Format, Index, IndexExpression, Statement,
|
AbstractTree, AssignmentOperator, Context, Format, Identifier, Index, IndexExpression,
|
||||||
SyntaxNode, Type, Value,
|
Statement, SyntaxNode, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
@ -44,11 +44,14 @@ impl AbstractTree for IndexAssignment {
|
|||||||
|
|
||||||
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
||||||
let _index_collection = self.index.collection.run(source, context)?;
|
let _index_collection = self.index.collection.run(source, context)?;
|
||||||
let index_key = if let IndexExpression::Identifier(identifier) = &self.index.index {
|
let index_identifier = if let IndexExpression::Identifier(identifier) = &self.index.index {
|
||||||
identifier.inner()
|
identifier
|
||||||
} else {
|
} else {
|
||||||
|
let index_run = self.index.index.run(source, context)?;
|
||||||
|
let expected_identifier = Identifier::new(index_run.as_string()?);
|
||||||
|
|
||||||
return Err(RuntimeError::VariableIdentifierNotFound(
|
return Err(RuntimeError::VariableIdentifierNotFound(
|
||||||
self.index.index.run(source, context)?.to_string(),
|
expected_identifier,
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -56,7 +59,7 @@ impl AbstractTree for IndexAssignment {
|
|||||||
|
|
||||||
let new_value = match self.operator {
|
let new_value = match self.operator {
|
||||||
AssignmentOperator::PlusEqual => {
|
AssignmentOperator::PlusEqual => {
|
||||||
if let Some(mut previous_value) = context.get_value(index_key)? {
|
if let Some(mut previous_value) = context.get_value(index_identifier)? {
|
||||||
previous_value += value;
|
previous_value += value;
|
||||||
previous_value
|
previous_value
|
||||||
} else {
|
} else {
|
||||||
@ -64,7 +67,7 @@ impl AbstractTree for IndexAssignment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssignmentOperator::MinusEqual => {
|
AssignmentOperator::MinusEqual => {
|
||||||
if let Some(mut previous_value) = context.get_value(index_key)? {
|
if let Some(mut previous_value) = context.get_value(index_identifier)? {
|
||||||
previous_value -= value;
|
previous_value -= value;
|
||||||
previous_value
|
previous_value
|
||||||
} else {
|
} else {
|
||||||
@ -74,7 +77,7 @@ impl AbstractTree for IndexAssignment {
|
|||||||
AssignmentOperator::Equal => value,
|
AssignmentOperator::Equal => value,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.set_value(index_key.clone(), new_value)?;
|
context.set_value(index_identifier.clone(), new_value)?;
|
||||||
|
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,12 @@ use crate::{
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct MapNode {
|
pub struct MapNode {
|
||||||
properties: BTreeMap<String, (Statement, Option<Type>)>,
|
properties: BTreeMap<Identifier, (Statement, Option<Type>)>,
|
||||||
position: SourcePosition,
|
position: SourcePosition,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapNode {
|
impl MapNode {
|
||||||
pub fn properties(&self) -> &BTreeMap<String, (Statement, Option<Type>)> {
|
pub fn properties(&self) -> &BTreeMap<Identifier, (Statement, Option<Type>)> {
|
||||||
&self.properties
|
&self.properties
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -26,14 +26,14 @@ impl AbstractTree for MapNode {
|
|||||||
SyntaxError::expect_syntax_node(source, "map", node)?;
|
SyntaxError::expect_syntax_node(source, "map", node)?;
|
||||||
|
|
||||||
let mut properties = BTreeMap::new();
|
let mut properties = BTreeMap::new();
|
||||||
let mut current_key = "".to_string();
|
let mut current_identifier = None;
|
||||||
let mut current_type = None;
|
let mut current_type = None;
|
||||||
|
|
||||||
for index in 0..node.child_count() - 1 {
|
for index in 0..node.child_count() - 1 {
|
||||||
let child = node.child(index).unwrap();
|
let child = node.child(index).unwrap();
|
||||||
|
|
||||||
if child.kind() == "identifier" {
|
if child.kind() == "identifier" {
|
||||||
current_key = Identifier::from_syntax(child, source, context)?.take_inner();
|
current_identifier = Some(Identifier::from_syntax(child, source, context)?);
|
||||||
current_type = None;
|
current_type = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +45,9 @@ impl AbstractTree for MapNode {
|
|||||||
if child.kind() == "statement" {
|
if child.kind() == "statement" {
|
||||||
let statement = Statement::from_syntax(child, source, context)?;
|
let statement = Statement::from_syntax(child, source, context)?;
|
||||||
|
|
||||||
properties.insert(current_key.clone(), (statement, current_type.clone()));
|
if let Some(identifier) = ¤t_identifier {
|
||||||
|
properties.insert(identifier.clone(), (statement, current_type.clone()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,16 +84,15 @@ impl AbstractTree for Match {
|
|||||||
if let (Value::Enum(enum_instance), MatchPattern::EnumPattern(enum_pattern)) =
|
if let (Value::Enum(enum_instance), MatchPattern::EnumPattern(enum_pattern)) =
|
||||||
(&matcher_value, pattern)
|
(&matcher_value, pattern)
|
||||||
{
|
{
|
||||||
if enum_instance.name() == enum_pattern.name().inner()
|
if enum_instance.name() == enum_pattern.name()
|
||||||
&& enum_instance.variant_name() == enum_pattern.variant().inner()
|
&& enum_instance.variant() == enum_pattern.variant()
|
||||||
{
|
{
|
||||||
let statement_context = Context::with_variables_from(context)?;
|
let statement_context = Context::with_variables_from(context)?;
|
||||||
|
|
||||||
if let (Some(identifier), Some(value)) =
|
if let (Some(identifier), Some(value)) =
|
||||||
(enum_pattern.inner_identifier(), enum_instance.value())
|
(enum_pattern.inner_identifier(), enum_instance.value())
|
||||||
{
|
{
|
||||||
statement_context
|
statement_context.set_value(identifier.clone(), value.as_ref().clone())?;
|
||||||
.set_value(identifier.inner().clone(), value.as_ref().clone())?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return statement.run(source, &statement_context);
|
return statement.run(source, &statement_context);
|
||||||
|
@ -12,7 +12,7 @@ use crate::{
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct StructDefinition {
|
pub struct StructDefinition {
|
||||||
name: Identifier,
|
name: Identifier,
|
||||||
properties: BTreeMap<String, (Option<Statement>, Type)>,
|
properties: BTreeMap<Identifier, (Option<Statement>, Type)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StructDefinition {
|
impl StructDefinition {
|
||||||
@ -38,10 +38,7 @@ impl StructDefinition {
|
|||||||
all_properties.set(key.clone(), value);
|
all_properties.set(key.clone(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(StructInstance::new(
|
Ok(StructInstance::new(self.name.clone(), all_properties))
|
||||||
self.name.inner().clone(),
|
|
||||||
all_properties,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +60,7 @@ impl AbstractTree for StructDefinition {
|
|||||||
if child_syntax_node.kind() == "identifier" {
|
if child_syntax_node.kind() == "identifier" {
|
||||||
if current_statement.is_none() {
|
if current_statement.is_none() {
|
||||||
if let (Some(identifier), Some(r#type)) = (¤t_identifier, ¤t_type) {
|
if let (Some(identifier), Some(r#type)) = (¤t_identifier, ¤t_type) {
|
||||||
properties.insert(identifier.inner().clone(), (None, r#type.clone()));
|
properties.insert(identifier.clone(), (None, r#type.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +88,7 @@ impl AbstractTree for StructDefinition {
|
|||||||
};
|
};
|
||||||
|
|
||||||
properties.insert(
|
properties.insert(
|
||||||
identifier.inner().clone(),
|
identifier.clone(),
|
||||||
(current_statement.clone(), r#type.clone()),
|
(current_statement.clone(), r#type.clone()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -110,10 +107,7 @@ impl AbstractTree for StructDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
fn run(&self, _source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
||||||
context.set_definition(
|
context.set_definition(self.name.clone(), TypeDefinition::Struct(self.clone()))?;
|
||||||
self.name.inner().clone(),
|
|
||||||
TypeDefinition::Struct(self.clone()),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tree_sitter::Node as SyntaxNode;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
built_in_types::BuiltInType,
|
built_in_types::BuiltInType,
|
||||||
error::{RuntimeError, SyntaxError, ValidationError},
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
AbstractTree, Context, Format, Identifier, SyntaxNode, Value,
|
AbstractTree, Context, Format, Identifier, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
@ -13,10 +14,9 @@ pub enum Type {
|
|||||||
Any,
|
Any,
|
||||||
Boolean,
|
Boolean,
|
||||||
Collection,
|
Collection,
|
||||||
Custom(Identifier),
|
Custom {
|
||||||
CustomWithArgument {
|
|
||||||
name: Identifier,
|
name: Identifier,
|
||||||
argument: Box<Type>,
|
argument: Option<Box<Type>>,
|
||||||
},
|
},
|
||||||
Float,
|
Float,
|
||||||
Function {
|
Function {
|
||||||
@ -33,8 +33,15 @@ pub enum Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Type {
|
impl Type {
|
||||||
|
pub fn custom(name: Identifier, argument: Option<Type>) -> Self {
|
||||||
|
Type::Custom {
|
||||||
|
name,
|
||||||
|
argument: argument.map(|r#type| Box::new(r#type)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn option(inner_type: Option<Type>) -> Self {
|
pub fn option(inner_type: Option<Type>) -> Self {
|
||||||
BuiltInType::Option.get(inner_type).clone()
|
BuiltInType::Option(inner_type).get().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list(item_type: Type) -> Self {
|
pub fn list(item_type: Type) -> Self {
|
||||||
@ -75,13 +82,12 @@ impl Type {
|
|||||||
| (Type::Integer, Type::Number)
|
| (Type::Integer, Type::Number)
|
||||||
| (Type::Float, Type::Number)
|
| (Type::Float, Type::Number)
|
||||||
| (Type::String, Type::String) => true,
|
| (Type::String, Type::String) => true,
|
||||||
(Type::Custom(left), Type::Custom(right)) => left == right,
|
|
||||||
(
|
(
|
||||||
Type::CustomWithArgument {
|
Type::Custom {
|
||||||
name: left_name,
|
name: left_name,
|
||||||
argument: left_argument,
|
argument: left_argument,
|
||||||
},
|
},
|
||||||
Type::CustomWithArgument {
|
Type::Custom {
|
||||||
name: right_name,
|
name: right_name,
|
||||||
argument: right_argument,
|
argument: right_argument,
|
||||||
},
|
},
|
||||||
@ -138,7 +144,7 @@ impl AbstractTree for Type {
|
|||||||
fn from_syntax(
|
fn from_syntax(
|
||||||
node: SyntaxNode,
|
node: SyntaxNode,
|
||||||
_source: &str,
|
_source: &str,
|
||||||
_context: &Context,
|
context: &Context,
|
||||||
) -> Result<Self, SyntaxError> {
|
) -> Result<Self, SyntaxError> {
|
||||||
SyntaxError::expect_syntax_node(_source, "type", node)?;
|
SyntaxError::expect_syntax_node(_source, "type", node)?;
|
||||||
|
|
||||||
@ -146,23 +152,18 @@ impl AbstractTree for Type {
|
|||||||
|
|
||||||
let r#type = match type_node.kind() {
|
let r#type = match type_node.kind() {
|
||||||
"identifier" => {
|
"identifier" => {
|
||||||
if node.child_count() == 1 {
|
let name = Identifier::from_syntax(type_node, _source, context)?;
|
||||||
Type::Custom(Identifier::from_syntax(type_node, _source, _context)?)
|
let argument = if let Some(child) = node.child(2) {
|
||||||
|
Some(Type::from_syntax(child, _source, context)?)
|
||||||
} else {
|
} else {
|
||||||
let name = Identifier::from_syntax(type_node, _source, _context)?;
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let argument_node = node.child(2).unwrap();
|
Type::custom(name, argument)
|
||||||
let argument = Type::from_syntax(argument_node, _source, _context)?;
|
|
||||||
|
|
||||||
Type::CustomWithArgument {
|
|
||||||
name,
|
|
||||||
argument: Box::new(argument),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
"[" => {
|
"[" => {
|
||||||
let item_type_node = node.child(1).unwrap();
|
let item_type_node = node.child(1).unwrap();
|
||||||
let item_type = Type::from_syntax(item_type_node, _source, _context)?;
|
let item_type = Type::from_syntax(item_type_node, _source, context)?;
|
||||||
|
|
||||||
Type::List(Box::new(item_type))
|
Type::List(Box::new(item_type))
|
||||||
}
|
}
|
||||||
@ -178,7 +179,7 @@ impl AbstractTree for Type {
|
|||||||
let child = node.child(index).unwrap();
|
let child = node.child(index).unwrap();
|
||||||
|
|
||||||
if child.is_named() {
|
if child.is_named() {
|
||||||
let parameter_type = Type::from_syntax(child, _source, _context)?;
|
let parameter_type = Type::from_syntax(child, _source, context)?;
|
||||||
|
|
||||||
parameter_types.push(parameter_type);
|
parameter_types.push(parameter_type);
|
||||||
}
|
}
|
||||||
@ -186,7 +187,7 @@ impl AbstractTree for Type {
|
|||||||
|
|
||||||
let final_node = node.child(child_count - 1).unwrap();
|
let final_node = node.child(child_count - 1).unwrap();
|
||||||
let return_type = if final_node.is_named() {
|
let return_type = if final_node.is_named() {
|
||||||
Type::from_syntax(final_node, _source, _context)?
|
Type::from_syntax(final_node, _source, context)?
|
||||||
} else {
|
} else {
|
||||||
Type::option(None)
|
Type::option(None)
|
||||||
};
|
};
|
||||||
@ -233,8 +234,7 @@ impl Format for Type {
|
|||||||
Type::Any => output.push_str("any"),
|
Type::Any => output.push_str("any"),
|
||||||
Type::Boolean => output.push_str("bool"),
|
Type::Boolean => output.push_str("bool"),
|
||||||
Type::Collection => output.push_str("collection"),
|
Type::Collection => output.push_str("collection"),
|
||||||
Type::Custom(_) => todo!(),
|
Type::Custom {
|
||||||
Type::CustomWithArgument {
|
|
||||||
name: _,
|
name: _,
|
||||||
argument: _,
|
argument: _,
|
||||||
} => todo!(),
|
} => todo!(),
|
||||||
@ -279,9 +279,12 @@ impl Display for Type {
|
|||||||
Type::Any => write!(f, "any"),
|
Type::Any => write!(f, "any"),
|
||||||
Type::Boolean => write!(f, "bool"),
|
Type::Boolean => write!(f, "bool"),
|
||||||
Type::Collection => write!(f, "collection"),
|
Type::Collection => write!(f, "collection"),
|
||||||
Type::Custom(identifier) => write!(f, "{identifier}"),
|
Type::Custom { name, argument } => {
|
||||||
Type::CustomWithArgument { name, argument } => {
|
if let Some(argument) = argument {
|
||||||
write!(f, "{name}<{argument}>")
|
write!(f, "{name}<{argument}>")
|
||||||
|
} else {
|
||||||
|
write!(f, "{name}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Type::Float => write!(f, "float"),
|
Type::Float => write!(f, "float"),
|
||||||
Type::Function {
|
Type::Function {
|
||||||
|
@ -121,7 +121,7 @@ impl AbstractTree for ValueNode {
|
|||||||
let r#type = match self {
|
let r#type = match self {
|
||||||
ValueNode::Boolean(_) => Type::Boolean,
|
ValueNode::Boolean(_) => Type::Boolean,
|
||||||
ValueNode::Float(_) => Type::Float,
|
ValueNode::Float(_) => Type::Float,
|
||||||
ValueNode::Function(function) => function.r#type().clone(),
|
ValueNode::Function(function) => function.r#type(),
|
||||||
ValueNode::Integer(_) => Type::Integer,
|
ValueNode::Integer(_) => Type::Integer,
|
||||||
ValueNode::String(_) => Type::String,
|
ValueNode::String(_) => Type::String,
|
||||||
ValueNode::List(expressions) => {
|
ValueNode::List(expressions) => {
|
||||||
@ -147,17 +147,20 @@ impl AbstractTree for ValueNode {
|
|||||||
}
|
}
|
||||||
ValueNode::Map(_) => Type::Map,
|
ValueNode::Map(_) => Type::Map,
|
||||||
ValueNode::Struct { name, .. } => {
|
ValueNode::Struct { name, .. } => {
|
||||||
Type::Custom(name.clone())
|
Type::Custom { name: name.clone(), argument: None }
|
||||||
}
|
}
|
||||||
ValueNode::Range(_) => Type::Range,
|
ValueNode::Range(_) => Type::Range,
|
||||||
ValueNode::Enum { name, variant: _, expression } => {
|
ValueNode::Enum { name, variant: _, expression } => {
|
||||||
if let Some(expression) = expression {
|
if let Some(expression) = expression {
|
||||||
Type::CustomWithArgument {
|
Type::Custom {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
argument: Box::new(expression.expected_type(context)?)
|
argument: Some(Box::new(expression.expected_type(context)?))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Type::Custom(name.clone())
|
Type::Custom{
|
||||||
|
name: name.clone(),
|
||||||
|
argument: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -204,7 +207,7 @@ impl AbstractTree for ValueNode {
|
|||||||
ValueNode::Map(map_node) => map_node.run(source, context)?,
|
ValueNode::Map(map_node) => map_node.run(source, context)?,
|
||||||
ValueNode::Range(range) => Value::Range(range.clone()),
|
ValueNode::Range(range) => Value::Range(range.clone()),
|
||||||
ValueNode::Struct { name, properties } => {
|
ValueNode::Struct { name, properties } => {
|
||||||
let instance = if let Some(definition) = context.get_definition(name.inner())? {
|
let instance = if let Some(definition) = context.get_definition(name)? {
|
||||||
if let TypeDefinition::Struct(struct_definition) = definition {
|
if let TypeDefinition::Struct(struct_definition) = definition {
|
||||||
struct_definition.instantiate(properties, source, context)?
|
struct_definition.instantiate(properties, source, context)?
|
||||||
} else {
|
} else {
|
||||||
@ -212,7 +215,7 @@ impl AbstractTree for ValueNode {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::TypeDefinitionNotFound(name.inner().clone())
|
ValidationError::TypeDefinitionNotFound(name.clone())
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -225,9 +228,9 @@ impl AbstractTree for ValueNode {
|
|||||||
} else {
|
} else {
|
||||||
Value::none()
|
Value::none()
|
||||||
};
|
};
|
||||||
let instance = if let Some(definition) = context.get_definition(name.inner())? {
|
let instance = if let Some(definition) = context.get_definition(name)? {
|
||||||
if let TypeDefinition::Enum(enum_defintion) = definition {
|
if let TypeDefinition::Enum(enum_defintion) = definition {
|
||||||
enum_defintion.instantiate(variant.inner().clone(), Some(value))
|
enum_defintion.instantiate(variant.clone(), Some(value))
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::ExpectedEnumDefintion {
|
ValidationError::ExpectedEnumDefintion {
|
||||||
@ -237,7 +240,7 @@ impl AbstractTree for ValueNode {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::TypeDefinitionNotFound(name.inner().clone())
|
ValidationError::TypeDefinitionNotFound(name.clone())
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ pub trait Callable {
|
|||||||
&self,
|
&self,
|
||||||
arguments: &[Value],
|
arguments: &[Value],
|
||||||
source: &str,
|
source: &str,
|
||||||
outer_context: &Context,
|
context: &Context,
|
||||||
) -> Result<Value, RuntimeError>;
|
) -> Result<Value, RuntimeError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +72,10 @@ impl Callable for BuiltInFunction {
|
|||||||
match self {
|
match self {
|
||||||
BuiltInFunction::AssertEqual => Type::function(
|
BuiltInFunction::AssertEqual => Type::function(
|
||||||
vec![Type::Any, Type::Any],
|
vec![Type::Any, Type::Any],
|
||||||
Type::Custom(Identifier::new("Result")),
|
Type::Custom {
|
||||||
|
name: Identifier::new("Result"),
|
||||||
|
argument: None,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
BuiltInFunction::Fs(fs_function) => fs_function.r#type(),
|
BuiltInFunction::Fs(fs_function) => fs_function.r#type(),
|
||||||
BuiltInFunction::Json(json_function) => json_function.r#type(),
|
BuiltInFunction::Json(json_function) => json_function.r#type(),
|
||||||
@ -90,7 +93,7 @@ impl Callable for BuiltInFunction {
|
|||||||
&self,
|
&self,
|
||||||
arguments: &[Value],
|
arguments: &[Value],
|
||||||
_source: &str,
|
_source: &str,
|
||||||
_outer_context: &Context,
|
context: &Context,
|
||||||
) -> Result<Value, RuntimeError> {
|
) -> Result<Value, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
BuiltInFunction::AssertEqual => {
|
BuiltInFunction::AssertEqual => {
|
||||||
@ -101,26 +104,22 @@ impl Callable for BuiltInFunction {
|
|||||||
|
|
||||||
let result = if left == right {
|
let result = if left == right {
|
||||||
Value::Enum(EnumInstance::new(
|
Value::Enum(EnumInstance::new(
|
||||||
"Result".to_string(),
|
Identifier::new("Result"),
|
||||||
"Ok".to_string(),
|
Identifier::new("Ok"),
|
||||||
Some(Value::none()),
|
Some(Value::none()),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Value::Enum(EnumInstance::new(
|
Value::Enum(EnumInstance::new(
|
||||||
"Result".to_string(),
|
Identifier::new("Result"),
|
||||||
"Error".to_string(),
|
Identifier::new("Error"),
|
||||||
Some(Value::none()),
|
Some(Value::none()),
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
BuiltInFunction::Fs(fs_function) => {
|
BuiltInFunction::Fs(fs_function) => fs_function.call(arguments, _source, context),
|
||||||
fs_function.call(arguments, _source, _outer_context)
|
BuiltInFunction::Json(json_function) => json_function.call(arguments, _source, context),
|
||||||
}
|
|
||||||
BuiltInFunction::Json(json_function) => {
|
|
||||||
json_function.call(arguments, _source, _outer_context)
|
|
||||||
}
|
|
||||||
BuiltInFunction::Length => {
|
BuiltInFunction::Length => {
|
||||||
RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?;
|
RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?;
|
||||||
|
|
||||||
@ -184,7 +183,7 @@ impl Callable for BuiltInFunction {
|
|||||||
Ok(Value::Integer(random()))
|
Ok(Value::Integer(random()))
|
||||||
}
|
}
|
||||||
BuiltInFunction::String(string_function) => {
|
BuiltInFunction::String(string_function) => {
|
||||||
string_function.call(arguments, _source, _outer_context)
|
string_function.call(arguments, _source, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use enum_iterator::Sequence;
|
use enum_iterator::Sequence;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{error::RuntimeError, Context, EnumInstance, List, Type, Value};
|
use crate::{error::RuntimeError, Context, EnumInstance, Identifier, List, Type, Value};
|
||||||
|
|
||||||
use super::Callable;
|
use super::Callable;
|
||||||
|
|
||||||
@ -203,7 +203,7 @@ impl Callable for StrFunction {
|
|||||||
&self,
|
&self,
|
||||||
arguments: &[Value],
|
arguments: &[Value],
|
||||||
_source: &str,
|
_source: &str,
|
||||||
_outer_context: &Context,
|
context: &Context,
|
||||||
) -> Result<Value, RuntimeError> {
|
) -> Result<Value, RuntimeError> {
|
||||||
let value = match self {
|
let value = match self {
|
||||||
StrFunction::AsBytes => {
|
StrFunction::AsBytes => {
|
||||||
@ -238,14 +238,14 @@ impl Callable for StrFunction {
|
|||||||
|
|
||||||
if let Some(index) = find {
|
if let Some(index) = find {
|
||||||
Value::Enum(EnumInstance::new(
|
Value::Enum(EnumInstance::new(
|
||||||
"Option".to_string(),
|
Identifier::new("Option"),
|
||||||
"Some".to_string(),
|
Identifier::new("Some"),
|
||||||
Some(index),
|
Some(index),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Value::Enum(EnumInstance::new(
|
Value::Enum(EnumInstance::new(
|
||||||
"Option".to_string(),
|
Identifier::new("Option"),
|
||||||
"None".to_string(),
|
Identifier::new("None"),
|
||||||
Some(Value::none()),
|
Some(Value::none()),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -477,8 +477,8 @@ impl Callable for StrFunction {
|
|||||||
|
|
||||||
if let Some(value) = stripped {
|
if let Some(value) = stripped {
|
||||||
Value::Enum(EnumInstance::new(
|
Value::Enum(EnumInstance::new(
|
||||||
"Option".to_string(),
|
Identifier::new("Option"),
|
||||||
"Some".to_string(),
|
Identifier::new("Some"),
|
||||||
Some(value),
|
Some(value),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
|
29
src/built_in_identifiers.rs
Normal file
29
src/built_in_identifiers.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
use enum_iterator::{all, Sequence};
|
||||||
|
|
||||||
|
use crate::Identifier;
|
||||||
|
|
||||||
|
pub fn all_built_in_identifiers() -> impl Iterator<Item = BuiltInIdentifier> {
|
||||||
|
all()
|
||||||
|
}
|
||||||
|
|
||||||
|
const OPTION: OnceLock<Identifier> = OnceLock::new();
|
||||||
|
const NONE: OnceLock<Identifier> = OnceLock::new();
|
||||||
|
|
||||||
|
#[derive(Sequence)]
|
||||||
|
pub enum BuiltInIdentifier {
|
||||||
|
Option,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BuiltInIdentifier {
|
||||||
|
pub fn get(&self) -> &Identifier {
|
||||||
|
match self {
|
||||||
|
BuiltInIdentifier::Option => {
|
||||||
|
return OPTION.get_or_init(|| Identifier::new("Option"));
|
||||||
|
}
|
||||||
|
BuiltInIdentifier::None => return NONE.get_or_init(|| Identifier::new("None")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,10 +2,13 @@ use std::sync::OnceLock;
|
|||||||
|
|
||||||
use enum_iterator::{all, Sequence};
|
use enum_iterator::{all, Sequence};
|
||||||
|
|
||||||
use crate::{EnumDefinition, Identifier, Type, TypeDefinition, VariantContent};
|
use crate::{
|
||||||
|
error::rw_lock_error::RwLockError, Context, EnumDefinition, Identifier, Type, TypeDefinition,
|
||||||
|
VariantContent,
|
||||||
|
};
|
||||||
|
|
||||||
static OPTION: OnceLock<TypeDefinition> = OnceLock::new();
|
static OPTION: OnceLock<Result<TypeDefinition, RwLockError>> = OnceLock::new();
|
||||||
static RESULT: OnceLock<TypeDefinition> = OnceLock::new();
|
static RESULT: OnceLock<Result<TypeDefinition, RwLockError>> = OnceLock::new();
|
||||||
|
|
||||||
pub fn all_built_in_type_definitions() -> impl Iterator<Item = BuiltInTypeDefinition> {
|
pub fn all_built_in_type_definitions() -> impl Iterator<Item = BuiltInTypeDefinition> {
|
||||||
all()
|
all()
|
||||||
@ -25,25 +28,29 @@ impl BuiltInTypeDefinition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self) -> &TypeDefinition {
|
pub fn get(&self, context: &Context) -> &Result<TypeDefinition, RwLockError> {
|
||||||
match self {
|
match self {
|
||||||
BuiltInTypeDefinition::Option => OPTION.get_or_init(|| {
|
BuiltInTypeDefinition::Option => OPTION.get_or_init(|| {
|
||||||
TypeDefinition::Enum(EnumDefinition::new(
|
let definition = TypeDefinition::Enum(EnumDefinition::new(
|
||||||
Identifier::new(self.name()),
|
Identifier::new(self.name()),
|
||||||
vec![
|
vec![
|
||||||
(Identifier::new("Some"), VariantContent::Type(Type::Any)),
|
(Identifier::new("Some"), VariantContent::Type(Type::Any)),
|
||||||
(Identifier::new("None"), VariantContent::None),
|
(Identifier::new("None"), VariantContent::None),
|
||||||
],
|
],
|
||||||
))
|
));
|
||||||
|
|
||||||
|
Ok(definition)
|
||||||
}),
|
}),
|
||||||
BuiltInTypeDefinition::Result => RESULT.get_or_init(|| {
|
BuiltInTypeDefinition::Result => RESULT.get_or_init(|| {
|
||||||
TypeDefinition::Enum(EnumDefinition::new(
|
let definition = TypeDefinition::Enum(EnumDefinition::new(
|
||||||
Identifier::new(self.name()),
|
Identifier::new(self.name()),
|
||||||
vec![
|
vec![
|
||||||
(Identifier::new("Ok"), VariantContent::Type(Type::Any)),
|
(Identifier::new("Ok"), VariantContent::Type(Type::Any)),
|
||||||
(Identifier::new("Err"), VariantContent::Type(Type::Any)),
|
(Identifier::new("Err"), VariantContent::Type(Type::Any)),
|
||||||
],
|
],
|
||||||
))
|
));
|
||||||
|
|
||||||
|
Ok(definition)
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,33 @@
|
|||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
use enum_iterator::Sequence;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{Identifier, Type};
|
use crate::{Identifier, Type};
|
||||||
|
|
||||||
static OPTION: OnceLock<Type> = OnceLock::new();
|
static OPTION: OnceLock<Type> = OnceLock::new();
|
||||||
|
|
||||||
#[derive(Sequence, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
|
||||||
pub enum BuiltInType {
|
pub enum BuiltInType {
|
||||||
Option,
|
Option(Option<Type>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuiltInType {
|
impl BuiltInType {
|
||||||
pub fn name(&self) -> &'static str {
|
pub fn name(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
BuiltInType::Option => todo!(),
|
BuiltInType::Option(_) => "Option",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, inner_type: Option<Type>) -> &Type {
|
pub fn get(&self) -> &Type {
|
||||||
match self {
|
match self {
|
||||||
BuiltInType::Option => OPTION.get_or_init(|| {
|
BuiltInType::Option(content_type) => OPTION.get_or_init(|| {
|
||||||
if let Some(inner_type) = inner_type {
|
if let Some(content_type) = content_type {
|
||||||
Type::CustomWithArgument {
|
Type::Custom {
|
||||||
name: Identifier::new("Option"),
|
name: Identifier::new("Option"),
|
||||||
argument: Box::new(inner_type),
|
argument: Some(Box::new(content_type.clone())),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Type::Custom(Identifier::new("Option"))
|
Type::Custom {
|
||||||
|
name: Identifier::new("Option"),
|
||||||
|
argument: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,19 @@
|
|||||||
use std::{collections::BTreeMap, env::args, sync::OnceLock};
|
use std::{env::args, sync::OnceLock};
|
||||||
|
|
||||||
use enum_iterator::{all, Sequence};
|
use enum_iterator::{all, Sequence};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
built_in_functions::{fs::fs_functions, json::json_functions, str::string_functions, Callable},
|
built_in_functions::{fs::fs_functions, json::json_functions, str::string_functions, Callable},
|
||||||
error::{RuntimeError, SyntaxError, ValidationError},
|
BuiltInFunction, EnumInstance, Function, Identifier, List, Map, Value,
|
||||||
AbstractTree, BuiltInFunction, Context, EnumInstance, Format, Function, Identifier, List, Map,
|
|
||||||
SyntaxNode, Type, Value,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static ARGS: OnceLock<Value> = OnceLock::new();
|
static ARGS: OnceLock<Value> = OnceLock::new();
|
||||||
static FS: OnceLock<Value> = OnceLock::new();
|
static FS: OnceLock<Value> = OnceLock::new();
|
||||||
static JSON: OnceLock<Value> = OnceLock::new();
|
static JSON: OnceLock<Value> = OnceLock::new();
|
||||||
static RANDOM: OnceLock<Value> = OnceLock::new();
|
|
||||||
static STRING: OnceLock<Value> = OnceLock::new();
|
|
||||||
static NONE: OnceLock<Value> = OnceLock::new();
|
static NONE: OnceLock<Value> = OnceLock::new();
|
||||||
|
static RANDOM: OnceLock<Value> = OnceLock::new();
|
||||||
|
static STR: OnceLock<Value> = OnceLock::new();
|
||||||
|
|
||||||
/// Returns the entire built-in value API.
|
/// Returns the entire built-in value API.
|
||||||
pub fn all_built_in_values() -> impl Iterator<Item = BuiltInValue> {
|
pub fn all_built_in_values() -> impl Iterator<Item = BuiltInValue> {
|
||||||
@ -86,23 +84,6 @@ impl BuiltInValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the value's type.
|
|
||||||
///
|
|
||||||
/// This is checked with a unit test to ensure it matches the value.
|
|
||||||
pub fn r#type(&self) -> Type {
|
|
||||||
match self {
|
|
||||||
BuiltInValue::Args => Type::list(Type::String),
|
|
||||||
BuiltInValue::AssertEqual => BuiltInFunction::AssertEqual.r#type(),
|
|
||||||
BuiltInValue::Fs => Type::Map,
|
|
||||||
BuiltInValue::Json => Type::Map,
|
|
||||||
BuiltInValue::Length => BuiltInFunction::Length.r#type(),
|
|
||||||
BuiltInValue::None => Type::Custom(Identifier::new("Option")),
|
|
||||||
BuiltInValue::Output => BuiltInFunction::Output.r#type(),
|
|
||||||
BuiltInValue::Random => Type::Map,
|
|
||||||
BuiltInValue::Str => Type::Map,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the value by creating it or, if it has already been accessed, retrieving it from its
|
/// Returns the value by creating it or, if it has already been accessed, retrieving it from its
|
||||||
/// [OnceLock][].
|
/// [OnceLock][].
|
||||||
pub fn get(&self) -> &Value {
|
pub fn get(&self) -> &Value {
|
||||||
@ -116,42 +97,40 @@ impl BuiltInValue {
|
|||||||
&Value::Function(Function::BuiltIn(BuiltInFunction::AssertEqual))
|
&Value::Function(Function::BuiltIn(BuiltInFunction::AssertEqual))
|
||||||
}
|
}
|
||||||
BuiltInValue::Fs => FS.get_or_init(|| {
|
BuiltInValue::Fs => FS.get_or_init(|| {
|
||||||
let mut fs_context = BTreeMap::new();
|
let mut fs_map = Map::new();
|
||||||
|
|
||||||
for fs_function in fs_functions() {
|
for fs_function in fs_functions() {
|
||||||
let key = fs_function.name().to_string();
|
let key = fs_function.name();
|
||||||
let value =
|
let value =
|
||||||
Value::Function(Function::BuiltIn(BuiltInFunction::Fs(fs_function)));
|
Value::Function(Function::BuiltIn(BuiltInFunction::Fs(fs_function)));
|
||||||
|
|
||||||
fs_context.insert(key, value);
|
fs_map.set(Identifier::new(key), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Map(Map::with_values(fs_context))
|
Value::Map(fs_map)
|
||||||
}),
|
}),
|
||||||
BuiltInValue::Json => JSON.get_or_init(|| {
|
BuiltInValue::Json => JSON.get_or_init(|| {
|
||||||
let mut json_context = BTreeMap::new();
|
let mut json_map = Map::new();
|
||||||
|
|
||||||
for json_function in json_functions() {
|
for json_function in json_functions() {
|
||||||
let key = json_function.name().to_string();
|
let key = json_function.name();
|
||||||
let value =
|
let value =
|
||||||
Value::Function(Function::BuiltIn(BuiltInFunction::Json(json_function)));
|
Value::Function(Function::BuiltIn(BuiltInFunction::Json(json_function)));
|
||||||
|
|
||||||
json_context.insert(key, value);
|
json_map.set(Identifier::new(key), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Map(Map::with_values(json_context))
|
Value::Map(json_map)
|
||||||
}),
|
}),
|
||||||
BuiltInValue::Length => &Value::Function(Function::BuiltIn(BuiltInFunction::Length)),
|
BuiltInValue::Length => &Value::Function(Function::BuiltIn(BuiltInFunction::Length)),
|
||||||
BuiltInValue::None => NONE.get_or_init(|| {
|
BuiltInValue::None => &Value::Enum(EnumInstance::new(
|
||||||
Value::Enum(EnumInstance::new(
|
Identifier::new("Option"),
|
||||||
"Option".to_string(),
|
Identifier::new("None"),
|
||||||
"None".to_string(),
|
None,
|
||||||
None,
|
)),
|
||||||
))
|
|
||||||
}),
|
|
||||||
BuiltInValue::Output => &Value::Function(Function::BuiltIn(BuiltInFunction::Output)),
|
BuiltInValue::Output => &Value::Function(Function::BuiltIn(BuiltInFunction::Output)),
|
||||||
BuiltInValue::Random => RANDOM.get_or_init(|| {
|
BuiltInValue::Random => RANDOM.get_or_init(|| {
|
||||||
let mut random_context = BTreeMap::new();
|
let mut random_map = Map::new();
|
||||||
|
|
||||||
for built_in_function in [
|
for built_in_function in [
|
||||||
BuiltInFunction::RandomBoolean,
|
BuiltInFunction::RandomBoolean,
|
||||||
@ -159,83 +138,28 @@ impl BuiltInValue {
|
|||||||
BuiltInFunction::RandomFrom,
|
BuiltInFunction::RandomFrom,
|
||||||
BuiltInFunction::RandomInteger,
|
BuiltInFunction::RandomInteger,
|
||||||
] {
|
] {
|
||||||
let key = built_in_function.name().to_string();
|
let identifier = Identifier::new(built_in_function.name());
|
||||||
let value = Value::Function(Function::BuiltIn(built_in_function));
|
let value = Value::Function(Function::BuiltIn(built_in_function));
|
||||||
|
|
||||||
random_context.insert(key, value);
|
random_map.set(identifier, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Map(Map::with_values(random_context))
|
Value::Map(random_map)
|
||||||
}),
|
}),
|
||||||
BuiltInValue::Str => STRING.get_or_init(|| {
|
BuiltInValue::Str => STR.get_or_init(|| {
|
||||||
let mut string_context = BTreeMap::new();
|
let mut str_map = Map::new();
|
||||||
|
|
||||||
for string_function in string_functions() {
|
for string_function in string_functions() {
|
||||||
let key = string_function.name().to_string();
|
let identifier = Identifier::new(string_function.name());
|
||||||
let value = Value::Function(Function::BuiltIn(BuiltInFunction::String(
|
let value = Value::Function(Function::BuiltIn(BuiltInFunction::String(
|
||||||
string_function,
|
string_function,
|
||||||
)));
|
)));
|
||||||
|
|
||||||
string_context.insert(key, value);
|
str_map.set(identifier, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Map(Map::with_values(string_context))
|
Value::Map(str_map)
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for BuiltInValue {
|
|
||||||
fn from_syntax(
|
|
||||||
node: SyntaxNode,
|
|
||||||
_source: &str,
|
|
||||||
_context: &Context,
|
|
||||||
) -> Result<Self, SyntaxError> {
|
|
||||||
let built_in_value = match node.kind() {
|
|
||||||
"args" => BuiltInValue::Args,
|
|
||||||
"assert_equal" => BuiltInValue::AssertEqual,
|
|
||||||
"fs" => BuiltInValue::Fs,
|
|
||||||
"json" => BuiltInValue::Json,
|
|
||||||
"length" => BuiltInValue::Length,
|
|
||||||
"output" => BuiltInValue::Output,
|
|
||||||
"random" => BuiltInValue::Random,
|
|
||||||
"str" => BuiltInValue::Str,
|
|
||||||
_ => todo!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(built_in_value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
|
||||||
Ok(self.r#type())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate(&self, _source: &str, _context: &Context) -> Result<(), ValidationError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, _source: &str, _context: &Context) -> Result<Value, RuntimeError> {
|
|
||||||
Ok(self.get().clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Format for BuiltInValue {
|
|
||||||
fn format(&self, output: &mut String, _indent_level: u8) {
|
|
||||||
output.push_str(&self.get().to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::all_built_in_values;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn check_built_in_types() {
|
|
||||||
for built_in_value in all_built_in_values() {
|
|
||||||
let expected = built_in_value.r#type();
|
|
||||||
let actual = built_in_value.get().r#type();
|
|
||||||
|
|
||||||
assert_eq!(expected, actual);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -35,7 +35,7 @@ use std::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
built_in_type_definitions::all_built_in_type_definitions, built_in_values::all_built_in_values,
|
built_in_type_definitions::all_built_in_type_definitions, built_in_values::all_built_in_values,
|
||||||
error::rw_lock_error::RwLockError, Type, TypeDefinition, Value,
|
error::rw_lock_error::RwLockError, Identifier, Type, TypeDefinition, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An execution context that variable and type data during the [Interpreter]'s
|
/// An execution context that variable and type data during the [Interpreter]'s
|
||||||
@ -44,7 +44,7 @@ use crate::{
|
|||||||
/// See the [module-level docs][self] for more info.
|
/// See the [module-level docs][self] for more info.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
inner: Arc<RwLock<BTreeMap<String, ValueData>>>,
|
inner: Arc<RwLock<BTreeMap<Identifier, ValueData>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
@ -56,7 +56,7 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return a lock guard to the inner BTreeMap.
|
/// Return a lock guard to the inner BTreeMap.
|
||||||
pub fn inner(&self) -> Result<RwLockReadGuard<BTreeMap<String, ValueData>>, RwLockError> {
|
pub fn inner(&self) -> Result<RwLockReadGuard<BTreeMap<Identifier, ValueData>>, RwLockError> {
|
||||||
Ok(self.inner.read()?)
|
Ok(self.inner.read()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,15 +112,15 @@ impl Context {
|
|||||||
///
|
///
|
||||||
/// This will also return a built-in value if one matches the key. See the
|
/// This will also return a built-in value if one matches the key. See the
|
||||||
/// [module-level docs][self] for more info.
|
/// [module-level docs][self] for more info.
|
||||||
pub fn get_value(&self, key: &str) -> Result<Option<Value>, RwLockError> {
|
pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockError> {
|
||||||
if let Some(value_data) = self.inner.read()?.get(key) {
|
if let Some(value_data) = self.inner.read()?.get(identifier) {
|
||||||
if let ValueData::Value { inner, .. } = value_data {
|
if let ValueData::Value { inner, .. } = value_data {
|
||||||
return Ok(Some(inner.clone()));
|
return Ok(Some(inner.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for built_in_value in all_built_in_values() {
|
for built_in_value in all_built_in_values() {
|
||||||
if key == built_in_value.name() {
|
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()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,8 +132,8 @@ impl Context {
|
|||||||
///
|
///
|
||||||
/// If the key matches a stored value, its type will be returned. It if
|
/// If the key matches a stored value, its type will be returned. It if
|
||||||
/// matches a type hint, the type hint will be returned.
|
/// matches a type hint, the type hint will be returned.
|
||||||
pub fn get_type(&self, key: &str) -> Result<Option<Type>, RwLockError> {
|
pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, RwLockError> {
|
||||||
if let Some(value_data) = self.inner.read()?.get(key) {
|
if let Some(value_data) = self.inner.read()?.get(identifier) {
|
||||||
match value_data {
|
match value_data {
|
||||||
ValueData::Value { inner, .. } => return Ok(Some(inner.r#type())),
|
ValueData::Value { inner, .. } => return Ok(Some(inner.r#type())),
|
||||||
ValueData::TypeHint { inner, .. } => return Ok(Some(inner.clone())),
|
ValueData::TypeHint { inner, .. } => return Ok(Some(inner.clone())),
|
||||||
@ -141,12 +141,6 @@ impl Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for built_in_value in all_built_in_values() {
|
|
||||||
if key == built_in_value.name() {
|
|
||||||
return Ok(Some(built_in_value.r#type()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,16 +148,19 @@ impl Context {
|
|||||||
///
|
///
|
||||||
/// This will also return a built-in type definition if one matches the key.
|
/// This will also return a built-in type definition if one matches the key.
|
||||||
/// See the [module-level docs][self] for more info.
|
/// See the [module-level docs][self] for more info.
|
||||||
pub fn get_definition(&self, key: &str) -> Result<Option<TypeDefinition>, RwLockError> {
|
pub fn get_definition(
|
||||||
if let Some(value_data) = self.inner.read()?.get(key) {
|
&self,
|
||||||
|
identifier: &Identifier,
|
||||||
|
) -> Result<Option<TypeDefinition>, RwLockError> {
|
||||||
|
if let Some(value_data) = self.inner.read()?.get(identifier) {
|
||||||
if let ValueData::TypeDefinition(definition) = value_data {
|
if let ValueData::TypeDefinition(definition) = value_data {
|
||||||
return Ok(Some(definition.clone()));
|
return Ok(Some(definition.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for built_in_definition in all_built_in_type_definitions() {
|
for built_in_definition in all_built_in_type_definitions() {
|
||||||
if key == built_in_definition.name() {
|
if built_in_definition.name() == identifier.inner().as_ref() {
|
||||||
return Ok(Some(built_in_definition.get().clone()));
|
return Ok(Some(built_in_definition.get(self).clone()?));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +168,7 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set a value to a key.
|
/// Set a value to a key.
|
||||||
pub fn set_value(&self, key: String, value: Value) -> Result<(), RwLockError> {
|
pub fn set_value(&self, key: Identifier, value: Value) -> Result<(), RwLockError> {
|
||||||
self.inner.write()?.insert(
|
self.inner.write()?.insert(
|
||||||
key,
|
key,
|
||||||
ValueData::Value {
|
ValueData::Value {
|
||||||
@ -187,7 +184,7 @@ 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: String, r#type: Type) -> Result<(), RwLockError> {
|
pub fn set_type(&self, key: Identifier, r#type: Type) -> Result<(), RwLockError> {
|
||||||
self.inner
|
self.inner
|
||||||
.write()?
|
.write()?
|
||||||
.insert(key, ValueData::TypeHint { inner: r#type });
|
.insert(key, ValueData::TypeHint { inner: r#type });
|
||||||
@ -201,7 +198,7 @@ impl Context {
|
|||||||
/// later while using this context.
|
/// later while using this context.
|
||||||
pub fn set_definition(
|
pub fn set_definition(
|
||||||
&self,
|
&self,
|
||||||
key: String,
|
key: Identifier,
|
||||||
definition: TypeDefinition,
|
definition: TypeDefinition,
|
||||||
) -> Result<(), RwLockError> {
|
) -> Result<(), RwLockError> {
|
||||||
self.inner
|
self.inner
|
||||||
@ -212,7 +209,7 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Remove a key-value pair.
|
/// Remove a key-value pair.
|
||||||
pub fn unset(&self, key: &str) -> Result<(), RwLockError> {
|
pub fn unset(&self, key: &Identifier) -> Result<(), RwLockError> {
|
||||||
self.inner.write()?.remove(key);
|
self.inner.write()?.remove(key);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -7,7 +7,7 @@ use std::{
|
|||||||
time,
|
time,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{Type, Value};
|
use crate::{Identifier, Type, Value};
|
||||||
|
|
||||||
use super::{rw_lock_error::RwLockError, ValidationError};
|
use super::{rw_lock_error::RwLockError, ValidationError};
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ pub enum RuntimeError {
|
|||||||
Utf8(FromUtf8Error),
|
Utf8(FromUtf8Error),
|
||||||
|
|
||||||
/// Failed to find a variable with a value for this key.
|
/// Failed to find a variable with a value for this key.
|
||||||
VariableIdentifierNotFound(String),
|
VariableIdentifierNotFound(Identifier),
|
||||||
|
|
||||||
/// A built-in function was called with the wrong amount of arguments.
|
/// A built-in function was called with the wrong amount of arguments.
|
||||||
ExpectedBuiltInFunctionArgumentAmount {
|
ExpectedBuiltInFunctionArgumentAmount {
|
||||||
|
@ -65,7 +65,7 @@ pub enum ValidationError {
|
|||||||
VariableIdentifierNotFound(Identifier),
|
VariableIdentifierNotFound(Identifier),
|
||||||
|
|
||||||
/// Failed to find a type definition with this key.
|
/// Failed to find a type definition with this key.
|
||||||
TypeDefinitionNotFound(String),
|
TypeDefinitionNotFound(Identifier),
|
||||||
|
|
||||||
/// Failed to find an enum definition with this key.
|
/// Failed to find an enum definition with this key.
|
||||||
ExpectedEnumDefintion { actual: TypeDefinition },
|
ExpectedEnumDefintion { actual: TypeDefinition },
|
||||||
|
@ -17,6 +17,7 @@ pub use tree_sitter::Node as SyntaxNode;
|
|||||||
|
|
||||||
pub mod abstract_tree;
|
pub mod abstract_tree;
|
||||||
pub mod built_in_functions;
|
pub mod built_in_functions;
|
||||||
|
pub mod built_in_identifiers;
|
||||||
pub mod built_in_type_definitions;
|
pub mod built_in_type_definitions;
|
||||||
pub mod built_in_types;
|
pub mod built_in_types;
|
||||||
pub mod built_in_values;
|
pub mod built_in_values;
|
||||||
|
@ -2,30 +2,30 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::Value;
|
use crate::{Identifier, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct EnumInstance {
|
pub struct EnumInstance {
|
||||||
name: String,
|
name: Identifier,
|
||||||
variant_name: String,
|
variant: Identifier,
|
||||||
value: Option<Box<Value>>,
|
value: Option<Box<Value>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnumInstance {
|
impl EnumInstance {
|
||||||
pub fn new(name: String, variant_name: String, value: Option<Value>) -> Self {
|
pub fn new(name: Identifier, variant_name: Identifier, value: Option<Value>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
variant_name,
|
variant: variant_name,
|
||||||
value: value.map(|value| Box::new(value)),
|
value: value.map(|value| Box::new(value)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &String {
|
pub fn name(&self) -> &Identifier {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn variant_name(&self) -> &String {
|
pub fn variant(&self) -> &Identifier {
|
||||||
&self.variant_name
|
&self.variant
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value(&self) -> &Option<Box<Value>> {
|
pub fn value(&self) -> &Option<Box<Value>> {
|
||||||
@ -35,6 +35,6 @@ impl EnumInstance {
|
|||||||
|
|
||||||
impl Display for EnumInstance {
|
impl Display for EnumInstance {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
write!(f, "{}::{}({:?})", self.name, self.variant_name, self.value)
|
write!(f, "{}::{}({:?})", self.name, self.variant, self.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
use std::{
|
use std::fmt::{self, Display, Formatter};
|
||||||
cmp::Ordering,
|
|
||||||
fmt::{self, Display, Formatter},
|
|
||||||
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
|
||||||
};
|
|
||||||
|
|
||||||
use stanza::{
|
use stanza::{
|
||||||
renderer::{console::Console, Renderer},
|
renderer::{console::Console, Renderer},
|
||||||
@ -12,8 +8,8 @@ use stanza::{
|
|||||||
|
|
||||||
use crate::Value;
|
use crate::Value;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct List(Arc<RwLock<Vec<Value>>>);
|
pub struct List(Vec<Value>);
|
||||||
|
|
||||||
impl Default for List {
|
impl Default for List {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
@ -23,23 +19,23 @@ impl Default for List {
|
|||||||
|
|
||||||
impl List {
|
impl List {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
List(Arc::new(RwLock::new(Vec::new())))
|
List(Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_capacity(capacity: usize) -> Self {
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
List(Arc::new(RwLock::new(Vec::with_capacity(capacity))))
|
List(Vec::with_capacity(capacity))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_items(items: Vec<Value>) -> Self {
|
pub fn with_items(items: Vec<Value>) -> Self {
|
||||||
List(Arc::new(RwLock::new(items)))
|
List(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn items(&self) -> RwLockReadGuard<'_, Vec<Value>> {
|
pub fn items(&self) -> &Vec<Value> {
|
||||||
self.0.read().unwrap()
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn items_mut(&self) -> RwLockWriteGuard<'_, Vec<Value>> {
|
pub fn items_mut(&mut self) -> &mut Vec<Value> {
|
||||||
self.0.write().unwrap()
|
&mut self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_text_table(&self) -> Table {
|
pub fn as_text_table(&self) -> Table {
|
||||||
@ -73,32 +69,6 @@ impl List {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for List {}
|
|
||||||
|
|
||||||
impl PartialEq for List {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
let left = self.0.read().unwrap().clone().into_iter();
|
|
||||||
let right = other.0.read().unwrap().clone().into_iter();
|
|
||||||
|
|
||||||
left.eq(right)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for List {
|
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
|
||||||
let left = self.0.read().unwrap().clone().into_iter();
|
|
||||||
let right = other.0.read().unwrap().clone().into_iter();
|
|
||||||
|
|
||||||
left.cmp(right)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for List {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for List {
|
impl Display for List {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
let renderer = Console::default();
|
let renderer = Console::default();
|
||||||
|
@ -9,7 +9,7 @@ use std::{
|
|||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::value::Value;
|
use crate::{Identifier, Value};
|
||||||
|
|
||||||
/// A collection dust variables comprised of key-value pairs.
|
/// A collection dust variables comprised of key-value pairs.
|
||||||
///
|
///
|
||||||
@ -17,7 +17,7 @@ use crate::value::Value;
|
|||||||
/// to one another.
|
/// to one another.
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Map {
|
pub struct Map {
|
||||||
inner: BTreeMap<String, Value>,
|
inner: BTreeMap<Identifier, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Map {
|
impl Map {
|
||||||
@ -28,19 +28,19 @@ impl Map {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_values(variables: BTreeMap<String, Value>) -> Self {
|
pub fn with_values(variables: BTreeMap<Identifier, Value>) -> Self {
|
||||||
Map { inner: variables }
|
Map { inner: variables }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner(&self) -> &BTreeMap<String, Value> {
|
pub fn inner(&self) -> &BTreeMap<Identifier, Value> {
|
||||||
&self.inner
|
&self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, key: &str) -> Option<&Value> {
|
pub fn get(&self, key: &Identifier) -> Option<&Value> {
|
||||||
self.inner.get(key)
|
self.inner.get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&mut self, key: String, value: Value) {
|
pub fn set(&mut self, key: Identifier, value: Value) {
|
||||||
self.inner.insert(key, value);
|
self.inner.insert(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ impl Map {
|
|||||||
vec![key.into(), list.as_text_table().into()],
|
vec![key.into(), list.as_text_table().into()],
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
table.push_row([key, &value.to_string()]);
|
table.push_row([key.to_string(), value.to_string()]);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ use serde::{
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
collections::BTreeMap,
|
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
@ -55,8 +54,8 @@ impl Value {
|
|||||||
|
|
||||||
pub fn some(value: Value) -> Value {
|
pub fn some(value: Value) -> Value {
|
||||||
Value::Enum(EnumInstance::new(
|
Value::Enum(EnumInstance::new(
|
||||||
"Option".to_string(),
|
Identifier::new("Option"),
|
||||||
"Some".to_string(),
|
Identifier::new("Some"),
|
||||||
Some(value),
|
Some(value),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -97,7 +96,7 @@ impl Value {
|
|||||||
|
|
||||||
for (key, value) in map.inner() {
|
for (key, value) in map.inner() {
|
||||||
identifier_types.push((
|
identifier_types.push((
|
||||||
Identifier::new(key.clone()),
|
Identifier::new(key.inner()),
|
||||||
TypeSpecification::new(value.r#type()),
|
TypeSpecification::new(value.r#type()),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -828,13 +827,15 @@ impl<'de> Visitor<'de> for ValueVisitor {
|
|||||||
where
|
where
|
||||||
M: MapAccess<'de>,
|
M: MapAccess<'de>,
|
||||||
{
|
{
|
||||||
let mut map = BTreeMap::new();
|
let mut map = Map::new();
|
||||||
|
|
||||||
while let Some((key, value)) = access.next_entry::<String, Value>()? {
|
while let Some((key, value)) = access.next_entry::<String, Value>()? {
|
||||||
map.insert(key, value);
|
let identifier = Identifier::new(&key);
|
||||||
|
|
||||||
|
map.set(identifier, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Map(Map::with_values(map)))
|
Ok(Value::Map(map))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_enum<A>(self, data: A) -> std::result::Result<Self::Value, A::Error>
|
fn visit_enum<A>(self, data: A) -> std::result::Result<Self::Value, A::Error>
|
||||||
|
@ -2,16 +2,16 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use serde::{ser::SerializeMap, Serialize, Serializer};
|
use serde::{ser::SerializeMap, Serialize, Serializer};
|
||||||
|
|
||||||
use crate::Map;
|
use crate::{Identifier, Map};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct StructInstance {
|
pub struct StructInstance {
|
||||||
name: String,
|
name: Identifier,
|
||||||
map: Map,
|
map: Map,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StructInstance {
|
impl StructInstance {
|
||||||
pub fn new(name: String, map: Map) -> Self {
|
pub fn new(name: Identifier, map: Map) -> Self {
|
||||||
StructInstance { name, map }
|
StructInstance { name, map }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,7 @@ fn function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&vec![Identifier::new("x".to_string())],
|
&vec![Identifier::new_or_get("x".to_string())],
|
||||||
function.parameters()
|
function.parameters()
|
||||||
);
|
);
|
||||||
assert_eq!(&Type::Boolean, function.return_type());
|
assert_eq!(&Type::Boolean, function.return_type());
|
||||||
|
Loading…
Reference in New Issue
Block a user