Skip to content

Commit

Permalink
Allow using range for param type
Browse files Browse the repository at this point in the history
  • Loading branch information
RoyalIcing committed Dec 5, 2023
1 parent f006049 commit 42038c8
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 18 deletions.
67 changes: 49 additions & 18 deletions lib/orb/dsl.ex
Original file line number Diff line number Diff line change
Expand Up @@ -91,42 +91,71 @@ defmodule Orb.DSL do
:private -> []
end

params =
# update_in(args.foo, fn a -> a + 1 end)

{param_types, runtime_checks} =
case args do
[] ->
[]
{[], []}

# Keywords
[args] when is_list(args) ->
for {name, type} <- args do
Macro.escape(%Orb.Func.Param{name: name, type: Macro.expand_literals(type, env)})
end
alias Orb.I32

%{types: types, checks: checks} =
for {name, type} <- args, reduce: %{types: [], checks: []} do
%{types: types, checks: checks} ->
{type, check} =
case Macro.expand_literals(type, env) do
# Range
{:.., _, [min, max]} when min <= max ->
{I32,
Orb.DSL.assert!(
I32.band(
Orb.Instruction.local_get(I32, name) |> I32.ge_s(min),
Orb.Instruction.local_get(I32, name) |> I32.le_s(max)
)
)
|> Macro.escape()}

type when is_atom(type) ->
{type, nil}
end

types = [{name, type} | types]

checks =
case check do
nil ->
checks

check ->
[check | checks]
end

%{types: types, checks: checks}
end

{Enum.reverse(types), Enum.reverse(checks)}

[_ | _] ->
raise CompileError,
line: line,
file: env.file,
description:
"Cannot define function with multiple arguments, use keyword list instead."
description: "Function params must use keyword list."
end

param_types =
case args do
[] ->
[]

# Keywords
[args] when is_list(args) ->
for {name, type} <- args do
{name, Macro.expand_literals(type, env)}
end
params =
for {name, type} <- param_types do
Macro.escape(%Orb.Func.Param{name: name, type: type})
end

result_type = Keyword.get(options, :result, nil) |> Macro.expand_literals(env)

local_types =
for {key, type} <- Keyword.get(options, :locals, []) do
{key, Macro.expand_literals(type, env)}
type = Macro.expand_literals(type, env)
{key, type}
end

locals = Map.new(param_types ++ local_types)
Expand All @@ -142,6 +171,8 @@ defmodule Orb.DSL do
block_items = Macro.expand(block_items, env)
block_items = do_snippet(locals, block_items)

block_items = runtime_checks ++ block_items

quote do
%Orb.Func{
name:
Expand Down
33 changes: 33 additions & 0 deletions test/orb_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,39 @@ defmodule OrbTest do
assert {0.0, 0.5, 1.0} === Wasm.call(TupleTypes, :rgb_reverse, 1.0, 0.5, 0.0)
end

test "range-bounded params" do
defmodule RangeBounded do
use Orb

defw two_to_five(a: 2..5), I32 do
# guard when a >= 2 and a <= 5, else: unreachable()
# unreachable! unless a >= 2 and a <= 5
# assert!(a >= 2 &&& a <= 5)
# assert!(a in 2..5)
# assert! do
# a in 2..5
# b in 2..5
# end

a
end
end

wat = RangeBounded.to_wat()
assert wat =~ "unreachable"
assert wat =~ "(i32.ge_s (local.get $a) (i32.const 2))"
assert wat =~ "(i32.le_s (local.get $a) (i32.const 5))"

alias OrbWasmtime.Wasm
assert 2 = Wasm.call(RangeBounded, :two_to_five, 2)
assert 3 = Wasm.call(RangeBounded, :two_to_five, 3)
assert 4 = Wasm.call(RangeBounded, :two_to_five, 4)
assert 5 = Wasm.call(RangeBounded, :two_to_five, 5)
assert {:error, _} = Wasm.call(RangeBounded, :two_to_five, 0)
assert {:error, _} = Wasm.call(RangeBounded, :two_to_five, 1)
assert {:error, _} = Wasm.call(RangeBounded, :two_to_five, 6)
end

test "loop" do
defmodule FileNameSafe do
use Orb
Expand Down

0 comments on commit 42038c8

Please sign in to comment.