Continue implementing type checks
This commit is contained in:
parent
9181c319b8
commit
7f1b53aabe
@ -2,8 +2,10 @@ cast = (download "https://api.sampleapis.com/futurama/cast")
|
|||||||
characters = (download "https://api.sampleapis.com/futurama/characters")
|
characters = (download "https://api.sampleapis.com/futurama/characters")
|
||||||
episodes = (download "https://api.sampleapis.com/futurama/episodes")
|
episodes = (download "https://api.sampleapis.com/futurama/episodes")
|
||||||
|
|
||||||
cast_len = (length (from_json cast))
|
async {
|
||||||
characters_len = (length (from_json characters))
|
cast_len = (length (from_json cast))
|
||||||
episodes_len = (length (from_json episodes))
|
characters_len = (length (from_json characters))
|
||||||
|
episodes_len = (length (from_json episodes))
|
||||||
|
}
|
||||||
|
|
||||||
(output [cast_len, characters_len, episodes_len])
|
(output [cast_len, characters_len, episodes_len])
|
||||||
|
@ -29,7 +29,7 @@ impl AbstractTree for Assignment {
|
|||||||
|
|
||||||
let type_node = node.child(1);
|
let type_node = node.child(1);
|
||||||
let type_definition = if let Some(type_node) = type_node {
|
let type_definition = if let Some(type_node) = type_node {
|
||||||
if type_node.kind() == "type_defintion" {
|
if type_node.kind() == "type_definition" {
|
||||||
Some(TypeDefinition::from_syntax_node(
|
Some(TypeDefinition::from_syntax_node(
|
||||||
source, type_node, context,
|
source, type_node, context,
|
||||||
)?)
|
)?)
|
||||||
@ -63,35 +63,30 @@ impl AbstractTree for Assignment {
|
|||||||
|
|
||||||
match operator {
|
match operator {
|
||||||
AssignmentOperator::Equal => {
|
AssignmentOperator::Equal => {
|
||||||
type_definition.abstract_check(
|
type_definition.check(&statement_type, context, statement_node, source)?;
|
||||||
&statement_type,
|
|
||||||
context,
|
|
||||||
statement_node,
|
|
||||||
source,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
AssignmentOperator::PlusEqual => {
|
AssignmentOperator::PlusEqual => {
|
||||||
let identifier_type = identifier.expected_type(context)?;
|
let identifier_type = identifier.expected_type(context)?;
|
||||||
|
|
||||||
type_definition.abstract_check(
|
if let Type::List(item_type) = type_definition.inner() {
|
||||||
&identifier_type,
|
let item_type_definition = TypeDefinition::new(*item_type.clone());
|
||||||
context,
|
|
||||||
type_node.unwrap(),
|
|
||||||
source,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let type_definition = if let Type::List(item_type) = type_definition.inner() {
|
item_type_definition.check(&identifier_type, context, node, source)?;
|
||||||
TypeDefinition::new(item_type.as_ref().clone())
|
item_type_definition.check(
|
||||||
|
&statement_type,
|
||||||
|
context,
|
||||||
|
statement_node,
|
||||||
|
source,
|
||||||
|
)?;
|
||||||
} else {
|
} else {
|
||||||
type_definition.clone()
|
type_definition.check(
|
||||||
};
|
&identifier_type,
|
||||||
|
context,
|
||||||
type_definition.abstract_check(
|
identifier_node,
|
||||||
&statement_type,
|
source,
|
||||||
context,
|
)?;
|
||||||
statement_node,
|
type_definition.check(&statement_type, context, statement_node, source)?;
|
||||||
source,
|
}
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
AssignmentOperator::MinusEqual => todo!(),
|
AssignmentOperator::MinusEqual => todo!(),
|
||||||
}
|
}
|
||||||
@ -112,22 +107,6 @@ impl AbstractTree for Assignment {
|
|||||||
let new_value = match self.operator {
|
let new_value = match self.operator {
|
||||||
AssignmentOperator::PlusEqual => {
|
AssignmentOperator::PlusEqual => {
|
||||||
if let Some(mut previous_value) = context.variables()?.get(key).cloned() {
|
if let Some(mut previous_value) = context.variables()?.get(key).cloned() {
|
||||||
if let Ok(list) = previous_value.as_list() {
|
|
||||||
let item_type = if let Some(type_defintion) = &self.type_definition {
|
|
||||||
if let Type::List(item_type) = type_defintion.inner() {
|
|
||||||
TypeDefinition::new(item_type.as_ref().clone())
|
|
||||||
} else {
|
|
||||||
TypeDefinition::new(Type::Empty)
|
|
||||||
}
|
|
||||||
} else if let Some(first) = list.items().first() {
|
|
||||||
first.r#type(context)?
|
|
||||||
} else {
|
|
||||||
TypeDefinition::new(Type::Any)
|
|
||||||
};
|
|
||||||
|
|
||||||
item_type.runtime_check(&value.r#type(context)?, context)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
previous_value += value;
|
previous_value += value;
|
||||||
previous_value
|
previous_value
|
||||||
} else {
|
} else {
|
||||||
@ -145,12 +124,6 @@ impl AbstractTree for Assignment {
|
|||||||
AssignmentOperator::Equal => value,
|
AssignmentOperator::Equal => value,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(type_definition) = &self.type_definition {
|
|
||||||
let new_value_type = new_value.r#type(context)?;
|
|
||||||
|
|
||||||
type_definition.runtime_check(&new_value_type, context)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
context.variables_mut()?.insert(key.clone(), new_value);
|
context.variables_mut()?.insert(key.clone(), new_value);
|
||||||
|
|
||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
@ -183,7 +156,7 @@ mod tests {
|
|||||||
fn list_add_assign() {
|
fn list_add_assign() {
|
||||||
let test = evaluate(
|
let test = evaluate(
|
||||||
"
|
"
|
||||||
x <list int> = []
|
x <[int]> = []
|
||||||
x += 1
|
x += 1
|
||||||
x
|
x
|
||||||
",
|
",
|
||||||
|
@ -2,21 +2,21 @@ use serde::{Deserialize, Serialize};
|
|||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AbstractTree, Error, Identifier, Map, Result, TypeDefinition, Value, BUILT_IN_FUNCTIONS,
|
AbstractTree, Error, Map, Result, TypeDefinition, Value, ValueNode, BUILT_IN_FUNCTIONS,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::expression::Expression;
|
use super::expression::Expression;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct FunctionCall {
|
pub struct FunctionCall {
|
||||||
function_name: Identifier,
|
function_expression: Expression,
|
||||||
arguments: Vec<Expression>,
|
arguments: Vec<Expression>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionCall {
|
impl FunctionCall {
|
||||||
pub fn new(function_name: Identifier, arguments: Vec<Expression>) -> Self {
|
pub fn new(function_expression: Expression, arguments: Vec<Expression>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
function_name,
|
function_expression,
|
||||||
arguments,
|
arguments,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -26,8 +26,8 @@ impl AbstractTree for FunctionCall {
|
|||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
||||||
debug_assert_eq!("function_call", node.kind());
|
debug_assert_eq!("function_call", node.kind());
|
||||||
|
|
||||||
let identifier_node = node.child(1).unwrap();
|
let expression_node = node.child(1).unwrap();
|
||||||
let function_name = Identifier::from_syntax_node(source, identifier_node, context)?;
|
let function_expression = Expression::from_syntax_node(source, expression_node, context)?;
|
||||||
|
|
||||||
let mut arguments = Vec::new();
|
let mut arguments = Vec::new();
|
||||||
|
|
||||||
@ -41,13 +41,13 @@ impl AbstractTree for FunctionCall {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let function_type = function_name.expected_type(context)?;
|
let function_type = function_expression.expected_type(context)?;
|
||||||
let function_call = FunctionCall {
|
let function_call = FunctionCall {
|
||||||
function_name,
|
function_expression,
|
||||||
arguments,
|
arguments,
|
||||||
};
|
};
|
||||||
|
|
||||||
function_type.abstract_check(
|
function_type.check(
|
||||||
&function_call.expected_type(context)?,
|
&function_call.expected_type(context)?,
|
||||||
context,
|
context,
|
||||||
node,
|
node,
|
||||||
@ -58,43 +58,67 @@ impl AbstractTree for FunctionCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||||
let key = self.function_name.inner();
|
let value = match &self.function_expression {
|
||||||
|
Expression::Value(value_node) => value_node.run(source, context)?,
|
||||||
|
Expression::Identifier(identifier) => {
|
||||||
|
let key = identifier.inner();
|
||||||
|
|
||||||
for built_in_function in BUILT_IN_FUNCTIONS {
|
for built_in_function in BUILT_IN_FUNCTIONS {
|
||||||
if key == built_in_function.name() {
|
if key == built_in_function.name() {
|
||||||
let mut arguments = Vec::with_capacity(self.arguments.len());
|
let mut arguments = Vec::with_capacity(self.arguments.len());
|
||||||
|
|
||||||
for expression in &self.arguments {
|
for expression in &self.arguments {
|
||||||
let value = expression.run(source, context)?;
|
let value = expression.run(source, context)?;
|
||||||
|
|
||||||
arguments.push(value);
|
arguments.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return built_in_function.run(&arguments, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return built_in_function.run(&arguments, context);
|
let variables = context.variables()?;
|
||||||
|
if let Some(value) = variables.get(key) {
|
||||||
|
value.clone()
|
||||||
|
} else {
|
||||||
|
return Err(Error::FunctionIdentifierNotFound(identifier.clone()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
Expression::Index(index) => index.run(source, context)?,
|
||||||
|
Expression::Math(math) => math.run(source, context)?,
|
||||||
let variables = context.variables()?;
|
Expression::Logic(logic) => logic.run(source, context)?,
|
||||||
let function = if let Some(value) = variables.get(key) {
|
Expression::FunctionCall(function_call) => function_call.run(source, context)?,
|
||||||
value.as_function()?
|
Expression::Yield(r#yield) => r#yield.run(source, context)?,
|
||||||
} else {
|
|
||||||
return Err(Error::FunctionIdentifierNotFound(
|
|
||||||
self.function_name.clone(),
|
|
||||||
));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function.call(&self.arguments, source, context)
|
value.as_function()?.call(&self.arguments, source, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
||||||
let function_name = self.function_name.inner();
|
match &self.function_expression {
|
||||||
|
Expression::Value(value_node) => {
|
||||||
|
if let ValueNode::Function(function) = value_node {
|
||||||
|
Ok(function.return_type().clone())
|
||||||
|
} else {
|
||||||
|
value_node.expected_type(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expression::Identifier(identifier) => {
|
||||||
|
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();
|
||||||
|
|
||||||
Ok(return_type.clone())
|
Ok(return_type.clone())
|
||||||
} else {
|
} else {
|
||||||
self.function_name.expected_type(context)
|
self.function_expression.expected_type(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expression::Index(index) => index.expected_type(context),
|
||||||
|
Expression::Math(math) => math.expected_type(context),
|
||||||
|
Expression::Logic(logic) => logic.expected_type(context),
|
||||||
|
Expression::FunctionCall(function_call) => function_call.expected_type(context),
|
||||||
|
Expression::Yield(r#yield) => r#yield.expected_type(context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ impl AbstractTree for Identifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(TypeDefinition::new(Type::Empty))
|
Ok(TypeDefinition::new(Type::Any))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,79 +23,14 @@ impl TypeDefinition {
|
|||||||
self.r#type
|
self.r#type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn abstract_check(
|
pub fn check(
|
||||||
&self,
|
&self,
|
||||||
other: &TypeDefinition,
|
other: &TypeDefinition,
|
||||||
context: &Map,
|
context: &Map,
|
||||||
node: Node,
|
node: Node,
|
||||||
source: &str,
|
source: &str,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
self.runtime_check(other, context)
|
self.r#type.check(&other.r#type, context, node, source)
|
||||||
.map_err(|_| Error::TypeCheck {
|
|
||||||
expected: self.clone(),
|
|
||||||
actual: other.clone(),
|
|
||||||
location: node.start_position(),
|
|
||||||
source: source[node.byte_range()].to_string(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn runtime_check(&self, other: &TypeDefinition, context: &Map) -> Result<()> {
|
|
||||||
// match (&self.r#type, &other.r#type) {
|
|
||||||
// (Type::Any, _)
|
|
||||||
// | (_, Type::Any)
|
|
||||||
// | (Type::Boolean, Type::Boolean)
|
|
||||||
// | (Type::Empty, Type::Empty)
|
|
||||||
// | (Type::Float, Type::Float)
|
|
||||||
// | (Type::Integer, Type::Integer)
|
|
||||||
// | (Type::Map, Type::Map)
|
|
||||||
// | (Type::Number, Type::Number)
|
|
||||||
// | (Type::Number, Type::Integer)
|
|
||||||
// | (Type::Number, Type::Float)
|
|
||||||
// | (Type::Integer, Type::Number)
|
|
||||||
// | (Type::Float, Type::Number)
|
|
||||||
// | (Type::String, Type::String)
|
|
||||||
// | (Type::Table, Type::Table) => Ok(()),
|
|
||||||
// (Type::List(self_item_type), Type::List(other_item_type)) => {
|
|
||||||
// let self_defintion = TypeDefinition::new(self_item_type.as_ref().clone());
|
|
||||||
// let other_definition = &TypeDefinition::new(other_item_type.as_ref().clone());
|
|
||||||
|
|
||||||
// self_defintion.runtime_check(other_definition, context)
|
|
||||||
// }
|
|
||||||
// (
|
|
||||||
// Type::Function {
|
|
||||||
// parameter_types: self_parameter_types,
|
|
||||||
// return_type: self_return_type,
|
|
||||||
// },
|
|
||||||
// Type::Function {
|
|
||||||
// parameter_types: other_parameter_types,
|
|
||||||
// return_type: other_return_type,
|
|
||||||
// },
|
|
||||||
// ) => {
|
|
||||||
// let parameter_type_pairs = self_parameter_types
|
|
||||||
// .iter()
|
|
||||||
// .zip(other_parameter_types.iter());
|
|
||||||
|
|
||||||
// for (self_parameter_type, other_parameter_type) in parameter_type_pairs {
|
|
||||||
// TypeDefinition::new(self_parameter_type.clone()).runtime_check(
|
|
||||||
// &TypeDefinition::new(other_parameter_type.clone()),
|
|
||||||
// context,
|
|
||||||
// )?;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TypeDefinition::new(self_return_type.as_ref().clone()).runtime_check(
|
|
||||||
// &TypeDefinition::new(other_return_type.as_ref().clone()),
|
|
||||||
// context,
|
|
||||||
// )?;
|
|
||||||
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
// _ => Err(Error::RuntimeTypeCheck {
|
|
||||||
// expected: self.clone(),
|
|
||||||
// actual: other.clone(),
|
|
||||||
// }),
|
|
||||||
// }
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,6 +77,58 @@ pub enum Type {
|
|||||||
Table,
|
Table,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Type {
|
||||||
|
pub fn check(&self, other: &Type, context: &Map, node: Node, source: &str) -> Result<()> {
|
||||||
|
match (self, other) {
|
||||||
|
(Type::Any, _)
|
||||||
|
| (_, Type::Any)
|
||||||
|
| (Type::Boolean, Type::Boolean)
|
||||||
|
| (Type::Empty, Type::Empty)
|
||||||
|
| (Type::Float, Type::Float)
|
||||||
|
| (Type::Integer, Type::Integer)
|
||||||
|
| (Type::Map, Type::Map)
|
||||||
|
| (Type::Number, Type::Number)
|
||||||
|
| (Type::Number, Type::Integer)
|
||||||
|
| (Type::Number, Type::Float)
|
||||||
|
| (Type::Integer, Type::Number)
|
||||||
|
| (Type::Float, Type::Number)
|
||||||
|
| (Type::String, Type::String)
|
||||||
|
| (Type::Table, Type::Table) => Ok(()),
|
||||||
|
(Type::List(self_item_type), Type::List(other_item_type)) => {
|
||||||
|
self_item_type.check(&other_item_type, context, node, source)
|
||||||
|
}
|
||||||
|
(
|
||||||
|
Type::Function {
|
||||||
|
parameter_types: self_parameter_types,
|
||||||
|
return_type: self_return_type,
|
||||||
|
},
|
||||||
|
Type::Function {
|
||||||
|
parameter_types: other_parameter_types,
|
||||||
|
return_type: other_return_type,
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
let parameter_type_pairs = self_parameter_types
|
||||||
|
.iter()
|
||||||
|
.zip(other_parameter_types.iter());
|
||||||
|
|
||||||
|
for (self_parameter_type, other_parameter_type) in parameter_type_pairs {
|
||||||
|
self_parameter_type.check(&other_parameter_type, context, node, source)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self_return_type.check(other_return_type, context, node, source)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => Err(Error::TypeCheck {
|
||||||
|
expected: self.clone(),
|
||||||
|
actual: other.clone(),
|
||||||
|
location: node.start_position(),
|
||||||
|
source: source[node.byte_range()].to_string(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AbstractTree for Type {
|
impl AbstractTree for Type {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "type", node)?;
|
Error::expect_syntax_node(source, "type", node)?;
|
||||||
@ -182,7 +169,6 @@ impl AbstractTree for Type {
|
|||||||
"map" => Type::Map,
|
"map" => Type::Map,
|
||||||
"num" => Type::Number,
|
"num" => Type::Number,
|
||||||
"str" => Type::String,
|
"str" => Type::String,
|
||||||
"table" => Type::Table,
|
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedSyntaxNode {
|
return Err(Error::UnexpectedSyntaxNode {
|
||||||
expected: "any, bool, float, fn, int, list, map, num, str or table",
|
expected: "any, bool, float, fn, int, list, map, num, str or table",
|
||||||
@ -225,7 +211,7 @@ impl Display for Type {
|
|||||||
write!(f, "-> {return_type}")
|
write!(f, "-> {return_type}")
|
||||||
}
|
}
|
||||||
Type::Integer => write!(f, "int"),
|
Type::Integer => write!(f, "int"),
|
||||||
Type::List(item_type) => write!(f, "list {item_type}"),
|
Type::List(item_type) => write!(f, "[{item_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"),
|
||||||
|
@ -195,7 +195,7 @@ impl AbstractTree for ValueNode {
|
|||||||
|
|
||||||
if let Some(previous) = previous_type {
|
if let Some(previous) = previous_type {
|
||||||
if expression_type != previous {
|
if expression_type != previous {
|
||||||
return Ok(TypeDefinition::new(Type::Any));
|
return Ok(TypeDefinition::new(Type::List(Box::new(Type::Any))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{
|
use crate::{AbstractTree, Expression, FunctionCall, Map, Result, TypeDefinition, Value};
|
||||||
AbstractTree, Expression, FunctionCall, Identifier, Map, Result, TypeDefinition, Value,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Yield {
|
pub struct Yield {
|
||||||
@ -15,24 +13,24 @@ impl AbstractTree for Yield {
|
|||||||
let input_node = node.child(0).unwrap();
|
let input_node = node.child(0).unwrap();
|
||||||
let input = Expression::from_syntax_node(source, input_node, context)?;
|
let input = Expression::from_syntax_node(source, input_node, context)?;
|
||||||
|
|
||||||
let function_node = node.child(3).unwrap();
|
let expression_node = node.child(3).unwrap();
|
||||||
let function = Identifier::from_syntax_node(source, function_node, context)?;
|
let function_expression = Expression::from_syntax_node(source, expression_node, context)?;
|
||||||
|
|
||||||
let mut arguments = Vec::new();
|
let mut arguments = Vec::new();
|
||||||
|
|
||||||
arguments.push(input);
|
arguments.push(input);
|
||||||
|
|
||||||
for index in 4..node.child_count() - 1 {
|
for index in 4..node.child_count() - 1 {
|
||||||
let node = node.child(index).unwrap();
|
let child = node.child(index).unwrap();
|
||||||
|
|
||||||
if node.is_named() {
|
if child.is_named() {
|
||||||
let expression = Expression::from_syntax_node(source, node, context)?;
|
let expression = Expression::from_syntax_node(source, child, context)?;
|
||||||
|
|
||||||
arguments.push(expression);
|
arguments.push(expression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let call = FunctionCall::new(function, arguments);
|
let call = FunctionCall::new(function_expression, arguments);
|
||||||
|
|
||||||
Ok(Yield { call })
|
Ok(Yield { call })
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ mod assert;
|
|||||||
mod collections;
|
mod collections;
|
||||||
mod data_formats;
|
mod data_formats;
|
||||||
mod fs;
|
mod fs;
|
||||||
|
mod network;
|
||||||
mod output;
|
mod output;
|
||||||
mod random;
|
mod random;
|
||||||
mod r#type;
|
mod r#type;
|
||||||
@ -22,7 +23,7 @@ pub const BUILT_IN_FUNCTIONS: [&dyn BuiltInFunction; 14] = [
|
|||||||
&random::RandomBoolean,
|
&random::RandomBoolean,
|
||||||
&random::RandomFloat,
|
&random::RandomFloat,
|
||||||
&random::RandomInteger,
|
&random::RandomInteger,
|
||||||
&r#type::Type,
|
&r#type::TypeFunction,
|
||||||
];
|
];
|
||||||
|
|
||||||
pub trait BuiltInFunction {
|
pub trait BuiltInFunction {
|
||||||
|
27
src/built_in_functions/network.rs
Normal file
27
src/built_in_functions/network.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use reqwest::blocking::get;
|
||||||
|
|
||||||
|
use crate::{BuiltInFunction, Error, Map, Result, Type, TypeDefinition, Value};
|
||||||
|
|
||||||
|
pub struct Download;
|
||||||
|
|
||||||
|
impl BuiltInFunction for Download {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"download"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
||||||
|
Error::expect_argument_amount(self, 1, arguments.len())?;
|
||||||
|
|
||||||
|
let url = arguments.first().unwrap().as_string()?;
|
||||||
|
let response = get(url)?;
|
||||||
|
|
||||||
|
Ok(Value::String(response.text()?))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_definition(&self) -> TypeDefinition {
|
||||||
|
TypeDefinition::new(Type::Function {
|
||||||
|
parameter_types: vec![Type::String],
|
||||||
|
return_type: Box::new(Type::String),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
use crate::{BuiltInFunction, Error, List, Map, Result, Value};
|
use crate::{BuiltInFunction, Error, List, Map, Result, Type, TypeDefinition, Value};
|
||||||
|
|
||||||
pub struct Type;
|
pub struct TypeFunction;
|
||||||
|
|
||||||
impl BuiltInFunction for Type {
|
impl BuiltInFunction for TypeFunction {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"type"
|
"type"
|
||||||
}
|
}
|
||||||
@ -33,6 +33,9 @@ impl BuiltInFunction for Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn type_definition(&self) -> crate::TypeDefinition {
|
fn type_definition(&self) -> crate::TypeDefinition {
|
||||||
todo!()
|
TypeDefinition::new(Type::Function {
|
||||||
|
parameter_types: vec![Type::String],
|
||||||
|
return_type: Box::new(Type::Any),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
src/error.rs
10
src/error.rs
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
use tree_sitter::{Node, Point};
|
use tree_sitter::{Node, Point};
|
||||||
|
|
||||||
use crate::{value::Value, BuiltInFunction, Identifier, TypeDefinition};
|
use crate::{value::Value, BuiltInFunction, Identifier, Type};
|
||||||
|
|
||||||
use std::{fmt, io, num::ParseFloatError, string::FromUtf8Error, sync::PoisonError, time};
|
use std::{fmt, io, num::ParseFloatError, string::FromUtf8Error, sync::PoisonError, time};
|
||||||
|
|
||||||
@ -21,15 +21,15 @@ pub enum Error {
|
|||||||
},
|
},
|
||||||
|
|
||||||
TypeCheck {
|
TypeCheck {
|
||||||
expected: TypeDefinition,
|
expected: Type,
|
||||||
actual: TypeDefinition,
|
actual: Type,
|
||||||
location: Point,
|
location: Point,
|
||||||
source: String,
|
source: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
RuntimeTypeCheck {
|
RuntimeTypeCheck {
|
||||||
expected: TypeDefinition,
|
expected: Type,
|
||||||
actual: TypeDefinition,
|
actual: Type,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// The 'assert' macro did not resolve successfully.
|
/// The 'assert' macro did not resolve successfully.
|
||||||
|
@ -62,15 +62,11 @@ impl Function {
|
|||||||
|
|
||||||
println!("{key} {value}");
|
println!("{key} {value}");
|
||||||
|
|
||||||
type_definition.runtime_check(&value.r#type(context)?, context)?;
|
|
||||||
function_context.variables_mut()?.insert(key.clone(), value);
|
function_context.variables_mut()?.insert(key.clone(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
let return_value = self.body.run(source, &function_context)?;
|
let return_value = self.body.run(source, &function_context)?;
|
||||||
|
|
||||||
self.return_type
|
|
||||||
.runtime_check(&return_value.r#type(context)?, context)?;
|
|
||||||
|
|
||||||
Ok(return_value)
|
Ok(return_value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,11 +86,11 @@ impl AbstractTree for Function {
|
|||||||
(parameter_types, return_type)
|
(parameter_types, return_type)
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::TypeCheck {
|
return Err(Error::TypeCheck {
|
||||||
expected: TypeDefinition::new(Type::Function {
|
expected: Type::Function {
|
||||||
parameter_types: Vec::with_capacity(0),
|
parameter_types: Vec::with_capacity(0),
|
||||||
return_type: Box::new(Type::Empty),
|
return_type: Box::new(Type::Empty),
|
||||||
}),
|
},
|
||||||
actual: type_definition,
|
actual: type_definition.take_inner(),
|
||||||
location: type_node.start_position(),
|
location: type_node.start_position(),
|
||||||
source: source[type_node.byte_range()].to_string(),
|
source: source[type_node.byte_range()].to_string(),
|
||||||
});
|
});
|
||||||
|
@ -12,7 +12,8 @@ async { (output 'Whaddup') }
|
|||||||
(statement
|
(statement
|
||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(identifier)
|
(expression
|
||||||
|
(identifier))
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(string)))))))))
|
(string)))))))))
|
||||||
|
@ -28,7 +28,8 @@ for i in [1, 2, 3] {
|
|||||||
(statement
|
(statement
|
||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(identifier)
|
(expression
|
||||||
|
(identifier))
|
||||||
(expression
|
(expression
|
||||||
(identifier)))))))))
|
(identifier)))))))))
|
||||||
|
|
||||||
@ -60,6 +61,7 @@ for list in list_of_lists {
|
|||||||
(statement
|
(statement
|
||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(identifier)
|
(expression
|
||||||
|
(identifier))
|
||||||
(expression
|
(expression
|
||||||
(identifier))))))))))))
|
(identifier))))))))))))
|
||||||
|
@ -58,7 +58,8 @@ Function Call
|
|||||||
(statement
|
(statement
|
||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(identifier)
|
(expression
|
||||||
|
(identifier))
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(string)))))))
|
(string)))))))
|
||||||
@ -89,13 +90,15 @@ Complex Function
|
|||||||
(statement
|
(statement
|
||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(identifier)
|
(expression
|
||||||
|
(identifier))
|
||||||
(expression
|
(expression
|
||||||
(identifier)))))
|
(identifier)))))
|
||||||
(statement
|
(statement
|
||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(identifier)
|
(expression
|
||||||
|
(identifier))
|
||||||
(expression
|
(expression
|
||||||
(identifier)))))))))))
|
(identifier)))))))))))
|
||||||
|
|
||||||
@ -118,7 +121,8 @@ Complex Function Call
|
|||||||
(statement
|
(statement
|
||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(identifier)
|
(expression
|
||||||
|
(identifier))
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(string)))
|
(string)))
|
||||||
|
@ -109,7 +109,8 @@ x:(y):0
|
|||||||
(identifier))
|
(identifier))
|
||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(identifier)))))
|
(expression
|
||||||
|
(identifier))))))
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(integer)))))))
|
(integer)))))))
|
||||||
|
@ -18,7 +18,8 @@ while true {
|
|||||||
(statement
|
(statement
|
||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(identifier)
|
(expression
|
||||||
|
(identifier))
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(string))))))))))
|
(string))))))))))
|
||||||
|
@ -13,7 +13,8 @@ Simple Yield
|
|||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(integer)))
|
(integer)))
|
||||||
(identifier)))))
|
(expression
|
||||||
|
(identifier))))))
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
Yield Chain
|
Yield Chain
|
||||||
@ -33,6 +34,9 @@ x -> (foo) -> (bar) -> (abc)
|
|||||||
(yield
|
(yield
|
||||||
(expression
|
(expression
|
||||||
(identifier))
|
(identifier))
|
||||||
(identifier)))
|
(expression
|
||||||
(identifier)))
|
(identifier))))
|
||||||
(identifier)))))
|
(expression
|
||||||
|
(identifier))))
|
||||||
|
(expression
|
||||||
|
(identifier))))))
|
||||||
|
@ -361,24 +361,22 @@ module.exports = grammar({
|
|||||||
function: $ =>
|
function: $ =>
|
||||||
seq(
|
seq(
|
||||||
$.type_definition,
|
$.type_definition,
|
||||||
seq(
|
'|',
|
||||||
'|',
|
repeat(
|
||||||
repeat(
|
seq(
|
||||||
seq(
|
$.identifier,
|
||||||
$.identifier,
|
optional(','),
|
||||||
optional(','),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
'|',
|
|
||||||
$.block,
|
|
||||||
),
|
),
|
||||||
|
'|',
|
||||||
|
$.block,
|
||||||
),
|
),
|
||||||
|
|
||||||
function_call: $ =>
|
function_call: $ =>
|
||||||
prec.right(
|
prec.right(
|
||||||
seq(
|
seq(
|
||||||
'(',
|
'(',
|
||||||
$.identifier,
|
$.expression,
|
||||||
optional($._expression_list),
|
optional($._expression_list),
|
||||||
')',
|
')',
|
||||||
),
|
),
|
||||||
@ -390,7 +388,7 @@ module.exports = grammar({
|
|||||||
$.expression,
|
$.expression,
|
||||||
'->',
|
'->',
|
||||||
'(',
|
'(',
|
||||||
$.identifier,
|
$.expression,
|
||||||
optional($._expression_list),
|
optional($._expression_list),
|
||||||
')',
|
')',
|
||||||
),
|
),
|
||||||
|
@ -36,7 +36,6 @@
|
|||||||
"if"
|
"if"
|
||||||
"else"
|
"else"
|
||||||
"for"
|
"for"
|
||||||
"transform"
|
|
||||||
"in"
|
"in"
|
||||||
"function"
|
"function"
|
||||||
] @keyword
|
] @keyword
|
||||||
|
@ -1223,7 +1223,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "identifier"
|
"name": "expression"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "CHOICE",
|
"type": "CHOICE",
|
||||||
@ -1264,7 +1264,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "identifier"
|
"name": "expression"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "CHOICE",
|
"type": "CHOICE",
|
||||||
|
@ -181,10 +181,6 @@
|
|||||||
{
|
{
|
||||||
"type": "expression",
|
"type": "expression",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "identifier",
|
|
||||||
"named": true
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -565,10 +561,6 @@
|
|||||||
{
|
{
|
||||||
"type": "expression",
|
"type": "expression",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "identifier",
|
|
||||||
"named": true
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user