Skip to content

Commit

Permalink
Initial support for dispatching class method calls
Browse files Browse the repository at this point in the history
  • Loading branch information
Tony Arcieri committed Dec 26, 2010
1 parent 08f87dc commit ce67bb2
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 34 deletions.
62 changes: 36 additions & 26 deletions src/core/reia.erl
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@

-module(reia).
-export([
init/0,
load/1,
parse/1,
eval/2,
inst/2, inst/3,
invoke/3, invoke/4,
throw/2, throw/3
init/0,
load/1,
parse/1,
eval/2,
inst/2, inst/3,
invoke/3, invoke/4,
throw/2, throw/3,
list_to_string/1,
binary_to_string/1
]).
-include("reia_types.hrl").

Expand All @@ -36,34 +38,42 @@ load(Filename) ->

% Parse the given string of Reia source code
parse(String) ->
reia_compiler:parse(String).
reia_compiler:parse(String).

% Evaluate the given string of Reia source code
eval(String, Binding) ->
reia_eval:exprs(parse(String), Binding).
reia_eval:exprs(parse(String), Binding).
% Create a new instance of the given class
inst(Class, Arguments) -> inst(Class, Arguments, nil).
inst(Class, Arguments, Block) ->
% FIXME: initial object construction should thunk to the metaclass, not be
% spelled out explicitly here.
Object = #reia_object{class=Class, ivars=dict:new()},
Class:call({Object, initialize, Arguments}, Block).
% FIXME: initial object construction should thunk to the metaclass, not be
% spelled out explicitly here.
Object = #reia_object{class=Class, ivars=dict:new()},
Class:call({Object, initialize, Arguments}, Block).
% Invoke the given method on the given object
invoke(Receiver, Method, Arguments) -> invoke(Receiver, Method, Arguments, nil).
invoke(Receiver, Method, Arguments, Block) ->
Arguments2 = if
is_tuple(Arguments) -> Arguments;
is_list(Arguments) -> list_to_tuple(Arguments);
true -> throw({error, "invalid type for arguments"})
end,
Class = Receiver#reia_object.class,
Class:call({Receiver, Method, Arguments2}, Block).
Arguments2 = if
is_tuple(Arguments) -> Arguments;
is_list(Arguments) -> list_to_tuple(Arguments);
true -> throw({error, "invalid type for arguments"})
end,
Class = Receiver#reia_object.class,
Class:call({Receiver, Method, Arguments2}, Block).
% Throw a Reia exception
throw(Class, Message) ->
throw(Class, nil, Message).
throw(Class, nil, Message).
throw(Class, Line, Message) ->
erlang:throw(inst(Class, {Line, Message})).
erlang:throw(inst(Class, {Line, Message})).

% Convert an Erlang list to a Reia string
list_to_string(List) ->
#reia_string{elements=List}.

% Convert an Erlang binary to a Reia string
binary_to_string(Bin) ->
#reia_string{elements=Bin}.
34 changes: 26 additions & 8 deletions src/core/reia_dispatch.erl
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,8 @@ call(#reia_regexp{} = Receiver, Method, Arguments, Block) ->
'Regexp':call({Receiver, Method, Arguments}, Block);
call(#reia_range{} = Receiver, Method, Arguments, Block) ->
'Range':call({Receiver, Method, Arguments}, Block);
call(#reia_module{name=Name} = Receiver, Method, Arguments, Block) ->
case code:ensure_loaded(Name) of
{module, Name} ->
'Module':call({Receiver, Method, Arguments, Block}, nil);
_ ->
Message = lists:flatten(io_lib:format("undefined module ~s", [Name])),
reia:throw('NameError', Message)
end;
call(#reia_module{} = Receiver, Method, Arguments, Block) ->
dispatch_module_call(Receiver, Method, Arguments, Block);
call(#reia_funref{} = Receiver, Method, Arguments, Block) ->
'Funref':call({Receiver, Method, Arguments}, Block);
call(Receiver, Method, Arguments, Block) when is_tuple(Receiver) ->
Expand All @@ -56,3 +50,27 @@ call(Receiver, Method, Arguments, Block) when is_port(Receiver) ->
'Channel':call({Receiver, Method, Arguments}, Block);
call(Receiver, _, _, _) ->
throw({error, unknown_receiver, Receiver}).

dispatch_module_call(#reia_module{name=Name} = Receiver, Method, Arguments, Block) ->
case code:ensure_loaded(Name) of
{module, Name} ->
Attributes = Name:module_info(attributes),
case proplists:get_value(module_type, Attributes) of
[module] ->
'Module':call({Receiver, Method, Arguments, Block}, nil);
[class] ->
% FIXME: to_s and inspect shouldn't be implemented here!
case Method of
to_s -> reia:list_to_string(atom_to_list(Name));
inspect -> reia:list_to_string(atom_to_list(Name));
_ ->
reia:throw('RuntimeError', "class methods not implemented yet, sorry!")
end;
undefined ->
Message = lists:flatten(io_lib:format("missing module_type attribute in ~s", [Name])),
reia:throw('RuntimeError', Message)
end;
_ ->
Message = lists:flatten(io_lib:format("undefined module ~s", [Name])),
reia:throw('NameError', Message)
end.

0 comments on commit ce67bb2

Please sign in to comment.