Implement collection type
This commit is contained in:
parent
ae66e2a211
commit
f136cafb41
85
src/abstract_tree/built_in_value.rs
Normal file
85
src/abstract_tree/built_in_value.rs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
use std::{env::args, sync::OnceLock};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tree_sitter::Node;
|
||||||
|
|
||||||
|
use crate::{AbstractTree, BuiltInFunction, Function, List, Map, Result, Type, Value};
|
||||||
|
|
||||||
|
static ARGS: OnceLock<Value> = OnceLock::new();
|
||||||
|
static RANDOM: OnceLock<Value> = OnceLock::new();
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
|
pub enum BuiltInValue {
|
||||||
|
Args,
|
||||||
|
AssertEqual,
|
||||||
|
Length,
|
||||||
|
Output,
|
||||||
|
Random,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BuiltInValue {
|
||||||
|
fn r#type(&self) -> Type {
|
||||||
|
match self {
|
||||||
|
BuiltInValue::Args => Type::list_of(Type::String),
|
||||||
|
BuiltInValue::AssertEqual => BuiltInFunction::AssertEqual.r#type(),
|
||||||
|
BuiltInValue::Length => BuiltInFunction::Length.r#type(),
|
||||||
|
BuiltInValue::Output => BuiltInFunction::Output.r#type(),
|
||||||
|
BuiltInValue::Random => Type::Map,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self) -> &Value {
|
||||||
|
match self {
|
||||||
|
BuiltInValue::Args => ARGS.get_or_init(|| {
|
||||||
|
let args = args().map(|arg| Value::String(arg.to_string())).collect();
|
||||||
|
|
||||||
|
Value::List(List::with_items(args))
|
||||||
|
}),
|
||||||
|
BuiltInValue::AssertEqual => {
|
||||||
|
&Value::Function(Function::BuiltIn(BuiltInFunction::AssertEqual))
|
||||||
|
}
|
||||||
|
BuiltInValue::Length => &Value::Function(Function::BuiltIn(BuiltInFunction::Length)),
|
||||||
|
BuiltInValue::Output => &Value::Function(Function::BuiltIn(BuiltInFunction::Output)),
|
||||||
|
BuiltInValue::Random => RANDOM.get_or_init(|| {
|
||||||
|
let random_context = Map::new();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut variables = random_context.variables_mut().unwrap();
|
||||||
|
|
||||||
|
for built_in_function in [BuiltInFunction::RandomBoolean] {
|
||||||
|
let key = built_in_function.name().to_string();
|
||||||
|
let value = Value::Function(Function::BuiltIn(built_in_function));
|
||||||
|
let r#type = built_in_function.r#type();
|
||||||
|
|
||||||
|
variables.insert(key, (value, r#type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Value::Map(random_context)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbstractTree for BuiltInValue {
|
||||||
|
fn from_syntax_node(_source: &str, node: Node, _context: &Map) -> Result<Self> {
|
||||||
|
let built_in_value = match node.kind() {
|
||||||
|
"args" => BuiltInValue::Args,
|
||||||
|
"assert_equal" => BuiltInValue::AssertEqual,
|
||||||
|
"length" => BuiltInValue::Length,
|
||||||
|
"output" => BuiltInValue::Output,
|
||||||
|
"random" => BuiltInValue::Random,
|
||||||
|
_ => todo!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(built_in_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
||||||
|
Ok(self.get().clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||||
|
Ok(self.r#type())
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
pub mod assignment;
|
pub mod assignment;
|
||||||
pub mod block;
|
pub mod block;
|
||||||
|
pub mod built_in_value;
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
pub mod r#for;
|
pub mod r#for;
|
||||||
pub mod function_call;
|
pub mod function_call;
|
||||||
@ -27,10 +28,10 @@ pub mod r#while;
|
|||||||
pub mod r#yield;
|
pub mod r#yield;
|
||||||
|
|
||||||
pub use {
|
pub use {
|
||||||
assignment::*, block::*, expression::*, function_call::*, function_expression::*,
|
assignment::*, block::*, built_in_value::*, expression::*, function_call::*,
|
||||||
identifier::*, if_else::*, index::*, index_assignment::IndexAssignment, index_expression::*,
|
function_expression::*, identifier::*, if_else::*, index::*, index_assignment::IndexAssignment,
|
||||||
logic::*, math::*, r#for::*, r#match::*, r#while::*, r#yield::*, statement::*,
|
index_expression::*, logic::*, math::*, r#for::*, r#match::*, r#while::*, r#yield::*,
|
||||||
type_definition::*, value_node::*,
|
statement::*, type_definition::*, value_node::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
@ -53,6 +53,7 @@ impl Display for TypeDefinition {
|
|||||||
pub enum Type {
|
pub enum Type {
|
||||||
Any,
|
Any,
|
||||||
Boolean,
|
Boolean,
|
||||||
|
Collection,
|
||||||
Float,
|
Float,
|
||||||
Function {
|
Function {
|
||||||
parameter_types: Vec<Type>,
|
parameter_types: Vec<Type>,
|
||||||
@ -84,6 +85,13 @@ impl Type {
|
|||||||
(Type::Any, _)
|
(Type::Any, _)
|
||||||
| (_, Type::Any)
|
| (_, Type::Any)
|
||||||
| (Type::Boolean, Type::Boolean)
|
| (Type::Boolean, Type::Boolean)
|
||||||
|
| (Type::Collection, Type::Collection)
|
||||||
|
| (Type::Collection, Type::List(_))
|
||||||
|
| (Type::List(_), Type::Collection)
|
||||||
|
| (Type::Collection, Type::Map)
|
||||||
|
| (Type::Map, Type::Collection)
|
||||||
|
| (Type::Collection, Type::String)
|
||||||
|
| (Type::String, Type::Collection)
|
||||||
| (Type::Float, Type::Float)
|
| (Type::Float, Type::Float)
|
||||||
| (Type::Integer, Type::Integer)
|
| (Type::Integer, Type::Integer)
|
||||||
| (Type::Map, Type::Map)
|
| (Type::Map, Type::Map)
|
||||||
@ -165,7 +173,8 @@ impl AbstractTree for Type {
|
|||||||
|
|
||||||
let type_node = node.child(0).unwrap();
|
let type_node = node.child(0).unwrap();
|
||||||
|
|
||||||
let r#type = match type_node.kind() {
|
let r#type =
|
||||||
|
match type_node.kind() {
|
||||||
"[" => {
|
"[" => {
|
||||||
let item_type_node = node.child(1).unwrap();
|
let item_type_node = node.child(1).unwrap();
|
||||||
let item_type = Type::from_syntax_node(source, item_type_node, _context)?;
|
let item_type = Type::from_syntax_node(source, item_type_node, _context)?;
|
||||||
@ -174,6 +183,7 @@ impl AbstractTree for Type {
|
|||||||
}
|
}
|
||||||
"any" => Type::Any,
|
"any" => Type::Any,
|
||||||
"bool" => Type::Boolean,
|
"bool" => Type::Boolean,
|
||||||
|
"collection" => Type::Collection,
|
||||||
"float" => Type::Float,
|
"float" => Type::Float,
|
||||||
"(" => {
|
"(" => {
|
||||||
let child_count = node.child_count();
|
let child_count = node.child_count();
|
||||||
@ -212,15 +222,14 @@ impl AbstractTree for Type {
|
|||||||
|
|
||||||
Type::Option(Box::new(inner_type))
|
Type::Option(Box::new(inner_type))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => return Err(Error::UnexpectedSyntaxNode {
|
||||||
return Err(Error::UnexpectedSyntaxNode {
|
expected:
|
||||||
expected: "any, bool, float, function, int, list, map, num, str or option"
|
"any, bool, collection, float, function, int, list, map, num, str or option"
|
||||||
.to_string(),
|
.to_string(),
|
||||||
actual: type_node.kind().to_string(),
|
actual: type_node.kind().to_string(),
|
||||||
location: type_node.start_position(),
|
location: type_node.start_position(),
|
||||||
relevant_source: source[type_node.byte_range()].to_string(),
|
relevant_source: source[type_node.byte_range()].to_string(),
|
||||||
})
|
}),
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(r#type)
|
Ok(r#type)
|
||||||
@ -240,6 +249,7 @@ impl Display for Type {
|
|||||||
match self {
|
match self {
|
||||||
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::Float => write!(f, "float"),
|
Type::Float => write!(f, "float"),
|
||||||
Type::Function {
|
Type::Function {
|
||||||
parameter_types,
|
parameter_types,
|
||||||
|
@ -34,9 +34,7 @@ impl BuiltInFunction {
|
|||||||
BuiltInFunction::FsRead => Type::function(vec![Type::String], Type::String),
|
BuiltInFunction::FsRead => Type::function(vec![Type::String], Type::String),
|
||||||
BuiltInFunction::Output => Type::function(vec![Type::Any], Type::None),
|
BuiltInFunction::Output => Type::function(vec![Type::Any], Type::None),
|
||||||
BuiltInFunction::RandomBoolean => Type::function(vec![], Type::Boolean),
|
BuiltInFunction::RandomBoolean => Type::function(vec![], Type::Boolean),
|
||||||
BuiltInFunction::Length => {
|
BuiltInFunction::Length => Type::function(vec![Type::Collection], Type::Integer),
|
||||||
Type::function(vec![Type::list_of(Type::Any)], Type::Integer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,9 +73,20 @@ impl BuiltInFunction {
|
|||||||
BuiltInFunction::Length => {
|
BuiltInFunction::Length => {
|
||||||
Error::expect_argument_amount(self, 1, arguments.len())?;
|
Error::expect_argument_amount(self, 1, arguments.len())?;
|
||||||
|
|
||||||
let list_len = arguments.first().unwrap().as_list()?.items().len() as i64;
|
let value = arguments.first().unwrap();
|
||||||
|
let length = if let Ok(list) = value.as_list() {
|
||||||
|
list.items().len()
|
||||||
|
} else if let Ok(map) = value.as_map() {
|
||||||
|
map.variables()?.len()
|
||||||
|
} else if let Ok(string) = value.as_string() {
|
||||||
|
string.chars().count()
|
||||||
|
} else {
|
||||||
|
return Err(Error::ExpectedCollection {
|
||||||
|
actual: value.clone(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Value::Integer(list_len))
|
Ok(Value::Integer(length as i64))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ pub use crate::{
|
|||||||
function::{ContextDefinedFunction, Function},
|
function::{ContextDefinedFunction, Function},
|
||||||
list::List,
|
list::List,
|
||||||
map::Map,
|
map::Map,
|
||||||
BuiltInValue, Value,
|
Value,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Types that represent runtime values.
|
//! Types that represent runtime values.
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{Error, Result},
|
error::{Error, Result},
|
||||||
AbstractTree, BuiltInFunction, Function, List, Map, Type,
|
Function, List, Map, Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::{
|
use serde::{
|
||||||
@ -9,101 +9,19 @@ use serde::{
|
|||||||
ser::SerializeTuple,
|
ser::SerializeTuple,
|
||||||
Deserialize, Serialize, Serializer,
|
Deserialize, Serialize, Serializer,
|
||||||
};
|
};
|
||||||
use tree_sitter::Node;
|
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
env::args,
|
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
ops::{Add, AddAssign, Div, Mul, Rem, Sub, SubAssign},
|
ops::{Add, AddAssign, Div, Mul, Rem, Sub, SubAssign},
|
||||||
sync::OnceLock,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod function;
|
pub mod function;
|
||||||
pub mod list;
|
pub mod list;
|
||||||
pub mod map;
|
pub mod map;
|
||||||
|
|
||||||
static ARGS: OnceLock<Value> = OnceLock::new();
|
|
||||||
static RANDOM: OnceLock<Value> = OnceLock::new();
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
|
||||||
pub enum BuiltInValue {
|
|
||||||
Args,
|
|
||||||
AssertEqual,
|
|
||||||
Length,
|
|
||||||
Output,
|
|
||||||
Random,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BuiltInValue {
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
match self {
|
|
||||||
BuiltInValue::Args => Type::list_of(Type::String),
|
|
||||||
BuiltInValue::AssertEqual => BuiltInFunction::AssertEqual.r#type(),
|
|
||||||
BuiltInValue::Length => BuiltInFunction::Length.r#type(),
|
|
||||||
BuiltInValue::Output => BuiltInFunction::Output.r#type(),
|
|
||||||
BuiltInValue::Random => Type::Map,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self) -> &Value {
|
|
||||||
match self {
|
|
||||||
BuiltInValue::Args => ARGS.get_or_init(|| {
|
|
||||||
let args = args().map(|arg| Value::String(arg.to_string())).collect();
|
|
||||||
|
|
||||||
Value::List(List::with_items(args))
|
|
||||||
}),
|
|
||||||
BuiltInValue::AssertEqual => {
|
|
||||||
&Value::Function(Function::BuiltIn(BuiltInFunction::AssertEqual))
|
|
||||||
}
|
|
||||||
BuiltInValue::Length => &Value::Function(Function::BuiltIn(BuiltInFunction::Length)),
|
|
||||||
BuiltInValue::Output => &Value::Function(Function::BuiltIn(BuiltInFunction::Output)),
|
|
||||||
BuiltInValue::Random => RANDOM.get_or_init(|| {
|
|
||||||
let random_context = Map::new();
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut variables = random_context.variables_mut().unwrap();
|
|
||||||
|
|
||||||
for built_in_function in [BuiltInFunction::RandomBoolean] {
|
|
||||||
let key = built_in_function.name().to_string();
|
|
||||||
let value = Value::Function(Function::BuiltIn(built_in_function));
|
|
||||||
let r#type = built_in_function.r#type();
|
|
||||||
|
|
||||||
variables.insert(key, (value, r#type));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Value::Map(random_context)
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AbstractTree for BuiltInValue {
|
|
||||||
fn from_syntax_node(_source: &str, node: Node, _context: &Map) -> Result<Self> {
|
|
||||||
let built_in_value = match node.kind() {
|
|
||||||
"args" => BuiltInValue::Args,
|
|
||||||
"assert_equal" => BuiltInValue::AssertEqual,
|
|
||||||
"length" => BuiltInValue::Length,
|
|
||||||
"output" => BuiltInValue::Output,
|
|
||||||
"random" => BuiltInValue::Random,
|
|
||||||
_ => todo!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(built_in_value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
|
||||||
Ok(self.get().clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
|
||||||
Ok(self.r#type())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Dust value representation.
|
/// Dust value representation.
|
||||||
///
|
///
|
||||||
/// Every dust variable has a key and a Value. Variables are represented by
|
/// Every dust variable has a key and a Value. Variables are represented by
|
||||||
|
@ -344,6 +344,7 @@ module.exports = grammar({
|
|||||||
choice(
|
choice(
|
||||||
'any',
|
'any',
|
||||||
'bool',
|
'bool',
|
||||||
|
'collection',
|
||||||
'float',
|
'float',
|
||||||
'int',
|
'int',
|
||||||
'map',
|
'map',
|
||||||
|
@ -1087,6 +1087,10 @@
|
|||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"value": "bool"
|
"value": "bool"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "collection"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"value": "float"
|
"value": "float"
|
||||||
|
@ -772,6 +772,10 @@
|
|||||||
"type": "bool",
|
"type": "bool",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "collection",
|
||||||
|
"named": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "else",
|
"type": "else",
|
||||||
"named": false
|
"named": false
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user