1
0

Add type argument syntax

This commit is contained in:
Jeff 2024-02-18 15:07:53 -05:00
parent a5f3127bcf
commit 0805b96809
22 changed files with 23448 additions and 21860 deletions

View File

@ -37,9 +37,9 @@ impl AbstractTree for As {
fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> {
let initial_type = self.expression.expected_type(context)?;
if let Type::List(item_type) = &self.r#type {
if let Type::ListOf(item_type) = &self.r#type {
match &initial_type {
Type::List(expected_item_type) => {
Type::ListOf(expected_item_type) => {
if !item_type.accepts(&expected_item_type) {
return Err(ValidationError::TypeCheck {
expected: self.r#type.clone(),
@ -77,7 +77,7 @@ impl AbstractTree for As {
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
let value = self.expression.run(source, context)?;
let converted_value = if let Type::List(_) = self.r#type {
let converted_value = if let Type::ListOf(_) = self.r#type {
match value {
Value::List(list) => Value::List(list),
Value::String(string) => {

View File

@ -78,7 +78,7 @@ impl AbstractTree for Assignment {
}
}
AssignmentOperator::PlusEqual => {
if let Type::List(expected) = type_specification.inner() {
if let Type::ListOf(expected) = type_specification.inner() {
let actual = self.identifier.expected_type(context)?;
if !expected.accepts(&actual) {
@ -107,7 +107,7 @@ impl AbstractTree for Assignment {
match self.operator {
AssignmentOperator::Equal => {}
AssignmentOperator::PlusEqual => {
if let Type::List(expected) = self.identifier.expected_type(context)? {
if let Type::ListOf(expected) = self.identifier.expected_type(context)? {
let actual = self.statement.expected_type(context)?;
if !expected.accepts(&actual) {

View File

@ -9,11 +9,11 @@ use crate::{
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct EnumDefinition {
identifier: Identifier,
variants: Vec<(Identifier, Option<Type>)>,
variants: Vec<(Identifier, Vec<Type>)>,
}
impl EnumDefinition {
pub fn new(identifier: Identifier, variants: Vec<(Identifier, Option<Type>)>) -> Self {
pub fn new(identifier: Identifier, variants: Vec<(Identifier, Vec<Type>)>) -> Self {
Self {
identifier,
variants,
@ -27,6 +27,10 @@ impl EnumDefinition {
pub fn identifier(&self) -> &Identifier {
&self.identifier
}
pub fn variants(&self) -> &Vec<(Identifier, Vec<Type>)> {
&self.variants
}
}
impl AbstractTree for EnumDefinition {
@ -37,21 +41,25 @@ impl AbstractTree for EnumDefinition {
let identifier = Identifier::from_syntax(identifier_node, source, context)?;
let mut variants = Vec::new();
let mut current_identifier = None;
let mut current_identifier: Option<Identifier> = None;
let mut types = Vec::new();
for index in 3..node.child_count() - 1 {
let child = node.child(index).unwrap();
if child.kind() == "identifier" {
if let Some(identifier) = &current_identifier {
variants.push((identifier.clone(), types));
}
current_identifier = Some(Identifier::from_syntax(child, source, context)?);
types = Vec::new();
}
if let Some(identifier) = &current_identifier {
if child.kind() == "type" {
let r#type = Type::from_syntax(child, source, context)?;
if child.kind() == "type" {
let r#type = Type::from_syntax(child, source, context)?;
variants.push((identifier.clone(), Some(r#type)));
}
types.push(r#type);
}
}
@ -65,13 +73,14 @@ impl AbstractTree for EnumDefinition {
Ok(Type::None)
}
fn validate(&self, _source: &str, _context: &Context) -> Result<(), ValidationError> {
fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> {
context.set_definition(self.identifier.clone(), TypeDefinition::Enum(self.clone()))?;
self.identifier.validate(_source, context)?;
Ok(())
}
fn run(&self, _source: &str, context: &Context) -> Result<Value, RuntimeError> {
context.set_definition(self.identifier.clone(), TypeDefinition::Enum(self.clone()))?;
fn run(&self, _source: &str, _context: &Context) -> Result<Value, RuntimeError> {
Ok(Value::none())
}
}

View File

@ -66,7 +66,7 @@ impl AbstractTree for For {
self.collection.validate(_source, context)?;
let collection_type = self.collection.expected_type(context)?;
let item_type = if let Type::List(item_type) = collection_type {
let item_type = if let Type::ListOf(item_type) = collection_type {
item_type.as_ref().clone()
} else if let Type::Range = collection_type {
Type::Integer

View File

@ -35,7 +35,7 @@ impl AbstractTree for Index {
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
match self.collection.expected_type(context)? {
Type::List(item_type) => Ok(*item_type.clone()),
Type::ListOf(item_type) => Ok(*item_type.clone()),
Type::Map(map_types_option) => {
if let (Some(map_type), IndexExpression::Identifier(identifier)) =
(map_types_option, &self.index)

View File

@ -19,7 +19,7 @@ pub enum Type {
Collection,
Custom {
name: Identifier,
argument: Option<Box<Type>>,
arguments: Vec<Type>,
},
Float,
Function {
@ -27,20 +27,19 @@ pub enum Type {
return_type: Box<Type>,
},
Integer,
List(Box<Type>),
List,
ListOf(Box<Type>),
ListExact(Vec<Type>),
Map(Option<BTreeMap<Identifier, Type>>),
None,
Number,
String,
Range,
None,
}
impl Type {
pub fn custom(name: Identifier, argument: Option<Type>) -> Self {
Type::Custom {
name,
argument: argument.map(|r#type| Box::new(r#type)),
}
pub fn custom(name: Identifier, arguments: Vec<Type>) -> Self {
Type::Custom { name, arguments }
}
pub fn option(inner_type: Option<Type>) -> Self {
@ -48,7 +47,7 @@ impl Type {
}
pub fn list(item_type: Type) -> Self {
Type::List(Box::new(item_type))
Type::ListOf(Box::new(item_type))
}
pub fn function(parameter_types: Vec<Type>, return_type: Type) -> Self {
@ -70,14 +69,15 @@ impl Type {
| (_, Type::Any)
| (Type::Boolean, Type::Boolean)
| (Type::Collection, Type::Collection)
| (Type::Collection, Type::List(_))
| (Type::List(_), Type::Collection)
| (Type::Collection, Type::ListOf(_))
| (Type::ListOf(_), Type::Collection)
| (Type::Collection, Type::Map(_))
| (Type::Map(_), Type::Collection)
| (Type::Collection, Type::String)
| (Type::String, Type::Collection)
| (Type::Float, Type::Float)
| (Type::Integer, Type::Integer)
| (Type::List, Type::List)
| (Type::Map(None), Type::Map(None))
| (Type::Number, Type::Number)
| (Type::Number, Type::Integer)
@ -90,22 +90,25 @@ impl Type {
(
Type::Custom {
name: left_name,
argument: left_argument,
arguments: left_arguments,
},
Type::Custom {
name: right_name,
argument: right_argument,
arguments: right_arguments,
},
) => {
if left_name != right_name {
false
} else {
left_argument == right_argument
}
}
(Type::List(self_item_type), Type::List(other_item_type)) => {
) => left_name == right_name && left_arguments == right_arguments,
(Type::ListOf(self_item_type), Type::ListOf(other_item_type)) => {
self_item_type.accepts(&other_item_type)
}
(Type::ListExact(self_types), Type::ListExact(other_types)) => {
for (left, right) in self_types.iter().zip(other_types.iter()) {
if !left.accepts(right) {
return false;
}
}
true
}
(
Type::Function {
parameter_types: self_parameter_types,
@ -137,7 +140,7 @@ impl Type {
}
pub fn is_list(&self) -> bool {
matches!(self, Type::List(_))
matches!(self, Type::ListOf(_))
}
pub fn is_map(&self) -> bool {
@ -158,13 +161,19 @@ impl AbstractTree for Type {
let r#type = match type_node.kind() {
"identifier" => {
let name = Identifier::from_syntax(type_node, _source, context)?;
let argument = if let Some(child) = node.child(2) {
Some(Type::from_syntax(child, _source, context)?)
} else {
None
};
let mut arguments = Vec::new();
Type::custom(name, argument)
for index in 2..node.child_count() - 1 {
let child = node.child(index).unwrap();
if child.is_named() {
let r#type = Type::from_syntax(child, _source, context)?;
arguments.push(r#type);
}
}
Type::custom(name, arguments)
}
"{" => {
let mut type_map = BTreeMap::new();
@ -191,7 +200,7 @@ impl AbstractTree for Type {
let item_type_node = node.child(1).unwrap();
let item_type = Type::from_syntax(item_type_node, _source, context)?;
Type::List(Box::new(item_type))
Type::ListOf(Box::new(item_type))
}
"any" => Type::Any,
"bool" => Type::Boolean,
@ -261,7 +270,7 @@ impl Format for Type {
Type::Collection => output.push_str("collection"),
Type::Custom {
name: _,
argument: _,
arguments: _,
} => todo!(),
Type::Float => output.push_str("float"),
Type::Function {
@ -282,11 +291,13 @@ impl Format for Type {
return_type.format(output, indent_level);
}
Type::Integer => output.push_str("int"),
Type::List(item_type) => {
Type::List => todo!(),
Type::ListOf(item_type) => {
output.push('[');
item_type.format(output, indent_level);
output.push(']');
}
Type::ListExact(_) => todo!(),
Type::Map(_) => {
output.push_str("map");
}
@ -304,9 +315,19 @@ impl Display for Type {
Type::Any => write!(f, "any"),
Type::Boolean => write!(f, "bool"),
Type::Collection => write!(f, "collection"),
Type::Custom { name, argument } => {
if let Some(argument) = argument {
write!(f, "{name}<{argument}>")
Type::Custom { name, arguments } => {
if !arguments.is_empty() {
write!(f, "<")?;
for (index, r#type) in arguments.into_iter().enumerate() {
if index == arguments.len() - 1 {
write!(f, "{}", r#type)?;
} else {
write!(f, "{}, ", r#type)?;
}
}
write!(f, ">")
} else {
write!(f, "{name}")
}
@ -330,7 +351,21 @@ impl Display for Type {
write!(f, " -> {return_type}")
}
Type::Integer => write!(f, "int"),
Type::List(item_type) => write!(f, "[{item_type}]"),
Type::List => write!(f, "list"),
Type::ListOf(item_type) => write!(f, "[{item_type}]"),
Type::ListExact(types) => {
write!(f, "[")?;
for (index, r#type) in types.into_iter().enumerate() {
if index == types.len() - 1 {
write!(f, "{}", r#type)?;
} else {
write!(f, "{}, ", r#type)?;
}
}
write!(f, "]")
}
Type::Map(_) => write!(f, "map"),
Type::Number => write!(f, "num"),
Type::None => write!(f, "none"),

View File

@ -124,43 +124,47 @@ impl AbstractTree for ValueNode {
ValueNode::Integer(_) => Type::Integer,
ValueNode::String(_) => Type::String,
ValueNode::List(expressions) => {
let mut previous_type = None;
let mut item_types = Vec::new();
for expression in expressions {
let expression_type = expression.expected_type(context)?;
if let Some(previous) = previous_type {
if expression_type != previous {
return Ok(Type::List(Box::new(Type::Any)));
}
}
previous_type = Some(expression_type);
item_types.push(expression_type);
}
if let Some(previous) = previous_type {
Type::List(Box::new(previous))
} else {
Type::List(Box::new(Type::Any))
}
Type::ListExact(item_types)
}
ValueNode::Map(map_node) => map_node.expected_type(context)?,
ValueNode::Struct { name, .. } => {
Type::Custom { name: name.clone(), argument: None }
Type::custom(name.clone(), Vec::with_capacity(0))
}
ValueNode::Range(_) => Type::Range,
ValueNode::Enum { name, variant: _, expression } => {
if let Some(expression) = expression {
Type::Custom {
name: name.clone(),
argument: Some(Box::new(expression.expected_type(context)?))
ValueNode::Enum { name, variant, expression: _ } => {
let types: Vec<Type> = if let Some(type_definition) = context.get_definition(name)? {
if let TypeDefinition::Enum(enum_definition) = type_definition {
let types = enum_definition.variants().into_iter().find_map(|(identifier, types)| {
if identifier == variant {
Some(types.clone())
} else {
None
}
});
if let Some(types) = types {
types
} else {
return Err(ValidationError::VariableIdentifierNotFound(variant.clone()));
}
} else {
return Err(ValidationError::ExpectedEnumDefintion { actual: type_definition.clone() });
}
} else {
Type::Custom{
name: name.clone(),
argument: None,
}
}
return Err(ValidationError::VariableIdentifierNotFound(name.clone()));
};
Type::custom(name.clone(), types.clone())
},
};

View File

@ -73,13 +73,7 @@ impl Callable for BuiltInFunction {
fn r#type(&self) -> Type {
match self {
BuiltInFunction::AssertEqual => Type::function(
vec![Type::Any, Type::Any],
Type::Custom {
name: Identifier::new("Result"),
argument: None,
},
),
BuiltInFunction::AssertEqual => Type::function(vec![Type::Any, Type::Any], Type::None),
BuiltInFunction::Fs(fs_function) => fs_function.r#type(),
BuiltInFunction::Json(json_function) => json_function.r#type(),
BuiltInFunction::Length => Type::function(vec![Type::Collection], Type::Integer),

View File

@ -33,8 +33,8 @@ impl BuiltInTypeDefinition {
let definition = TypeDefinition::Enum(EnumDefinition::new(
Identifier::new(self.name()),
vec![
(Identifier::new("Some"), Some(Type::Any)),
(Identifier::new("None"), None),
(Identifier::new("Some"), vec![Type::Any]),
(Identifier::new("None"), Vec::with_capacity(0)),
],
));
@ -44,8 +44,8 @@ impl BuiltInTypeDefinition {
let definition = TypeDefinition::Enum(EnumDefinition::new(
Identifier::new(self.name()),
vec![
(Identifier::new("Ok"), Some(Type::Any)),
(Identifier::new("Err"), Some(Type::Any)),
(Identifier::new("Ok"), vec![Type::Any]),
(Identifier::new("Error"), vec![Type::Any]),
],
));

View File

@ -19,15 +19,9 @@ impl BuiltInType {
match self {
BuiltInType::Option(content_type) => OPTION.get_or_init(|| {
if let Some(content_type) = content_type {
Type::Custom {
name: Identifier::new("Option"),
argument: Some(Box::new(content_type.clone())),
}
Type::custom(Identifier::new("Option"), vec![content_type.clone()])
} else {
Type::Custom {
name: Identifier::new("Option"),
argument: None,
}
Type::custom(Identifier::new("Option"), Vec::with_capacity(0))
}
}),
}

View File

@ -270,7 +270,7 @@ impl Context {
let old_data = map.remove(&key);
if let Some((_, old_counter)) = old_data {
map.insert(key, (ValueData::Value(value), old_counter.clone()));
map.insert(key, (ValueData::Value(value), old_counter));
} else {
map.insert(key, (ValueData::Value(value), UsageCounter::new()));
}

View File

@ -16,7 +16,7 @@ use tree_sitter::LanguageError;
use std::fmt::{self, Formatter};
#[derive(PartialEq)]
#[derive(Debug, PartialEq)]
pub enum Error {
Syntax(SyntaxError),
@ -95,12 +95,6 @@ impl From<LanguageError> for Error {
impl std::error::Error for Error {}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self}")
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use Error::*;

View File

@ -74,25 +74,15 @@ impl Value {
pub fn r#type(&self) -> Result<Type, RwLockError> {
let r#type = match self {
Value::List(list) => {
let mut previous_type = None;
let mut item_types = Vec::new();
for value in list.items()?.iter() {
let value_type = value.r#type();
let r#type = value.r#type()?;
if let Some(previous) = &previous_type {
if &value_type != previous {
return Ok(Type::List(Box::new(Type::Any)));
}
}
previous_type = Some(value_type);
item_types.push(r#type);
}
if let Some(previous) = previous_type {
Type::List(Box::new(previous?))
} else {
Type::List(Box::new(Type::Any))
}
Type::ListExact(item_types)
}
Value::Map(map) => {
if map.inner().is_empty() {

View File

@ -24,7 +24,7 @@ fn string_as_list_error() {
interpret("'foobar' as [float]"),
Err(Error::Validation(ValidationError::ConversionImpossible {
initial_type: Type::String,
target_type: Type::List(Box::new(Type::Float))
target_type: Type::ListOf(Box::new(Type::Float))
}))
)
}
@ -39,7 +39,7 @@ fn conversion_runtime_error() {
interpret(&format!("json:parse('{JSON}') as [map]")),
Err(Error::Runtime(RuntimeError::ConversionImpossible {
from: json_value.r#type().unwrap(),
to: Type::List(Box::new(Type::Map(None))),
to: Type::ListOf(Box::new(Type::Map(None))),
position: SourcePosition {
start_byte: 0,
end_byte: 33,

View File

@ -1,5 +1,26 @@
use dust_lang::*;
#[test]
fn override_built_ins() {
assert_eq!(
interpret(
"
enum Option {
Some<str>
None
}
my_option <Option> = Option::Some('foo')
"
),
Ok(Value::Enum(EnumInstance::new(
Identifier::new("Option"),
Identifier::new("Some"),
Some(Value::String("foo".to_string())),
)))
);
}
#[test]
fn option() {
assert_eq!(
@ -13,14 +34,12 @@ fn option() {
assert_eq!(
interpret(
"
opt <Option<int>> = Option::Some(1);
opt
Option::Some(1)
"
),
Ok(Value::Enum(EnumInstance::new(
Identifier::new("Option"),
Identifier::new("None"),
Identifier::new("Some"),
Some(Value::Integer(1)),
)))
);
@ -39,8 +58,7 @@ fn result() {
assert_eq!(
interpret(
"
result <Result<int, str>> = Result::Error('uh-oh!')
result
Result::Error('uh-oh!')
"
),
Ok(Value::Enum(EnumInstance::new(

View File

@ -1,4 +1,4 @@
use dust_lang::*;
use dust_lang::{error::RuntimeError, *};
#[test]
fn args() {
@ -23,10 +23,9 @@ fn assert_equal() {
);
assert_eq!(
interpret("assert_equal(true, false)"),
Ok(Value::Enum(EnumInstance::new(
Identifier::new("Result"),
Identifier::new("Error"),
Some(Value::none()),
)))
Err(Error::Runtime(RuntimeError::AssertEqualFailed {
left: true.into(),
right: false.into()
}))
);
}

View File

@ -19,15 +19,12 @@ enum Foobar {
(identifier))))))
================================================================================
Nested Enum
Enum with Arguments
================================================================================
enum Foobar {
Foo(str),
Bar(enum BazBuff {
Baz,
Buff,
})
enum Foobar<T, U> {
Foo<T>,
Bar<U>,
}
--------------------------------------------------------------------------------
@ -38,15 +35,56 @@ enum Foobar {
(type_definition
(enum_definition
(identifier)
(type_arguments
(type
(identifier))
(type
(identifier)))
(identifier)
(type)
(type_arguments
(type
(identifier)))
(identifier)
(type_definition
(enum_definition
(identifier)
(identifier)
(type_arguments
(type
(identifier))))))))
================================================================================
Complex Enum
================================================================================
enum Foobar<T> {
Foo<Foo>,
Bar<int, float>,
Baz<Option<T>>
}
--------------------------------------------------------------------------------
(root
(statement
(statement_kind
(type_definition
(enum_definition
(identifier)
(type_arguments
(type
(identifier)))
(identifier)
(type_arguments
(type
(identifier)))
(identifier)
(type_arguments
(type)
(type))
(identifier)
(type_arguments
(type
(identifier)
(type
(identifier)))))))))
================================================================================
Simple Enum Instance
================================================================================

View File

@ -28,3 +28,69 @@ x <{ y <int> }> = { y = 2 }
(expression
(value
(integer))))))))))))))
================================================================================
List Of
================================================================================
x <list<str>> = ['foo', 'bar', 'baz']
--------------------------------------------------------------------------------
(root
(statement
(statement_kind
(assignment
(identifier)
(type_specification
(type
(type)))
(assignment_operator)
(statement
(statement_kind
(expression
(value
(list
(expression
(value
(string)))
(expression
(value
(string)))
(expression
(value
(string))))))))))))
================================================================================
Exact List
================================================================================
foo <[int, float, int]> = [1, 2.0, 3]
--------------------------------------------------------------------------------
(root
(statement
(statement_kind
(assignment
(identifier)
(type_specification
(type
(type)
(type)
(type)))
(assignment_operator)
(statement
(statement_kind
(expression
(value
(list
(expression
(value
(integer)))
(expression
(value
(float)))
(expression
(value
(integer))))))))))))

View File

@ -354,21 +354,15 @@ module.exports = grammar({
'collection',
'float',
'int',
'list',
'map',
seq(
'{',
repeat1(
seq(
$.identifier,
$.type_specification,
),
),
'}',
),
'none',
'num',
'str',
// Custom type
$.identifier,
// Custom type with arguments
seq(
$.identifier,
'<',
@ -380,7 +374,35 @@ module.exports = grammar({
),
'>',
),
seq('[', $.type, ']'),
// Map with exact fields
seq(
'{',
repeat1(
seq(
$.identifier,
$.type_specification,
),
),
'}',
),
// List of
seq('list', '<', $.type, '>'),
// Exact list
seq(
'[',
repeat(
seq(
$.type,
optional(','),
),
),
']',
),
// Function
seq(
'(',
repeat(
@ -447,27 +469,31 @@ module.exports = grammar({
$.struct_definition,
),
type_arguments: $ =>
seq(
'<',
repeat1(
seq(
$.type,
optional(','),
),
),
'>',
),
enum_definition: $ =>
prec.right(
seq(
'enum',
$.identifier,
optional($.type_arguments),
repeat(
seq(
'{',
repeat1(
seq(
$.identifier,
optional(
seq(
'(',
choice(
$.type,
$.type_definition,
),
')',
),
),
optional($.type_arguments),
optional(','),
),
),

View File

@ -1074,36 +1074,11 @@
},
{
"type": "STRING",
"value": "map"
"value": "list"
},
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "{"
},
{
"type": "REPEAT1",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "identifier"
},
{
"type": "SYMBOL",
"name": "type_specification"
}
]
}
},
{
"type": "STRING",
"value": "}"
}
]
"type": "STRING",
"value": "map"
},
{
"type": "STRING",
@ -1167,12 +1142,82 @@
"members": [
{
"type": "STRING",
"value": "["
"value": "{"
},
{
"type": "REPEAT1",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "identifier"
},
{
"type": "SYMBOL",
"name": "type_specification"
}
]
}
},
{
"type": "STRING",
"value": "}"
}
]
},
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "list"
},
{
"type": "STRING",
"value": "<"
},
{
"type": "SYMBOL",
"name": "type"
},
{
"type": "STRING",
"value": ">"
}
]
},
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "["
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "type"
},
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "BLANK"
}
]
}
]
}
},
{
"type": "STRING",
"value": "]"
@ -1386,6 +1431,43 @@
}
]
},
"type_arguments": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "<"
},
{
"type": "REPEAT1",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "type"
},
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "BLANK"
}
]
}
]
}
},
{
"type": "STRING",
"value": ">"
}
]
},
"enum_definition": {
"type": "PREC_RIGHT",
"value": 0,
@ -1400,6 +1482,18 @@
"type": "SYMBOL",
"name": "identifier"
},
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "type_arguments"
},
{
"type": "BLANK"
}
]
},
{
"type": "REPEAT",
"content": {
@ -1422,30 +1516,8 @@
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "("
},
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "type"
},
{
"type": "SYMBOL",
"name": "type_definition"
}
]
},
{
"type": "STRING",
"value": ")"
}
]
"type": "SYMBOL",
"name": "type_arguments"
},
{
"type": "BLANK"

View File

@ -141,11 +141,7 @@
"named": true
},
{
"type": "type",
"named": true
},
{
"type": "type_definition",
"type": "type_arguments",
"named": true
}
]
@ -738,6 +734,21 @@
]
}
},
{
"type": "type_arguments",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "type",
"named": true
}
]
}
},
{
"type": "type_definition",
"named": true,
@ -1030,6 +1041,10 @@
"type": "integer",
"named": true
},
{
"type": "list",
"named": false
},
{
"type": "map",
"named": false

File diff suppressed because it is too large Load Diff