Implement matching for enums
This commit is contained in:
parent
85cb641af8
commit
a6e52e4ee6
70
src/abstract_tree/enum_pattern.rs
Normal file
70
src/abstract_tree/enum_pattern.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tree_sitter::Node as SyntaxNode;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
|
AbstractTree, Context, Format, Identifier, Type, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
|
pub struct EnumPattern {
|
||||||
|
name: Identifier,
|
||||||
|
variant: Identifier,
|
||||||
|
inner_identifier: Option<Identifier>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EnumPattern {
|
||||||
|
pub fn name(&self) -> &Identifier {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn variant(&self) -> &Identifier {
|
||||||
|
&self.variant
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inner_identifier(&self) -> &Option<Identifier> {
|
||||||
|
&self.inner_identifier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbstractTree for EnumPattern {
|
||||||
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Context) -> Result<Self, SyntaxError> {
|
||||||
|
SyntaxError::expect_syntax_node(source, "enum_pattern", node)?;
|
||||||
|
|
||||||
|
let enum_name_node = node.child(0).unwrap();
|
||||||
|
let name = Identifier::from_syntax(enum_name_node, source, context)?;
|
||||||
|
|
||||||
|
let enum_variant_node = node.child(2).unwrap();
|
||||||
|
let variant = Identifier::from_syntax(enum_variant_node, source, context)?;
|
||||||
|
|
||||||
|
let inner_identifier = if let Some(child) = node.child(4) {
|
||||||
|
Some(Identifier::from_syntax(child, source, context)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(EnumPattern {
|
||||||
|
name,
|
||||||
|
variant,
|
||||||
|
inner_identifier,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
|
Ok(Type::None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(&self, _source: &str, _context: &Context) -> Result<(), ValidationError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, _source: &str, _context: &Context) -> Result<Value, RuntimeError> {
|
||||||
|
Ok(Value::none())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Format for EnumPattern {
|
||||||
|
fn format(&self, _output: &mut String, _indent_level: u8) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
@ -3,17 +3,18 @@
|
|||||||
//! Note that this module is called "match" but is escaped as "r#match" because
|
//! Note that this module is called "match" but is escaped as "r#match" because
|
||||||
//! "match" is a keyword in Rust.
|
//! "match" is a keyword in Rust.
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tree_sitter::Node as SyntaxNode;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{RuntimeError, SyntaxError, ValidationError},
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
AbstractTree, Context, Expression, Format, Statement, SyntaxNode, Type, Value,
|
AbstractTree, Context, Expression, Format, MatchPattern, Statement, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Abstract representation of a match statement.
|
/// Abstract representation of a match statement.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Match {
|
pub struct Match {
|
||||||
matcher: Expression,
|
matcher: Expression,
|
||||||
options: Vec<(Expression, Statement)>,
|
options: Vec<(MatchPattern, Statement)>,
|
||||||
fallback: Option<Box<Statement>>,
|
fallback: Option<Box<Statement>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,19 +26,15 @@ impl AbstractTree for Match {
|
|||||||
let matcher = Expression::from_syntax(matcher_node, source, context)?;
|
let matcher = Expression::from_syntax(matcher_node, source, context)?;
|
||||||
|
|
||||||
let mut options = Vec::new();
|
let mut options = Vec::new();
|
||||||
let mut previous_expression = None;
|
let mut previous_pattern = None;
|
||||||
let mut next_statement_is_fallback = false;
|
let mut next_statement_is_fallback = false;
|
||||||
let mut fallback = None;
|
let mut fallback = None;
|
||||||
|
|
||||||
for index in 2..node.child_count() {
|
for index in 2..node.child_count() {
|
||||||
let child = node.child(index).unwrap();
|
let child = node.child(index).unwrap();
|
||||||
|
|
||||||
if child.kind() == "*" {
|
if child.kind() == "match_pattern" {
|
||||||
next_statement_is_fallback = true;
|
previous_pattern = Some(MatchPattern::from_syntax(child, source, context)?);
|
||||||
}
|
|
||||||
|
|
||||||
if child.kind() == "expression" {
|
|
||||||
previous_expression = Some(Expression::from_syntax(child, source, context)?);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if child.kind() == "statement" {
|
if child.kind() == "statement" {
|
||||||
@ -46,7 +43,7 @@ impl AbstractTree for Match {
|
|||||||
if next_statement_is_fallback {
|
if next_statement_is_fallback {
|
||||||
fallback = Some(Box::new(statement));
|
fallback = Some(Box::new(statement));
|
||||||
next_statement_is_fallback = false;
|
next_statement_is_fallback = false;
|
||||||
} else if let Some(expression) = &previous_expression {
|
} else if let Some(expression) = &previous_pattern {
|
||||||
options.push((expression.clone(), statement));
|
options.push((expression.clone(), statement));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,10 +80,26 @@ impl AbstractTree for Match {
|
|||||||
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
||||||
let matcher_value = self.matcher.run(source, context)?;
|
let matcher_value = self.matcher.run(source, context)?;
|
||||||
|
|
||||||
for (expression, statement) in &self.options {
|
for (pattern, statement) in &self.options {
|
||||||
let option_value = expression.run(source, context)?;
|
if let (Value::Enum(enum_instance), MatchPattern::EnumPattern(enum_pattern)) =
|
||||||
|
(&matcher_value, pattern)
|
||||||
|
{
|
||||||
|
if enum_instance.name() == enum_pattern.name().inner()
|
||||||
|
&& enum_instance.variant_name() == enum_pattern.variant().inner()
|
||||||
|
{
|
||||||
|
let statement_context = Context::with_variables_from(context)?;
|
||||||
|
|
||||||
if matcher_value == option_value {
|
if let Some(identifier) = enum_pattern.inner_identifier() {
|
||||||
|
statement_context
|
||||||
|
.set_value(identifier.inner().clone(), enum_instance.value().clone())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
return statement.run(source, &statement_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let pattern_value = pattern.run(source, context)?;
|
||||||
|
|
||||||
|
if matcher_value == pattern_value {
|
||||||
return statement.run(source, context);
|
return statement.run(source, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
65
src/abstract_tree/match_pattern.rs
Normal file
65
src/abstract_tree/match_pattern.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tree_sitter::Node as SyntaxNode;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
|
AbstractTree, Context, EnumPattern, Format, Type, Value, ValueNode,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
|
pub enum MatchPattern {
|
||||||
|
EnumPattern(EnumPattern),
|
||||||
|
Value(ValueNode),
|
||||||
|
Wildcard,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbstractTree for MatchPattern {
|
||||||
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Context) -> Result<Self, SyntaxError> {
|
||||||
|
SyntaxError::expect_syntax_node(source, "match_pattern", node)?;
|
||||||
|
|
||||||
|
let child = node.child(0).unwrap();
|
||||||
|
let pattern = match child.kind() {
|
||||||
|
"enum_pattern" => {
|
||||||
|
MatchPattern::EnumPattern(EnumPattern::from_syntax(child, source, context)?)
|
||||||
|
}
|
||||||
|
"value" => MatchPattern::Value(ValueNode::from_syntax(child, source, context)?),
|
||||||
|
"*" => MatchPattern::Wildcard,
|
||||||
|
_ => {
|
||||||
|
return Err(SyntaxError::UnexpectedSyntaxNode {
|
||||||
|
expected: "enum pattern or value".to_string(),
|
||||||
|
actual: child.kind().to_string(),
|
||||||
|
location: child.start_position(),
|
||||||
|
relevant_source: source[child.byte_range()].to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(pattern)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
|
match self {
|
||||||
|
MatchPattern::EnumPattern(enum_pattern) => enum_pattern.expected_type(_context),
|
||||||
|
MatchPattern::Value(value_node) => value_node.expected_type(_context),
|
||||||
|
MatchPattern::Wildcard => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(&self, _source: &str, _context: &Context) -> Result<(), ValidationError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, _source: &str, _context: &Context) -> Result<Value, RuntimeError> {
|
||||||
|
match self {
|
||||||
|
MatchPattern::EnumPattern(enum_pattern) => enum_pattern.run(_source, _context),
|
||||||
|
MatchPattern::Value(value_node) => value_node.run(_source, _context),
|
||||||
|
MatchPattern::Wildcard => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Format for MatchPattern {
|
||||||
|
fn format(&self, _output: &mut String, _indent_level: u8) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ pub mod assignment_operator;
|
|||||||
pub mod block;
|
pub mod block;
|
||||||
pub mod command;
|
pub mod command;
|
||||||
pub mod enum_defintion;
|
pub mod enum_defintion;
|
||||||
|
pub mod enum_pattern;
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
pub mod r#for;
|
pub mod r#for;
|
||||||
pub mod function_call;
|
pub mod function_call;
|
||||||
@ -26,6 +27,7 @@ pub mod logic;
|
|||||||
pub mod logic_operator;
|
pub mod logic_operator;
|
||||||
pub mod map_node;
|
pub mod map_node;
|
||||||
pub mod r#match;
|
pub mod r#match;
|
||||||
|
pub mod match_pattern;
|
||||||
pub mod math;
|
pub mod math;
|
||||||
pub mod math_operator;
|
pub mod math_operator;
|
||||||
pub mod new;
|
pub mod new;
|
||||||
@ -38,12 +40,12 @@ pub mod value_node;
|
|||||||
pub mod r#while;
|
pub mod r#while;
|
||||||
|
|
||||||
pub use {
|
pub use {
|
||||||
assignment::*, assignment_operator::*, block::*, command::*, enum_defintion::*, expression::*,
|
assignment::*, assignment_operator::*, block::*, command::*, enum_defintion::*,
|
||||||
function_call::*, function_expression::*, function_node::*, identifier::*, if_else::*,
|
enum_pattern::*, expression::*, function_call::*, function_expression::*, function_node::*,
|
||||||
index::*, index_assignment::IndexAssignment, index_expression::*, logic::*, logic_operator::*,
|
identifier::*, if_else::*, index::*, index_assignment::IndexAssignment, index_expression::*,
|
||||||
map_node::*, math::*, math_operator::*, new::*, r#as::*, r#for::*, r#match::*, r#type::*,
|
logic::*, logic_operator::*, map_node::*, match_pattern::*, math::*, math_operator::*, new::*,
|
||||||
r#while::*, statement::*, struct_definition::*, type_definition::*, type_specification::*,
|
r#as::*, r#for::*, r#match::*, r#type::*, r#while::*, statement::*, struct_definition::*,
|
||||||
value_node::*,
|
type_definition::*, type_specification::*, value_node::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use crate::Value;
|
use crate::Value;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
@ -15,4 +17,22 @@ impl EnumInstance {
|
|||||||
value: Box::new(value),
|
value: Box::new(value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &String {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn variant_name(&self) -> &String {
|
||||||
|
&self.variant_name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> &Value {
|
||||||
|
&self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for EnumInstance {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}::{}({})", self.name, self.variant_name, self.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -560,7 +560,7 @@ impl Display for Value {
|
|||||||
Value::Function(function) => write!(f, "{function}"),
|
Value::Function(function) => write!(f, "{function}"),
|
||||||
Value::Struct(structure) => write!(f, "{structure}"),
|
Value::Struct(structure) => write!(f, "{structure}"),
|
||||||
Value::Range(range) => write!(f, "{}..{}", range.start(), range.end()),
|
Value::Range(range) => write!(f, "{}..{}", range.start(), range.end()),
|
||||||
Value::Enum(_) => todo!(),
|
Value::Enum(enum_instance) => write!(f, "{enum_instance}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
use dust_lang::*;
|
use dust_lang::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn r#match() {
|
fn match_value() {
|
||||||
let test = interpret(
|
let test = interpret(
|
||||||
"
|
"
|
||||||
match 1 {
|
match 1 {
|
||||||
3 => false
|
3 => false
|
||||||
2 => { false }
|
2 => { false }
|
||||||
1 => true
|
1 => true
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -20,15 +20,31 @@ fn r#match() {
|
|||||||
fn match_assignment() {
|
fn match_assignment() {
|
||||||
let test = interpret(
|
let test = interpret(
|
||||||
"
|
"
|
||||||
x = match 1 {
|
x = match 1 {
|
||||||
3 => false
|
3 => false
|
||||||
2 => { false }
|
2 => { false }
|
||||||
1 => true
|
1 => true
|
||||||
}
|
}
|
||||||
x
|
x
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(Value::Boolean(true), test);
|
assert_eq!(Value::Boolean(true), test);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn match_enum() {
|
||||||
|
let result = interpret(
|
||||||
|
"
|
||||||
|
foobar = Option::Some(true)
|
||||||
|
|
||||||
|
match foobar {
|
||||||
|
Option::None => false,
|
||||||
|
Option::Some(content) => content,
|
||||||
|
}
|
||||||
|
",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(result, Ok(Value::Boolean(true)));
|
||||||
|
}
|
||||||
|
@ -16,7 +16,7 @@ match x {
|
|||||||
(match
|
(match
|
||||||
(expression
|
(expression
|
||||||
(identifier))
|
(identifier))
|
||||||
(expression
|
(match_pattern
|
||||||
(value
|
(value
|
||||||
(integer)))
|
(integer)))
|
||||||
(statement
|
(statement
|
||||||
@ -25,10 +25,43 @@ match x {
|
|||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(boolean))))))
|
(boolean))))))
|
||||||
(expression
|
(match_pattern
|
||||||
(value
|
(value
|
||||||
(integer)))
|
(integer)))
|
||||||
(statement
|
(statement
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(boolean)))))))
|
(boolean)))))))
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
Match Enum
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
match foobar {
|
||||||
|
FooBar::Foo => true
|
||||||
|
FooBar::Bar => false
|
||||||
|
}
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
(root
|
||||||
|
(statement
|
||||||
|
(match
|
||||||
|
(expression
|
||||||
|
(identifier))
|
||||||
|
(match_pattern
|
||||||
|
(enum_pattern
|
||||||
|
(identifier)
|
||||||
|
(identifier)))
|
||||||
|
(statement
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(boolean))))
|
||||||
|
(match_pattern
|
||||||
|
(enum_pattern
|
||||||
|
(identifier)
|
||||||
|
(identifier)))
|
||||||
|
(statement
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(boolean)))))))
|
||||||
|
@ -290,7 +290,7 @@ module.exports = grammar({
|
|||||||
'{',
|
'{',
|
||||||
repeat1(
|
repeat1(
|
||||||
seq(
|
seq(
|
||||||
choice($.expression, '*'),
|
$.match_pattern,
|
||||||
'=>',
|
'=>',
|
||||||
$.statement,
|
$.statement,
|
||||||
optional(','),
|
optional(','),
|
||||||
@ -300,6 +300,26 @@ module.exports = grammar({
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
match_pattern: $ =>
|
||||||
|
choice(
|
||||||
|
$.enum_pattern,
|
||||||
|
$.value,
|
||||||
|
'*',
|
||||||
|
),
|
||||||
|
|
||||||
|
enum_pattern: $ =>
|
||||||
|
prec(
|
||||||
|
1,
|
||||||
|
seq(
|
||||||
|
$.identifier,
|
||||||
|
'::',
|
||||||
|
$.identifier,
|
||||||
|
optional(
|
||||||
|
seq('(', $.identifier, ')'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
while: $ =>
|
while: $ =>
|
||||||
seq(
|
seq(
|
||||||
'while',
|
'while',
|
||||||
@ -341,7 +361,7 @@ module.exports = grammar({
|
|||||||
$.identifier,
|
$.identifier,
|
||||||
'<',
|
'<',
|
||||||
repeat1(
|
repeat1(
|
||||||
seq(
|
seq(
|
||||||
$.type,
|
$.type,
|
||||||
optional(','),
|
optional(','),
|
||||||
),
|
),
|
||||||
|
@ -857,17 +857,8 @@
|
|||||||
"type": "SEQ",
|
"type": "SEQ",
|
||||||
"members": [
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "CHOICE",
|
"type": "SYMBOL",
|
||||||
"members": [
|
"name": "match_pattern"
|
||||||
{
|
|
||||||
"type": "SYMBOL",
|
|
||||||
"name": "expression"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "*"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
@ -899,6 +890,69 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"match_pattern": {
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "enum_pattern"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "*"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"enum_pattern": {
|
||||||
|
"type": "PREC",
|
||||||
|
"value": 1,
|
||||||
|
"content": {
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "identifier"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "::"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "identifier"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "("
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "identifier"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": ")"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "BLANK"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"while": {
|
"while": {
|
||||||
"type": "SEQ",
|
"type": "SEQ",
|
||||||
"members": [
|
"members": [
|
||||||
|
@ -170,6 +170,21 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "enum_pattern",
|
||||||
|
"named": true,
|
||||||
|
"fields": {},
|
||||||
|
"children": {
|
||||||
|
"multiple": true,
|
||||||
|
"required": true,
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"type": "identifier",
|
||||||
|
"named": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "expression",
|
"type": "expression",
|
||||||
"named": true,
|
"named": true,
|
||||||
@ -495,6 +510,10 @@
|
|||||||
"type": "expression",
|
"type": "expression",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "match_pattern",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "statement",
|
"type": "statement",
|
||||||
"named": true
|
"named": true
|
||||||
@ -502,6 +521,25 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "match_pattern",
|
||||||
|
"named": true,
|
||||||
|
"fields": {},
|
||||||
|
"children": {
|
||||||
|
"multiple": false,
|
||||||
|
"required": false,
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"type": "enum_pattern",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "value",
|
||||||
|
"named": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "math",
|
"type": "math",
|
||||||
"named": true,
|
"named": true,
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user