1
0

Implement new function syntax

This commit is contained in:
Jeff 2023-12-05 16:42:11 -05:00
parent 7f1b53aabe
commit d6c679c0b3
20 changed files with 9678 additions and 10024 deletions

View File

@ -1,4 +1,4 @@
create_random_numbers = <fn int> |count| { create_random_numbers <(int)> = fn |count| {
numbers = [] numbers = []
while (length numbers) < count { while (length numbers) < count {

View File

@ -4,26 +4,26 @@ all_cards = {
weapons = ['Rope' 'Lead_Pipe' 'Knife'] weapons = ['Rope' 'Lead_Pipe' 'Knife']
} }
is_ready_to_solve = <fn map -> bool> |cards| { is_ready_to_solve <(map) -> bool> = fn |cards| {
((length cards:suspects) == 1) ((length cards:suspects) == 1)
&& ((length cards:rooms) == 1) && ((length cards:rooms) == 1)
&& ((length cards:weapons) == 1) && ((length cards:weapons) == 1)
} }
take_turn = <fn str str map -> map> |opponent_card current_room cards| { take_turn <(map str str) -> map> = fn |cards opponent_card current_room| {
(remove_card opponent_card cards) cards = (remove_card opponent_card cards)
(make_guess current_room cards) cards = (make_guess current_room cards)
cards cards
} }
remove_card = <fn str map> |opponent_card cards| { remove_card <(map str) -> map> = fn |cards opponent_card| {
(output opponent_card cards)
cards:rooms -= opponent_card cards:rooms -= opponent_card
cards:suspects -= opponent_card cards:suspects -= opponent_card
cards:weapons -= opponent_card cards:weapons -= opponent_card
cards
} }
make_guess = <fn str map> |current_room cards| { make_guess <(map str)> = fn |cards current_room| {
if (is_ready_to_solve cards) { if (is_ready_to_solve cards) {
(output 'It was ' (output 'It was '
+ cards:suspects:0 + cards:suspects:0
@ -41,12 +41,14 @@ make_guess = <fn str map> |current_room cards| {
+ (random cards:weapons) + (random cards:weapons)
+ '.') + '.')
} }
cards
} }
(take_turn 'Rope' 'Kitchen' all_cards
(take_turn 'Library' 'Kitchen' -> (take_turn 'Rope' 'Kitchen')
(take_turn 'Conservatory' 'Kitchen' -> (take_turn 'Library' 'Kitchen')
(take_turn 'White' 'Kitchen' -> (take_turn 'Conservatory' 'Kitchen')
(take_turn 'Green' 'Kitchen' -> (take_turn 'White' 'Kitchen')
(take_turn 'Knife' 'Kitchen' all_cards)))))) -> (take_turn 'Green' 'Kitchen')
-> (take_turn 'Knife' 'Kitchen')

View File

@ -1,4 +1,4 @@
fib = <fn int -> int> |i| { fib <(int) -> int> = fn |i| {
if i <= 1 { if i <= 1 {
1 1
} else { } else {

View File

@ -1,6 +1,6 @@
data = (from_json (read 'examples/assets/jq_data.json')) data = (from_json (read 'examples/assets/jq_data.json'))
new_data = []; new_data = []
for commit_data in data { for commit_data in data {
new_data += { new_data += {

View File

@ -1,6 +1,6 @@
1 -> (output) 1 -> (output)
add_one = <fn [int] -> [int]> |numbers| { add_one <([int]) -> [int]> = fn |numbers| {
new_numbers = [] new_numbers = []
for number in numbers { for number in numbers {

9
scripts/test.fish Executable file
View File

@ -0,0 +1,9 @@
#!/usr/bin/fish
# Build the project in debug mode.
cd tree-sitter-dust/
tree-sitter generate --debug-build --no-bindings
tree-sitter test
cd ..
cargo test

View File

@ -71,7 +71,12 @@ impl AbstractTree for Assignment {
if let Type::List(item_type) = type_definition.inner() { if let Type::List(item_type) = type_definition.inner() {
let item_type_definition = TypeDefinition::new(*item_type.clone()); let item_type_definition = TypeDefinition::new(*item_type.clone());
item_type_definition.check(&identifier_type, context, node, source)?; item_type_definition.check(
&identifier_type,
context,
identifier_node,
source,
)?;
item_type_definition.check( item_type_definition.check(
&statement_type, &statement_type,
context, context,

View File

@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{ use crate::{
AbstractTree, Error, Map, Result, TypeDefinition, Value, ValueNode, BUILT_IN_FUNCTIONS, AbstractTree, Error, Map, Result, Type, TypeDefinition, Value, ValueNode, BUILT_IN_FUNCTIONS,
}; };
use super::expression::Expression; use super::expression::Expression;
@ -41,19 +41,27 @@ impl AbstractTree for FunctionCall {
} }
} }
let function_type = function_expression.expected_type(context)?; let function_type = function_expression.expected_type(context)?.take_inner();
if let Type::Function {
parameter_types,
return_type,
} = function_type
{
let argument_type_pairs = arguments.iter().zip(parameter_types.iter());
for (argument, r#type) in argument_type_pairs {
let argument_type = argument.expected_type(context)?;
r#type.check(argument_type.inner(), context, node, source)?;
}
}
let function_call = FunctionCall { let function_call = FunctionCall {
function_expression, function_expression,
arguments, arguments,
}; };
function_type.check(
&function_call.expected_type(context)?,
context,
node,
source,
)?;
Ok(function_call) Ok(function_call)
} }
@ -98,7 +106,9 @@ impl AbstractTree for FunctionCall {
match &self.function_expression { match &self.function_expression {
Expression::Value(value_node) => { Expression::Value(value_node) => {
if let ValueNode::Function(function) = value_node { if let ValueNode::Function(function) = value_node {
Ok(function.return_type().clone()) let return_type = function.return_type()?.clone();
Ok(TypeDefinition::new(return_type))
} else { } else {
value_node.expected_type(context) value_node.expected_type(context)
} }
@ -107,9 +117,9 @@ impl AbstractTree for FunctionCall {
let function_name = identifier.inner(); let function_name = identifier.inner();
if let Some(value) = context.variables()?.get(function_name) { if let Some(value) = context.variables()?.get(function_name) {
let return_type = value.as_function()?.return_type(); let return_type = value.as_function()?.return_type()?.clone();
Ok(return_type.clone()) Ok(TypeDefinition::new(return_type))
} else { } else {
self.function_expression.expected_type(context) self.function_expression.expected_type(context)
} }
@ -132,7 +142,7 @@ mod tests {
assert_eq!( assert_eq!(
evaluate( evaluate(
" "
foobar = <fn str -> str> |message| { message } foobar <(str) -> str> = fn |message| { message }
(foobar 'Hiya') (foobar 'Hiya')
", ",
), ),
@ -140,6 +150,22 @@ mod tests {
); );
} }
#[test]
fn evaluate_callback() {
assert_eq!(
evaluate(
"
foobar <(() -> str) -> str> = fn |cb| {
(cb)
}
(foobar fn || { 'Hiya' })
",
),
Ok(Value::String("Hiya".to_string()))
);
}
#[test] #[test]
fn evaluate_built_in_function_call() { fn evaluate_built_in_function_call() {
assert_eq!(evaluate("(output 'Hiya')"), Ok(Value::Empty)); assert_eq!(evaluate("(output 'Hiya')"), Ok(Value::Empty));

View File

@ -107,7 +107,7 @@ mod tests {
let test = evaluate( let test = evaluate(
" "
x = [1 2 3] x = [1 2 3]
y = <fn -> int> || { 0 } y <() -> int> = fn || { 0 }
x:(y) x:(y)
", ",
) )

View File

@ -74,7 +74,6 @@ pub enum Type {
Map, Map,
Number, Number,
String, String,
Table,
} }
impl Type { impl Type {
@ -92,8 +91,7 @@ impl Type {
| (Type::Number, Type::Float) | (Type::Number, Type::Float)
| (Type::Integer, Type::Number) | (Type::Integer, Type::Number)
| (Type::Float, Type::Number) | (Type::Float, Type::Number)
| (Type::String, Type::String) | (Type::String, Type::String) => Ok(()),
| (Type::Table, Type::Table) => Ok(()),
(Type::List(self_item_type), Type::List(other_item_type)) => { (Type::List(self_item_type), Type::List(other_item_type)) => {
self_item_type.check(&other_item_type, context, node, source) self_item_type.check(&other_item_type, context, node, source)
} }
@ -145,20 +143,26 @@ impl AbstractTree for Type {
"any" => Type::Any, "any" => Type::Any,
"bool" => Type::Boolean, "bool" => Type::Boolean,
"float" => Type::Float, "float" => Type::Float,
"fn" => { "(" => {
let child_count = node.child_count(); let child_count = node.child_count();
let mut parameter_types = Vec::new(); let mut parameter_types = Vec::new();
for index in 1..child_count - 2 { for index in 1..child_count - 2 {
let parameter_type_node = node.child(index).unwrap(); let child = node.child(index).unwrap();
let parameter_type =
Type::from_syntax_node(source, parameter_type_node, context)?;
parameter_types.push(parameter_type); if child.is_named() {
let parameter_type = Type::from_syntax_node(source, child, context)?;
parameter_types.push(parameter_type);
}
} }
let return_type_node = node.child(child_count - 1).unwrap(); let final_node = node.child(child_count - 1).unwrap();
let return_type = Type::from_syntax_node(source, return_type_node, context)?; let return_type = if final_node.is_named() {
Type::from_syntax_node(source, final_node, context)?
} else {
Type::Empty
};
Type::Function { Type::Function {
parameter_types, parameter_types,
@ -215,7 +219,6 @@ impl Display for Type {
Type::Map => write!(f, "map"), Type::Map => write!(f, "map"),
Type::Number => write!(f, "num"), Type::Number => write!(f, "num"),
Type::String => write!(f, "str"), Type::String => write!(f, "str"),
Type::Table => write!(f, "table"),
} }
} }
} }

View File

@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{ use crate::{
AbstractTree, Error, Expression, Function, Identifier, List, Map, Result, Statement, Table, AbstractTree, Block, Error, Expression, Function, Identifier, List, Map, Result, Statement,
Type, TypeDefinition, Value, Type, TypeDefinition, Value,
}; };
@ -18,10 +18,6 @@ pub enum ValueNode {
List(Vec<Expression>), List(Vec<Expression>),
Empty, Empty,
Map(BTreeMap<String, Statement>), Map(BTreeMap<String, Statement>),
Table {
column_names: Vec<Identifier>,
rows: Box<Expression>,
},
} }
impl AbstractTree for ValueNode { impl AbstractTree for ValueNode {
@ -32,7 +28,25 @@ impl AbstractTree for ValueNode {
let value_node = match child.kind() { let value_node = match child.kind() {
"boolean" => ValueNode::Boolean(source[child.byte_range()].to_string()), "boolean" => ValueNode::Boolean(source[child.byte_range()].to_string()),
"float" => ValueNode::Float(source[child.byte_range()].to_string()), "float" => ValueNode::Float(source[child.byte_range()].to_string()),
"function" => ValueNode::Function(Function::from_syntax_node(source, child, context)?), "function" => {
let child_count = child.child_count();
let mut parameters = Vec::new();
for index in 2..child_count - 1 {
let child = child.child(index).unwrap();
if child.is_named() {
let identifier = Identifier::from_syntax_node(source, child, context)?;
parameters.push(identifier);
}
}
let body_node = child.child(child_count - 1).unwrap();
let body = Block::from_syntax_node(source, body_node, context)?;
ValueNode::Function(Function::new(parameters, body, None))
}
"integer" => ValueNode::Integer(source[child.byte_range()].to_string()), "integer" => ValueNode::Integer(source[child.byte_range()].to_string()),
"string" => { "string" => {
let without_quotes = child.start_byte() + 1..child.end_byte() - 1; let without_quotes = child.start_byte() + 1..child.end_byte() - 1;
@ -54,30 +68,6 @@ impl AbstractTree for ValueNode {
ValueNode::List(expressions) ValueNode::List(expressions)
} }
"table" => {
let identifier_list_node = child.child(1).unwrap();
let identifier_count = identifier_list_node.child_count();
let mut column_names = Vec::with_capacity(identifier_count);
for index in 0..identifier_count {
let identifier_node = identifier_list_node.child(index).unwrap();
if identifier_node.is_named() {
let identifier =
Identifier::from_syntax_node(source, identifier_node, context)?;
column_names.push(identifier)
}
}
let expression_node = child.child(2).unwrap();
let expression = Expression::from_syntax_node(source, expression_node, context)?;
ValueNode::Table {
column_names,
rows: Box::new(expression),
}
}
"map" => { "map" => {
let mut child_nodes = BTreeMap::new(); let mut child_nodes = BTreeMap::new();
let mut current_key = "".to_string(); let mut current_key = "".to_string();
@ -104,7 +94,7 @@ impl AbstractTree for ValueNode {
} }
_ => { _ => {
return Err(Error::UnexpectedSyntaxNode { return Err(Error::UnexpectedSyntaxNode {
expected: "string, integer, float, boolean, list, table, map, or empty", expected: "string, integer, float, boolean, list, map, or empty",
actual: child.kind(), actual: child.kind(),
location: child.start_position(), location: child.start_position(),
relevant_source: source[child.byte_range()].to_string(), relevant_source: source[child.byte_range()].to_string(),
@ -149,32 +139,6 @@ impl AbstractTree for ValueNode {
Value::Map(map) Value::Map(map)
} }
ValueNode::Table {
column_names,
rows: row_expression,
} => {
let mut headers = Vec::with_capacity(column_names.len());
let mut rows = Vec::new();
for identifier in column_names {
let name = identifier.inner().clone();
headers.push(name)
}
let _row_values = row_expression.run(source, context)?;
let row_values = _row_values.as_list()?.items();
for value in row_values.iter() {
let row = value.as_list()?.items().clone();
rows.push(row)
}
let table = Table::from_raw_parts(headers, rows);
Value::Table(table)
}
}; };
Ok(value) Ok(value)
@ -184,7 +148,7 @@ impl AbstractTree for ValueNode {
let type_definition = match self { let type_definition = match self {
ValueNode::Boolean(_) => TypeDefinition::new(Type::Boolean), ValueNode::Boolean(_) => TypeDefinition::new(Type::Boolean),
ValueNode::Float(_) => TypeDefinition::new(Type::Float), ValueNode::Float(_) => TypeDefinition::new(Type::Float),
ValueNode::Function(function) => Value::Function(function.clone()).r#type(context)?, ValueNode::Function(function) => TypeDefinition::new(function.r#type().clone()),
ValueNode::Integer(_) => TypeDefinition::new(Type::Integer), ValueNode::Integer(_) => TypeDefinition::new(Type::Integer),
ValueNode::String(_) => TypeDefinition::new(Type::String), ValueNode::String(_) => TypeDefinition::new(Type::String),
ValueNode::List(expressions) => { ValueNode::List(expressions) => {
@ -210,10 +174,6 @@ impl AbstractTree for ValueNode {
} }
ValueNode::Empty => TypeDefinition::new(Type::Any), ValueNode::Empty => TypeDefinition::new(Type::Any),
ValueNode::Map(_) => TypeDefinition::new(Type::Map), ValueNode::Map(_) => TypeDefinition::new(Type::Map),
ValueNode::Table {
column_names: _,
rows: _,
} => TypeDefinition::new(Type::Table),
}; };
Ok(type_definition) Ok(type_definition)

View File

@ -268,20 +268,9 @@ impl fmt::Display for Error {
match self { match self {
AssertEqualFailed { expected, actual } => { AssertEqualFailed { expected, actual } => {
write!(f, "Equality assertion failed")?; write!(f, "Equality assertion failed")?;
write!(f, " {expected} ")?;
if expected.is_table() {
write!(f, "\n{expected}\n")?;
} else {
write!(f, " {expected} ")?;
}
write!(f, "does not equal")?; write!(f, "does not equal")?;
write!(f, " {actual}.")
if actual.is_table() {
write!(f, "\n{actual}")
} else {
write!(f, " {actual}.")
}
} }
AssertFailed => write!( AssertFailed => write!(
f, f,

View File

@ -1,33 +1,31 @@
use std::fmt::{self, Display, Formatter}; use std::fmt::{self, Display, Formatter};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node;
use crate::{ use crate::{AbstractTree, Block, Error, Expression, Identifier, Map, Result, Type, Value};
AbstractTree, Block, Error, Expression, Identifier, Map, Result, Type, TypeDefinition, Value,
};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Function { pub struct Function {
parameters: Vec<(Identifier, TypeDefinition)>, parameters: Vec<Identifier>,
body: Block, body: Block,
return_type: TypeDefinition, r#type: Type,
} }
impl Function { impl Function {
pub fn new( pub fn new(parameters: Vec<Identifier>, body: Block, r#type: Option<Type>) -> Self {
parameters: Vec<(Identifier, TypeDefinition)>, let r#type = r#type.unwrap_or(Type::Function {
body: Block, parameter_types: vec![Type::Any; parameters.len()],
return_type: TypeDefinition, return_type: Box::new(Type::Any),
) -> Self { });
Self { Self {
parameters, parameters,
body, body,
return_type, r#type,
} }
} }
pub fn parameters(&self) -> &Vec<(Identifier, TypeDefinition)> { pub fn parameters(&self) -> &Vec<Identifier> {
&self.parameters &self.parameters
} }
@ -35,104 +33,125 @@ impl Function {
&self.body &self.body
} }
pub fn return_type(&self) -> &TypeDefinition { pub fn r#type(&self) -> &Type {
&self.return_type &self.r#type
} }
pub fn r#type(&self) -> TypeDefinition { pub fn return_type(&self) -> Result<&Type> {
let mut parameter_types = Vec::with_capacity(self.parameters.len()); match &self.r#type {
Type::Function {
for (_, type_definition) in &self.parameters { parameter_types: _,
parameter_types.push(type_definition.inner().clone()); return_type,
} => Ok(return_type.as_ref()),
_ => todo!(),
} }
TypeDefinition::new(Type::Function {
parameter_types,
return_type: Box::new(self.return_type.inner().clone()),
})
} }
pub fn call(&self, arguments: &[Expression], source: &str, context: &Map) -> Result<Value> { pub fn call(&self, arguments: &[Expression], source: &str, context: &Map) -> Result<Value> {
let function_context = Map::clone_from(context)?; let function_context = Map::clone_from(context)?;
let parameter_argument_pairs = self.parameters.iter().zip(arguments.iter());
for ((identifier, type_definition), expression) in parameter_argument_pairs { let (parameter_types, return_type) = if let Type::Function {
let key = identifier.inner(); parameter_types,
return_type,
} = &self.r#type
{
(parameter_types, return_type)
} else {
todo!()
};
if self.parameters.len() != arguments.len() {
return Err(Error::ExpectedArgumentAmount {
function_name: "",
expected: self.parameters.len(),
actual: arguments.len(),
});
}
let parameter_argument_pairs = self
.parameters
.iter()
.zip(parameter_types.iter())
.zip(arguments.iter());
for ((identifier, argument_type), expression) in parameter_argument_pairs {
let value = expression.run(source, context)?; let value = expression.run(source, context)?;
println!("{key} {value}"); match argument_type {
Type::Any => {}
Type::Boolean => {
value.as_boolean()?;
}
Type::Empty => {
value.as_empty()?;
}
Type::Float => {
value.as_float()?;
}
Type::Function { .. } => {
value.as_function()?;
}
Type::Integer => {
value.as_integer()?;
}
Type::List(_) => {
value.as_list()?;
}
Type::Map => {
value.as_map()?;
}
Type::Number => {
value.as_number()?;
}
Type::String => {
value.as_string()?;
}
};
function_context.variables_mut()?.insert(key.clone(), value); let key = identifier.inner().clone();
function_context.variables_mut()?.insert(key, value);
} }
let return_value = self.body.run(source, &function_context)?; let return_value = self.body.run(source, &function_context)?;
match return_type.as_ref() {
Type::Any => {}
Type::Boolean => {
return_value.as_boolean()?;
}
Type::Empty => {
return_value.as_empty()?;
}
Type::Float => {
return_value.as_float()?;
}
Type::Function { .. } => {
return_value.as_function()?;
}
Type::Integer => {
return_value.as_integer()?;
}
Type::List(_) => {
return_value.as_list()?;
}
Type::Map => {
return_value.as_map()?;
}
Type::Number => {
return_value.as_number()?;
}
Type::String => {
return_value.as_string()?;
}
};
Ok(return_value) Ok(return_value)
} }
} }
impl AbstractTree for Function {
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
Error::expect_syntax_node(source, "function", node)?;
let type_node = node.child(0).unwrap();
let type_definition = TypeDefinition::from_syntax_node(source, type_node, context)?;
let (parameter_types, return_type) = if let Type::Function {
parameter_types,
return_type,
} = type_definition.inner()
{
(parameter_types, return_type)
} else {
return Err(Error::TypeCheck {
expected: Type::Function {
parameter_types: Vec::with_capacity(0),
return_type: Box::new(Type::Empty),
},
actual: type_definition.take_inner(),
location: type_node.start_position(),
source: source[type_node.byte_range()].to_string(),
});
};
let child_count = node.child_count();
let mut parameters = Vec::new();
for index in 2..child_count - 2 {
let child = node.child(index).unwrap();
let parameter_index = parameters.len();
let parameter_type = parameter_types.get(parameter_index).unwrap_or(&Type::Empty);
if child.is_named() {
let identifier = Identifier::from_syntax_node(source, child, context)?;
parameters.push((identifier, TypeDefinition::new(parameter_type.clone())));
}
}
let body_node = node.child(child_count - 1).unwrap();
let body = Block::from_syntax_node(source, body_node, context)?;
Ok(Function::new(
parameters,
body,
TypeDefinition::new(return_type.as_ref().clone()),
))
}
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
Ok(Value::Function(self.clone()))
}
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
Value::Function(self.clone()).r#type(context)
}
}
impl Display for Function { impl Display for Function {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", Value::Function(self.clone()))?;
write!( write!(
f, f,
"Function {{ parameters: {:?}, body: {:?} }}", "Function {{ parameters: {:?}, body: {:?} }}",
@ -140,21 +159,3 @@ impl Display for Function {
) )
} }
} }
#[cfg(test)]
mod tests {
use crate::{evaluate, Value};
#[test]
fn simple_function_declaration() {
let test = evaluate(
"
foo = <fn int -> int> |x| { x }
(foo 42)
",
)
.unwrap();
assert_eq!(Value::Integer(42), test);
}
}

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},
Function, List, Map, Table, Type, TypeDefinition, Function, List, Map, Type, TypeDefinition,
}; };
use serde::{ use serde::{
@ -32,7 +32,6 @@ pub mod table;
pub enum Value { pub enum Value {
List(List), List(List),
Map(Map), Map(Map),
Table(Table),
Function(Function), Function(Function),
String(String), String(String),
Float(f64), Float(f64),
@ -67,8 +66,7 @@ impl Value {
} }
} }
Value::Map(_) => Type::Map, Value::Map(_) => Type::Map,
Value::Table(_) => Type::Table, Value::Function(function) => return Ok(TypeDefinition::new(function.r#type().clone())),
Value::Function(function) => return Ok(function.r#type()),
Value::String(_) => Type::String, Value::String(_) => Type::String,
Value::Float(_) => Type::Float, Value::Float(_) => Type::Float,
Value::Integer(_) => Type::Integer, Value::Integer(_) => Type::Integer,
@ -79,10 +77,6 @@ impl Value {
Ok(TypeDefinition::new(r#type)) Ok(TypeDefinition::new(r#type))
} }
pub fn is_table(&self) -> bool {
matches!(self, Value::Table(_))
}
pub fn is_string(&self) -> bool { pub fn is_string(&self) -> bool {
matches!(self, Value::String(_)) matches!(self, Value::String(_))
} }
@ -201,16 +195,6 @@ impl Value {
} }
} }
/// Borrows the value stored in `self` as `Vec<Value>`, or returns `Err` if `self` is not a `Value::Table`.
pub fn as_table(&self) -> Result<&Table> {
match self {
Value::Table(table) => Ok(table),
value => Err(Error::ExpectedTable {
actual: value.clone(),
}),
}
}
/// Borrows the value stored in `self` as `Function`, or returns `Err` if /// Borrows the value stored in `self` as `Function`, or returns `Err` if
/// `self` is not a `Value::Function`. /// `self` is not a `Value::Function`.
pub fn as_function(&self) -> Result<&Function> { pub fn as_function(&self) -> Result<&Function> {
@ -231,18 +215,6 @@ impl Value {
}), }),
} }
} }
/// Returns an owned table, either by cloning or converting the inner value.
pub fn to_table(&self) -> Result<Table> {
match self {
Value::Table(table) => Ok(table.clone()),
Value::List(list) => Ok(Table::from(list)),
Value::Map(map) => Result::from(map),
value => Err(Error::ExpectedTable {
actual: value.clone(),
}),
}
}
} }
impl Default for &Value { impl Default for &Value {
@ -398,7 +370,6 @@ impl PartialEq for Value {
(Value::String(left), Value::String(right)) => left == right, (Value::String(left), Value::String(right)) => left == right,
(Value::List(left), Value::List(right)) => left == right, (Value::List(left), Value::List(right)) => left == right,
(Value::Map(left), Value::Map(right)) => left == right, (Value::Map(left), Value::Map(right)) => left == right,
(Value::Table(left), Value::Table(right)) => left == right,
(Value::Function(left), Value::Function(right)) => left == right, (Value::Function(left), Value::Function(right)) => left == right,
(Value::Empty, Value::Empty) => true, (Value::Empty, Value::Empty) => true,
_ => false, _ => false,
@ -435,8 +406,6 @@ impl Ord for Value {
(Value::List(_), _) => Ordering::Greater, (Value::List(_), _) => Ordering::Greater,
(Value::Map(left), Value::Map(right)) => left.cmp(right), (Value::Map(left), Value::Map(right)) => left.cmp(right),
(Value::Map(_), _) => Ordering::Greater, (Value::Map(_), _) => Ordering::Greater,
(Value::Table(left), Value::Table(right)) => left.cmp(right),
(Value::Table(_), _) => Ordering::Greater,
(Value::Function(left), Value::Function(right)) => left.cmp(right), (Value::Function(left), Value::Function(right)) => left.cmp(right),
(Value::Function(_), _) => Ordering::Greater, (Value::Function(_), _) => Ordering::Greater,
(Value::Empty, Value::Empty) => Ordering::Equal, (Value::Empty, Value::Empty) => Ordering::Equal,
@ -467,7 +436,6 @@ impl Serialize for Value {
} }
Value::Empty => todo!(), Value::Empty => todo!(),
Value::Map(inner) => inner.serialize(serializer), Value::Map(inner) => inner.serialize(serializer),
Value::Table(inner) => inner.serialize(serializer),
Value::Function(inner) => inner.serialize(serializer), Value::Function(inner) => inner.serialize(serializer),
} }
} }
@ -489,7 +457,6 @@ impl Display for Value {
write!(f, "]") write!(f, "]")
} }
Value::Map(map) => write!(f, "{map}"), Value::Map(map) => write!(f, "{map}"),
Value::Table(table) => write!(f, "{table}"),
Value::Function(function) => write!(f, "{function}"), Value::Function(function) => write!(f, "{function}"),
} }
} }

View File

@ -159,7 +159,6 @@ impl Display for Table {
string string
} }
Value::Map(map) => format!("Map ({} items)", map.variables().unwrap().len()), Value::Map(map) => format!("Map ({} items)", map.variables().unwrap().len()),
Value::Table(table) => format!("Table ({} items)", table.len()),
Value::Function(_) => "Function".to_string(), Value::Function(_) => "Function".to_string(),
Value::Empty => "Empty".to_string(), Value::Empty => "Empty".to_string(),
value => value.to_string(), value => value.to_string(),
@ -234,7 +233,6 @@ impl From<&Value> for Table {
Value::List(list) => Self::from(list), Value::List(list) => Self::from(list),
Value::Empty => Table::new(Vec::with_capacity(0)), Value::Empty => Table::new(Vec::with_capacity(0)),
Value::Map(map) => Result::<Table>::from(map).unwrap(), Value::Map(map) => Result::<Table>::from(map).unwrap(),
Value::Table(table) => table.clone(),
Value::Function(function) => { Value::Function(function) => {
let mut table = Table::new(vec!["function".to_string()]); let mut table = Table::new(vec!["function".to_string()]);

View File

@ -2,7 +2,7 @@
Simple Function Simple Function
================================================================================ ================================================================================
<fn -> str> || { "Hiya" } fn || { "Hiya" }
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -11,9 +11,6 @@ Simple Function
(expression (expression
(value (value
(function (function
(type_definition
(type
(type)))
(block (block
(statement (statement
(expression (expression
@ -24,7 +21,7 @@ Simple Function
Function Assignment Function Assignment
================================================================================ ================================================================================
foobar = <fn -> str> |text| { text } foobar <(str) -> str> = fn |text| { text }
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -32,14 +29,15 @@ foobar = <fn -> str> |text| { text }
(statement (statement
(assignment (assignment
(identifier) (identifier)
(type_definition
(type
(type)
(type)))
(assignment_operator) (assignment_operator)
(statement (statement
(expression (expression
(value (value
(function (function
(type_definition
(type
(type)))
(identifier) (identifier)
(block (block
(statement (statement
@ -68,7 +66,7 @@ Function Call
Complex Function Complex Function
================================================================================ ================================================================================
<fn str num> |message number| { fn |message number| {
(output message) (output message)
(output number) (output number)
} }
@ -80,10 +78,6 @@ Complex Function
(expression (expression
(value (value
(function (function
(type_definition
(type
(type)
(type)))
(identifier) (identifier)
(identifier) (identifier)
(block (block
@ -142,3 +136,50 @@ Complex Function Call
(expression (expression
(value (value
(integer))))))))))) (integer)))))))))))
================================================================================
Callback Function
================================================================================
foobar <(() -> str) -> str> = fn |cb| {
(cb)
}
(foobar fn || { 'Hiya' })
--------------------------------------------------------------------------------
(root
(statement
(assignment
(identifier)
(type_definition
(type
(type
(type))
(type)))
(assignment_operator)
(statement
(expression
(value
(function
(identifier)
(block
(statement
(expression
(function_call
(expression
(identifier))))))))))))
(statement
(expression
(function_call
(expression
(identifier))
(expression
(value
(function
(block
(statement
(expression
(value
(string))))))))))))

View File

@ -308,22 +308,6 @@ module.exports = grammar({
$.block, $.block,
), ),
identifier_list: $ =>
prec.right(
choice(
seq(
'|',
repeat(
seq(
$.identifier,
optional(','),
),
),
'|',
),
),
),
return: $ => return: $ =>
prec.right( prec.right(
seq('return', $.expression), seq('return', $.expression),
@ -341,13 +325,14 @@ module.exports = grammar({
'bool', 'bool',
'float', 'float',
seq( seq(
'fn', '(',
repeat( repeat(
seq( seq(
$.type, $.type,
optional(','), optional(','),
), ),
), ),
')',
optional(seq('->', $.type)), optional(seq('->', $.type)),
), ),
'int', 'int',
@ -360,7 +345,7 @@ module.exports = grammar({
function: $ => function: $ =>
seq( seq(
$.type_definition, 'fn',
'|', '|',
repeat( repeat(
seq( seq(

View File

@ -960,52 +960,6 @@
} }
] ]
}, },
"identifier_list": {
"type": "PREC_RIGHT",
"value": 0,
"content": {
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "|"
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "identifier"
},
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "BLANK"
}
]
}
]
}
},
{
"type": "STRING",
"value": "|"
}
]
}
]
}
},
"return": { "return": {
"type": "PREC_RIGHT", "type": "PREC_RIGHT",
"value": 0, "value": 0,
@ -1076,7 +1030,7 @@
"members": [ "members": [
{ {
"type": "STRING", "type": "STRING",
"value": "fn" "value": "("
}, },
{ {
"type": "REPEAT", "type": "REPEAT",
@ -1102,6 +1056,10 @@
] ]
} }
}, },
{
"type": "STRING",
"value": ")"
},
{ {
"type": "CHOICE", "type": "CHOICE",
"members": [ "members": [
@ -1165,49 +1123,44 @@
"type": "SEQ", "type": "SEQ",
"members": [ "members": [
{ {
"type": "SYMBOL", "type": "STRING",
"name": "type_definition" "value": "fn"
}, },
{ {
"type": "SEQ", "type": "STRING",
"members": [ "value": "|"
{ },
"type": "STRING", {
"value": "|" "type": "REPEAT",
}, "content": {
{ "type": "SEQ",
"type": "REPEAT", "members": [
"content": { {
"type": "SEQ", "type": "SYMBOL",
"name": "identifier"
},
{
"type": "CHOICE",
"members": [ "members": [
{ {
"type": "SYMBOL", "type": "STRING",
"name": "identifier" "value": ","
}, },
{ {
"type": "CHOICE", "type": "BLANK"
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "BLANK"
}
]
} }
] ]
} }
}, ]
{ }
"type": "STRING", },
"value": "|" {
}, "type": "STRING",
{ "value": "|"
"type": "SYMBOL", },
"name": "block" {
} "type": "SYMBOL",
] "name": "block"
} }
] ]
}, },

View File

@ -162,10 +162,6 @@
{ {
"type": "identifier", "type": "identifier",
"named": true "named": true
},
{
"type": "type_definition",
"named": true
} }
] ]
} }

File diff suppressed because it is too large Load Diff