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> {
|
||||
if let AssignmentOperator::Equal = self.operator {
|
||||
let key = self.identifier.inner().clone();
|
||||
let r#type = if let Some(definition) = &self.type_specification {
|
||||
definition.inner().clone()
|
||||
} else {
|
||||
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 {
|
||||
@ -130,30 +129,33 @@ impl AbstractTree for Assignment {
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
||||
let key = self.identifier.inner();
|
||||
let value = self.statement.run(source, context)?;
|
||||
|
||||
let new_value = match self.operator {
|
||||
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
|
||||
} else {
|
||||
return Err(RuntimeError::VariableIdentifierNotFound(key.clone()));
|
||||
return Err(RuntimeError::VariableIdentifierNotFound(
|
||||
self.identifier.clone(),
|
||||
));
|
||||
}
|
||||
}
|
||||
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
|
||||
} else {
|
||||
return Err(RuntimeError::VariableIdentifierNotFound(key.clone()));
|
||||
return Err(RuntimeError::VariableIdentifierNotFound(
|
||||
self.identifier.clone(),
|
||||
));
|
||||
}
|
||||
}
|
||||
AssignmentOperator::Equal => value,
|
||||
};
|
||||
|
||||
context.set_value(key.clone(), new_value)?;
|
||||
context.set_value(self.identifier.clone(), new_value)?;
|
||||
|
||||
Ok(Value::none())
|
||||
}
|
||||
|
@ -27,8 +27,8 @@ impl EnumDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn instantiate(&self, variant: String, content: Option<Value>) -> EnumInstance {
|
||||
EnumInstance::new(self.identifier.inner().clone(), variant, content)
|
||||
pub fn instantiate(&self, variant: Identifier, content: Option<Value>) -> EnumInstance {
|
||||
EnumInstance::new(self.identifier.clone(), variant, content)
|
||||
}
|
||||
|
||||
pub fn identifier(&self) -> &Identifier {
|
||||
@ -86,10 +86,7 @@ impl AbstractTree for EnumDefinition {
|
||||
}
|
||||
|
||||
fn run(&self, _source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
||||
context.set_definition(
|
||||
self.identifier.inner().clone(),
|
||||
TypeDefinition::Enum(self.clone()),
|
||||
)?;
|
||||
context.set_definition(self.identifier.clone(), TypeDefinition::Enum(self.clone()))?;
|
||||
|
||||
Ok(Value::none())
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ impl AbstractTree for For {
|
||||
position: self.source_position,
|
||||
});
|
||||
};
|
||||
let key = self.item_id.inner().clone();
|
||||
let key = self.item_id.clone();
|
||||
|
||||
self.context.inherit_from(context)?;
|
||||
self.context.set_type(key, item_type)?;
|
||||
@ -87,7 +87,7 @@ impl AbstractTree for For {
|
||||
self.context.inherit_from(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 self.is_async {
|
||||
|
@ -142,16 +142,11 @@ impl AbstractTree for FunctionCall {
|
||||
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
||||
let value = match &self.function_expression {
|
||||
FunctionExpression::Identifier(identifier) => {
|
||||
let key = identifier.inner();
|
||||
|
||||
if let Some(value) = context.get_value(key)? {
|
||||
self.context
|
||||
.set_value(identifier.inner().clone(), value.clone())?;
|
||||
if let Some(value) = context.get_value(identifier)? {
|
||||
self.context.set_value(identifier.clone(), value.clone())?;
|
||||
value.clone()
|
||||
} else {
|
||||
return Err(RuntimeError::VariableIdentifierNotFound(
|
||||
identifier.inner().clone(),
|
||||
));
|
||||
return Err(RuntimeError::VariableIdentifierNotFound(identifier.clone()));
|
||||
}
|
||||
}
|
||||
FunctionExpression::FunctionCall(function_call) => {
|
||||
@ -181,7 +176,7 @@ impl AbstractTree for FunctionCall {
|
||||
for (identifier, expression) in parameter_expression_pairs {
|
||||
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)
|
||||
|
@ -118,7 +118,7 @@ impl AbstractTree for FunctionNode {
|
||||
let validation_context = Context::new();
|
||||
|
||||
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)?;
|
||||
|
@ -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::{
|
||||
built_in_identifiers::all_built_in_identifiers,
|
||||
error::{RuntimeError, SyntaxError, ValidationError},
|
||||
AbstractTree, Context, Format, SyntaxNode, Type, Value,
|
||||
};
|
||||
@ -10,22 +14,30 @@ use crate::{
|
||||
/// 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
|
||||
/// pair. Its inner value can be used to retrieve a Value instance from a Map.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||
pub struct Identifier(String);
|
||||
/// pair and can be used to retrieve a Value instance from a Map or Context.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||
pub struct Identifier(Arc<String>);
|
||||
|
||||
impl Identifier {
|
||||
pub fn new<T: Into<String>>(inner: T) -> Self {
|
||||
Identifier(inner.into())
|
||||
pub fn new(key: &str) -> Self {
|
||||
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 {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> &String {
|
||||
pub fn inner(&self) -> &Arc<String> {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub fn contains(&self, string: &str) -> bool {
|
||||
self.0.as_ref() == string
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractTree for Identifier {
|
||||
@ -40,7 +52,7 @@ impl AbstractTree for Identifier {
|
||||
|
||||
debug_assert!(!text.is_empty());
|
||||
|
||||
Ok(Identifier(text.to_string()))
|
||||
Ok(Identifier::new(text))
|
||||
}
|
||||
|
||||
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> {
|
||||
if let Some(r#type) = context.get_type(&self.0)? {
|
||||
if let Some(r#type) = context.get_type(self)? {
|
||||
Ok(r#type)
|
||||
} else {
|
||||
Err(ValidationError::VariableIdentifierNotFound(self.clone()))
|
||||
@ -56,10 +68,10 @@ impl AbstractTree for Identifier {
|
||||
}
|
||||
|
||||
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())
|
||||
} else {
|
||||
Err(RuntimeError::VariableIdentifierNotFound(self.0.clone()))
|
||||
Err(RuntimeError::VariableIdentifierNotFound(self.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -75,3 +87,38 @@ impl Display for Identifier {
|
||||
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::{
|
||||
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.
|
||||
@ -12,7 +13,6 @@ use crate::{
|
||||
pub struct Index {
|
||||
pub collection: IndexExpression,
|
||||
pub index: IndexExpression,
|
||||
pub index_end: Option<IndexExpression>,
|
||||
source_position: SourcePosition,
|
||||
}
|
||||
|
||||
@ -26,21 +26,9 @@ impl AbstractTree for Index {
|
||||
let index_node = node.child(2).unwrap();
|
||||
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 {
|
||||
collection,
|
||||
index,
|
||||
index_end,
|
||||
source_position: SourcePosition::from(node.range()),
|
||||
})
|
||||
}
|
||||
@ -58,10 +46,6 @@ impl AbstractTree for Index {
|
||||
self.collection.validate(_source, _context)?;
|
||||
self.index.validate(_source, _context)?;
|
||||
|
||||
if let Some(index_end) = &self.index_end {
|
||||
index_end.validate(_source, _context)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -71,36 +55,28 @@ impl AbstractTree for Index {
|
||||
match value {
|
||||
Value::List(list) => {
|
||||
let index = self.index.run(source, context)?.as_integer()? as usize;
|
||||
|
||||
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()
|
||||
};
|
||||
let item = list.items().get(index).cloned().unwrap_or_default();
|
||||
|
||||
Ok(item)
|
||||
}
|
||||
Value::Map(map) => {
|
||||
let map = map.inner();
|
||||
|
||||
let (key, value) = if let IndexExpression::Identifier(identifier) = &self.index {
|
||||
let key = identifier.inner();
|
||||
let value = map.get(key).unwrap_or_default();
|
||||
let (identifier, value) =
|
||||
if let IndexExpression::Identifier(identifier) = &self.index {
|
||||
let value = map.get(identifier).unwrap_or_default();
|
||||
|
||||
(key.clone(), value)
|
||||
} else {
|
||||
let index_value = self.index.run(source, context)?;
|
||||
let key = index_value.as_string()?;
|
||||
let value = map.get(key.as_str()).unwrap_or_default();
|
||||
(identifier.clone(), value)
|
||||
} else {
|
||||
let index_value = self.index.run(source, context)?;
|
||||
let identifier = Identifier::new(index_value.as_string()?);
|
||||
let value = map.get(&identifier).unwrap_or_default();
|
||||
|
||||
(key.clone(), value)
|
||||
};
|
||||
(identifier, value)
|
||||
};
|
||||
|
||||
if value.is_none() {
|
||||
Err(RuntimeError::VariableIdentifierNotFound(key))
|
||||
Err(RuntimeError::VariableIdentifierNotFound(identifier))
|
||||
} else {
|
||||
Ok(value.clone())
|
||||
}
|
||||
@ -121,10 +97,5 @@ impl Format for Index {
|
||||
self.collection.format(output, indent_level);
|
||||
output.push(':');
|
||||
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::{
|
||||
error::{RuntimeError, SyntaxError, ValidationError},
|
||||
AbstractTree, AssignmentOperator, Context, Format, Index, IndexExpression, Statement,
|
||||
SyntaxNode, Type, Value,
|
||||
AbstractTree, AssignmentOperator, Context, Format, Identifier, Index, IndexExpression,
|
||||
Statement, SyntaxNode, Type, Value,
|
||||
};
|
||||
|
||||
#[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> {
|
||||
let _index_collection = self.index.collection.run(source, context)?;
|
||||
let index_key = if let IndexExpression::Identifier(identifier) = &self.index.index {
|
||||
identifier.inner()
|
||||
let index_identifier = if let IndexExpression::Identifier(identifier) = &self.index.index {
|
||||
identifier
|
||||
} else {
|
||||
let index_run = self.index.index.run(source, context)?;
|
||||
let expected_identifier = Identifier::new(index_run.as_string()?);
|
||||
|
||||
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 {
|
||||
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
|
||||
} else {
|
||||
@ -64,7 +67,7 @@ impl AbstractTree for IndexAssignment {
|
||||
}
|
||||
}
|
||||
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
|
||||
} else {
|
||||
@ -74,7 +77,7 @@ impl AbstractTree for IndexAssignment {
|
||||
AssignmentOperator::Equal => value,
|
||||
};
|
||||
|
||||
context.set_value(index_key.clone(), new_value)?;
|
||||
context.set_value(index_identifier.clone(), new_value)?;
|
||||
|
||||
Ok(Value::none())
|
||||
}
|
||||
|
@ -11,12 +11,12 @@ use crate::{
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct MapNode {
|
||||
properties: BTreeMap<String, (Statement, Option<Type>)>,
|
||||
properties: BTreeMap<Identifier, (Statement, Option<Type>)>,
|
||||
position: SourcePosition,
|
||||
}
|
||||
|
||||
impl MapNode {
|
||||
pub fn properties(&self) -> &BTreeMap<String, (Statement, Option<Type>)> {
|
||||
pub fn properties(&self) -> &BTreeMap<Identifier, (Statement, Option<Type>)> {
|
||||
&self.properties
|
||||
}
|
||||
}
|
||||
@ -26,14 +26,14 @@ impl AbstractTree for MapNode {
|
||||
SyntaxError::expect_syntax_node(source, "map", node)?;
|
||||
|
||||
let mut properties = BTreeMap::new();
|
||||
let mut current_key = "".to_string();
|
||||
let mut current_identifier = None;
|
||||
let mut current_type = None;
|
||||
|
||||
for index in 0..node.child_count() - 1 {
|
||||
let child = node.child(index).unwrap();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -45,7 +45,9 @@ impl AbstractTree for MapNode {
|
||||
if child.kind() == "statement" {
|
||||
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)) =
|
||||
(&matcher_value, pattern)
|
||||
{
|
||||
if enum_instance.name() == enum_pattern.name().inner()
|
||||
&& enum_instance.variant_name() == enum_pattern.variant().inner()
|
||||
if enum_instance.name() == enum_pattern.name()
|
||||
&& enum_instance.variant() == enum_pattern.variant()
|
||||
{
|
||||
let statement_context = Context::with_variables_from(context)?;
|
||||
|
||||
if let (Some(identifier), Some(value)) =
|
||||
(enum_pattern.inner_identifier(), enum_instance.value())
|
||||
{
|
||||
statement_context
|
||||
.set_value(identifier.inner().clone(), value.as_ref().clone())?;
|
||||
statement_context.set_value(identifier.clone(), value.as_ref().clone())?;
|
||||
}
|
||||
|
||||
return statement.run(source, &statement_context);
|
||||
|
@ -12,7 +12,7 @@ use crate::{
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct StructDefinition {
|
||||
name: Identifier,
|
||||
properties: BTreeMap<String, (Option<Statement>, Type)>,
|
||||
properties: BTreeMap<Identifier, (Option<Statement>, Type)>,
|
||||
}
|
||||
|
||||
impl StructDefinition {
|
||||
@ -38,10 +38,7 @@ impl StructDefinition {
|
||||
all_properties.set(key.clone(), value);
|
||||
}
|
||||
|
||||
Ok(StructInstance::new(
|
||||
self.name.inner().clone(),
|
||||
all_properties,
|
||||
))
|
||||
Ok(StructInstance::new(self.name.clone(), all_properties))
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,7 +60,7 @@ impl AbstractTree for StructDefinition {
|
||||
if child_syntax_node.kind() == "identifier" {
|
||||
if current_statement.is_none() {
|
||||
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(
|
||||
identifier.inner().clone(),
|
||||
identifier.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> {
|
||||
context.set_definition(
|
||||
self.name.inner().clone(),
|
||||
TypeDefinition::Struct(self.clone()),
|
||||
)?;
|
||||
context.set_definition(self.name.clone(), TypeDefinition::Struct(self.clone()))?;
|
||||
|
||||
Ok(Value::none())
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node as SyntaxNode;
|
||||
|
||||
use crate::{
|
||||
built_in_types::BuiltInType,
|
||||
error::{RuntimeError, SyntaxError, ValidationError},
|
||||
AbstractTree, Context, Format, Identifier, SyntaxNode, Value,
|
||||
AbstractTree, Context, Format, Identifier, Value,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
@ -13,10 +14,9 @@ pub enum Type {
|
||||
Any,
|
||||
Boolean,
|
||||
Collection,
|
||||
Custom(Identifier),
|
||||
CustomWithArgument {
|
||||
Custom {
|
||||
name: Identifier,
|
||||
argument: Box<Type>,
|
||||
argument: Option<Box<Type>>,
|
||||
},
|
||||
Float,
|
||||
Function {
|
||||
@ -33,8 +33,15 @@ pub enum 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 {
|
||||
BuiltInType::Option.get(inner_type).clone()
|
||||
BuiltInType::Option(inner_type).get().clone()
|
||||
}
|
||||
|
||||
pub fn list(item_type: Type) -> Self {
|
||||
@ -75,13 +82,12 @@ impl Type {
|
||||
| (Type::Integer, Type::Number)
|
||||
| (Type::Float, Type::Number)
|
||||
| (Type::String, Type::String) => true,
|
||||
(Type::Custom(left), Type::Custom(right)) => left == right,
|
||||
(
|
||||
Type::CustomWithArgument {
|
||||
Type::Custom {
|
||||
name: left_name,
|
||||
argument: left_argument,
|
||||
},
|
||||
Type::CustomWithArgument {
|
||||
Type::Custom {
|
||||
name: right_name,
|
||||
argument: right_argument,
|
||||
},
|
||||
@ -138,7 +144,7 @@ impl AbstractTree for Type {
|
||||
fn from_syntax(
|
||||
node: SyntaxNode,
|
||||
_source: &str,
|
||||
_context: &Context,
|
||||
context: &Context,
|
||||
) -> Result<Self, SyntaxError> {
|
||||
SyntaxError::expect_syntax_node(_source, "type", node)?;
|
||||
|
||||
@ -146,23 +152,18 @@ impl AbstractTree for Type {
|
||||
|
||||
let r#type = match type_node.kind() {
|
||||
"identifier" => {
|
||||
if node.child_count() == 1 {
|
||||
Type::Custom(Identifier::from_syntax(type_node, _source, _context)?)
|
||||
let name = Identifier::from_syntax(type_node, _source, context)?;
|
||||
let argument = if let Some(child) = node.child(2) {
|
||||
Some(Type::from_syntax(child, _source, context)?)
|
||||
} else {
|
||||
let name = Identifier::from_syntax(type_node, _source, _context)?;
|
||||
None
|
||||
};
|
||||
|
||||
let argument_node = node.child(2).unwrap();
|
||||
let argument = Type::from_syntax(argument_node, _source, _context)?;
|
||||
|
||||
Type::CustomWithArgument {
|
||||
name,
|
||||
argument: Box::new(argument),
|
||||
}
|
||||
}
|
||||
Type::custom(name, argument)
|
||||
}
|
||||
"[" => {
|
||||
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))
|
||||
}
|
||||
@ -178,7 +179,7 @@ impl AbstractTree for Type {
|
||||
let child = node.child(index).unwrap();
|
||||
|
||||
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);
|
||||
}
|
||||
@ -186,7 +187,7 @@ impl AbstractTree for Type {
|
||||
|
||||
let final_node = node.child(child_count - 1).unwrap();
|
||||
let return_type = if final_node.is_named() {
|
||||
Type::from_syntax(final_node, _source, _context)?
|
||||
Type::from_syntax(final_node, _source, context)?
|
||||
} else {
|
||||
Type::option(None)
|
||||
};
|
||||
@ -233,8 +234,7 @@ impl Format for Type {
|
||||
Type::Any => output.push_str("any"),
|
||||
Type::Boolean => output.push_str("bool"),
|
||||
Type::Collection => output.push_str("collection"),
|
||||
Type::Custom(_) => todo!(),
|
||||
Type::CustomWithArgument {
|
||||
Type::Custom {
|
||||
name: _,
|
||||
argument: _,
|
||||
} => todo!(),
|
||||
@ -279,9 +279,12 @@ impl Display for Type {
|
||||
Type::Any => write!(f, "any"),
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
Type::Collection => write!(f, "collection"),
|
||||
Type::Custom(identifier) => write!(f, "{identifier}"),
|
||||
Type::CustomWithArgument { name, argument } => {
|
||||
write!(f, "{name}<{argument}>")
|
||||
Type::Custom { name, argument } => {
|
||||
if let Some(argument) = argument {
|
||||
write!(f, "{name}<{argument}>")
|
||||
} else {
|
||||
write!(f, "{name}")
|
||||
}
|
||||
}
|
||||
Type::Float => write!(f, "float"),
|
||||
Type::Function {
|
||||
|
@ -121,7 +121,7 @@ impl AbstractTree for ValueNode {
|
||||
let r#type = match self {
|
||||
ValueNode::Boolean(_) => Type::Boolean,
|
||||
ValueNode::Float(_) => Type::Float,
|
||||
ValueNode::Function(function) => function.r#type().clone(),
|
||||
ValueNode::Function(function) => function.r#type(),
|
||||
ValueNode::Integer(_) => Type::Integer,
|
||||
ValueNode::String(_) => Type::String,
|
||||
ValueNode::List(expressions) => {
|
||||
@ -147,17 +147,20 @@ impl AbstractTree for ValueNode {
|
||||
}
|
||||
ValueNode::Map(_) => Type::Map,
|
||||
ValueNode::Struct { name, .. } => {
|
||||
Type::Custom(name.clone())
|
||||
Type::Custom { name: name.clone(), argument: None }
|
||||
}
|
||||
ValueNode::Range(_) => Type::Range,
|
||||
ValueNode::Enum { name, variant: _, expression } => {
|
||||
if let Some(expression) = expression {
|
||||
Type::CustomWithArgument {
|
||||
Type::Custom {
|
||||
name: name.clone(),
|
||||
argument: Box::new(expression.expected_type(context)?)
|
||||
argument: Some(Box::new(expression.expected_type(context)?))
|
||||
}
|
||||
} 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::Range(range) => Value::Range(range.clone()),
|
||||
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 {
|
||||
struct_definition.instantiate(properties, source, context)?
|
||||
} else {
|
||||
@ -212,7 +215,7 @@ impl AbstractTree for ValueNode {
|
||||
}
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::TypeDefinitionNotFound(name.inner().clone())
|
||||
ValidationError::TypeDefinitionNotFound(name.clone())
|
||||
));
|
||||
};
|
||||
|
||||
@ -225,9 +228,9 @@ impl AbstractTree for ValueNode {
|
||||
} else {
|
||||
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 {
|
||||
enum_defintion.instantiate(variant.inner().clone(), Some(value))
|
||||
enum_defintion.instantiate(variant.clone(), Some(value))
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::ExpectedEnumDefintion {
|
||||
@ -237,7 +240,7 @@ impl AbstractTree for ValueNode {
|
||||
}
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::TypeDefinitionNotFound(name.inner().clone())
|
||||
ValidationError::TypeDefinitionNotFound(name.clone())
|
||||
));
|
||||
};
|
||||
|
||||
|
@ -19,7 +19,7 @@ pub trait Callable {
|
||||
&self,
|
||||
arguments: &[Value],
|
||||
source: &str,
|
||||
outer_context: &Context,
|
||||
context: &Context,
|
||||
) -> Result<Value, RuntimeError>;
|
||||
}
|
||||
|
||||
@ -72,7 +72,10 @@ impl Callable for BuiltInFunction {
|
||||
match self {
|
||||
BuiltInFunction::AssertEqual => Type::function(
|
||||
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::Json(json_function) => json_function.r#type(),
|
||||
@ -90,7 +93,7 @@ impl Callable for BuiltInFunction {
|
||||
&self,
|
||||
arguments: &[Value],
|
||||
_source: &str,
|
||||
_outer_context: &Context,
|
||||
context: &Context,
|
||||
) -> Result<Value, RuntimeError> {
|
||||
match self {
|
||||
BuiltInFunction::AssertEqual => {
|
||||
@ -101,26 +104,22 @@ impl Callable for BuiltInFunction {
|
||||
|
||||
let result = if left == right {
|
||||
Value::Enum(EnumInstance::new(
|
||||
"Result".to_string(),
|
||||
"Ok".to_string(),
|
||||
Identifier::new("Result"),
|
||||
Identifier::new("Ok"),
|
||||
Some(Value::none()),
|
||||
))
|
||||
} else {
|
||||
Value::Enum(EnumInstance::new(
|
||||
"Result".to_string(),
|
||||
"Error".to_string(),
|
||||
Identifier::new("Result"),
|
||||
Identifier::new("Error"),
|
||||
Some(Value::none()),
|
||||
))
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
BuiltInFunction::Fs(fs_function) => {
|
||||
fs_function.call(arguments, _source, _outer_context)
|
||||
}
|
||||
BuiltInFunction::Json(json_function) => {
|
||||
json_function.call(arguments, _source, _outer_context)
|
||||
}
|
||||
BuiltInFunction::Fs(fs_function) => fs_function.call(arguments, _source, context),
|
||||
BuiltInFunction::Json(json_function) => json_function.call(arguments, _source, context),
|
||||
BuiltInFunction::Length => {
|
||||
RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?;
|
||||
|
||||
@ -184,7 +183,7 @@ impl Callable for BuiltInFunction {
|
||||
Ok(Value::Integer(random()))
|
||||
}
|
||||
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 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;
|
||||
|
||||
@ -203,7 +203,7 @@ impl Callable for StrFunction {
|
||||
&self,
|
||||
arguments: &[Value],
|
||||
_source: &str,
|
||||
_outer_context: &Context,
|
||||
context: &Context,
|
||||
) -> Result<Value, RuntimeError> {
|
||||
let value = match self {
|
||||
StrFunction::AsBytes => {
|
||||
@ -238,14 +238,14 @@ impl Callable for StrFunction {
|
||||
|
||||
if let Some(index) = find {
|
||||
Value::Enum(EnumInstance::new(
|
||||
"Option".to_string(),
|
||||
"Some".to_string(),
|
||||
Identifier::new("Option"),
|
||||
Identifier::new("Some"),
|
||||
Some(index),
|
||||
))
|
||||
} else {
|
||||
Value::Enum(EnumInstance::new(
|
||||
"Option".to_string(),
|
||||
"None".to_string(),
|
||||
Identifier::new("Option"),
|
||||
Identifier::new("None"),
|
||||
Some(Value::none()),
|
||||
))
|
||||
}
|
||||
@ -477,8 +477,8 @@ impl Callable for StrFunction {
|
||||
|
||||
if let Some(value) = stripped {
|
||||
Value::Enum(EnumInstance::new(
|
||||
"Option".to_string(),
|
||||
"Some".to_string(),
|
||||
Identifier::new("Option"),
|
||||
Identifier::new("Some"),
|
||||
Some(value),
|
||||
))
|
||||
} 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 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 RESULT: OnceLock<TypeDefinition> = OnceLock::new();
|
||||
static OPTION: OnceLock<Result<TypeDefinition, RwLockError>> = OnceLock::new();
|
||||
static RESULT: OnceLock<Result<TypeDefinition, RwLockError>> = OnceLock::new();
|
||||
|
||||
pub fn all_built_in_type_definitions() -> impl Iterator<Item = BuiltInTypeDefinition> {
|
||||
all()
|
||||
@ -25,25 +28,29 @@ impl BuiltInTypeDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self) -> &TypeDefinition {
|
||||
pub fn get(&self, context: &Context) -> &Result<TypeDefinition, RwLockError> {
|
||||
match self {
|
||||
BuiltInTypeDefinition::Option => OPTION.get_or_init(|| {
|
||||
TypeDefinition::Enum(EnumDefinition::new(
|
||||
let definition = TypeDefinition::Enum(EnumDefinition::new(
|
||||
Identifier::new(self.name()),
|
||||
vec![
|
||||
(Identifier::new("Some"), VariantContent::Type(Type::Any)),
|
||||
(Identifier::new("None"), VariantContent::None),
|
||||
],
|
||||
))
|
||||
));
|
||||
|
||||
Ok(definition)
|
||||
}),
|
||||
BuiltInTypeDefinition::Result => RESULT.get_or_init(|| {
|
||||
TypeDefinition::Enum(EnumDefinition::new(
|
||||
let definition = TypeDefinition::Enum(EnumDefinition::new(
|
||||
Identifier::new(self.name()),
|
||||
vec![
|
||||
(Identifier::new("Ok"), VariantContent::Type(Type::Any)),
|
||||
(Identifier::new("Err"), VariantContent::Type(Type::Any)),
|
||||
],
|
||||
))
|
||||
));
|
||||
|
||||
Ok(definition)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +1,33 @@
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use enum_iterator::Sequence;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Identifier, Type};
|
||||
|
||||
static OPTION: OnceLock<Type> = OnceLock::new();
|
||||
|
||||
#[derive(Sequence, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum BuiltInType {
|
||||
Option,
|
||||
Option(Option<Type>),
|
||||
}
|
||||
|
||||
impl BuiltInType {
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
BuiltInType::Option => todo!(),
|
||||
BuiltInType::Option(_) => "Option",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, inner_type: Option<Type>) -> &Type {
|
||||
pub fn get(&self) -> &Type {
|
||||
match self {
|
||||
BuiltInType::Option => OPTION.get_or_init(|| {
|
||||
if let Some(inner_type) = inner_type {
|
||||
Type::CustomWithArgument {
|
||||
BuiltInType::Option(content_type) => OPTION.get_or_init(|| {
|
||||
if let Some(content_type) = content_type {
|
||||
Type::Custom {
|
||||
name: Identifier::new("Option"),
|
||||
argument: Box::new(inner_type),
|
||||
argument: Some(Box::new(content_type.clone())),
|
||||
}
|
||||
} 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 serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
built_in_functions::{fs::fs_functions, json::json_functions, str::string_functions, Callable},
|
||||
error::{RuntimeError, SyntaxError, ValidationError},
|
||||
AbstractTree, BuiltInFunction, Context, EnumInstance, Format, Function, Identifier, List, Map,
|
||||
SyntaxNode, Type, Value,
|
||||
BuiltInFunction, EnumInstance, Function, Identifier, List, Map, Value,
|
||||
};
|
||||
|
||||
static ARGS: OnceLock<Value> = OnceLock::new();
|
||||
static FS: 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 RANDOM: OnceLock<Value> = OnceLock::new();
|
||||
static STR: OnceLock<Value> = OnceLock::new();
|
||||
|
||||
/// Returns the entire built-in value API.
|
||||
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
|
||||
/// [OnceLock][].
|
||||
pub fn get(&self) -> &Value {
|
||||
@ -116,42 +97,40 @@ impl BuiltInValue {
|
||||
&Value::Function(Function::BuiltIn(BuiltInFunction::AssertEqual))
|
||||
}
|
||||
BuiltInValue::Fs => FS.get_or_init(|| {
|
||||
let mut fs_context = BTreeMap::new();
|
||||
let mut fs_map = Map::new();
|
||||
|
||||
for fs_function in fs_functions() {
|
||||
let key = fs_function.name().to_string();
|
||||
let key = fs_function.name();
|
||||
let value =
|
||||
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(|| {
|
||||
let mut json_context = BTreeMap::new();
|
||||
let mut json_map = Map::new();
|
||||
|
||||
for json_function in json_functions() {
|
||||
let key = json_function.name().to_string();
|
||||
let key = json_function.name();
|
||||
let value =
|
||||
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::None => NONE.get_or_init(|| {
|
||||
Value::Enum(EnumInstance::new(
|
||||
"Option".to_string(),
|
||||
"None".to_string(),
|
||||
None,
|
||||
))
|
||||
}),
|
||||
BuiltInValue::None => &Value::Enum(EnumInstance::new(
|
||||
Identifier::new("Option"),
|
||||
Identifier::new("None"),
|
||||
None,
|
||||
)),
|
||||
BuiltInValue::Output => &Value::Function(Function::BuiltIn(BuiltInFunction::Output)),
|
||||
BuiltInValue::Random => RANDOM.get_or_init(|| {
|
||||
let mut random_context = BTreeMap::new();
|
||||
let mut random_map = Map::new();
|
||||
|
||||
for built_in_function in [
|
||||
BuiltInFunction::RandomBoolean,
|
||||
@ -159,83 +138,28 @@ impl BuiltInValue {
|
||||
BuiltInFunction::RandomFrom,
|
||||
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));
|
||||
|
||||
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(|| {
|
||||
let mut string_context = BTreeMap::new();
|
||||
BuiltInValue::Str => STR.get_or_init(|| {
|
||||
let mut str_map = Map::new();
|
||||
|
||||
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(
|
||||
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::{
|
||||
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
|
||||
@ -44,7 +44,7 @@ use crate::{
|
||||
/// See the [module-level docs][self] for more info.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Context {
|
||||
inner: Arc<RwLock<BTreeMap<String, ValueData>>>,
|
||||
inner: Arc<RwLock<BTreeMap<Identifier, ValueData>>>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
@ -56,7 +56,7 @@ impl Context {
|
||||
}
|
||||
|
||||
/// 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()?)
|
||||
}
|
||||
|
||||
@ -112,15 +112,15 @@ impl Context {
|
||||
///
|
||||
/// This will also return a built-in value if one matches the key. See the
|
||||
/// [module-level docs][self] for more info.
|
||||
pub fn get_value(&self, key: &str) -> Result<Option<Value>, RwLockError> {
|
||||
if let Some(value_data) = self.inner.read()?.get(key) {
|
||||
pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockError> {
|
||||
if let Some(value_data) = self.inner.read()?.get(identifier) {
|
||||
if let ValueData::Value { inner, .. } = value_data {
|
||||
return Ok(Some(inner.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
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()));
|
||||
}
|
||||
}
|
||||
@ -132,8 +132,8 @@ impl Context {
|
||||
///
|
||||
/// If the key matches a stored value, its type will be returned. It if
|
||||
/// matches a type hint, the type hint will be returned.
|
||||
pub fn get_type(&self, key: &str) -> Result<Option<Type>, RwLockError> {
|
||||
if let Some(value_data) = self.inner.read()?.get(key) {
|
||||
pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, RwLockError> {
|
||||
if let Some(value_data) = self.inner.read()?.get(identifier) {
|
||||
match value_data {
|
||||
ValueData::Value { inner, .. } => return Ok(Some(inner.r#type())),
|
||||
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)
|
||||
}
|
||||
|
||||
@ -154,16 +148,19 @@ impl Context {
|
||||
///
|
||||
/// This will also return a built-in type definition if one matches the key.
|
||||
/// See the [module-level docs][self] for more info.
|
||||
pub fn get_definition(&self, key: &str) -> Result<Option<TypeDefinition>, RwLockError> {
|
||||
if let Some(value_data) = self.inner.read()?.get(key) {
|
||||
pub fn get_definition(
|
||||
&self,
|
||||
identifier: &Identifier,
|
||||
) -> Result<Option<TypeDefinition>, RwLockError> {
|
||||
if let Some(value_data) = self.inner.read()?.get(identifier) {
|
||||
if let ValueData::TypeDefinition(definition) = value_data {
|
||||
return Ok(Some(definition.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
for built_in_definition in all_built_in_type_definitions() {
|
||||
if key == built_in_definition.name() {
|
||||
return Ok(Some(built_in_definition.get().clone()));
|
||||
if built_in_definition.name() == identifier.inner().as_ref() {
|
||||
return Ok(Some(built_in_definition.get(self).clone()?));
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,7 +168,7 @@ impl Context {
|
||||
}
|
||||
|
||||
/// 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(
|
||||
key,
|
||||
ValueData::Value {
|
||||
@ -187,7 +184,7 @@ impl Context {
|
||||
///
|
||||
/// This allows the interpreter to check a value's type before the value
|
||||
/// 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
|
||||
.write()?
|
||||
.insert(key, ValueData::TypeHint { inner: r#type });
|
||||
@ -201,7 +198,7 @@ impl Context {
|
||||
/// later while using this context.
|
||||
pub fn set_definition(
|
||||
&self,
|
||||
key: String,
|
||||
key: Identifier,
|
||||
definition: TypeDefinition,
|
||||
) -> Result<(), RwLockError> {
|
||||
self.inner
|
||||
@ -212,7 +209,7 @@ impl Context {
|
||||
}
|
||||
|
||||
/// 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);
|
||||
|
||||
Ok(())
|
||||
|
@ -7,7 +7,7 @@ use std::{
|
||||
time,
|
||||
};
|
||||
|
||||
use crate::{Type, Value};
|
||||
use crate::{Identifier, Type, Value};
|
||||
|
||||
use super::{rw_lock_error::RwLockError, ValidationError};
|
||||
|
||||
@ -106,7 +106,7 @@ pub enum RuntimeError {
|
||||
Utf8(FromUtf8Error),
|
||||
|
||||
/// 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.
|
||||
ExpectedBuiltInFunctionArgumentAmount {
|
||||
|
@ -65,7 +65,7 @@ pub enum ValidationError {
|
||||
VariableIdentifierNotFound(Identifier),
|
||||
|
||||
/// Failed to find a type definition with this key.
|
||||
TypeDefinitionNotFound(String),
|
||||
TypeDefinitionNotFound(Identifier),
|
||||
|
||||
/// Failed to find an enum definition with this key.
|
||||
ExpectedEnumDefintion { actual: TypeDefinition },
|
||||
|
@ -17,6 +17,7 @@ pub use tree_sitter::Node as SyntaxNode;
|
||||
|
||||
pub mod abstract_tree;
|
||||
pub mod built_in_functions;
|
||||
pub mod built_in_identifiers;
|
||||
pub mod built_in_type_definitions;
|
||||
pub mod built_in_types;
|
||||
pub mod built_in_values;
|
||||
|
@ -2,30 +2,30 @@ use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::Value;
|
||||
use crate::{Identifier, Value};
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct EnumInstance {
|
||||
name: String,
|
||||
variant_name: String,
|
||||
name: Identifier,
|
||||
variant: Identifier,
|
||||
value: Option<Box<Value>>,
|
||||
}
|
||||
|
||||
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 {
|
||||
name,
|
||||
variant_name,
|
||||
variant: variant_name,
|
||||
value: value.map(|value| Box::new(value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &String {
|
||||
pub fn name(&self) -> &Identifier {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn variant_name(&self) -> &String {
|
||||
&self.variant_name
|
||||
pub fn variant(&self) -> &Identifier {
|
||||
&self.variant
|
||||
}
|
||||
|
||||
pub fn value(&self) -> &Option<Box<Value>> {
|
||||
@ -35,6 +35,6 @@ impl EnumInstance {
|
||||
|
||||
impl Display for EnumInstance {
|
||||
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::{
|
||||
cmp::Ordering,
|
||||
fmt::{self, Display, Formatter},
|
||||
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use stanza::{
|
||||
renderer::{console::Console, Renderer},
|
||||
@ -12,8 +8,8 @@ use stanza::{
|
||||
|
||||
use crate::Value;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct List(Arc<RwLock<Vec<Value>>>);
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct List(Vec<Value>);
|
||||
|
||||
impl Default for List {
|
||||
fn default() -> Self {
|
||||
@ -23,23 +19,23 @@ impl Default for List {
|
||||
|
||||
impl List {
|
||||
pub fn new() -> Self {
|
||||
List(Arc::new(RwLock::new(Vec::new())))
|
||||
List(Vec::new())
|
||||
}
|
||||
|
||||
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 {
|
||||
List(Arc::new(RwLock::new(items)))
|
||||
List(items)
|
||||
}
|
||||
|
||||
pub fn items(&self) -> RwLockReadGuard<'_, Vec<Value>> {
|
||||
self.0.read().unwrap()
|
||||
pub fn items(&self) -> &Vec<Value> {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub fn items_mut(&self) -> RwLockWriteGuard<'_, Vec<Value>> {
|
||||
self.0.write().unwrap()
|
||||
pub fn items_mut(&mut self) -> &mut Vec<Value> {
|
||||
&mut self.0
|
||||
}
|
||||
|
||||
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 {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
let renderer = Console::default();
|
||||
|
@ -9,7 +9,7 @@ use std::{
|
||||
fmt::{self, Display, Formatter},
|
||||
};
|
||||
|
||||
use crate::value::Value;
|
||||
use crate::{Identifier, Value};
|
||||
|
||||
/// A collection dust variables comprised of key-value pairs.
|
||||
///
|
||||
@ -17,7 +17,7 @@ use crate::value::Value;
|
||||
/// to one another.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Map {
|
||||
inner: BTreeMap<String, Value>,
|
||||
inner: BTreeMap<Identifier, Value>,
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> &BTreeMap<String, Value> {
|
||||
pub fn inner(&self) -> &BTreeMap<Identifier, Value> {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn get(&self, key: &str) -> Option<&Value> {
|
||||
pub fn get(&self, key: &Identifier) -> Option<&Value> {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ impl Map {
|
||||
vec![key.into(), list.as_text_table().into()],
|
||||
));
|
||||
} 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::{
|
||||
cmp::Ordering,
|
||||
collections::BTreeMap,
|
||||
convert::TryFrom,
|
||||
fmt::{self, Display, Formatter},
|
||||
marker::PhantomData,
|
||||
@ -55,8 +54,8 @@ impl Value {
|
||||
|
||||
pub fn some(value: Value) -> Value {
|
||||
Value::Enum(EnumInstance::new(
|
||||
"Option".to_string(),
|
||||
"Some".to_string(),
|
||||
Identifier::new("Option"),
|
||||
Identifier::new("Some"),
|
||||
Some(value),
|
||||
))
|
||||
}
|
||||
@ -97,7 +96,7 @@ impl Value {
|
||||
|
||||
for (key, value) in map.inner() {
|
||||
identifier_types.push((
|
||||
Identifier::new(key.clone()),
|
||||
Identifier::new(key.inner()),
|
||||
TypeSpecification::new(value.r#type()),
|
||||
));
|
||||
}
|
||||
@ -828,13 +827,15 @@ impl<'de> Visitor<'de> for ValueVisitor {
|
||||
where
|
||||
M: MapAccess<'de>,
|
||||
{
|
||||
let mut map = BTreeMap::new();
|
||||
let mut map = Map::new();
|
||||
|
||||
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>
|
||||
|
@ -2,16 +2,16 @@ use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{ser::SerializeMap, Serialize, Serializer};
|
||||
|
||||
use crate::Map;
|
||||
use crate::{Identifier, Map};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct StructInstance {
|
||||
name: String,
|
||||
name: Identifier,
|
||||
map: Map,
|
||||
}
|
||||
|
||||
impl StructInstance {
|
||||
pub fn new(name: String, map: Map) -> Self {
|
||||
pub fn new(name: Identifier, map: Map) -> Self {
|
||||
StructInstance { name, map }
|
||||
}
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ fn function() {
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
&vec![Identifier::new("x".to_string())],
|
||||
&vec![Identifier::new_or_get("x".to_string())],
|
||||
function.parameters()
|
||||
);
|
||||
assert_eq!(&Type::Boolean, function.return_type());
|
||||
|
Loading…
Reference in New Issue
Block a user