Packages
orb
0.0.45
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 pop_type: nil,
push_type: nil,
condition: nil,
when_true: nil,
when_false: nil
alias Orb.Ops
alias Orb.InstructionSequence
def new(%InstructionSequence{body: [if_else = %__MODULE__{}]}, concat_true) do
new(if_else, concat_true)
end
def new(if_else = %__MODULE__{}, concat_true) when is_struct(concat_true) do
when_true = InstructionSequence.concat(if_else.when_true, concat_true)
new(if_else.condition, when_true, if_else.when_false)
end
def new(condition, when_true) when is_struct(when_true) do
{_, type} = Ops.pop_push_of(when_true)
new(type, condition, when_true, nil)
end
def new(%InstructionSequence{body: [if_else = %__MODULE__{}]}, concat_true, concat_false) do
new(if_else, concat_true, concat_false)
end
def new(if_else = %__MODULE__{}, concat_true, concat_false)
when is_struct(concat_true) and is_struct(concat_false) do
when_true = InstructionSequence.concat(if_else.when_true, concat_true)
when_false = InstructionSequence.concat(if_else.when_false, concat_false)
new(if_else.condition, when_true, when_false)
end
def new(condition, when_true, %InstructionSequence{body: []})
when is_struct(when_true) do
new(condition, when_true)
end
def new(condition, when_true, when_false) when is_struct(when_true) and is_struct(when_false) do
case {Ops.pop_push_of(when_true), Ops.pop_push_of(when_false)} do
{same, same = {nil, push_type}} ->
new(push_type, condition, when_true, when_false)
{{nil, push_true}, {nil, push_false}} ->
cond do
Ops.types_compatible?(push_true, push_false) ->
new(push_true, condition, when_true, when_false)
true ->
raise Orb.TypeCheckError,
expected_type: push_true,
received_type: push_false,
instruction_identifier: :if
end
_ ->
raise ArgumentError,
"Cannot pop within if/else"
end
end
def new(result, condition, when_true, when_false)
when is_struct(when_false) or is_nil(when_false) do
%__MODULE__{
push_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
defimpl Orb.ToWat do
import Orb.ToWat.Helpers
require Orb.Ops |> alias
def to_wat(
%Orb.IfElse{
push_type: result,
condition: condition,
when_true: when_true,
when_false: when_false
} = ast,
indent
)
when not is_nil(condition) do
[
Orb.ToWat.to_wat(condition, indent),
[
"\n",
indent,
"(if",
case result do
nil -> ""
type -> [" (result ", do_type(type), ")"]
end,
?\n
],
[" ", indent, "(then", ?\n],
Orb.ToWat.to_wat(when_true, " " <> indent),
[" ", indent, ")", ?\n],
if when_false do
[
[" ", indent, "(else", ?\n],
Orb.ToWat.to_wat(when_false, " " <> indent),
[" ", indent, ")", ?\n]
]
else
[]
end,
[indent, ")"]
]
rescue
exception in [Orb.CustomType.InvalidError] ->
reraise Orb.ToWat.Error, [value: ast, exception: exception], __STACKTRACE__
# reraise exception, __STACKTRACE__
end
end
defimpl Orb.TypeNarrowable do
def type_narrow_to(%Orb.IfElse{push_type: current_type} = if_else, narrower_type) do
case Ops.types_compatible?(current_type, narrower_type) do
true ->
%{
if_else
| push_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
import Kernel, except: [if: 2, unless: 2]
require InstructionSequence |> alias
# Multi-line
defmacro if(condition, [result: result], do: when_true, else: when_false) do
quote bind_quoted: [
condition: condition,
result: result,
when_true: Orb.__get_block_items(when_true),
when_false: Orb.__get_block_items(when_false)
] do
Orb.IfElse.new(
result,
condition,
InstructionSequence.new(when_true),
InstructionSequence.new(when_false)
)
end
end
# Single-line
defmacro if(condition, result: result, do: when_true, else: when_false) do
quote bind_quoted: [
result: result,
condition: condition,
when_true: when_true,
when_false: when_false
] do
Orb.IfElse.new(result, condition, when_true, when_false)
end
end
defmacro if(condition, do: when_true, else: when_false) do
quote bind_quoted: [
condition: condition,
when_true: Orb.__get_block_items(when_true),
when_false: Orb.__get_block_items(when_false)
] do
Orb.IfElse.new(
condition,
InstructionSequence.new(when_true),
InstructionSequence.new(when_false)
)
end
end
defmacro if(condition, do: when_true) do
quote bind_quoted: [
condition: condition,
when_true: Orb.__get_block_items(when_true)
] do
Orb.IfElse.new(
condition,
InstructionSequence.new(when_true)
)
end
end
defmacro unless(condition, clauses) do
build_unless(condition, clauses)
end
defp build_unless(condition, do: when_false) do
quote bind_quoted: [
condition: condition,
when_false: Orb.__get_block_items(when_false)
] do
Orb.IfElse.new(
condition,
InstructionSequence.empty(),
InstructionSequence.new(when_false)
)
end
end
defp build_unless(condition, do: when_false, else: when_true) do
quote bind_quoted: [
condition: condition,
when_true: Orb.__get_block_items(when_true),
when_false: Orb.__get_block_items(when_false)
] do
Orb.IfElse.new(
condition,
InstructionSequence.new(when_true),
InstructionSequence.new(when_false)
)
end
end
end
end