Skip to content

Commit

Permalink
Support accepting Str as func param
Browse files Browse the repository at this point in the history
And add [:ptr] and [:size] Access
  • Loading branch information
RoyalIcing committed Dec 11, 2024
1 parent fdb81eb commit 14bac8c
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 9 deletions.
36 changes: 28 additions & 8 deletions lib/orb/dsl/dsl.ex
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,12 @@ defmodule Orb.DSL do
%{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
{types, check} =
Macro.expand_literals(type, env)
|> case do
# Range
{:.., _, [min, max]} when min <= max ->
{I32,
{[{name, I32} | types],
Orb.DSL.assert!(
I32.band(
Orb.Instruction.local_get(I32, name) |> I32.ge_s(min),
Expand All @@ -122,11 +123,9 @@ defmodule Orb.DSL do
|> Macro.escape()}

type when is_atom(type) ->
{type, nil}
{[{name, type} | types], nil}
end

types = [{name, type} | types]

checks =
case check do
nil ->
Expand All @@ -150,8 +149,18 @@ defmodule Orb.DSL do

params =
for {name, type} <- param_types do
Macro.escape(%Orb.Func.Param{name: name, type: type})
case type do
Orb.Str ->
[
%Orb.Func.Param{name: "#{name}.ptr", type: Orb.I32.UnsafePointer},
%Orb.Func.Param{name: "#{name}.size", type: Orb.I32}
]

type ->
%Orb.Func.Param{name: name, type: type}
end
end
|> List.flatten()

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

Expand Down Expand Up @@ -198,7 +207,7 @@ defmodule Orb.DSL do
{nil, name} -> name
{prefix, name} -> "#{prefix}.#{name}"
end,
params: unquote(params),
params: unquote(Macro.escape(params)),
result: result,
local_types: local_types,
body: Orb.InstructionSequence.new(result, block_items),
Expand Down Expand Up @@ -228,6 +237,7 @@ defmodule Orb.DSL do
quote do: Orb.Instruction.local_set(unquote(locals[local]), unquote(local), unquote(input))
end

# De-structuring a tuple of two values
def do_match({{a, _, nil}, {b, _, nil}}, input, locals)
when is_local(a, locals) and is_local(b, locals) do
quote do:
Expand All @@ -240,6 +250,15 @@ defmodule Orb.DSL do
])
end

# def do_match({local, _, nil}, input, locals)
# when is_atom(local) and is_map_key(locals, local) do
# end
# {{:., _, [Access, :get]}, _,
# [
# {local, _, nil},
# [:ptr]
# ]}

# @some_global = input
def do_match({:@, _, [{global, _, nil}]}, input, _locals) do
quote do:
Expand All @@ -253,6 +272,7 @@ defmodule Orb.DSL do
def do_match(_left, _right, _locals), do: nil

def do_snippet(locals, block_items) do
# dbg(locals)
Macro.prewalk(block_items, fn
# TODO: remove this
# local[at!: delta] = value
Expand Down
13 changes: 12 additions & 1 deletion lib/orb/func.ex
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,19 @@ defmodule Orb.Func do
case args do
[args] when is_list(args) ->
for {name, type} <- args do
%Orb.Func.Param{name: name, type: Macro.expand_literals(type, env)}
Macro.expand_literals(type, env)
|> case do
# Orb.Str ->
# [
# %Orb.Func.Param{name: {name, :ptr}, type: I32.UnsafePointer},
# %Orb.Func.Param{name: {name, :size}, type: I32}
# ]

type ->
%Orb.Func.Param{name: name, type: type}
end
end
|> List.flatten()

[] ->
[]
Expand Down
6 changes: 6 additions & 0 deletions lib/orb/instruction/call.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ defmodule Orb.Instruction.Call do
{nil, []} ->
[]

{Orb.Str, [value]} when is_struct(value, Orb.VariableReference) ->
[value[:ptr], value[:size]]

{Orb.Str, [value]} ->
[Orb.Constants.expand_if_needed(value)]

{type, [value]} when is_atom(type) ->
[Orb.Instruction.Const.wrap(type, value)]

Expand Down
20 changes: 20 additions & 0 deletions lib/orb/str.ex
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,26 @@ defmodule Orb.Str do
str.memory_offset
end

# with @behaviour Access do
# @impl Access
# def fetch(%VariableReference{} = var_ref, :ptr) do
# ast = %Orb.VariableReference.Local{
# identifier:
# }
# {:ok, ast}
# end
#
# @impl Access
# def get_and_update(_data, _key, _function) do
# raise UndefinedFunctionError, module: __MODULE__, function: :get_and_update, arity: 3
# end
#
# @impl Access
# def pop(_data, _key) do
# raise UndefinedFunctionError, module: __MODULE__, function: :pop, arity: 2
# end
# end

defimpl Orb.ToWat do
def to_wat(
%Orb.Str{memory_offset: memory_offset, string: string},
Expand Down
34 changes: 34 additions & 0 deletions lib/orb/variable_reference.ex
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,40 @@ defmodule Orb.VariableReference do
end

with @behaviour Access do
# some_str[:ptr]
@impl Access
def fetch(
%__MODULE__{entries: [%Local{identifier: local_name, type: Orb.Str}]},
:ptr
) do
{:ok,
%__MODULE__{
entries: [
%Local{
identifier: "#{local_name}.ptr",
type: I32.UnsafePointer
}
]
}}
end

# some_str[:size]
@impl Access
def fetch(
%__MODULE__{entries: [%Local{identifier: local_name, type: Orb.Str}]},
:size
) do
{:ok,
%__MODULE__{
entries: [
%Local{
identifier: "#{local_name}.size",
type: I32
}
]
}}
end

@impl Access
def fetch(
%__MODULE__{entries: [%Local{type: mod}]} = var_ref,
Expand Down
38 changes: 38 additions & 0 deletions test/defw_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,44 @@ defmodule DefwTest do
end
end

test "Str argument is flattened into two params" do
defmodule AcceptStr do
use Orb

defwp str_length(a: Str), I32 do
a[:size]
end

defwp middleman(a: Str), I32 do
str_length(a)
end

defw example(), I32 do
middleman("abc")
end
end

assert ~S"""
(module $AcceptStr
(memory (export "memory") 1)
(; constants 4 bytes ;)
(data (i32.const 255) "abc")
(func $str_length (param $a.ptr i32) (param $a.size i32) (result i32)
(local.get $a.size)
)
(func $middleman (param $a.ptr i32) (param $a.size i32) (result i32)
(call $str_length (local.get $a.ptr) (local.get $a.size))
)
(func $example (export "example") (result i32)
(call $middleman (i32.const 255) (i32.const 3))
)
)
""" = Orb.to_wat(AcceptStr)

i = Instance.run(AcceptStr)
assert Instance.call(i, :example) == 3
end

test "constant strings are mapped into a single address space" do
defmodule SharedStringConstants do
use Orb
Expand Down

0 comments on commit 14bac8c

Please sign in to comment.