Skip to content
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

Refactorings working towards nested destructuring #428

Merged
merged 4 commits into from
May 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/ast/enum_destructuring.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/ast/tuple_destructuring.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
21 changes: 15 additions & 6 deletions src/compilers/array_destructuring.cr
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
51 changes: 5 additions & 46 deletions src/compilers/case_branch.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
28 changes: 28 additions & 0 deletions src/compilers/enum_destructuring.cr
Original file line number Diff line number Diff line change
@@ -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
15 changes: 15 additions & 0 deletions src/compilers/tuple_destructuring.cr
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion src/parsers/enum_destructuring.cr
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module Mint

option = type_id! EnumDestructuringExpectedOption

parameters = [] of Ast::TypeVariable
parameters = [] of Ast::Node

if char! '('
parameters.concat list(
Expand Down
5 changes: 3 additions & 2 deletions src/parsers/tuple_destructuring.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
106 changes: 59 additions & 47 deletions src/type_checkers/case_branch.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
4 changes: 2 additions & 2 deletions src/type_checkers/scope.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down