Skip to content

Commit

Permalink
Dirty merge of Graeme's fixes.
Browse files Browse the repository at this point in the history
  • Loading branch information
seancribbs committed Mar 13, 2011
1 parent 1c0f9f8 commit fbcde98
Show file tree
Hide file tree
Showing 10 changed files with 1,023 additions and 504 deletions.
85 changes: 85 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
require 'rake/clean'

task :default => %w(check_erl_version build test)

# Build rules
task :build => %w(neotoma)
task :neotoma => %w(parser compile)
task :parser => %w(src/neotoma_parse.erl)

# include file
file "priv/peg_includes.hrl" => ["src/peg_includes.erl"] do
sh "cat src/peg_includes.erl | grep -v \"^%\" | grep -v \"^-\" > priv/peg_includes.hrl"
end

# Parser
if File.exist?("ebin/neotoma_parse.beam")
file "src/neotoma_parse.erl" => ["src/neotoma_parse.peg", "priv/peg_includes.hrl"] do
erl_eval 'neotoma:file("src/neotoma_parse.peg")', 'ebin/'
end
else
sh "cp src/neotoma_parse.erl.safe src/neotoma_parse.erl"
end

task :compile => %w(ebin src/neotoma.app priv/peg_includes.hrl) do
sh "cd src;erl -pa ../ebin -make"
end

task :test_beams => %w(ebin_tests) do
sh "cd tests;erl -pa ../ebin -make"
end

# create directories
task :ebin do mkdir "ebin" end
task :priv do mkdir "priv" end
task :ebin_tests do mkdir "ebin_tests" end

def mkdir(dir)
File.exist?(dir) || sh("mkdir #{dir}")
end


# Test suite
task :test => %w(build test_beams) do
erl_eval 'test_suite:test()', 'ebin', 'ebin_tests', 'ebin_tests/examples'
end

# Cleaning
CLEAN.include %w(ebin ebin_tests src/neotoma_parse.erl priv/peg_includes.hrl)

#---- generic erlang version tests ------

# Returns the installed Erlang version
def erlang_version
version = `erl -version 2>&1`.strip.match(/\d\.\d(\.\d)?$/)
unless version
STDERR.puts "Error retrieving Erlang version. Do you have it installed?"
exit 1
end

version[0]
end

# Evaluate the given Erlang statement
def erl_eval(cmd, *pa)
pa_str = pa.empty? ? "" : "-pa #{pa.join(' ')}"
sh "erl -noshell #{pa_str} -eval '#{cmd}' -s erlang halt"
end

# Ensure the version of Erlang installed is recent enough
task :check_erl_version do
print "Checking Erlang version... "
version = erlang_version

if version >= "5.6.3"
puts "#{version} (ok)"
else
puts "#{version} (too old)"
puts "Sorry, the version of Erlang you have installed is too old to run Reia"
puts "Reia requires a minimum Erlang version of R12B-3 (5.6.3)"
puts "Please see http://wiki.reia-lang.org/wiki/Building#Prerequisites"
exit 1
end
end


33 changes: 26 additions & 7 deletions priv/neotoma_parse.peg
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,9 @@ terminal <- quoted_string / character_class / anything_symbol ~;

quoted_string <- single_quoted_string / double_quoted_string
`
["p_string(",
io_lib:format("~p",[iolist_to_binary(proplists:get_value(string, Node))]),
")"]
lists:flatten(["p_string(<<\"",
escape_string(binary_to_list(iolist_to_binary(proplists:get_value(string, Node)))),
"\">>)"])
`;

double_quoted_string <- '"' string:(!'"' ("\\\\" / '\\"' / .))* '"' ~;
Expand All @@ -137,7 +137,7 @@ single_quoted_string <- "'" string:(!"'" ("\\\\" / "\\'" / .))* "'" ~;
character_class <- '[' characters:(!']' ('\\\\' . / !'\\\\' .))+ ']'
`
["p_charclass(<<\"[",
escape_quotes(io_lib:format("~s", [iolist_to_binary(proplists:get_value(characters, Node))])),
escape_string(binary_to_list(iolist_to_binary(proplists:get_value(characters, Node)))),
"]\">>)"]
`;

Expand Down Expand Up @@ -165,9 +165,28 @@ code_block <- ( '%{' code:('\\%' / '$%' / !'%}' .)+ '%}' ) /

