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 block;
|
||||
pub mod built_in_value;
|
||||
pub mod expression;
|
||||
pub mod r#for;
|
||||
pub mod function_call;
|
||||
@ -27,10 +28,10 @@ pub mod r#while;
|
||||
pub mod r#yield;
|
||||
|
||||
pub use {
|
||||
assignment::*, block::*, expression::*, function_call::*, function_expression::*,
|
||||
identifier::*, if_else::*, index::*, index_assignment::IndexAssignment, index_expression::*,
|
||||
logic::*, math::*, r#for::*, r#match::*, r#while::*, r#yield::*, statement::*,
|
||||
type_definition::*, value_node::*,
|
||||
assignment::*, block::*, built_in_value::*, expression::*, function_call::*,
|
||||
function_expression::*, identifier::*, if_else::*, index::*, index_assignment::IndexAssignment,
|
||||
index_expression::*, logic::*, math::*, r#for::*, r#match::*, r#while::*, r#yield::*,
|
||||
statement::*, type_definition::*, value_node::*,
|
||||
};
|
||||
|
||||
use tree_sitter::Node;
|
||||
|
@ -53,6 +53,7 @@ impl Display for TypeDefinition {
|
||||
pub enum Type {
|
||||
Any,
|
||||
Boolean,
|
||||
Collection,
|
||||
Float,
|
||||
Function {
|
||||
parameter_types: Vec<Type>,
|
||||
@ -84,6 +85,13 @@ impl Type {
|
||||
(Type::Any, _)
|
||||
| (_, Type::Any)
|
||||
| (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::Integer, Type::Integer)
|
||||
| (Type::Map, Type::Map)
|
||||
@ -165,7 +173,8 @@ impl AbstractTree for Type {
|
||||
|
||||
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 = Type::from_syntax_node(source, item_type_node, _context)?;
|
||||
@ -174,6 +183,7 @@ impl AbstractTree for Type {
|
||||
}
|
||||
"any" => Type::Any,
|
||||
"bool" => Type::Boolean,
|
||||
"collection" => Type::Collection,
|
||||
"float" => Type::Float,
|
||||
"(" => {
|
||||
let child_count = node.child_count();
|
||||
@ -212,15 +222,14 @@ impl AbstractTree for Type {
|
||||
|
||||
Type::Option(Box::new(inner_type))
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::UnexpectedSyntaxNode {
|
||||
expected: "any, bool, float, function, int, list, map, num, str or option"
|
||||
_ => return Err(Error::UnexpectedSyntaxNode {
|
||||
expected:
|
||||
"any, bool, collection, float, function, int, list, map, num, str or option"
|
||||
.to_string(),
|
||||
actual: type_node.kind().to_string(),
|
||||
location: type_node.start_position(),
|
||||
relevant_source: source[type_node.byte_range()].to_string(),
|
||||
})
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
||||
Ok(r#type)
|
||||
@ -240,6 +249,7 @@ impl Display for Type {
|
||||
match self {
|
||||
Type::Any => write!(f, "any"),
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
Type::Collection => write!(f, "collection"),
|
||||
Type::Float => write!(f, "float"),
|
||||
Type::Function {
|
||||
parameter_types,
|
||||
|
@ -34,9 +34,7 @@ impl BuiltInFunction {
|
||||
BuiltInFunction::FsRead => Type::function(vec![Type::String], Type::String),
|
||||
BuiltInFunction::Output => Type::function(vec![Type::Any], Type::None),
|
||||
BuiltInFunction::RandomBoolean => Type::function(vec![], Type::Boolean),
|
||||
BuiltInFunction::Length => {
|
||||
Type::function(vec![Type::list_of(Type::Any)], Type::Integer)
|
||||
}
|
||||
BuiltInFunction::Length => Type::function(vec![Type::Collection], Type::Integer),
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,9 +73,20 @@ impl BuiltInFunction {
|
||||
BuiltInFunction::Length => {
|
||||
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},
|
||||
list::List,
|
||||
map::Map,
|
||||
BuiltInValue, Value,
|
||||
Value,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Types that represent runtime values.
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
AbstractTree, BuiltInFunction, Function, List, Map, Type,
|
||||
Function, List, Map, Type,
|
||||
};
|
||||
|
||||
use serde::{
|
||||
@ -9,101 +9,19 @@ use serde::{
|
||||
ser::SerializeTuple,
|
||||
Deserialize, Serialize, Serializer,
|
||||
};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
convert::TryFrom,
|
||||
env::args,
|
||||
fmt::{self, Display, Formatter},
|
||||
marker::PhantomData,
|
||||
ops::{Add, AddAssign, Div, Mul, Rem, Sub, SubAssign},
|
||||
sync::OnceLock,
|
||||
};
|
||||
|
||||
pub mod function;
|
||||
pub mod list;
|
||||
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.
|
||||
///
|
||||
/// Every dust variable has a key and a Value. Variables are represented by
|
||||
|
@ -344,6 +344,7 @@ module.exports = grammar({
|
||||
choice(
|
||||
'any',
|
||||
'bool',
|
||||
'collection',
|
||||
'float',
|
||||
'int',
|
||||
'map',
|
||||
|
@ -1087,6 +1087,10 @@
|
||||
"type": "STRING",
|
||||
"value": "bool"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "collection"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "float"
|
||||
|
@ -772,6 +772,10 @@
|
||||
"type": "bool",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "collection",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "else",
|
||||
"named": false
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user