Permalink
Browse files

Nested macros; flexible macro expansion

  • Loading branch information...
1 parent a36f0cb commit a02b6384afcbf9953ef712dc7afd6e7f105fb8bd @evanmiller evanmiller committed Jun 24, 2010
Showing with 152 additions and 89 deletions.
  1. +40 −9 src/aleppo.erl
  2. +112 −80 src/aleppo_parser.yrl
View
@@ -85,11 +85,13 @@ process_tree([Node|Rest], MacroDict, InclusionTrail, TokenAcc) ->
process_tree(Rest, MacroDict, InclusionTrail, [{integer, Line, Line}|TokenAcc]);
{'macro', {_Type, _Loc, MacroName}} ->
InsertTokens = dict:fetch(MacroName, MacroDict),
- process_tree(Rest, MacroDict, InclusionTrail, lists:reverse(InsertTokens) ++ TokenAcc);
+ {_, RevProcessedTokens} = process_tree(InsertTokens, MacroDict, InclusionTrail, []),
+ process_tree(Rest, MacroDict, InclusionTrail, RevProcessedTokens ++ TokenAcc);
{'macro', {_Type, Loc, MacroName}, MacroArgs} ->
{DefinedArgs, DefinedTokens} = dict:fetch({MacroName, length(MacroArgs)}, MacroDict),
InsertTokens = expand_macro_fun(Loc, DefinedArgs, DefinedTokens, MacroArgs),
- process_tree(Rest, MacroDict, InclusionTrail, lists:reverse(InsertTokens) ++ TokenAcc);
+ {_, RevProcessedTokens} = process_tree(InsertTokens, MacroDict, InclusionTrail, []),
+ process_tree(Rest, MacroDict, InclusionTrail, RevProcessedTokens ++ TokenAcc);
OtherToken ->
process_tree(Rest, MacroDict, InclusionTrail, [OtherToken|TokenAcc])
end.
@@ -158,8 +160,8 @@ scan_tokens(Data, StartLocation) ->
{ok, Tokens ++ NewTokens};
Err -> Err
end;
- {eof, _EndLocation} ->
- {ok, []};
+ {eof, EndLocation} ->
+ {ok, [{eof, EndLocation}]};
{error, ErrorInfo, _EndLocation} ->
{error, ErrorInfo}
end;
@@ -168,19 +170,48 @@ scan_tokens(Data, StartLocation) ->
case Return of
{ok, Tokens, _EndLocation} ->
{ok, Tokens};
- {eof, _EndLocation} ->
- {ok, []};
+ {eof, EndLocation} ->
+ {ok, [{eof, EndLocation}]};
{error, ErrorInfo, _EndLocation} ->
{error, ErrorInfo}
end
end.
expand_macro_fun(Loc, DefinedArgs, DefinedTokens, ApplyArgs) ->
- [{'(', Loc}, {'fun', Loc}, {'(', Loc}|DefinedArgs] ++ % includes commas
- [{')', Loc}, {'->', Loc}|DefinedTokens] ++
- [{'end', Loc}, {')', Loc}, {'(', Loc}|ApplyArgs] ++
+ ExpandedTokens = replace_macro_strings(DefinedTokens, DefinedArgs, ApplyArgs),
+ DefinedArgsWithCommas = insert_comma_tokens(DefinedArgs, Loc),
+ ApplyArgsWithCommas = insert_comma_tokens(ApplyArgs, Loc),
+ [{'(', Loc}, {'fun', Loc}, {'(', Loc}|DefinedArgsWithCommas] ++
+ [{')', Loc}, {'->', Loc}|ExpandedTokens] ++
+ [{'end', Loc}, {')', Loc}, {'(', Loc}|ApplyArgsWithCommas] ++
[{')', Loc}].
+replace_macro_strings(DefinedTokens, DefinedArgs, ApplyArgs) ->
+ MacroStringDict = dict:from_list(lists:zipwith(fun({var, _, VarName}, ApplyTokens) ->
+ ArgAsString = lists:concat(lists:foldr(
+ fun
+ (Token, []) ->
+ [erl_scan:token_info(Token, symbol)];
+ (Token, Acc) ->
+ [erl_scan:token_info(Token, symbol), " "|Acc]
+ end, [], ApplyTokens)),
+ {VarName, ArgAsString}
+ end, DefinedArgs, ApplyArgs)),
+ replace_macro_strings1(DefinedTokens, MacroStringDict, []).
+
+replace_macro_strings1([], _, Acc) ->
+ lists:reverse(Acc);
+replace_macro_strings1([{'macro_string', {var, Loc, VarName}}|Rest], MacroStringDict, Acc) ->
+ replace_macro_strings1(Rest, MacroStringDict, [{string, Loc, dict:fetch(VarName, MacroStringDict)}|Acc]);
+replace_macro_strings1([OtherToken|Rest], MacroStringDict, Acc) ->
+ replace_macro_strings1(Rest, MacroStringDict, [OtherToken|Acc]).
+
+insert_comma_tokens(Args, Loc) ->
+ lists:foldr(fun
+ (Arg, []) -> Arg;
+ (Arg, Acc) -> Arg ++ [{',', Loc}|Acc]
+ end, Args).
+
mark_keywords(Tokens) ->
mark_keywords(Tokens, undefined, []).
View
@@ -11,19 +11,31 @@ Nonterminals
Define
Include
IncludeLib
+ File
+
Elements
FormTokens
Token
+
Macro
MacroName
+ MacroString
MacroArgs
+ NonEmptyMacroArgs
ApplyMacroArgs
- ApplyMacroArg.
+ NonEmptyApplyMacroArgs
+ ApplyMacroArg
+
+ Expression
+ NonEmptyExpression
+ ExpressionList
+ NonEmptyExpressionList
+ ExpressionToken.
% Terminals taken from erl_parse.yrl
Terminals
ifdef_keyword else_keyword ifndef_keyword endif_keyword undef_keyword
- define_keyword include_keyword include_lib_keyword
+ define_keyword include_keyword include_lib_keyword eof
'?'
@@ -41,7 +53,9 @@ Terminals
'!' '=' '::'
dot.
-Rootsymbol Elements.
+Rootsymbol File.
+
+File -> Elements eof : '$1' ++ ['$2'].
Elements -> '$empty' : [].
Elements -> Elements IfBlock : '$1' ++ ['$2'].
@@ -56,6 +70,8 @@ Elements -> Elements dot : '$1' ++ ['$2'].
FormTokens -> '$empty' : [].
FormTokens -> FormTokens Token : '$1' ++ ['$2'].
+FormTokens -> FormTokens Macro : '$1' ++ ['$2'].
+FormTokens -> FormTokens MacroString : '$1' ++ ['$2'].
Define -> '-' define_keyword '(' MacroName ')' dot : {'macro_define', '$4'}.
Define -> '-' define_keyword '(' MacroName ',' FormTokens ')' dot : {'macro_define', '$4', '$6'}.
@@ -80,93 +96,109 @@ Undef -> '-' undef_keyword '(' MacroName ')' dot : {'macro_undef', '$4'}.
Macro -> '?' MacroName : {'macro', '$2'}.
Macro -> '?' MacroName '(' ApplyMacroArgs ')' : {'macro', '$2', '$4'}.
+MacroString -> '?' '?' var : {'macro_string', '$3'}.
+
+MacroName -> atom : '$1'.
+MacroName -> var : '$1'.
+
MacroArgs -> '$empty' : [].
-MacroArgs -> MacroArgs ',' var : '$1' ++ ['$2', '$3'].
-MacroArgs -> var : ['$1'].
+MacroArgs -> NonEmptyMacroArgs : '$1'.
+
+NonEmptyMacroArgs -> NonEmptyMacroArgs ',' var : '$1' ++ ['$3'].
+NonEmptyMacroArgs -> var : ['$1'].
ApplyMacroArgs -> '$empty' : [].
-ApplyMacroArgs -> ApplyMacroArgs ',' ApplyMacroArg : '$1' ++ ['$2', '$3'].
-ApplyMacroArgs -> ApplyMacroArg : ['$1'].
-
-% This is weak -- we really want to allow any valid Erlang term.
-% For now, just variables, macros, and literals
-ApplyMacroArg -> var : '$1'.
-ApplyMacroArg -> integer : '$1'.
-ApplyMacroArg -> float : '$1'.
-ApplyMacroArg -> string : '$1'.
-ApplyMacroArg -> atom : '$1'.
-ApplyMacroArg -> Macro : '$1'.
+ApplyMacroArgs -> NonEmptyApplyMacroArgs : '$1'.
-MacroName -> atom : '$1'.
-MacroName -> var : '$1'.
+NonEmptyApplyMacroArgs -> ApplyMacroArg : '$1'.
+NonEmptyApplyMacroArgs -> NonEmptyApplyMacroArgs ',' ApplyMacroArg : '$1' ++ ['$3'].
+
+ApplyMacroArg -> NonEmptyExpression : ['$1'].
+
+NonEmptyExpression -> Expression ExpressionToken : '$1' ++ ['$2'].
+NonEmptyExpression -> Expression Macro : '$1' ++ ['$2'].
+NonEmptyExpression -> Expression MacroString : '$1' ++ ['$2'].
+NonEmptyExpression -> Expression '(' ExpressionList ')' : '$1' ++ ['$2'] ++ '$3' ++ ['$4'].
+NonEmptyExpression -> Expression '{' ExpressionList '}' : '$1' ++ ['$2'] ++ '$3' ++ ['$4'].
+NonEmptyExpression -> Expression '[' ExpressionList ']' : '$1' ++ ['$2'] ++ '$3' ++ ['$4'].
+
+Expression -> '$empty' : [].
+Expression -> NonEmptyExpression : '$1'.
+
+ExpressionList -> '$empty' : [].
+ExpressionList -> NonEmptyExpressionList : '$1'.
+NonEmptyExpressionList -> NonEmptyExpressionList ',' NonEmptyExpression : '$1' ++ ['$2'] ++ '$3'.
+NonEmptyExpressionList -> NonEmptyExpression : '$1'.
-Token -> char : '$1'.
-Token -> integer : '$1'.
-Token -> float : '$1'.
-Token -> atom : '$1'.
-Token -> string : '$1'.
-Token -> var : '$1'.
Token -> '(' : '$1'.
Token -> ')' : '$1'.
Token -> ',' : '$1'.
-Token -> '->' : '$1'.
-Token -> ':-' : '$1'.
Token -> '{' : '$1'.
Token -> '}' : '$1'.
Token -> '[' : '$1'.
Token -> ']' : '$1'.
-Token -> '|' : '$1'.
-Token -> '||' : '$1'.
-Token -> '<-' : '$1'.
-Token -> ';' : '$1'.
-Token -> ':' : '$1'.
-Token -> '#' : '$1'.
-Token -> '.' : '$1'.
-Token -> 'after' : '$1'.
-Token -> 'begin' : '$1'.
-Token -> 'case' : '$1'.
-Token -> 'try' : '$1'.
-Token -> 'catch' : '$1'.
-Token -> 'end' : '$1'.
-Token -> 'fun' : '$1'.
-Token -> 'if' : '$1'.
-Token -> 'of' : '$1'.
-Token -> 'receive' : '$1'.
-Token -> 'when' : '$1'.
-Token -> 'andalso' : '$1'.
-Token -> 'orelse' : '$1'.
-Token -> 'query' : '$1'.
-Token -> 'spec' : '$1'.
-Token -> 'bnot' : '$1'.
-Token -> 'not' : '$1'.
-Token -> '*' : '$1'.
-Token -> '/' : '$1'.
-Token -> 'div' : '$1'.
-Token -> 'rem' : '$1'.
-Token -> 'band' : '$1'.
-Token -> 'and' : '$1'.
-Token -> '+' : '$1'.
-Token -> '-' : '$1'.
-Token -> 'bor' : '$1'.
-Token -> 'bxor' : '$1'.
-Token -> 'bsl' : '$1'.
-Token -> 'bsr' : '$1'.
-Token -> 'or' : '$1'.
-Token -> 'xor' : '$1'.
-Token -> '++' : '$1'.
-Token -> '--' : '$1'.
-Token -> '==' : '$1'.
-Token -> '/=' : '$1'.
-Token -> '=<' : '$1'.
-Token -> '<' : '$1'.
-Token -> '>=' : '$1'.
-Token -> '>' : '$1'.
-Token -> '=:=' : '$1'.
-Token -> '=/=' : '$1'.
-Token -> '<=' : '$1'.
-Token -> '<<' : '$1'.
-Token -> '>>' : '$1'.
-Token -> '!' : '$1'.
-Token -> '=' : '$1'.
-Token -> '::' : '$1'.
+Token -> ExpressionToken : '$1'.
+
+ExpressionToken -> char : '$1'.
+ExpressionToken -> integer : '$1'.
+ExpressionToken -> float : '$1'.
+ExpressionToken -> atom : '$1'.
+ExpressionToken -> string : '$1'.
+ExpressionToken -> var : '$1'.
+ExpressionToken -> '->' : '$1'.
+ExpressionToken -> ':-' : '$1'.
+ExpressionToken -> '|' : '$1'.
+ExpressionToken -> '||' : '$1'.
+ExpressionToken -> '<-' : '$1'.
+ExpressionToken -> ';' : '$1'.
+ExpressionToken -> ':' : '$1'.
+ExpressionToken -> '#' : '$1'.
+ExpressionToken -> '.' : '$1'.
+ExpressionToken -> 'after' : '$1'.
+ExpressionToken -> 'begin' : '$1'.
+ExpressionToken -> 'case' : '$1'.
+ExpressionToken -> 'try' : '$1'.
+ExpressionToken -> 'catch' : '$1'.
+ExpressionToken -> 'end' : '$1'.
+ExpressionToken -> 'fun' : '$1'.
+ExpressionToken -> 'if' : '$1'.
+ExpressionToken -> 'of' : '$1'.
+ExpressionToken -> 'receive' : '$1'.
+ExpressionToken -> 'when' : '$1'.
+ExpressionToken -> 'andalso' : '$1'.
+ExpressionToken -> 'orelse' : '$1'.
+ExpressionToken -> 'query' : '$1'.
+ExpressionToken -> 'spec' : '$1'.
+ExpressionToken -> 'bnot' : '$1'.
+ExpressionToken -> 'not' : '$1'.
+ExpressionToken -> '*' : '$1'.
+ExpressionToken -> '/' : '$1'.
+ExpressionToken -> 'div' : '$1'.
+ExpressionToken -> 'rem' : '$1'.
+ExpressionToken -> 'band' : '$1'.
+ExpressionToken -> 'and' : '$1'.
+ExpressionToken -> '+' : '$1'.
+ExpressionToken -> '-' : '$1'.
+ExpressionToken -> 'bor' : '$1'.
+ExpressionToken -> 'bxor' : '$1'.
+ExpressionToken -> 'bsl' : '$1'.
+ExpressionToken -> 'bsr' : '$1'.
+ExpressionToken -> 'or' : '$1'.
+ExpressionToken -> 'xor' : '$1'.
+ExpressionToken -> '++' : '$1'.
+ExpressionToken -> '--' : '$1'.
+ExpressionToken -> '==' : '$1'.
+ExpressionToken -> '/=' : '$1'.
+ExpressionToken -> '=<' : '$1'.
+ExpressionToken -> '<' : '$1'.
+ExpressionToken -> '>=' : '$1'.
+ExpressionToken -> '>' : '$1'.
+ExpressionToken -> '=:=' : '$1'.
+ExpressionToken -> '=/=' : '$1'.
+ExpressionToken -> '<=' : '$1'.
+ExpressionToken -> '<<' : '$1'.
+ExpressionToken -> '>>' : '$1'.
+ExpressionToken -> '!' : '$1'.
+ExpressionToken -> '=' : '$1'.
+ExpressionToken -> '::' : '$1'.

0 comments on commit a02b638

Please sign in to comment.