Permalink
Browse files

Some pretty gnarly refactoring of how the class_decl and module_decl …

…parse tree nodes are structured

This change is part of an overall sweeping set of changes which allow arbitrary expressions to be interspersed into class bodies.
  • Loading branch information...
1 parent 758167a commit 87b9ed743079fdf5d5e0ac0797f96f1ba34a2d85 Tony Arcieri committed Oct 5, 2010
@@ -37,19 +37,19 @@ revert(BAExprs) ->
% Node transformations
%
-% Module declarations create a new scope
-transform_node(#module{functions=Functions} = Node, State) ->
- Fun = fun(Function) ->
- {[Function2], _State2} = reia_syntax:mapfold_subtrees(
+% Modules have their own scope
+transform_node(#module{exprs=Exprs} = Module, State) ->
+ Fun = fun(Expr) ->
+ {[NewExpr], _State2} = reia_syntax:mapfold_subtrees(
fun transform_node/2,
#state{scope=module},
- [Function]
+ [Expr]
),
- Function2
+ NewExpr
end,
- output(Node#module{functions=lists:map(Fun, Functions)}, State);
+ output(Module#module{exprs=lists:map(Fun, Exprs)}, State);
-% Function declarations create a new scope
+% Functions have their own scope
transform_node(#function{line=Line, name=Name, args=Args, block=Block, body=Exprs}, State) ->
{Args2, #state{bindings=Bindings}} = reia_syntax:mapfold_subtrees(
fun transform_node/2,
@@ -56,7 +56,7 @@ compile_expressions(Filename, Exprs, Options) ->
Header = module_header(Module#module.name, Filename, Options),
ParentAttr = {attribute, 1, parent, list_to_atom(filename:rootname(Filename))},
SubmoduleAttr = {attribute, 1, submodules, Submodules2},
- ErlModule = lists:flatten([Header, ParentAttr, SubmoduleAttr, Module#module.functions]),
+ ErlModule = lists:flatten([Header, ParentAttr, SubmoduleAttr, Module#module.exprs]),
compile:forms(ErlModule, compile_options(Options)).
@@ -66,7 +66,7 @@ compile_submodules(Submodules, Filename, Options) ->
compile_submodule(Module, Filename, Options) ->
Header = module_header(Module#module.name, Filename, Options),
ParentAttr = {attribute, 1, parent, list_to_atom(filename:rootname(Filename))},
- ErlModule = lists:flatten([Header, ParentAttr, Module#module.functions]),
+ ErlModule = lists:flatten([Header, ParentAttr, Module#module.exprs]),
{ok, Name, Bin} = compile:forms(ErlModule, compile_options(Options)),
{static, Name, Bin}.
@@ -84,14 +84,14 @@ wrapped_module(Filename, Exprs) ->
Function = {function, 1, toplevel, 0, [
{clause, 1, [], [], Exprs2}
]},
- Module = #module{line=1, name=Name, functions=[Function]},
+ Module = #module{line=1, name=Name, exprs=[Function]},
{Module, Submodules}.
unwrapped_module(Exprs) ->
case Exprs of
[{module, Line, Name, Functions}] ->
{ok, Functions2, Submodules} = reia_modules:replace(Functions, fun module_loader/1),
- Module = #module{line=Line, name=Name, functions=Functions2},
+ Module = #module{line=Line, name=Name, exprs=Functions2},
{Module, Submodules};
_ ->
throw({error, "code without a toplevel wrapper should define exactly one module"})
@@ -19,12 +19,12 @@ transform(#class{} = Expr) ->
transform(Expr) ->
reia_syntax:map_subtrees(fun transform/1, Expr).
-transform_class(#class{line=Line, name=Name, superclass=Ancestor, methods=Methods}) ->
+transform_class(#class{line=Line, name=Name, parent=Parent, exprs=Methods}) ->
MethodTable = build_method_table(Methods),
Initializers = transform_initialize_methods(Name, MethodTable),
CallifiedInitializers = [callify_method(Initialize) || Initialize <- Initializers],
- MethodMissings = transform_method_missings(Ancestor, MethodTable),
+ MethodMissings = transform_method_missings(Parent, MethodTable),
MethodTable2 = orddict:erase(initialize, MethodTable),
MethodTable3 = orddict:store(method_missing, MethodMissings, MethodTable2),
@@ -33,7 +33,7 @@ transform_class(#class{line=Line, name=Name, superclass=Ancestor, methods=Method
Methods3 = [prepare_method(Method) || Method <- lists:flatten(Methods2)],
Methods4 = CallifiedInitializers ++ Methods3 ++ [method_missing_thunk()],
- #class{line=Line, name=Name, methods=Methods4}.
+ #class{line=Line, name=Name, exprs=Methods4}.
% Create a orddict of methods by name
build_method_table(Methods) ->
@@ -82,7 +82,7 @@ transform_initialize_methods(_Name, MethodTable) ->
end, Methods).
% Transform the method_missing method or create it if it wasn't defined
-transform_method_missings(Ancestor, MethodTable) ->
+transform_method_missings(Parent, MethodTable) ->
case orddict:find(method_missing, MethodTable) of
{ok, Methods} -> Methods;
error -> % Use default (call super) if the method doesn't exist
@@ -94,7 +94,7 @@ transform_method_missings(Ancestor, MethodTable) ->
body = [
#native_call{
line = 1,
- module = Ancestor,
+ module = Parent,
function = call,
args = [
#tuple{
@@ -22,8 +22,8 @@
-record(self, {line}).
% Modules and Classes
--record(module, {line, name, functions}).
--record(class, {line, name, superclass='Object', methods}).
+-record(module, {line, name, exprs}).
+-record(class, {line, name, parent='Object', exprs}).
% Functions
-record(function, {line, name, args=[], block=#var{line=1,name='_'}, body}).
View
@@ -57,8 +57,8 @@ Nonterminals
def_exprs
def_expr
body
- pargs
- pargs_tail
+ args
+ args_tail
block_capture
boolean
class_inst
@@ -307,47 +307,25 @@ unary_op -> '~' : '$1'.
%% Module declarations
module_decl -> module module_name eol def_exprs 'end' :
#module{
- line = ?line('$1'),
- name = element(3, '$2'),
- functions = '$4'
+ line = ?line('$1'),
+ name = element(3, '$2'),
+ exprs = '$4'
}.
%% Class declarations
-class_decl -> class module_name eol def_exprs 'end' :
+class_decl -> class module_name def_exprs 'end' :
#class{
- line = ?line('$1'),
- name = ?identifier_name('$2'),
- methods = '$4'
+ line = ?line('$1'),
+ name = ?identifier_name('$2'),
+ exprs = '$3'
}.
-class_decl -> class module_name '<' module_name eol def_exprs 'end' :
+class_decl -> class module_name '<' module_name def_exprs 'end' :
#class{
- line = ?line('$1'),
- name = ?identifier_name('$2'),
- superclass = ?identifier_name('$4'),
- methods = '$6'
- }.
-
-%% Parenthesized arguments
-pargs -> '(' ')' : #pargs{}.
-pargs -> '(' eol ')' : #pargs{}.
-pargs -> '(' expr pargs_tail : ?pargs_add('$2', '$3').
-pargs -> '(' eol expr pargs_tail : ?pargs_add('$3', '$4').
-pargs -> '(' block_capture ')' : '$2'.
-
-pargs_tail -> ',' expr pargs_tail : ?pargs_add('$2', '$3').
-pargs_tail -> ',' eol expr pargs_tail : ?pargs_add('$3', '$4').
-pargs_tail -> eol ',' expr pargs_tail : ?pargs_add('$3', '$4').
-pargs_tail -> eol ',' eol expr pargs_tail : ?pargs_add('$4', '$5').
-
-pargs_tail -> ')' : #pargs{}.
-pargs_tail -> eol ')' : #pargs{}.
-pargs_tail -> ',' block_capture ')' : '$2'.
-pargs_tail -> eol ',' block_capture ')' : '$3'.
-
-block_capture -> '&' expr : #pargs{block='$2'}.
-block_capture -> '&' expr eol : #pargs{block='$2'}.
-block_capture -> eol '&' expr : #pargs{block='$3'}.
-block_capture -> eol '&' expr eol : #pargs{block='$3'}.
+ line = ?line('$1'),
+ name = ?identifier_name('$2'),
+ parent = ?identifier_name('$4'),
+ exprs = '$5'
+ }.
%% Expression lists with interspersed defs (eol delimited)
def_exprs -> eol : [].
@@ -363,12 +341,12 @@ def_expr -> def_prefix eol body 'end' :
name = '$1',
body = '$3'
}.
-def_expr -> def_prefix pargs eol body 'end' :
+def_expr -> def_prefix args eol body 'end' :
#function{
line = ?line('$3'),
name = '$1',
- args = '$2'#pargs.args,
- block = '$2'#pargs.block,
+ args = '$2'#args.args,
+ block = '$2'#args.block,
body = '$4'
}.
def_expr -> expr.
@@ -387,22 +365,44 @@ function_identifier -> self : {identifier, ?line('$1'), self}.
body -> '$empty' : [#nil{}].
body -> expr_list : '$1'.
+%% Arguments
+args -> '(' ')' : #args{}.
+args -> '(' eol ')' : #args{}.
+args -> '(' expr args_tail : ?args_add('$2', '$3').
+args -> '(' eol expr args_tail : ?args_add('$3', '$4').
+args -> '(' block_capture ')' : '$2'.
+
+args_tail -> ',' expr args_tail : ?args_add('$2', '$3').
+args_tail -> ',' eol expr args_tail : ?args_add('$3', '$4').
+args_tail -> eol ',' expr args_tail : ?args_add('$3', '$4').
+args_tail -> eol ',' eol expr args_tail : ?args_add('$4', '$5').
+
+args_tail -> ')' : #args{}.
+args_tail -> eol ')' : #args{}.
+args_tail -> ',' block_capture ')' : '$2'.
+args_tail -> eol ',' block_capture ')' : '$3'.
+
+block_capture -> '&' expr : #args{block='$2'}.
+block_capture -> '&' expr eol : #args{block='$2'}.
+block_capture -> eol '&' expr : #args{block='$3'}.
+block_capture -> eol '&' expr eol : #args{block='$3'}.
+
%% Class instantiations
-class_inst -> module_name pargs :
+class_inst -> module_name args :
#class_inst{
line = ?line('$1'),
class = ?identifier_name('$1'),
- args = '$2'#pargs.args,
- block = ?pargs_default_block(#nil{}, '$2')
+ args = '$2'#args.args,
+ block = ?args_default_block(#nil{}, '$2')
}.
%% Local function calls
-call -> function_identifier pargs :
+call -> function_identifier args :
#local_call{
line = ?line('$1'),
name = ?identifier_name('$1'),
- args = '$2'#pargs.args,
- block = ?pargs_default_block(#nil{}, '$2')
+ args = '$2'#args.args,
+ block = ?args_default_block(#nil{}, '$2')
}.
%% Local function calls with blocks
@@ -412,13 +412,13 @@ call -> function_identifier block :
name = ?identifier_name('$1'),
block = '$2'
}.
-call -> function_identifier pargs block :
- case '$2'#pargs.block of
+call -> function_identifier args block :
+ case '$2'#args.block of
#var{line=1, name='_'} -> % user didn't pass a &block
#local_call{
line = ?line('$1'),
name = ?identifier_name('$1'),
- args = '$2'#pargs.args,
+ args = '$2'#args.args,
block = '$3'
};
_ ->
@@ -772,12 +772,12 @@ Erlang code.
-export([string/1]).
-include("reia_nodes.hrl").
--record(pargs, {args=[], block={var,1,'_'}}).
+-record(args, {args=[], block={var,1,'_'}}).
-define(line(Node), element(2, Node)).
-define(op(Node), element(1, Node)).
-define(identifier_name(Id), element(3, Id)).
--define(pargs_add(Arg, Pargs), Pargs#pargs{args=[Arg|Pargs#pargs.args]}).
--define(pargs_default_block(Block, Pargs), case (Pargs)#pargs.block of {var,1,'_'} -> Block; _ -> (Pargs)#pargs.block end).
+-define(args_add(Arg, Args), Args#args{args=[Arg|Args#args.args]}).
+-define(args_default_block(Block, Args), case (Args)#args.block of {var,1,'_'} -> Block; _ -> (Args)#args.block end).
%% Parse a given string with nicely formatted errors
string(String) ->
View
@@ -34,23 +34,23 @@ transform(Exprs, _Options) ->
[transform(Expr) || Expr <- Exprs].
% Modules
-transform(#module{line=Line, name=Name, functions=Funcs}) ->
+transform(#module{line=Line, name=Name, exprs=Exprs}) ->
% Modules need some postprocessing, so we leave them in a similar form but
% with their subtrees converted
#module{
line = Line,
name = Name,
- functions = group_clauses([transform(Func) || Func <- Funcs])
+ exprs = group_clauses([transform(Expr) || Expr <- Exprs])
};
% Classes
-transform(#class{line=Line, name=Name, methods=Funcs}) ->
+transform(#class{line=Line, name=Name, exprs=Exprs}) ->
% Modules need some postprocessing, so we leave them in a similar form but
% with their subtrees converted
#module{
- line = Line,
- name = Name,
- functions = group_clauses([transform(Func) || Func <- Funcs])
+ line = Line,
+ name = Name,
+ exprs = group_clauses([transform(Expr) || Expr <- Exprs])
};
% Functions
View
@@ -60,7 +60,7 @@ stamp() ->
string:join(Timestamp, "_").
temporary_module(Name, Args, Exprs) ->
- #module{line=1, name=Name, functions=[
+ #module{line=1, name=Name, exprs=[
#function{line=1, name=toplevel, args=Args, body=Exprs}
]}.

0 comments on commit 87b9ed7

Please sign in to comment.