Implement collection type

This commit is contained in:
Jeff 2024-01-01 05:20:11 -05:00
parent ae66e2a211
commit f136cafb41
10 changed files with 1203 additions and 1116 deletions

View 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())
}
}

View File

@ -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;

View File

@ -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,

View File

@ -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))
}
}
}

View File

@ -12,7 +12,7 @@ pub use crate::{
function::{ContextDefinedFunction, Function},
list::List,
map::Map,
BuiltInValue, Value,
Value,
},
};

View File

@ -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

View File

@ -344,6 +344,7 @@ module.exports = grammar({
choice(
'any',
'bool',
'collection',
'float',
'int',
'map',

View File

@ -1087,6 +1087,10 @@
"type": "STRING",
"value": "bool"
},
{
"type": "STRING",
"value": "collection"
},
{
"type": "STRING",
"value": "float"

View File

@ -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