diff --git a/src/ast/enum_destructuring.cr b/src/ast/enum_destructuring.cr index 19942e99a..511f1b250 100644 --- a/src/ast/enum_destructuring.cr +++ b/src/ast/enum_destructuring.cr @@ -3,7 +3,7 @@ module Mint class EnumDestructuring < Node getter name, option, parameters - def initialize(@parameters : Array(TypeVariable), + def initialize(@parameters : Array(Node), @option : String, @name : String, @input : Data, diff --git a/src/ast/tuple_destructuring.cr b/src/ast/tuple_destructuring.cr index 42e29b17a..c0f82b2b4 100644 --- a/src/ast/tuple_destructuring.cr +++ b/src/ast/tuple_destructuring.cr @@ -3,7 +3,7 @@ module Mint class TupleDestructuring < Node getter parameters - def initialize(@parameters : Array(Variable), + def initialize(@parameters : Array(Node), @input : Data, @from : Int32, @to : Int32) diff --git a/src/compilers/array_destructuring.cr b/src/compilers/array_destructuring.cr index fbefa1562..7bd5724ce 100644 --- a/src/compilers/array_destructuring.cr +++ b/src/compilers/array_destructuring.cr @@ -1,10 +1,9 @@ module Mint class Compiler - def _compile(node : Ast::ArrayDestructuring, value) + def _compile(node : Ast::ArrayDestructuring, variable : String) : Tuple(String, Array(String)) + statements = [] of String if node.spread? - statements = [ - "const __ = Array.from(#{value})", - ] + statements << "const __ = Array.from(#{variable})" node .items @@ -22,15 +21,25 @@ module Mint end statements << "const #{js.variable_of(node.items.select(Ast::Spread).first.variable)} = __" - statements else variables = node .items .join(',') { |param| js.variable_of(param) } - ["const [#{variables}] = #{value}"] + statements << "const [#{variables}] = #{variable}" end + condition = + if node.spread? + "Array.isArray(#{variable}) && #{variable}.length >= #{node.items.size - 1}" + else + "Array.isArray(#{variable}) && #{variable}.length === #{node.items.size}" + end + + { + condition, + statements, + } end end end diff --git a/src/compilers/case_branch.cr b/src/compilers/case_branch.cr index 15c6c36d3..9eb7374ee 100644 --- a/src/compilers/case_branch.cr +++ b/src/compilers/case_branch.cr @@ -21,55 +21,14 @@ module Mint if match = node.match case match - when Ast::ArrayDestructuring - statements = + when Ast::ArrayDestructuring, Ast::TupleDestructuring, Ast::EnumDestructuring + compiled = _compile(match, variable) - statements << expression - - if match.spread? - { - "Array.isArray(#{variable}) && #{variable}.length >= #{match.items.size - 1}", - js.statements(statements), - } - else - { - "Array.isArray(#{variable}) && #{variable}.length === #{match.items.size}", - js.statements(statements), - } - end - when Ast::TupleDestructuring - variables = - match - .parameters - .join(',') { |param| js.variable_of(param) } - - { - "Array.isArray(#{variable})", - js.statements([ - "const [#{variables}] = #{variable}", - expression, - ]), - } - when Ast::EnumDestructuring - variables = - case lookups[match].as(Ast::EnumOption).parameters[0]? - when Ast::EnumRecordDefinition - match.parameters.map do |param| - "const #{js.variable_of(param)} = #{variable}._0.#{param.value}" - end - else - match.parameters.map_with_index do |param, index1| - "const #{js.variable_of(param)} = #{variable}._#{index1}" - end - end - - name = - js.class_of(lookups[match]) - + compiled[1] << expression { - "#{variable} instanceof #{name}", - js.statements(variables + [expression]), + compiled[0], + js.statements(compiled[1]), } else compiled = diff --git a/src/compilers/enum_destructuring.cr b/src/compilers/enum_destructuring.cr new file mode 100644 index 000000000..b012efa94 --- /dev/null +++ b/src/compilers/enum_destructuring.cr @@ -0,0 +1,28 @@ +module Mint + class Compiler + def _compile(node : Ast::EnumDestructuring, variable : String) : Tuple(String, Array(String)) + variables = + case lookups[node].as(Ast::EnumOption).parameters[0]? + when Ast::EnumRecordDefinition + node.parameters.compact_map do |param| + case param + when Ast::TypeVariable + "const #{js.variable_of(param)} = #{variable}._0.#{param.value}" + end + end + else + node.parameters.map_with_index do |param, index1| + "const #{js.variable_of(param)} = #{variable}._#{index1}" + end + end + + name = + js.class_of(lookups[node]) + + { + "#{variable} instanceof #{name}", + variables, + } + end + end +end diff --git a/src/compilers/tuple_destructuring.cr b/src/compilers/tuple_destructuring.cr new file mode 100644 index 000000000..083ace54e --- /dev/null +++ b/src/compilers/tuple_destructuring.cr @@ -0,0 +1,15 @@ +module Mint + class Compiler + def _compile(node : Ast::TupleDestructuring, variable : String) : Tuple(String, Array(String)) + variables = + node + .parameters + .join(',') { |param| js.variable_of(param) } + + { + "Array.isArray(#{variable})", + ["const [#{variables}] = #{variable}"], + } + end + end +end diff --git a/src/parsers/enum_destructuring.cr b/src/parsers/enum_destructuring.cr index d841af868..cbc06cb07 100644 --- a/src/parsers/enum_destructuring.cr +++ b/src/parsers/enum_destructuring.cr @@ -12,7 +12,7 @@ module Mint option = type_id! EnumDestructuringExpectedOption - parameters = [] of Ast::TypeVariable + parameters = [] of Ast::Node if char! '(' parameters.concat list( diff --git a/src/parsers/tuple_destructuring.cr b/src/parsers/tuple_destructuring.cr index 903decbbe..bcebdaa37 100644 --- a/src/parsers/tuple_destructuring.cr +++ b/src/parsers/tuple_destructuring.cr @@ -15,8 +15,9 @@ module Mint skip unless head - parameters = [head].concat( - list(terminator: '}', separator: ',') { variable }) + parameters = [] of Ast::Node + parameters << head + parameters.concat(list(terminator: '}', separator: ',') { variable }) whitespace diff --git a/src/type_checkers/case_branch.cr b/src/type_checkers/case_branch.cr index 90f63ff59..39fbe14d1 100644 --- a/src/type_checkers/case_branch.cr +++ b/src/type_checkers/case_branch.cr @@ -45,17 +45,7 @@ module Mint "node" => node, } if spreads > 1 - variables = - item.items.compact_map do |variable| - case variable - when Ast::Variable - {variable.value, condition.parameters[0], variable} - when Ast::Spread - {variable.variable.value, condition, variable.variable} - end - end - - scope(variables) do + scope(destructuring_variables(item, condition)) do resolve_expression(node) end when Ast::TupleDestructuring @@ -70,57 +60,79 @@ module Mint "node" => item, } if item.parameters.size > condition.parameters.size - variables = - item.parameters.map_with_index do |variable, index| - {variable.value, condition.parameters[index], variable} - end - - scope(variables) do + scope(destructuring_variables(item, condition)) do resolve_expression(node) end when Ast::EnumDestructuring check_match(item, condition) - entity = - ast.enums.find(&.name.==(item.name)).not_nil! - - option = - entity.options.find(&.value.==(item.option)).not_nil! + scope(destructuring_variables(item, condition)) do + resolve_expression(node) + end + else + check_match(item, condition) + end + end || resolve_expression(node) + end - variables = - case option_param = option.parameters[0]? - when Ast::EnumRecordDefinition - item.parameters.map do |param| - record = - resolve(option_param).as(Record) + private def destructuring_variables(item : Ast::EnumDestructuring, condition) + entity = + ast.enums.find(&.name.==(item.name)).not_nil! - {param.value, record.fields[param.value], param} - end - else - item.parameters.map_with_index do |param, index| - option_type = - resolve(option.parameters[index]).not_nil! + option = + entity.options.find(&.value.==(item.option)).not_nil! - mapping = {} of String => Checkable + case option_param = option.parameters[0]? + when Ast::EnumRecordDefinition + item.parameters.compact_map do |param| + case param + when Ast::TypeVariable + record = + resolve(option_param).as(Record) - entity.parameters.each_with_index do |param2, index2| - mapping[param2.value] = condition.parameters[index2] - end + {param.value, record.fields[param.value], param} + end + end + else + item.parameters.map_with_index do |param, index| + case param + when Ast::TypeVariable + option_type = + resolve(option.parameters[index]).not_nil! - resolved_type = - Comparer.fill(option_type, mapping) + mapping = {} of String => Checkable - {param.value, resolved_type.not_nil!, param} - end + entity.parameters.each_with_index do |param2, index2| + mapping[param2.value] = condition.parameters[index2] end - scope(variables) do - resolve_expression(node) + resolved_type = + Comparer.fill(option_type, mapping) + + {param.value, resolved_type.not_nil!, param} end - else - check_match(item, condition) + end.compact + end + end + + private def destructuring_variables(item : Ast::TupleDestructuring, condition) + item.parameters.map_with_index do |variable, index| + case variable + when Ast::Variable + {variable.value, condition.parameters[index], variable} end - end || resolve_expression(node) + end.compact + end + + private def destructuring_variables(item : Ast::ArrayDestructuring, condition) + item.items.compact_map do |variable| + case variable + when Ast::Variable + {variable.value, condition.parameters[0], variable} + when Ast::Spread + {variable.variable.value, condition, variable.variable} + end + end end end end diff --git a/src/type_checkers/scope.cr b/src/type_checkers/scope.cr index f9885fe35..98c111e93 100644 --- a/src/type_checkers/scope.cr +++ b/src/type_checkers/scope.cr @@ -120,7 +120,7 @@ module Mint when Ast::Variable node if target.value == variable when Ast::TupleDestructuring - target.parameters.find(&.value.==(variable)).try do |item| + target.parameters.select(Ast::Variable).find(&.value.==(variable)).try do |item| {node, target.parameters.index(item).not_nil!} end end @@ -131,7 +131,7 @@ module Mint when Ast::Variable node if target.value == variable when Ast::TupleDestructuring - target.parameters.find(&.value.==(variable)).try do |item| + target.parameters.select(Ast::Variable).find(&.value.==(variable)).try do |item| {node, target.parameters.index(item).not_nil!} end end