%% Extra functions
`
escape_quotes(String) ->
{ok, RE} = re:compile("\""),
re:replace(String, RE, "\\\\\"", [global, {return, binary}]).
% insert escapes into a string
escape_string(String) -> escape_string(String, []).

escape_string([], Output) ->
lists:reverse(Output);
escape_string([H|T], Output) ->
escape_string(T,
case H of
$/ -> [$/,$\\|Output];
$\" -> [$\",$\\|Output]; % " comment inserted to help some editors with highlighting the generated parser
$\' -> [$\',$\\|Output]; % ' comment inserted to help some editors with highlighting the generated parser
$\b -> [$b,$\\|Output];
$\d -> [$d,$\\|Output];
$\e -> [$e,$\\|Output];
$\f -> [$f,$\\|Output];
$\n -> [$n,$\\|Output];
$\r -> [$r,$\\|Output];
$\s -> [$s,$\\|Output];
$\t -> [$t,$\\|Output];
$\v -> [$v,$\\|Output];
_ -> [H|Output]
end).

add_lhs(Symbol, Index) ->
case ets:lookup(memo_table_name(), lhs) of
Expand Down
56 changes: 29 additions & 27 deletions priv/peg_includes.erl → priv/peg_includes.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,19 @@ p(Inp, Index, Name, ParseFun) ->
p(Inp, Index, Name, ParseFun, fun(N, _Idx) -> N end).

p(Inp, StartIndex, Name, ParseFun, TransformFun) ->
% Grab the memo table from ets
Memo = get_memo(StartIndex),
% See if the current reduction is memoized
case proplists:lookup(Name, Memo) of
% If it is, return the result
{Name, Result} -> Result;
% If not, attempt to parse
_ ->
case get_memo(StartIndex, Name) of % See if the current reduction is memoized
{ok, Memo} -> %Memo; % If it is, return the stored result
Memo;
_ -> % If not, attempt to parse
case ParseFun(Inp, StartIndex) of
% If it fails, memoize the failure
{fail,_} = Failure ->
memoize(StartIndex, [{Name, Failure}|Memo]),
Failure;
% If it passes, transform and memoize the result.
{Result, InpRem, NewIndex} ->
Transformed = TransformFun(Result, StartIndex),
memoize(StartIndex, [{Name, {Transformed, InpRem, NewIndex}}|Memo]),
{Transformed, InpRem, NewIndex}
end
{fail,_} = Failure -> % If it fails, memoize the failure
Result = Failure;
{Match, InpRem, NewIndex} -> % If it passes, transform and memoize the result.
Transformed = TransformFun(Match, StartIndex),
Result = {Transformed, InpRem, NewIndex}
end,
memoize(StartIndex, Name, Result),
Result
end.

setup_memo() ->
Expand All @@ -34,14 +28,22 @@ setup_memo() ->
release_memo() ->
ets:delete(memo_table_name()).

memoize(Position, Struct) ->
ets:insert(memo_table_name(), {Position, Struct}).

get_memo(Position) ->
case ets:lookup(memo_table_name(), Position) of
[] -> [];
[{Position, PList}] -> PList
end.
memoize(Index, Name, Result) ->
Memo = case ets:lookup(memo_table_name(), Index) of
[] -> [];
[{Index, Plist}] -> Plist
end,
ets:insert(memo_table_name(), {Index, [{Name, Result}|Memo]}).

get_memo(Index, Name) ->
case ets:lookup(memo_table_name(), Index) of
[] -> {error, not_found};
[{Index, Plist}] ->
case proplists:lookup(Name, Plist) of
{Name, Result} -> {ok, Result};
_ -> {error, not_found}
end
end.

memo_table_name() ->
get(parse_memo_table).
Expand Down Expand Up @@ -166,7 +168,7 @@ p_charclass(Class) ->
{match, [{0, Length}|_]} ->
{Head, Tail} = erlang:split_binary(Inp, Length),
{Head, Tail, p_advance_index(Head, Index)};
_ -> {fail, {expected, {character_class, Class}, Index}}
_ -> {fail, {expected, {character_class, binary_to_list(Class)}, Index}}
end
end.

Expand Down
Binary file modified rebar
Binary file not shown.
3 changes: 2 additions & 1 deletion src/neotoma.erl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ file(InputGrammar, Options) ->
ModuleAttrs = generate_module_attrs(ModuleName),
EntryFuns = generate_entry_functions(Root),
TransformFun = create_transform(TransformModule, OutputDir, GenTransform),
{ok, PegIncludes} = file:read_file(filename:join([filename:dirname(code:which(neotoma)), "..", "priv", "peg_includes.erl"])),
% {ok, PegIncludes} = file:read_file(code:priv_dir(neotoma) ++ "/peg_includes.hrl"),
{ok, PegIncludes} = file:read_file(filename:dirname(filename:dirname(code:where_is_file("neotoma.beam"))) ++ "/priv/peg_includes.hrl"),
file:write_file(OutputFilename, [ModuleAttrs, "\n", Code, "\n", EntryFuns, "\n", Rules, "\n", TransformFun, "\n", PegIncludes]).

validate_params(InputGrammar, _, _, OutputFile) when InputGrammar =:= OutputFile ->
Expand Down
Loading

0 comments on commit fbcde98

Please sign in to comment.