Packages
orb
0.0.30
0.2.2
0.2.1
0.2.0
0.1.1
0.1.0
0.0.51
0.0.49
0.0.48
0.0.47
0.0.46
0.0.45
0.0.44
0.0.43
0.0.42
0.0.41
0.0.40
0.0.39
0.0.38
0.0.37
0.0.36
0.0.35
0.0.34
0.0.33
0.0.32
0.0.31
0.0.30
0.0.28
0.0.27
0.0.26
0.0.25
0.0.24
0.0.23
0.0.22
0.0.21
0.0.20
0.0.19
0.0.18
0.0.17
0.0.16
0.0.15
0.0.14
0.0.13
0.0.12
retired
0.0.11
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.3
0.0.2
0.0.1
DSL for WebAssembly
Current section
Files
Jump to
Current section
Files
lib/orb/if_else.ex
defmodule Orb.IfElse do
@moduledoc false
defstruct type: :unknown_effect, condition: nil, when_true: nil, when_false: nil
alias Orb.Ops
# def new(:i32, condition, {:i32_const, a}, {:i32_const, b}) do
# [
# a,
# b,
# condition,
# :select!
# ]
# end
def new(condition, when_true) do
type = Ops.typeof(when_true)
new_unchecked(type, optimize_condition(condition), when_true, nil)
end
def new(condition, when_true, when_false) do
type = Ops.extract_common_type(when_true, when_false)
case type do
nil ->
raise Orb.TypeCheckError,
expected_type: Ops.typeof(when_true),
received_type: Ops.typeof(when_false),
instruction_identifier: "if/else"
type ->
new_unchecked(type, optimize_condition(condition), when_true, when_false)
end
end
def new(result, condition, when_true, when_false)
when not is_nil(result) and not is_nil(when_false) do
new_unchecked(result, optimize_condition(condition), when_true, when_false)
end
defp new_unchecked(result, condition, when_true, when_false) when not is_nil(result) do
%__MODULE__{
type: result,
condition: condition,
when_true: when_true,
when_false: when_false
}
end
def expand(%__MODULE__{} = statement) do
when_true = statement.when_true |> Orb.Constants.expand_if_needed()
when_false = statement.when_false |> Orb.Constants.expand_if_needed()
%{statement | when_true: when_true, when_false: when_false}
end
# TODO: probably remove this.
defp optimize_condition({:i32, :gt_u, {n, 0}}), do: n
defp optimize_condition(condition), do: condition
defimpl Orb.ToWat do
import Orb.ToWat.Helpers
alias Orb.ToWat.Instructions
require Orb.Ops |> alias
def to_wat(
%Orb.IfElse{
type: result,
condition: condition,
when_true: when_true,
when_false: when_false
},
indent
)
when not is_nil(condition) do
[
Instructions.do_wat(condition, indent),
[
"\n",
indent,
"(if",
case result do
effect when Ops.is_effect(effect) -> ""
type -> [" (result ", do_type(type), ")"]
end,
?\n
],
[" ", indent, "(then", ?\n],
Instructions.do_wat(when_true, " " <> indent),
[" ", indent, ")", ?\n],
if when_false do
[
[" ", indent, "(else", ?\n],
Instructions.do_wat(when_false, " " <> indent),
[" ", indent, ")", ?\n]
]
else
[]
end,
[indent, ")"]
]
end
end
defimpl Orb.TypeNarrowable do
def type_narrow_to(%Orb.IfElse{type: current_type} = if_else, narrower_type) do
case Ops.types_compatible?(current_type, narrower_type) do
true ->
%{
if_else
| type: narrower_type,
when_true: Orb.TypeNarrowable.type_narrow_to(if_else.when_true, narrower_type),
when_false: Orb.TypeNarrowable.type_narrow_to(if_else.when_false, narrower_type)
}
false ->
# raise "Incompatible types Elixir.Integer and #{inspect(narrower_type)}."
if_else
end
end
def type_narrow_to(%Orb.IfElse{} = if_else, _), do: if_else
end
defmodule DSL do
@moduledoc false
alias Orb.InstructionSequence
import Kernel, except: [if: 2]
require Orb.InstructionSequence |> alias
# Multi-line
defmacro if(condition, [result: result], do: when_true, else: when_false) do
quote do
Orb.IfElse.new(
unquote(result),
unquote(condition),
unquote(Orb.__get_block_items(when_true)) |> InstructionSequence.new(),
unquote(Orb.__get_block_items(when_false)) |> InstructionSequence.new()
)
end
end
# Single-line
defmacro if(condition, result: result, do: when_true, else: when_false) do
quote do
Orb.IfElse.new(
unquote(result),
unquote(condition),
unquote(when_true),
unquote(when_false)
)
end
end
defmacro if(condition, do: when_true, else: when_false) do
quote do
Orb.IfElse.new(
unquote(condition),
unquote(Orb.__get_block_items(when_true)) |> InstructionSequence.new(),
unquote(Orb.__get_block_items(when_false)) |> InstructionSequence.new()
)
end
end
defmacro if(condition, do: when_true) do
quote do
Orb.IfElse.new(
unquote(condition),
unquote(Orb.__get_block_items(when_true)) |> InstructionSequence.new()
)
end
end
end
end