From 2e6f5967fb4b1e2fddeb6635e5e40d1f61ad5211 Mon Sep 17 00:00:00 2001 From: matthewmcgarvey Date: Wed, 19 May 2021 16:42:00 -0400 Subject: [PATCH 1/4] Refactor TypeChecker#check for Ast::CaseBranch Prepare for extra code to extract variables and recurse --- src/type_checkers/case_branch.cr | 99 ++++++++++++++++---------------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/src/type_checkers/case_branch.cr b/src/type_checkers/case_branch.cr index 90f63ff59..55bd939d8 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,70 @@ 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! + scope(destructuring_variables(item, condition)) do + resolve_expression(node) + end + else + check_match(item, condition) + end + end || resolve_expression(node) + end - option = - entity.options.find(&.value.==(item.option)).not_nil! + private def destructuring_variables(item : Ast::EnumDestructuring, condition) + entity = + ast.enums.find(&.name.==(item.name)).not_nil! - variables = - case option_param = option.parameters[0]? - when Ast::EnumRecordDefinition - item.parameters.map do |param| - record = - resolve(option_param).as(Record) + option = + entity.options.find(&.value.==(item.option)).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! + case option_param = option.parameters[0]? + when Ast::EnumRecordDefinition + item.parameters.map do |param| + record = + resolve(option_param).as(Record) - mapping = {} of String => Checkable + {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! - entity.parameters.each_with_index do |param2, index2| - mapping[param2.value] = condition.parameters[index2] - end + mapping = {} of String => Checkable - resolved_type = - Comparer.fill(option_type, mapping) + entity.parameters.each_with_index do |param2, index2| + mapping[param2.value] = condition.parameters[index2] + end - {param.value, resolved_type.not_nil!, param} - end - end + resolved_type = + Comparer.fill(option_type, mapping) - scope(variables) do - resolve_expression(node) - end - else - check_match(item, condition) + {param.value, resolved_type.not_nil!, param} end - end || resolve_expression(node) + end + end + + private def destructuring_variables(item : Ast::TupleDestructuring, condition) + item.parameters.map_with_index do |variable, index| + {variable.value, condition.parameters[index], variable} + end + 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 From cb82d957df41ed4490ea90d5e77ac1ec054969ca Mon Sep 17 00:00:00 2001 From: matthewmcgarvey Date: Thu, 20 May 2021 20:04:18 -0400 Subject: [PATCH 2/4] Update Ast::TupleDestructuring#parameters to nodes --- src/ast/tuple_destructuring.cr | 2 +- src/parsers/tuple_destructuring.cr | 5 +++-- src/type_checkers/case_branch.cr | 7 +++++-- src/type_checkers/scope.cr | 4 ++-- 4 files changed, 11 insertions(+), 7 deletions(-) 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/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 55bd939d8..7a33570fa 100644 --- a/src/type_checkers/case_branch.cr +++ b/src/type_checkers/case_branch.cr @@ -111,8 +111,11 @@ module Mint private def destructuring_variables(item : Ast::TupleDestructuring, condition) item.parameters.map_with_index do |variable, index| - {variable.value, condition.parameters[index], variable} - end + case variable + when Ast::Variable + {variable.value, condition.parameters[index], variable} + end + end.compact end private def destructuring_variables(item : Ast::ArrayDestructuring, condition) 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 From 770d2300d976de85ead9827ac378d84329387317 Mon Sep 17 00:00:00 2001 From: matthewmcgarvey Date: Thu, 20 May 2021 22:18:25 -0400 Subject: [PATCH 3/4] Update Ast::EnumDestructuring#parameters to Nodes --- src/ast/enum_destructuring.cr | 2 +- src/compilers/case_branch.cr | 7 +++++-- src/parsers/enum_destructuring.cr | 2 +- src/type_checkers/case_branch.cr | 34 ++++++++++++++++++------------- 4 files changed, 27 insertions(+), 18 deletions(-) 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/compilers/case_branch.cr b/src/compilers/case_branch.cr index 15c6c36d3..0d1e13661 100644 --- a/src/compilers/case_branch.cr +++ b/src/compilers/case_branch.cr @@ -55,8 +55,11 @@ module Mint 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}" + match.parameters.compact_map do |param| + case param + when Ast::TypeVariable + "const #{js.variable_of(param)} = #{variable}._0.#{param.value}" + end end else match.parameters.map_with_index do |param, index1| 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/type_checkers/case_branch.cr b/src/type_checkers/case_branch.cr index 7a33570fa..39fbe14d1 100644 --- a/src/type_checkers/case_branch.cr +++ b/src/type_checkers/case_branch.cr @@ -84,28 +84,34 @@ module Mint case option_param = option.parameters[0]? when Ast::EnumRecordDefinition - item.parameters.map do |param| - record = - resolve(option_param).as(Record) + item.parameters.compact_map do |param| + case param + when Ast::TypeVariable + record = + resolve(option_param).as(Record) - {param.value, record.fields[param.value], param} + {param.value, record.fields[param.value], param} + end end else item.parameters.map_with_index do |param, index| - option_type = - resolve(option.parameters[index]).not_nil! + case param + when Ast::TypeVariable + option_type = + resolve(option.parameters[index]).not_nil! - mapping = {} of String => Checkable + mapping = {} of String => Checkable - entity.parameters.each_with_index do |param2, index2| - mapping[param2.value] = condition.parameters[index2] - end + entity.parameters.each_with_index do |param2, index2| + mapping[param2.value] = condition.parameters[index2] + end - resolved_type = - Comparer.fill(option_type, mapping) + resolved_type = + Comparer.fill(option_type, mapping) - {param.value, resolved_type.not_nil!, param} - end + {param.value, resolved_type.not_nil!, param} + end + end.compact end end From f079ff0782c48f260a9000f154083658f1e19586 Mon Sep 17 00:00:00 2001 From: matthewmcgarvey Date: Thu, 20 May 2021 22:31:19 -0400 Subject: [PATCH 4/4] Extract _compile methods for case branch destructuring types --- src/compilers/array_destructuring.cr | 21 +++++++---- src/compilers/case_branch.cr | 54 +++------------------------- src/compilers/enum_destructuring.cr | 28 +++++++++++++++ src/compilers/tuple_destructuring.cr | 15 ++++++++ 4 files changed, 63 insertions(+), 55 deletions(-) create mode 100644 src/compilers/enum_destructuring.cr create mode 100644 src/compilers/tuple_destructuring.cr 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 0d1e13661..9eb7374ee 100644 --- a/src/compilers/case_branch.cr +++ b/src/compilers/case_branch.cr @@ -21,58 +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.compact_map do |param| - case param - when Ast::TypeVariable - "const #{js.variable_of(param)} = #{variable}._0.#{param.value}" - end - 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