1
0

Continue implementing type checks

This commit is contained in:
Jeff 2023-12-02 02:34:23 -05:00
parent 9181c319b8
commit 7f1b53aabe
23 changed files with 7672 additions and 7816 deletions

View File

@ -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")
async {
cast_len = (length (from_json cast)) cast_len = (length (from_json cast))
characters_len = (length (from_json characters)) characters_len = (length (from_json characters))
episodes_len = (length (from_json episodes)) episodes_len = (length (from_json episodes))
}
(output [cast_len, characters_len, episodes_len]) (output [cast_len, characters_len, episodes_len])

View File

@ -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(
} else {
type_definition.clone()
};
type_definition.abstract_check(
&statement_type, &statement_type,
context, context,
statement_node, statement_node,
source, source,
)?; )?;
} else {
type_definition.check(
&identifier_type,
context,
identifier_node,
source,
)?;
type_definition.check(&statement_type, context, statement_node, 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
", ",

View File

@ -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,7 +58,10 @@ 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() {
@ -75,26 +78,47 @@ impl AbstractTree for FunctionCall {
} }
let variables = context.variables()?; let variables = context.variables()?;
let function = if let Some(value) = variables.get(key) { if let Some(value) = variables.get(key) {
value.as_function()? value.clone()
} else { } else {
return Err(Error::FunctionIdentifierNotFound( return Err(Error::FunctionIdentifierNotFound(identifier.clone()));
self.function_name.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> { 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),
} }
} }
} }

View File

@ -47,7 +47,7 @@ impl AbstractTree for Identifier {
} }
} }
Ok(TypeDefinition::new(Type::Empty)) Ok(TypeDefinition::new(Type::Any))
} }
} }
} }

View File

@ -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"),

View File

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

View File

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

View File

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

View 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),
})
}
}

View File

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

View File

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

View File

@ -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(),
}); });

View File

@ -12,7 +12,8 @@ async { (output 'Whaddup') }
(statement (statement
(expression (expression
(function_call (function_call
(identifier) (expression
(identifier))
(expression (expression
(value (value
(string))))))))) (string)))))))))

View File

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

View File

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

View File

@ -109,7 +109,8 @@ x:(y):0
(identifier)) (identifier))
(expression (expression
(function_call (function_call
(identifier))))) (expression
(identifier))))))
(expression (expression
(value (value
(integer))))))) (integer)))))))

View File

@ -18,7 +18,8 @@ while true {
(statement (statement
(expression (expression
(function_call (function_call
(identifier) (expression
(identifier))
(expression (expression
(value (value
(string)))))))))) (string))))))))))

View File

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

View File

@ -361,7 +361,6 @@ module.exports = grammar({
function: $ => function: $ =>
seq( seq(
$.type_definition, $.type_definition,
seq(
'|', '|',
repeat( repeat(
seq( seq(
@ -372,13 +371,12 @@ module.exports = grammar({
'|', '|',
$.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),
')', ')',
), ),

View File

@ -36,7 +36,6 @@
"if" "if"
"else" "else"
"for" "for"
"transform"
"in" "in"
"function" "function"
] @keyword ] @keyword

View File

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

View File

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