Implement new function syntax
This commit is contained in:
parent
7f1b53aabe
commit
d6c679c0b3
@ -1,4 +1,4 @@
|
||||
create_random_numbers = <fn int> |count| {
|
||||
create_random_numbers <(int)> = fn |count| {
|
||||
numbers = []
|
||||
|
||||
while (length numbers) < count {
|
||||
|
@ -4,26 +4,26 @@ all_cards = {
|
||||
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:rooms) == 1)
|
||||
&& ((length cards:weapons) == 1)
|
||||
}
|
||||
|
||||
take_turn = <fn str str map -> map> |opponent_card current_room cards| {
|
||||
(remove_card opponent_card cards)
|
||||
(make_guess current_room cards)
|
||||
take_turn <(map str str) -> map> = fn |cards opponent_card current_room| {
|
||||
cards = (remove_card opponent_card cards)
|
||||
cards = (make_guess current_room cards)
|
||||
cards
|
||||
}
|
||||
|
||||
remove_card = <fn str map> |opponent_card cards| {
|
||||
(output opponent_card cards)
|
||||
remove_card <(map str) -> map> = fn |cards opponent_card| {
|
||||
cards:rooms -= opponent_card
|
||||
cards:suspects -= 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) {
|
||||
(output 'It was '
|
||||
+ cards:suspects:0
|
||||
@ -41,12 +41,14 @@ make_guess = <fn str map> |current_room cards| {
|
||||
+ (random cards:weapons)
|
||||
+ '.')
|
||||
}
|
||||
cards
|
||||
}
|
||||
|
||||
(take_turn 'Rope' 'Kitchen'
|
||||
(take_turn 'Library' 'Kitchen'
|
||||
(take_turn 'Conservatory' 'Kitchen'
|
||||
(take_turn 'White' 'Kitchen'
|
||||
(take_turn 'Green' 'Kitchen'
|
||||
(take_turn 'Knife' 'Kitchen' all_cards))))))
|
||||
all_cards
|
||||
-> (take_turn 'Rope' 'Kitchen')
|
||||
-> (take_turn 'Library' 'Kitchen')
|
||||
-> (take_turn 'Conservatory' 'Kitchen')
|
||||
-> (take_turn 'White' 'Kitchen')
|
||||
-> (take_turn 'Green' 'Kitchen')
|
||||
-> (take_turn 'Knife' 'Kitchen')
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
fib = <fn int -> int> |i| {
|
||||
fib <(int) -> int> = fn |i| {
|
||||
if i <= 1 {
|
||||
1
|
||||
} else {
|
||||
|
@ -1,6 +1,6 @@
|
||||
data = (from_json (read 'examples/assets/jq_data.json'))
|
||||
|
||||
new_data = [];
|
||||
new_data = []
|
||||
|
||||
for commit_data in data {
|
||||
new_data += {
|
||||
|
@ -1,6 +1,6 @@
|
||||
1 -> (output)
|
||||
|
||||
add_one = <fn [int] -> [int]> |numbers| {
|
||||
add_one <([int]) -> [int]> = fn |numbers| {
|
||||
new_numbers = []
|
||||
|
||||
for number in numbers {
|
||||
|
9
scripts/test.fish
Executable file
9
scripts/test.fish
Executable 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
|
@ -71,7 +71,12 @@ impl AbstractTree for Assignment {
|
||||
if let Type::List(item_type) = type_definition.inner() {
|
||||
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(
|
||||
&statement_type,
|
||||
context,
|
||||
|
@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
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;
|
||||
@ -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 {
|
||||
function_expression,
|
||||
arguments,
|
||||
};
|
||||
|
||||
function_type.check(
|
||||
&function_call.expected_type(context)?,
|
||||
context,
|
||||
node,
|
||||
source,
|
||||
)?;
|
||||
|
||||
Ok(function_call)
|
||||
}
|
||||
|
||||
@ -98,7 +106,9 @@ impl AbstractTree for FunctionCall {
|
||||
match &self.function_expression {
|
||||
Expression::Value(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 {
|
||||
value_node.expected_type(context)
|
||||
}
|
||||
@ -107,9 +117,9 @@ impl AbstractTree for FunctionCall {
|
||||
let function_name = identifier.inner();
|
||||
|
||||
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 {
|
||||
self.function_expression.expected_type(context)
|
||||
}
|
||||
@ -132,7 +142,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
evaluate(
|
||||
"
|
||||
foobar = <fn str -> str> |message| { message }
|
||||
foobar <(str) -> str> = fn |message| { message }
|
||||
(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]
|
||||
fn evaluate_built_in_function_call() {
|
||||
assert_eq!(evaluate("(output 'Hiya')"), Ok(Value::Empty));
|
||||
|
@ -107,7 +107,7 @@ mod tests {
|
||||
let test = evaluate(
|
||||
"
|
||||
x = [1 2 3]
|
||||
y = <fn -> int> || { 0 }
|
||||
y <() -> int> = fn || { 0 }
|
||||
x:(y)
|
||||
",
|
||||
)
|
||||
|
@ -74,7 +74,6 @@ pub enum Type {
|
||||
Map,
|
||||
Number,
|
||||
String,
|
||||
Table,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
@ -92,8 +91,7 @@ impl Type {
|
||||
| (Type::Number, Type::Float)
|
||||
| (Type::Integer, Type::Number)
|
||||
| (Type::Float, Type::Number)
|
||||
| (Type::String, Type::String)
|
||||
| (Type::Table, Type::Table) => Ok(()),
|
||||
| (Type::String, Type::String) => Ok(()),
|
||||
(Type::List(self_item_type), Type::List(other_item_type)) => {
|
||||
self_item_type.check(&other_item_type, context, node, source)
|
||||
}
|
||||
@ -145,20 +143,26 @@ impl AbstractTree for Type {
|
||||
"any" => Type::Any,
|
||||
"bool" => Type::Boolean,
|
||||
"float" => Type::Float,
|
||||
"fn" => {
|
||||
"(" => {
|
||||
let child_count = node.child_count();
|
||||
let mut parameter_types = Vec::new();
|
||||
|
||||
for index in 1..child_count - 2 {
|
||||
let parameter_type_node = node.child(index).unwrap();
|
||||
let parameter_type =
|
||||
Type::from_syntax_node(source, parameter_type_node, context)?;
|
||||
let child = node.child(index).unwrap();
|
||||
|
||||
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 return_type = Type::from_syntax_node(source, return_type_node, context)?;
|
||||
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::Empty
|
||||
};
|
||||
|
||||
Type::Function {
|
||||
parameter_types,
|
||||
@ -215,7 +219,6 @@ impl Display for Type {
|
||||
Type::Map => write!(f, "map"),
|
||||
Type::Number => write!(f, "num"),
|
||||
Type::String => write!(f, "str"),
|
||||
Type::Table => write!(f, "table"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
@ -18,10 +18,6 @@ pub enum ValueNode {
|
||||
List(Vec<Expression>),
|
||||
Empty,
|
||||
Map(BTreeMap<String, Statement>),
|
||||
Table {
|
||||
column_names: Vec<Identifier>,
|
||||
rows: Box<Expression>,
|
||||
},
|
||||
}
|
||||
|
||||
impl AbstractTree for ValueNode {
|
||||
@ -32,7 +28,25 @@ impl AbstractTree for ValueNode {
|
||||
let value_node = match child.kind() {
|
||||
"boolean" => ValueNode::Boolean(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()),
|
||||
"string" => {
|
||||
let without_quotes = child.start_byte() + 1..child.end_byte() - 1;
|
||||
@ -54,30 +68,6 @@ impl AbstractTree for ValueNode {
|
||||
|
||||
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" => {
|
||||
let mut child_nodes = BTreeMap::new();
|
||||
let mut current_key = "".to_string();
|
||||
@ -104,7 +94,7 @@ impl AbstractTree for ValueNode {
|
||||
}
|
||||
_ => {
|
||||
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(),
|
||||
location: child.start_position(),
|
||||
relevant_source: source[child.byte_range()].to_string(),
|
||||
@ -149,32 +139,6 @@ impl AbstractTree for ValueNode {
|
||||
|
||||
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)
|
||||
@ -184,7 +148,7 @@ impl AbstractTree for ValueNode {
|
||||
let type_definition = match self {
|
||||
ValueNode::Boolean(_) => TypeDefinition::new(Type::Boolean),
|
||||
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::String(_) => TypeDefinition::new(Type::String),
|
||||
ValueNode::List(expressions) => {
|
||||
@ -210,10 +174,6 @@ impl AbstractTree for ValueNode {
|
||||
}
|
||||
ValueNode::Empty => TypeDefinition::new(Type::Any),
|
||||
ValueNode::Map(_) => TypeDefinition::new(Type::Map),
|
||||
ValueNode::Table {
|
||||
column_names: _,
|
||||
rows: _,
|
||||
} => TypeDefinition::new(Type::Table),
|
||||
};
|
||||
|
||||
Ok(type_definition)
|
||||
|
15
src/error.rs
15
src/error.rs
@ -268,20 +268,9 @@ impl fmt::Display for Error {
|
||||
match self {
|
||||
AssertEqualFailed { expected, actual } => {
|
||||
write!(f, "Equality assertion failed")?;
|
||||
|
||||
if expected.is_table() {
|
||||
write!(f, "\n{expected}\n")?;
|
||||
} else {
|
||||
write!(f, " {expected} ")?;
|
||||
}
|
||||
|
||||
write!(f, " {expected} ")?;
|
||||
write!(f, "does not equal")?;
|
||||
|
||||
if actual.is_table() {
|
||||
write!(f, "\n{actual}")
|
||||
} else {
|
||||
write!(f, " {actual}.")
|
||||
}
|
||||
write!(f, " {actual}.")
|
||||
}
|
||||
AssertFailed => write!(
|
||||
f,
|
||||
|
@ -1,33 +1,31 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{
|
||||
AbstractTree, Block, Error, Expression, Identifier, Map, Result, Type, TypeDefinition, Value,
|
||||
};
|
||||
use crate::{AbstractTree, Block, Error, Expression, Identifier, Map, Result, Type, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Function {
|
||||
parameters: Vec<(Identifier, TypeDefinition)>,
|
||||
parameters: Vec<Identifier>,
|
||||
body: Block,
|
||||
return_type: TypeDefinition,
|
||||
r#type: Type,
|
||||
}
|
||||
|
||||
impl Function {
|
||||
pub fn new(
|
||||
parameters: Vec<(Identifier, TypeDefinition)>,
|
||||
body: Block,
|
||||
return_type: TypeDefinition,
|
||||
) -> Self {
|
||||
pub fn new(parameters: Vec<Identifier>, body: Block, r#type: Option<Type>) -> Self {
|
||||
let r#type = r#type.unwrap_or(Type::Function {
|
||||
parameter_types: vec![Type::Any; parameters.len()],
|
||||
return_type: Box::new(Type::Any),
|
||||
});
|
||||
|
||||
Self {
|
||||
parameters,
|
||||
body,
|
||||
return_type,
|
||||
r#type,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parameters(&self) -> &Vec<(Identifier, TypeDefinition)> {
|
||||
pub fn parameters(&self) -> &Vec<Identifier> {
|
||||
&self.parameters
|
||||
}
|
||||
|
||||
@ -35,104 +33,125 @@ impl Function {
|
||||
&self.body
|
||||
}
|
||||
|
||||
pub fn return_type(&self) -> &TypeDefinition {
|
||||
&self.return_type
|
||||
pub fn r#type(&self) -> &Type {
|
||||
&self.r#type
|
||||
}
|
||||
|
||||
pub fn r#type(&self) -> TypeDefinition {
|
||||
let mut parameter_types = Vec::with_capacity(self.parameters.len());
|
||||
|
||||
for (_, type_definition) in &self.parameters {
|
||||
parameter_types.push(type_definition.inner().clone());
|
||||
pub fn return_type(&self) -> Result<&Type> {
|
||||
match &self.r#type {
|
||||
Type::Function {
|
||||
parameter_types: _,
|
||||
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> {
|
||||
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 key = identifier.inner();
|
||||
let (parameter_types, return_type) = if let Type::Function {
|
||||
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)?;
|
||||
|
||||
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)?;
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", Value::Function(self.clone()))?;
|
||||
write!(
|
||||
f,
|
||||
"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);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Types that represent runtime values.
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
Function, List, Map, Table, Type, TypeDefinition,
|
||||
Function, List, Map, Type, TypeDefinition,
|
||||
};
|
||||
|
||||
use serde::{
|
||||
@ -32,7 +32,6 @@ pub mod table;
|
||||
pub enum Value {
|
||||
List(List),
|
||||
Map(Map),
|
||||
Table(Table),
|
||||
Function(Function),
|
||||
String(String),
|
||||
Float(f64),
|
||||
@ -67,8 +66,7 @@ impl Value {
|
||||
}
|
||||
}
|
||||
Value::Map(_) => Type::Map,
|
||||
Value::Table(_) => Type::Table,
|
||||
Value::Function(function) => return Ok(function.r#type()),
|
||||
Value::Function(function) => return Ok(TypeDefinition::new(function.r#type().clone())),
|
||||
Value::String(_) => Type::String,
|
||||
Value::Float(_) => Type::Float,
|
||||
Value::Integer(_) => Type::Integer,
|
||||
@ -79,10 +77,6 @@ impl Value {
|
||||
Ok(TypeDefinition::new(r#type))
|
||||
}
|
||||
|
||||
pub fn is_table(&self) -> bool {
|
||||
matches!(self, Value::Table(_))
|
||||
}
|
||||
|
||||
pub fn is_string(&self) -> bool {
|
||||
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
|
||||
/// `self` is not a `Value::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 {
|
||||
@ -398,7 +370,6 @@ impl PartialEq for Value {
|
||||
(Value::String(left), Value::String(right)) => left == right,
|
||||
(Value::List(left), Value::List(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::Empty, Value::Empty) => true,
|
||||
_ => false,
|
||||
@ -435,8 +406,6 @@ impl Ord for Value {
|
||||
(Value::List(_), _) => Ordering::Greater,
|
||||
(Value::Map(left), Value::Map(right)) => left.cmp(right),
|
||||
(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(_), _) => Ordering::Greater,
|
||||
(Value::Empty, Value::Empty) => Ordering::Equal,
|
||||
@ -467,7 +436,6 @@ impl Serialize for Value {
|
||||
}
|
||||
Value::Empty => todo!(),
|
||||
Value::Map(inner) => inner.serialize(serializer),
|
||||
Value::Table(inner) => inner.serialize(serializer),
|
||||
Value::Function(inner) => inner.serialize(serializer),
|
||||
}
|
||||
}
|
||||
@ -489,7 +457,6 @@ impl Display for Value {
|
||||
write!(f, "]")
|
||||
}
|
||||
Value::Map(map) => write!(f, "{map}"),
|
||||
Value::Table(table) => write!(f, "{table}"),
|
||||
Value::Function(function) => write!(f, "{function}"),
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +159,6 @@ impl Display for Table {
|
||||
string
|
||||
}
|
||||
Value::Map(map) => format!("Map ({} items)", map.variables().unwrap().len()),
|
||||
Value::Table(table) => format!("Table ({} items)", table.len()),
|
||||
Value::Function(_) => "Function".to_string(),
|
||||
Value::Empty => "Empty".to_string(),
|
||||
value => value.to_string(),
|
||||
@ -234,7 +233,6 @@ impl From<&Value> for Table {
|
||||
Value::List(list) => Self::from(list),
|
||||
Value::Empty => Table::new(Vec::with_capacity(0)),
|
||||
Value::Map(map) => Result::<Table>::from(map).unwrap(),
|
||||
Value::Table(table) => table.clone(),
|
||||
Value::Function(function) => {
|
||||
let mut table = Table::new(vec!["function".to_string()]);
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
Simple Function
|
||||
================================================================================
|
||||
|
||||
<fn -> str> || { "Hiya" }
|
||||
fn || { "Hiya" }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -11,9 +11,6 @@ Simple Function
|
||||
(expression
|
||||
(value
|
||||
(function
|
||||
(type_definition
|
||||
(type
|
||||
(type)))
|
||||
(block
|
||||
(statement
|
||||
(expression
|
||||
@ -24,7 +21,7 @@ Simple Function
|
||||
Function Assignment
|
||||
================================================================================
|
||||
|
||||
foobar = <fn -> str> |text| { text }
|
||||
foobar <(str) -> str> = fn |text| { text }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -32,14 +29,15 @@ foobar = <fn -> str> |text| { text }
|
||||
(statement
|
||||
(assignment
|
||||
(identifier)
|
||||
(type_definition
|
||||
(type
|
||||
(type)
|
||||
(type)))
|
||||
(assignment_operator)
|
||||
(statement
|
||||
(expression
|
||||
(value
|
||||
(function
|
||||
(type_definition
|
||||
(type
|
||||
(type)))
|
||||
(identifier)
|
||||
(block
|
||||
(statement
|
||||
@ -68,7 +66,7 @@ Function Call
|
||||
Complex Function
|
||||
================================================================================
|
||||
|
||||
<fn str num> |message number| {
|
||||
fn |message number| {
|
||||
(output message)
|
||||
(output number)
|
||||
}
|
||||
@ -80,10 +78,6 @@ Complex Function
|
||||
(expression
|
||||
(value
|
||||
(function
|
||||
(type_definition
|
||||
(type
|
||||
(type)
|
||||
(type)))
|
||||
(identifier)
|
||||
(identifier)
|
||||
(block
|
||||
@ -142,3 +136,50 @@ Complex Function Call
|
||||
(expression
|
||||
(value
|
||||
(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))))))))))))
|
||||
|
@ -308,22 +308,6 @@ module.exports = grammar({
|
||||
$.block,
|
||||
),
|
||||
|
||||
identifier_list: $ =>
|
||||
prec.right(
|
||||
choice(
|
||||
seq(
|
||||
'|',
|
||||
repeat(
|
||||
seq(
|
||||
$.identifier,
|
||||
optional(','),
|
||||
),
|
||||
),
|
||||
'|',
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
return: $ =>
|
||||
prec.right(
|
||||
seq('return', $.expression),
|
||||
@ -341,13 +325,14 @@ module.exports = grammar({
|
||||
'bool',
|
||||
'float',
|
||||
seq(
|
||||
'fn',
|
||||
'(',
|
||||
repeat(
|
||||
seq(
|
||||
$.type,
|
||||
optional(','),
|
||||
),
|
||||
),
|
||||
')',
|
||||
optional(seq('->', $.type)),
|
||||
),
|
||||
'int',
|
||||
@ -360,7 +345,7 @@ module.exports = grammar({
|
||||
|
||||
function: $ =>
|
||||
seq(
|
||||
$.type_definition,
|
||||
'fn',
|
||||
'|',
|
||||
repeat(
|
||||
seq(
|
||||
|
@ -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": {
|
||||
"type": "PREC_RIGHT",
|
||||
"value": 0,
|
||||
@ -1076,7 +1030,7 @@
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "fn"
|
||||
"value": "("
|
||||
},
|
||||
{
|
||||
"type": "REPEAT",
|
||||
@ -1102,6 +1056,10 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ")"
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
@ -1165,49 +1123,44 @@
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "type_definition"
|
||||
"type": "STRING",
|
||||
"value": "fn"
|
||||
},
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "|"
|
||||
},
|
||||
{
|
||||
"type": "REPEAT",
|
||||
"content": {
|
||||
"type": "SEQ",
|
||||
"type": "STRING",
|
||||
"value": "|"
|
||||
},
|
||||
{
|
||||
"type": "REPEAT",
|
||||
"content": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
"type": "STRING",
|
||||
"value": ","
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ","
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "|"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "block"
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "|"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "block"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -162,10 +162,6 @@
|
||||
{
|
||||
"type": "identifier",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "type_definition",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user