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