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

View File

@ -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,63 +173,64 @@ 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 = Type::from_syntax_node(source, item_type_node, _context)?; let item_type_node = node.child(1).unwrap();
let item_type = Type::from_syntax_node(source, item_type_node, _context)?;
Type::List(Box::new(item_type)) Type::List(Box::new(item_type))
} }
"any" => Type::Any, "any" => Type::Any,
"bool" => Type::Boolean, "bool" => Type::Boolean,
"float" => Type::Float, "collection" => Type::Collection,
"(" => { "float" => Type::Float,
let child_count = node.child_count(); "(" => {
let mut parameter_types = Vec::new(); let child_count = node.child_count();
let mut parameter_types = Vec::new();
for index in 1..child_count - 2 { for index in 1..child_count - 2 {
let child = node.child(index).unwrap(); let child = node.child(index).unwrap();
if child.is_named() { if child.is_named() {
let parameter_type = Type::from_syntax_node(source, child, _context)?; let parameter_type = Type::from_syntax_node(source, child, _context)?;
parameter_types.push(parameter_type); parameter_types.push(parameter_type);
}
}
let final_node = node.child(child_count - 1).unwrap();
let return_type = if final_node.is_named() {
Type::from_syntax_node(source, final_node, _context)?
} else {
Type::None
};
Type::Function {
parameter_types,
return_type: Box::new(return_type),
} }
} }
"int" => Type::Integer,
"map" => Type::Map,
"num" => Type::Number,
"none" => Type::None,
"str" => Type::String,
"option" => {
let inner_type_node = node.child(2).unwrap();
let inner_type = Type::from_syntax_node(source, inner_type_node, _context)?;
let final_node = node.child(child_count - 1).unwrap(); Type::Option(Box::new(inner_type))
let return_type = if final_node.is_named() {
Type::from_syntax_node(source, final_node, _context)?
} else {
Type::None
};
Type::Function {
parameter_types,
return_type: Box::new(return_type),
} }
} _ => return Err(Error::UnexpectedSyntaxNode {
"int" => Type::Integer, expected:
"map" => Type::Map, "any, bool, collection, float, function, int, list, map, num, str or option"
"num" => Type::Number, .to_string(),
"none" => Type::None,
"str" => Type::String,
"option" => {
let inner_type_node = node.child(2).unwrap();
let inner_type = Type::from_syntax_node(source, inner_type_node, _context)?;
Type::Option(Box::new(inner_type))
}
_ => {
return Err(Error::UnexpectedSyntaxNode {
expected: "any, bool, float, function, int, list, map, num, str or option"
.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,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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