-
-
Notifications
You must be signed in to change notification settings - Fork 148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/inner destructuring #283
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,11 @@ | ||
module Mint | ||
class Ast | ||
class EnumDestructuring < Node | ||
alias EnumDestructuringParameter = DestructuringType | TypeVariable | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also not necessary. |
||
|
||
getter name, option, parameters | ||
|
||
def initialize(@parameters : Array(TypeVariable), | ||
def initialize(@parameters : Array(EnumDestructuringParameter), | ||
@option : String, | ||
@name : String, | ||
@input : Data, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,64 @@ | ||
module Mint | ||
class Compiler | ||
def _compile(node : Ast::ArrayDestructuring, value) | ||
private macro compile_item!(initial_var, item = item, index = index1) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does this needs to be a macro? |
||
var_name = js.variable_of({{ item }}) | ||
vars = [ | ||
{{ initial_var }} | ||
] | ||
|
||
res = _compile_destructuring {{ item }}, var_name, "#{condition_var_name}[#{{{ index }}}]" | ||
if res | ||
condition += " && " + res[1] | ||
vars.concat(res[0]) | ||
end | ||
|
||
vars | ||
end | ||
|
||
def _compile(node : Ast::ArrayDestructuring, start_variable : String, condition_variable : String? = nil) | ||
variable = "#{start_variable}__arr" | ||
|
||
condition_var_name = condition_variable || start_variable | ||
if node.spread? | ||
statements = [ | ||
"const __ = Array.from(#{value})", | ||
] | ||
|
||
node | ||
.items | ||
.take_while(&.is_a?(Ast::Variable)) | ||
.each do |var| | ||
statements << "const #{js.variable_of(var)} = __.shift()" | ||
end | ||
|
||
node | ||
.items | ||
.reverse | ||
.take_while(&.is_a?(Ast::Variable)) | ||
.each do |var| | ||
statements << "const #{js.variable_of(var)} = __.pop()" | ||
end | ||
|
||
statements << "const #{js.variable_of(node.items.select(Ast::Spread).first.variable)} = __" | ||
statements | ||
condition = "Array.isArray(#{condition_var_name}) && #{condition_var_name}.length >== #{node.items.size - 1}" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can be |
||
else | ||
variables = | ||
node | ||
condition = "Array.isArray(#{condition_var_name}) && #{condition_var_name}.length === #{node.items.size}" | ||
end | ||
|
||
variables = [ | ||
"const #{variable} = Array.from(#{start_variable})", | ||
] + ( | ||
unless node.spread? | ||
node.items.map_with_index do |item, index1| | ||
compile_item! "const #{var_name} = #{variable}[#{index1}]" | ||
end.flatten | ||
else | ||
tmp = [] of Array(String) | ||
|
||
start_vars = node | ||
.items | ||
.join(',') { |param| js.variable_of(param) } | ||
.take_while { |item| !item.is_a?(Ast::Spread) } | ||
.map_with_index do |item, index1| | ||
compile_item! "const #{var_name} = #{variable}.shift()" | ||
end | ||
|
||
["const [#{variables}] = #{value}"] | ||
end | ||
end_vars = node | ||
.items | ||
.reverse | ||
.take_while { |item| !item.is_a?(Ast::Spread) } | ||
.map_with_index do |item, index1| | ||
compile_item! "const #{var_name} = #{variable}.pop()" | ||
end | ||
|
||
tmp += start_vars if start_vars | ||
tmp += end_vars if end_vars | ||
|
||
tmp << ["const #{js.variable_of(node.items.select(Ast::Spread).first.variable)} = #{variable}"] | ||
tmp.flatten | ||
end | ||
) | ||
|
||
{variables, condition} | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
module Mint | ||
class Compiler | ||
def _compile_destructuring(node : Ast::Node, variable : String, condition_variable : String? = nil) | ||
case node | ||
when Ast::ArrayDestructuring | ||
_compile node, variable, condition_variable | ||
when Ast::TupleDestructuring | ||
_compile node, variable, condition_variable | ||
when Ast::EnumDestructuring | ||
_compile node, variable, condition_variable | ||
else | ||
# ignore | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
module Mint | ||
class Compiler | ||
def _compile(node : Ast::EnumDestructuring, variable : String, condition_variable : String? = nil) | ||
name = | ||
js.class_of(lookups[node]) | ||
|
||
condition_var_name = condition_variable || variable | ||
condition = "#{condition_var_name} instanceof #{name}" | ||
|
||
variables = node.parameters.map_with_index do |param, index1| | ||
var_name = js.variable_of(param) | ||
vars = ["const #{var_name} = #{variable}._#{index1}"] | ||
|
||
res = _compile_destructuring param, var_name, "#{condition_var_name}._#{index1}" | ||
|
||
if res | ||
condition += " && " + res[1] | ||
vars.concat(res[0]) | ||
end | ||
|
||
vars | ||
end.flatten | ||
|
||
{variables, condition} | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
module Mint | ||
class Compiler | ||
def _compile(node : Ast::TupleDestructuring, variable : String, condition_variable : String? = nil) : {Array(String), String} | ||
condition_var_name = condition_variable || variable | ||
condition = "Array.isArray(#{condition_var_name})" | ||
|
||
variables = | ||
node.parameters.map_with_index do |param, index1| | ||
var_name = js.variable_of(param) | ||
vars = ["const #{var_name} = #{variable}[#{index1}]"] | ||
|
||
res = _compile_destructuring param, var_name, "#{condition_var_name}[#{index1}]" | ||
|
||
if res | ||
condition += " && " + res[1] | ||
vars.concat(res[0]) | ||
end | ||
|
||
vars | ||
end.flatten | ||
|
||
{variables, condition} | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
message EnumDestructuringExpectedClosingParentheses do | ||
title "Syntax Error" | ||
|
||
block do | ||
text "I was looing for the" | ||
code ")" | ||
text "after paranthesed parameter in enum destructuring, but found" | ||
code got | ||
text "instead." | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,7 @@ module Mint | |
start do |start_position| | ||
head = start do | ||
skip unless char! '[' | ||
value = variable || spread | ||
value = enum_destructuring || tuple_destructuring || array_destructuring || variable || spread | ||
whitespace | ||
keyword "," | ||
whitespace | ||
|
@@ -16,8 +16,8 @@ module Mint | |
skip unless head | ||
|
||
items = | ||
[head.as(Ast::Node)].concat(list(terminator: ']', separator: ',') do | ||
variable || spread | ||
[head.as(Ast::ArrayDestructuring::ArrayDestructuringItem)].concat(list(terminator: ']', separator: ',') do | ||
value = enum_destructuring || tuple_destructuring || array_destructuring || variable || spread | ||
end.compact) | ||
|
||
whitespace | ||
|
@@ -31,5 +31,8 @@ module Mint | |
input: data) | ||
end | ||
end | ||
|
||
def parse_destructuring_item | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Left over empty method. |
||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ module Mint | |
class Parser | ||
syntax_error EnumDestructuringExpectedDoubleColon | ||
syntax_error EnumDestructuringExpectedOption | ||
syntax_error EnumDestructuringExpectedClosingParentheses | ||
|
||
def enum_destructuring | ||
start do |start_position| | ||
|
@@ -11,7 +12,16 @@ module Mint | |
|
||
option = type_id! EnumDestructuringExpectedOption | ||
|
||
parameters = many { type_variable }.compact | ||
parameters = (many do | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should have only one syntax, in this case with parentheses. This will be a breaking change, but would fix the else branch since there it's not possible to inner destructure. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we want to have a comma between parameters? |
||
if char == '(' | ||
parended = char! '(' | ||
param = enum_destructuring || tuple_destructuring || array_destructuring || type_variable | ||
char(')', EnumDestructuringExpectedClosingParentheses) if parended | ||
else | ||
param = type_variable.try(&.as Ast::Node) | ||
end | ||
param | ||
end).compact | ||
|
||
Ast::EnumDestructuring.new( | ||
parameters: parameters, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not necessary and should be replaced with
Node