Add type argument syntax
This commit is contained in:
parent
a5f3127bcf
commit
0805b96809
@ -37,9 +37,9 @@ impl AbstractTree for As {
|
|||||||
fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> {
|
||||||
let initial_type = self.expression.expected_type(context)?;
|
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 {
|
match &initial_type {
|
||||||
Type::List(expected_item_type) => {
|
Type::ListOf(expected_item_type) => {
|
||||||
if !item_type.accepts(&expected_item_type) {
|
if !item_type.accepts(&expected_item_type) {
|
||||||
return Err(ValidationError::TypeCheck {
|
return Err(ValidationError::TypeCheck {
|
||||||
expected: self.r#type.clone(),
|
expected: self.r#type.clone(),
|
||||||
@ -77,7 +77,7 @@ impl AbstractTree for As {
|
|||||||
|
|
||||||
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
||||||
let value = self.expression.run(source, context)?;
|
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 {
|
match value {
|
||||||
Value::List(list) => Value::List(list),
|
Value::List(list) => Value::List(list),
|
||||||
Value::String(string) => {
|
Value::String(string) => {
|
||||||
|
@ -78,7 +78,7 @@ impl AbstractTree for Assignment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssignmentOperator::PlusEqual => {
|
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)?;
|
let actual = self.identifier.expected_type(context)?;
|
||||||
|
|
||||||
if !expected.accepts(&actual) {
|
if !expected.accepts(&actual) {
|
||||||
@ -107,7 +107,7 @@ impl AbstractTree for Assignment {
|
|||||||
match self.operator {
|
match self.operator {
|
||||||
AssignmentOperator::Equal => {}
|
AssignmentOperator::Equal => {}
|
||||||
AssignmentOperator::PlusEqual => {
|
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)?;
|
let actual = self.statement.expected_type(context)?;
|
||||||
|
|
||||||
if !expected.accepts(&actual) {
|
if !expected.accepts(&actual) {
|
||||||
|
@ -9,11 +9,11 @@ use crate::{
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct EnumDefinition {
|
pub struct EnumDefinition {
|
||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
variants: Vec<(Identifier, Option<Type>)>,
|
variants: Vec<(Identifier, Vec<Type>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnumDefinition {
|
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 {
|
Self {
|
||||||
identifier,
|
identifier,
|
||||||
variants,
|
variants,
|
||||||
@ -27,6 +27,10 @@ impl EnumDefinition {
|
|||||||
pub fn identifier(&self) -> &Identifier {
|
pub fn identifier(&self) -> &Identifier {
|
||||||
&self.identifier
|
&self.identifier
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn variants(&self) -> &Vec<(Identifier, Vec<Type>)> {
|
||||||
|
&self.variants
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for EnumDefinition {
|
impl AbstractTree for EnumDefinition {
|
||||||
@ -37,21 +41,25 @@ impl AbstractTree for EnumDefinition {
|
|||||||
let identifier = Identifier::from_syntax(identifier_node, source, context)?;
|
let identifier = Identifier::from_syntax(identifier_node, source, context)?;
|
||||||
|
|
||||||
let mut variants = Vec::new();
|
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 {
|
for index in 3..node.child_count() - 1 {
|
||||||
let child = node.child(index).unwrap();
|
let child = node.child(index).unwrap();
|
||||||
|
|
||||||
if child.kind() == "identifier" {
|
if child.kind() == "identifier" {
|
||||||
current_identifier = Some(Identifier::from_syntax(child, source, context)?);
|
if let Some(identifier) = ¤t_identifier {
|
||||||
|
variants.push((identifier.clone(), types));
|
||||||
|
}
|
||||||
|
|
||||||
|
current_identifier = Some(Identifier::from_syntax(child, source, context)?);
|
||||||
|
types = Vec::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(identifier) = ¤t_identifier {
|
|
||||||
if child.kind() == "type" {
|
if child.kind() == "type" {
|
||||||
let r#type = Type::from_syntax(child, source, context)?;
|
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)
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
fn run(&self, _source: &str, _context: &Context) -> Result<Value, RuntimeError> {
|
||||||
context.set_definition(self.identifier.clone(), TypeDefinition::Enum(self.clone()))?;
|
|
||||||
|
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ impl AbstractTree for For {
|
|||||||
self.collection.validate(_source, context)?;
|
self.collection.validate(_source, context)?;
|
||||||
|
|
||||||
let collection_type = self.collection.expected_type(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()
|
item_type.as_ref().clone()
|
||||||
} else if let Type::Range = collection_type {
|
} else if let Type::Range = collection_type {
|
||||||
Type::Integer
|
Type::Integer
|
||||||
|
@ -35,7 +35,7 @@ impl AbstractTree for Index {
|
|||||||
|
|
||||||
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
|
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
|
||||||
match self.collection.expected_type(context)? {
|
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) => {
|
Type::Map(map_types_option) => {
|
||||||
if let (Some(map_type), IndexExpression::Identifier(identifier)) =
|
if let (Some(map_type), IndexExpression::Identifier(identifier)) =
|
||||||
(map_types_option, &self.index)
|
(map_types_option, &self.index)
|
||||||
|
@ -19,7 +19,7 @@ pub enum Type {
|
|||||||
Collection,
|
Collection,
|
||||||
Custom {
|
Custom {
|
||||||
name: Identifier,
|
name: Identifier,
|
||||||
argument: Option<Box<Type>>,
|
arguments: Vec<Type>,
|
||||||
},
|
},
|
||||||
Float,
|
Float,
|
||||||
Function {
|
Function {
|
||||||
@ -27,20 +27,19 @@ pub enum Type {
|
|||||||
return_type: Box<Type>,
|
return_type: Box<Type>,
|
||||||
},
|
},
|
||||||
Integer,
|
Integer,
|
||||||
List(Box<Type>),
|
List,
|
||||||
|
ListOf(Box<Type>),
|
||||||
|
ListExact(Vec<Type>),
|
||||||
Map(Option<BTreeMap<Identifier, Type>>),
|
Map(Option<BTreeMap<Identifier, Type>>),
|
||||||
|
None,
|
||||||
Number,
|
Number,
|
||||||
String,
|
String,
|
||||||
Range,
|
Range,
|
||||||
None,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Type {
|
impl Type {
|
||||||
pub fn custom(name: Identifier, argument: Option<Type>) -> Self {
|
pub fn custom(name: Identifier, arguments: Vec<Type>) -> Self {
|
||||||
Type::Custom {
|
Type::Custom { name, arguments }
|
||||||
name,
|
|
||||||
argument: argument.map(|r#type| Box::new(r#type)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn option(inner_type: Option<Type>) -> Self {
|
pub fn option(inner_type: Option<Type>) -> Self {
|
||||||
@ -48,7 +47,7 @@ impl Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn list(item_type: Type) -> Self {
|
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 {
|
pub fn function(parameter_types: Vec<Type>, return_type: Type) -> Self {
|
||||||
@ -70,14 +69,15 @@ impl Type {
|
|||||||
| (_, Type::Any)
|
| (_, Type::Any)
|
||||||
| (Type::Boolean, Type::Boolean)
|
| (Type::Boolean, Type::Boolean)
|
||||||
| (Type::Collection, Type::Collection)
|
| (Type::Collection, Type::Collection)
|
||||||
| (Type::Collection, Type::List(_))
|
| (Type::Collection, Type::ListOf(_))
|
||||||
| (Type::List(_), Type::Collection)
|
| (Type::ListOf(_), Type::Collection)
|
||||||
| (Type::Collection, Type::Map(_))
|
| (Type::Collection, Type::Map(_))
|
||||||
| (Type::Map(_), Type::Collection)
|
| (Type::Map(_), Type::Collection)
|
||||||
| (Type::Collection, Type::String)
|
| (Type::Collection, Type::String)
|
||||||
| (Type::String, Type::Collection)
|
| (Type::String, Type::Collection)
|
||||||
| (Type::Float, Type::Float)
|
| (Type::Float, Type::Float)
|
||||||
| (Type::Integer, Type::Integer)
|
| (Type::Integer, Type::Integer)
|
||||||
|
| (Type::List, Type::List)
|
||||||
| (Type::Map(None), Type::Map(None))
|
| (Type::Map(None), Type::Map(None))
|
||||||
| (Type::Number, Type::Number)
|
| (Type::Number, Type::Number)
|
||||||
| (Type::Number, Type::Integer)
|
| (Type::Number, Type::Integer)
|
||||||
@ -90,22 +90,25 @@ impl Type {
|
|||||||
(
|
(
|
||||||
Type::Custom {
|
Type::Custom {
|
||||||
name: left_name,
|
name: left_name,
|
||||||
argument: left_argument,
|
arguments: left_arguments,
|
||||||
},
|
},
|
||||||
Type::Custom {
|
Type::Custom {
|
||||||
name: right_name,
|
name: right_name,
|
||||||
argument: right_argument,
|
arguments: right_arguments,
|
||||||
},
|
},
|
||||||
) => {
|
) => left_name == right_name && left_arguments == right_arguments,
|
||||||
if left_name != right_name {
|
(Type::ListOf(self_item_type), Type::ListOf(other_item_type)) => {
|
||||||
false
|
|
||||||
} else {
|
|
||||||
left_argument == right_argument
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(Type::List(self_item_type), Type::List(other_item_type)) => {
|
|
||||||
self_item_type.accepts(&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 {
|
Type::Function {
|
||||||
parameter_types: self_parameter_types,
|
parameter_types: self_parameter_types,
|
||||||
@ -137,7 +140,7 @@ impl Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_list(&self) -> bool {
|
pub fn is_list(&self) -> bool {
|
||||||
matches!(self, Type::List(_))
|
matches!(self, Type::ListOf(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_map(&self) -> bool {
|
pub fn is_map(&self) -> bool {
|
||||||
@ -158,13 +161,19 @@ impl AbstractTree for Type {
|
|||||||
let r#type = match type_node.kind() {
|
let r#type = match type_node.kind() {
|
||||||
"identifier" => {
|
"identifier" => {
|
||||||
let name = Identifier::from_syntax(type_node, _source, context)?;
|
let name = Identifier::from_syntax(type_node, _source, context)?;
|
||||||
let argument = if let Some(child) = node.child(2) {
|
let mut arguments = Vec::new();
|
||||||
Some(Type::from_syntax(child, _source, context)?)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
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();
|
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_node = node.child(1).unwrap();
|
||||||
let item_type = Type::from_syntax(item_type_node, _source, context)?;
|
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,
|
"any" => Type::Any,
|
||||||
"bool" => Type::Boolean,
|
"bool" => Type::Boolean,
|
||||||
@ -261,7 +270,7 @@ impl Format for Type {
|
|||||||
Type::Collection => output.push_str("collection"),
|
Type::Collection => output.push_str("collection"),
|
||||||
Type::Custom {
|
Type::Custom {
|
||||||
name: _,
|
name: _,
|
||||||
argument: _,
|
arguments: _,
|
||||||
} => todo!(),
|
} => todo!(),
|
||||||
Type::Float => output.push_str("float"),
|
Type::Float => output.push_str("float"),
|
||||||
Type::Function {
|
Type::Function {
|
||||||
@ -282,11 +291,13 @@ impl Format for Type {
|
|||||||
return_type.format(output, indent_level);
|
return_type.format(output, indent_level);
|
||||||
}
|
}
|
||||||
Type::Integer => output.push_str("int"),
|
Type::Integer => output.push_str("int"),
|
||||||
Type::List(item_type) => {
|
Type::List => todo!(),
|
||||||
|
Type::ListOf(item_type) => {
|
||||||
output.push('[');
|
output.push('[');
|
||||||
item_type.format(output, indent_level);
|
item_type.format(output, indent_level);
|
||||||
output.push(']');
|
output.push(']');
|
||||||
}
|
}
|
||||||
|
Type::ListExact(_) => todo!(),
|
||||||
Type::Map(_) => {
|
Type::Map(_) => {
|
||||||
output.push_str("map");
|
output.push_str("map");
|
||||||
}
|
}
|
||||||
@ -304,9 +315,19 @@ impl Display for Type {
|
|||||||
Type::Any => write!(f, "any"),
|
Type::Any => write!(f, "any"),
|
||||||
Type::Boolean => write!(f, "bool"),
|
Type::Boolean => write!(f, "bool"),
|
||||||
Type::Collection => write!(f, "collection"),
|
Type::Collection => write!(f, "collection"),
|
||||||
Type::Custom { name, argument } => {
|
Type::Custom { name, arguments } => {
|
||||||
if let Some(argument) = argument {
|
if !arguments.is_empty() {
|
||||||
write!(f, "{name}<{argument}>")
|
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 {
|
} else {
|
||||||
write!(f, "{name}")
|
write!(f, "{name}")
|
||||||
}
|
}
|
||||||
@ -330,7 +351,21 @@ 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, "[{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::Map(_) => write!(f, "map"),
|
||||||
Type::Number => write!(f, "num"),
|
Type::Number => write!(f, "num"),
|
||||||
Type::None => write!(f, "none"),
|
Type::None => write!(f, "none"),
|
||||||
|
@ -124,43 +124,47 @@ impl AbstractTree for ValueNode {
|
|||||||
ValueNode::Integer(_) => Type::Integer,
|
ValueNode::Integer(_) => Type::Integer,
|
||||||
ValueNode::String(_) => Type::String,
|
ValueNode::String(_) => Type::String,
|
||||||
ValueNode::List(expressions) => {
|
ValueNode::List(expressions) => {
|
||||||
let mut previous_type = None;
|
let mut item_types = Vec::new();
|
||||||
|
|
||||||
for expression in expressions {
|
for expression in expressions {
|
||||||
let expression_type = expression.expected_type(context)?;
|
let expression_type = expression.expected_type(context)?;
|
||||||
|
|
||||||
if let Some(previous) = previous_type {
|
item_types.push(expression_type);
|
||||||
if expression_type != previous {
|
|
||||||
return Ok(Type::List(Box::new(Type::Any)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
previous_type = Some(expression_type);
|
Type::ListExact(item_types)
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(previous) = previous_type {
|
|
||||||
Type::List(Box::new(previous))
|
|
||||||
} else {
|
|
||||||
Type::List(Box::new(Type::Any))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ValueNode::Map(map_node) => map_node.expected_type(context)?,
|
ValueNode::Map(map_node) => map_node.expected_type(context)?,
|
||||||
ValueNode::Struct { name, .. } => {
|
ValueNode::Struct { name, .. } => {
|
||||||
Type::Custom { name: name.clone(), argument: None }
|
Type::custom(name.clone(), Vec::with_capacity(0))
|
||||||
}
|
}
|
||||||
ValueNode::Range(_) => Type::Range,
|
ValueNode::Range(_) => Type::Range,
|
||||||
ValueNode::Enum { name, variant: _, expression } => {
|
ValueNode::Enum { name, variant, expression: _ } => {
|
||||||
if let Some(expression) = expression {
|
let types: Vec<Type> = if let Some(type_definition) = context.get_definition(name)? {
|
||||||
Type::Custom {
|
if let TypeDefinition::Enum(enum_definition) = type_definition {
|
||||||
name: name.clone(),
|
let types = enum_definition.variants().into_iter().find_map(|(identifier, types)| {
|
||||||
argument: Some(Box::new(expression.expected_type(context)?))
|
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 {
|
} else {
|
||||||
Type::Custom{
|
return Err(ValidationError::VariableIdentifierNotFound(name.clone()));
|
||||||
name: name.clone(),
|
};
|
||||||
argument: None,
|
|
||||||
}
|
Type::custom(name.clone(), types.clone())
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -73,13 +73,7 @@ impl Callable for BuiltInFunction {
|
|||||||
|
|
||||||
fn r#type(&self) -> Type {
|
fn r#type(&self) -> Type {
|
||||||
match self {
|
match self {
|
||||||
BuiltInFunction::AssertEqual => Type::function(
|
BuiltInFunction::AssertEqual => Type::function(vec![Type::Any, Type::Any], Type::None),
|
||||||
vec![Type::Any, Type::Any],
|
|
||||||
Type::Custom {
|
|
||||||
name: Identifier::new("Result"),
|
|
||||||
argument: None,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
BuiltInFunction::Fs(fs_function) => fs_function.r#type(),
|
BuiltInFunction::Fs(fs_function) => fs_function.r#type(),
|
||||||
BuiltInFunction::Json(json_function) => json_function.r#type(),
|
BuiltInFunction::Json(json_function) => json_function.r#type(),
|
||||||
BuiltInFunction::Length => Type::function(vec![Type::Collection], Type::Integer),
|
BuiltInFunction::Length => Type::function(vec![Type::Collection], Type::Integer),
|
||||||
|
@ -33,8 +33,8 @@ impl BuiltInTypeDefinition {
|
|||||||
let definition = TypeDefinition::Enum(EnumDefinition::new(
|
let definition = TypeDefinition::Enum(EnumDefinition::new(
|
||||||
Identifier::new(self.name()),
|
Identifier::new(self.name()),
|
||||||
vec![
|
vec![
|
||||||
(Identifier::new("Some"), Some(Type::Any)),
|
(Identifier::new("Some"), vec![Type::Any]),
|
||||||
(Identifier::new("None"), None),
|
(Identifier::new("None"), Vec::with_capacity(0)),
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -44,8 +44,8 @@ impl BuiltInTypeDefinition {
|
|||||||
let definition = TypeDefinition::Enum(EnumDefinition::new(
|
let definition = TypeDefinition::Enum(EnumDefinition::new(
|
||||||
Identifier::new(self.name()),
|
Identifier::new(self.name()),
|
||||||
vec![
|
vec![
|
||||||
(Identifier::new("Ok"), Some(Type::Any)),
|
(Identifier::new("Ok"), vec![Type::Any]),
|
||||||
(Identifier::new("Err"), Some(Type::Any)),
|
(Identifier::new("Error"), vec![Type::Any]),
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -19,15 +19,9 @@ impl BuiltInType {
|
|||||||
match self {
|
match self {
|
||||||
BuiltInType::Option(content_type) => OPTION.get_or_init(|| {
|
BuiltInType::Option(content_type) => OPTION.get_or_init(|| {
|
||||||
if let Some(content_type) = content_type {
|
if let Some(content_type) = content_type {
|
||||||
Type::Custom {
|
Type::custom(Identifier::new("Option"), vec![content_type.clone()])
|
||||||
name: Identifier::new("Option"),
|
|
||||||
argument: Some(Box::new(content_type.clone())),
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Type::Custom {
|
Type::custom(Identifier::new("Option"), Vec::with_capacity(0))
|
||||||
name: Identifier::new("Option"),
|
|
||||||
argument: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -270,7 +270,7 @@ impl Context {
|
|||||||
let old_data = map.remove(&key);
|
let old_data = map.remove(&key);
|
||||||
|
|
||||||
if let Some((_, old_counter)) = old_data {
|
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 {
|
} else {
|
||||||
map.insert(key, (ValueData::Value(value), UsageCounter::new()));
|
map.insert(key, (ValueData::Value(value), UsageCounter::new()));
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ use tree_sitter::LanguageError;
|
|||||||
|
|
||||||
use std::fmt::{self, Formatter};
|
use std::fmt::{self, Formatter};
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
Syntax(SyntaxError),
|
Syntax(SyntaxError),
|
||||||
|
|
||||||
@ -95,12 +95,6 @@ impl From<LanguageError> for Error {
|
|||||||
|
|
||||||
impl std::error::Error 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 {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
use Error::*;
|
use Error::*;
|
||||||
|
@ -74,25 +74,15 @@ impl Value {
|
|||||||
pub fn r#type(&self) -> Result<Type, RwLockError> {
|
pub fn r#type(&self) -> Result<Type, RwLockError> {
|
||||||
let r#type = match self {
|
let r#type = match self {
|
||||||
Value::List(list) => {
|
Value::List(list) => {
|
||||||
let mut previous_type = None;
|
let mut item_types = Vec::new();
|
||||||
|
|
||||||
for value in list.items()?.iter() {
|
for value in list.items()?.iter() {
|
||||||
let value_type = value.r#type();
|
let r#type = value.r#type()?;
|
||||||
|
|
||||||
if let Some(previous) = &previous_type {
|
item_types.push(r#type);
|
||||||
if &value_type != previous {
|
|
||||||
return Ok(Type::List(Box::new(Type::Any)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
previous_type = Some(value_type);
|
Type::ListExact(item_types)
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(previous) = previous_type {
|
|
||||||
Type::List(Box::new(previous?))
|
|
||||||
} else {
|
|
||||||
Type::List(Box::new(Type::Any))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Value::Map(map) => {
|
Value::Map(map) => {
|
||||||
if map.inner().is_empty() {
|
if map.inner().is_empty() {
|
||||||
|
@ -24,7 +24,7 @@ fn string_as_list_error() {
|
|||||||
interpret("'foobar' as [float]"),
|
interpret("'foobar' as [float]"),
|
||||||
Err(Error::Validation(ValidationError::ConversionImpossible {
|
Err(Error::Validation(ValidationError::ConversionImpossible {
|
||||||
initial_type: Type::String,
|
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]")),
|
interpret(&format!("json:parse('{JSON}') as [map]")),
|
||||||
Err(Error::Runtime(RuntimeError::ConversionImpossible {
|
Err(Error::Runtime(RuntimeError::ConversionImpossible {
|
||||||
from: json_value.r#type().unwrap(),
|
from: json_value.r#type().unwrap(),
|
||||||
to: Type::List(Box::new(Type::Map(None))),
|
to: Type::ListOf(Box::new(Type::Map(None))),
|
||||||
position: SourcePosition {
|
position: SourcePosition {
|
||||||
start_byte: 0,
|
start_byte: 0,
|
||||||
end_byte: 33,
|
end_byte: 33,
|
||||||
|
@ -1,5 +1,26 @@
|
|||||||
use dust_lang::*;
|
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]
|
#[test]
|
||||||
fn option() {
|
fn option() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -13,14 +34,12 @@ fn option() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpret(
|
interpret(
|
||||||
"
|
"
|
||||||
opt <Option<int>> = Option::Some(1);
|
Option::Some(1)
|
||||||
|
|
||||||
opt
|
|
||||||
"
|
"
|
||||||
),
|
),
|
||||||
Ok(Value::Enum(EnumInstance::new(
|
Ok(Value::Enum(EnumInstance::new(
|
||||||
Identifier::new("Option"),
|
Identifier::new("Option"),
|
||||||
Identifier::new("None"),
|
Identifier::new("Some"),
|
||||||
Some(Value::Integer(1)),
|
Some(Value::Integer(1)),
|
||||||
)))
|
)))
|
||||||
);
|
);
|
||||||
@ -39,8 +58,7 @@ fn result() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpret(
|
interpret(
|
||||||
"
|
"
|
||||||
result <Result<int, str>> = Result::Error('uh-oh!')
|
Result::Error('uh-oh!')
|
||||||
result
|
|
||||||
"
|
"
|
||||||
),
|
),
|
||||||
Ok(Value::Enum(EnumInstance::new(
|
Ok(Value::Enum(EnumInstance::new(
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use dust_lang::*;
|
use dust_lang::{error::RuntimeError, *};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn args() {
|
fn args() {
|
||||||
@ -23,10 +23,9 @@ fn assert_equal() {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpret("assert_equal(true, false)"),
|
interpret("assert_equal(true, false)"),
|
||||||
Ok(Value::Enum(EnumInstance::new(
|
Err(Error::Runtime(RuntimeError::AssertEqualFailed {
|
||||||
Identifier::new("Result"),
|
left: true.into(),
|
||||||
Identifier::new("Error"),
|
right: false.into()
|
||||||
Some(Value::none()),
|
}))
|
||||||
)))
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -19,15 +19,12 @@ enum Foobar {
|
|||||||
(identifier))))))
|
(identifier))))))
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
Nested Enum
|
Enum with Arguments
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
enum Foobar {
|
enum Foobar<T, U> {
|
||||||
Foo(str),
|
Foo<T>,
|
||||||
Bar(enum BazBuff {
|
Bar<U>,
|
||||||
Baz,
|
|
||||||
Buff,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
@ -38,14 +35,55 @@ enum Foobar {
|
|||||||
(type_definition
|
(type_definition
|
||||||
(enum_definition
|
(enum_definition
|
||||||
(identifier)
|
(identifier)
|
||||||
|
(type_arguments
|
||||||
|
(type
|
||||||
|
(identifier))
|
||||||
|
(type
|
||||||
|
(identifier)))
|
||||||
(identifier)
|
(identifier)
|
||||||
(type)
|
(type_arguments
|
||||||
|
(type
|
||||||
|
(identifier)))
|
||||||
(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
|
(type_definition
|
||||||
(enum_definition
|
(enum_definition
|
||||||
(identifier)
|
(identifier)
|
||||||
|
(type_arguments
|
||||||
|
(type
|
||||||
|
(identifier)))
|
||||||
(identifier)
|
(identifier)
|
||||||
(identifier))))))))
|
(type_arguments
|
||||||
|
(type
|
||||||
|
(identifier)))
|
||||||
|
(identifier)
|
||||||
|
(type_arguments
|
||||||
|
(type)
|
||||||
|
(type))
|
||||||
|
(identifier)
|
||||||
|
(type_arguments
|
||||||
|
(type
|
||||||
|
(identifier)
|
||||||
|
(type
|
||||||
|
(identifier)))))))))
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
Simple Enum Instance
|
Simple Enum Instance
|
||||||
|
@ -28,3 +28,69 @@ x <{ y <int> }> = { y = 2 }
|
|||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(integer))))))))))))))
|
(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))))))))))))
|
||||||
|
@ -354,21 +354,15 @@ module.exports = grammar({
|
|||||||
'collection',
|
'collection',
|
||||||
'float',
|
'float',
|
||||||
'int',
|
'int',
|
||||||
|
'list',
|
||||||
'map',
|
'map',
|
||||||
seq(
|
|
||||||
'{',
|
|
||||||
repeat1(
|
|
||||||
seq(
|
|
||||||
$.identifier,
|
|
||||||
$.type_specification,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'}',
|
|
||||||
),
|
|
||||||
'none',
|
'none',
|
||||||
'num',
|
'num',
|
||||||
'str',
|
'str',
|
||||||
|
// Custom type
|
||||||
$.identifier,
|
$.identifier,
|
||||||
|
|
||||||
|
// Custom type with arguments
|
||||||
seq(
|
seq(
|
||||||
$.identifier,
|
$.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(
|
seq(
|
||||||
'(',
|
'(',
|
||||||
repeat(
|
repeat(
|
||||||
@ -447,27 +469,31 @@ module.exports = grammar({
|
|||||||
$.struct_definition,
|
$.struct_definition,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
type_arguments: $ =>
|
||||||
|
seq(
|
||||||
|
'<',
|
||||||
|
repeat1(
|
||||||
|
seq(
|
||||||
|
$.type,
|
||||||
|
optional(','),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'>',
|
||||||
|
),
|
||||||
|
|
||||||
enum_definition: $ =>
|
enum_definition: $ =>
|
||||||
prec.right(
|
prec.right(
|
||||||
seq(
|
seq(
|
||||||
'enum',
|
'enum',
|
||||||
$.identifier,
|
$.identifier,
|
||||||
|
optional($.type_arguments),
|
||||||
repeat(
|
repeat(
|
||||||
seq(
|
seq(
|
||||||
'{',
|
'{',
|
||||||
repeat1(
|
repeat1(
|
||||||
seq(
|
seq(
|
||||||
$.identifier,
|
$.identifier,
|
||||||
optional(
|
optional($.type_arguments),
|
||||||
seq(
|
|
||||||
'(',
|
|
||||||
choice(
|
|
||||||
$.type,
|
|
||||||
$.type_definition,
|
|
||||||
),
|
|
||||||
')',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
optional(','),
|
optional(','),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1072,39 +1072,14 @@
|
|||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"value": "int"
|
"value": "int"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "list"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"value": "map"
|
"value": "map"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"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",
|
"type": "STRING",
|
||||||
"value": "none"
|
"value": "none"
|
||||||
@ -1167,12 +1142,82 @@
|
|||||||
"members": [
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "STRING",
|
"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",
|
"type": "SYMBOL",
|
||||||
"name": "type"
|
"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",
|
"type": "STRING",
|
||||||
"value": "]"
|
"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": {
|
"enum_definition": {
|
||||||
"type": "PREC_RIGHT",
|
"type": "PREC_RIGHT",
|
||||||
"value": 0,
|
"value": 0,
|
||||||
@ -1400,6 +1482,18 @@
|
|||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "identifier"
|
"name": "identifier"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "type_arguments"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "BLANK"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "REPEAT",
|
"type": "REPEAT",
|
||||||
"content": {
|
"content": {
|
||||||
@ -1418,34 +1512,12 @@
|
|||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "identifier"
|
"name": "identifier"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "CHOICE",
|
|
||||||
"members": [
|
|
||||||
{
|
|
||||||
"type": "SEQ",
|
|
||||||
"members": [
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "("
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "CHOICE",
|
"type": "CHOICE",
|
||||||
"members": [
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "type"
|
"name": "type_arguments"
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "SYMBOL",
|
|
||||||
"name": "type_definition"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": ")"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "BLANK"
|
"type": "BLANK"
|
||||||
|
@ -141,11 +141,7 @@
|
|||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "type",
|
"type": "type_arguments",
|
||||||
"named": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "type_definition",
|
|
||||||
"named": true
|
"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",
|
"type": "type_definition",
|
||||||
"named": true,
|
"named": true,
|
||||||
@ -1030,6 +1041,10 @@
|
|||||||
"type": "integer",
|
"type": "integer",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "list",
|
||||||
|
"named": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "map",
|
"type": "map",
|
||||||
"named": false
|
"named": false
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user