-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rewrite VariableReference, and support iterating through any type
- Loading branch information
1 parent
ab138b8
commit 7622c43
Showing
7 changed files
with
182 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,136 @@ | ||
defmodule Orb.VariableReference do | ||
@moduledoc false | ||
|
||
defstruct [:global_or_local, :identifier, :push_type] | ||
defmodule Global do | ||
defstruct [:identifier, :type] | ||
|
||
alias Orb.Instruction | ||
def set(%__MODULE__{identifier: identifier, type: type}, new_value) do | ||
Orb.Instruction.Global.Set.new(type, identifier, new_value) | ||
end | ||
|
||
def set_from_stack(%__MODULE__{identifier: identifier, type: type}) do | ||
Orb.Instruction.Global.Set.new(type, identifier, Orb.Stack.Pop.new(type)) | ||
end | ||
|
||
defimpl Orb.ToWat do | ||
def to_wat(%Orb.VariableReference.Global{identifier: identifier}, indent) do | ||
[indent, "(global.get $", to_string(identifier), ?)] | ||
end | ||
end | ||
end | ||
|
||
defmodule Local do | ||
defstruct [:identifier, :type] | ||
|
||
def set(%__MODULE__{identifier: identifier, type: type}, new_value) do | ||
Orb.Instruction.local_set(type, identifier, new_value) | ||
end | ||
|
||
def set_from_stack(%__MODULE__{identifier: identifier, type: type}) do | ||
Orb.Instruction.local_set(type, identifier, Orb.Stack.Pop.new(type)) | ||
end | ||
|
||
defimpl Orb.ToWat do | ||
def to_wat(%Orb.VariableReference.Local{identifier: identifier}, indent) do | ||
[indent, "(local.get $", to_string(identifier), ?)] | ||
end | ||
end | ||
|
||
defimpl Orb.ToWasm do | ||
import Orb.Leb | ||
|
||
def to_wasm(%Orb.VariableReference.Local{identifier: identifier}, context) do | ||
import Orb.Leb | ||
|
||
[0x20, leb128_u(Orb.ToWasm.Context.fetch_local_index!(context, identifier))] | ||
end | ||
end | ||
end | ||
|
||
defstruct [:entries, :push_type, :pop_type] | ||
|
||
def global(identifier, type) do | ||
%__MODULE__{global_or_local: :global, identifier: identifier, push_type: type} | ||
%__MODULE__{ | ||
entries: [%Global{identifier: identifier, type: type}], | ||
push_type: type | ||
} | ||
end | ||
|
||
def local(identifier, type) do | ||
%__MODULE__{global_or_local: :local, identifier: identifier, push_type: type} | ||
%__MODULE__{ | ||
entries: [%Local{identifier: identifier, type: type}], | ||
push_type: type | ||
} | ||
end | ||
|
||
def set( | ||
%__MODULE__{global_or_local: :local, identifier: identifier, push_type: type}, | ||
%__MODULE__{entries: entries}, | ||
new_value | ||
) do | ||
Instruction.local_set(type, identifier, new_value) | ||
end | ||
new_value = | ||
case new_value do | ||
new_value when is_tuple(new_value) -> | ||
Tuple.to_list(new_value) | ||
|
||
def as_set(%__MODULE__{global_or_local: :local, identifier: identifier, push_type: type}) do | ||
Instruction.local_set(type, identifier) | ||
end | ||
new_value when is_list(new_value) -> | ||
new_value | ||
|
||
@behaviour Access | ||
new_value -> | ||
List.wrap(new_value) | ||
end | ||
|
||
@impl Access | ||
# TODO: I think this should only live on custom types like UnsafePointer | ||
def fetch( | ||
%__MODULE__{global_or_local: :local, identifier: _identifier, push_type: :i32} = ref, | ||
at: offset | ||
) do | ||
ast = Instruction.i32(:load, Instruction.i32(:add, ref, offset)) | ||
{:ok, ast} | ||
for {entry, value} <- Enum.zip(entries, new_value) do | ||
entry.__struct__.set(entry, value) | ||
end | ||
|> Orb.InstructionSequence.new() | ||
end | ||
|
||
def fetch( | ||
%__MODULE__{global_or_local: :local, identifier: _identifier, push_type: mod} = ref, | ||
key | ||
) do | ||
mod.fetch(ref, key) | ||
def as_set(%__MODULE__{entries: entries}) when length(entries) === 1 do | ||
Orb.InstructionSequence.new( | ||
nil, | ||
for entry <- entries do | ||
entry.__struct__.set_from_stack(entry) | ||
end, | ||
pop_type: hd(entries).type | ||
) | ||
end | ||
|
||
@impl Access | ||
def get_and_update(_data, _key, _function) do | ||
raise UndefinedFunctionError, module: __MODULE__, function: :get_and_update, arity: 3 | ||
end | ||
with @behaviour Access do | ||
@impl Access | ||
def fetch( | ||
%__MODULE__{entries: [%Local{type: mod}]} = var_ref, | ||
key | ||
) do | ||
mod.fetch(var_ref, key) | ||
end | ||
|
||
@impl Access | ||
def pop(_data, _key) do | ||
raise UndefinedFunctionError, module: __MODULE__, function: :pop, arity: 2 | ||
end | ||
@impl Access | ||
def get_and_update(_data, _key, _function) do | ||
raise UndefinedFunctionError, module: __MODULE__, function: :get_and_update, arity: 3 | ||
end | ||
|
||
defimpl Orb.ToWat do | ||
def to_wat(%Orb.VariableReference{global_or_local: :global, identifier: identifier}, indent) do | ||
[indent, "(global.get $", to_string(identifier), ?)] | ||
@impl Access | ||
def pop(_data, _key) do | ||
raise UndefinedFunctionError, module: __MODULE__, function: :pop, arity: 2 | ||
end | ||
end | ||
|
||
def to_wat(%Orb.VariableReference{global_or_local: :local, identifier: identifier}, indent) do | ||
[indent, "(local.get $", to_string(identifier), ?)] | ||
defimpl Orb.ToWat do | ||
def to_wat(%Orb.VariableReference{entries: entries}, indent) do | ||
for entry <- entries do | ||
Orb.ToWat.to_wat(entry, indent) | ||
end | ||
end | ||
end | ||
|
||
defimpl Orb.ToWasm do | ||
import Orb.Leb | ||
|
||
def to_wasm( | ||
%Orb.VariableReference{global_or_local: :local, identifier: identifier}, | ||
%Orb.VariableReference{entries: entries}, | ||
context | ||
) do | ||
[0x20, leb128_u(Orb.ToWasm.Context.fetch_local_index!(context, identifier))] | ||
for entry <- entries do | ||
Orb.ToWasm.to_wasm(entry, context) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters