Skip to content
Browse files

Erlang SPKI SEXP.

  • Loading branch information...
1 parent 05123a4 commit f92a6e19deb3e8c43219a99262ed4c42740018da @tonyg committed May 30, 2012
View
2 experiments/erlang/.gitignore
@@ -0,0 +1,2 @@
+ebin
+erl_crash.dump
View
17 experiments/erlang/Makefile
@@ -0,0 +1,17 @@
+all: compile
+
+compile:
+ ./rebar compile
+
+clean:
+ ./rebar clean
+ -rmdir ebin
+
+veryclean: clean
+ rm -rf rel
+ rm -f erl_crash.dump
+
+run: compile
+ erl -pa ebin \
+ -boot start_sasl \
+ -run hop_demo start localhost
View
BIN experiments/erlang/rebar
Binary file not shown.
View
8 experiments/erlang/src/hop.app.src
@@ -0,0 +1,8 @@
+%% -*- erlang -*-
+{application, hop,
+ [{description, "Hop"},
+ {vsn, "0.0.1"},
+ {registered, []},
+ {applications, [kernel,
+ stdlib]},
+ {env, []}]}.
View
122 experiments/erlang/src/sexp.erl
@@ -0,0 +1,122 @@
+%% Copyright 2010, 2011, 2012 Tony Garnock-Jones <tonygarnockjones@gmail.com>.
+%%
+%% This file is part of Hop.
+%%
+%% Hop is free software: you can redistribute it and/or modify it
+%% under the terms of the GNU General Public License as published by
+%% the Free Software Foundation, either version 3 of the License, or
+%% (at your option) any later version.
+%%
+%% Hop is distributed in the hope that it will be useful, but WITHOUT
+%% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+%% or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+%% License for more details.
+%%
+%% You should have received a copy of the GNU General Public License
+%% along with Hop. If not, see <http://www.gnu.org/licenses/>.
+
+-module(sexp).
+%% SPKI SEXP.
+
+-export([lex_state/0, lex/1, lex/2]).
+-export([parse_state/0, parse/1, parse/2]).
+-export([format/1, format_iolist/1]).
+
+%% Lexer states
+-record(init, {}).
+-record(str, {remaining, pieces_rev}).
+-record(strlen, {value}).
+
+%% Parser states
+-record(parser, {lexer, stack}).
+
+-define(ZERO, 48).
+-define(NINE, 57).
+
+lex_state() ->
+ #init{}.
+
+lex(Chunk) ->
+ lex(Chunk, lex_state()).
+
+lex(<<"(", Rest/binary>>, State = #init{}) ->
+ {Events, FinalState} = lex(Rest, State),
+ {[open | Events], FinalState};
+lex(<<")", Rest/binary>>, State = #init{}) ->
+ {Events, FinalState} = lex(Rest, State),
+ {[close | Events], FinalState};
+lex(<<"[", Rest/binary>>, State = #init{}) ->
+ {Events, FinalState} = lex(Rest, State),
+ {[hint_open | Events], FinalState};
+lex(<<"]", Rest/binary>>, State = #init{}) ->
+ {Events, FinalState} = lex(Rest, State),
+ {[hint_close | Events], FinalState};
+lex(<<D, Rest/binary>>, #init{}) when D >= ?ZERO andalso D =< ?NINE ->
+ lex(Rest, #strlen{value = D - ?ZERO});
+lex(<<X, Rest/binary>>, State = #init{}) when X =< 32 ->
+ lex(Rest, State);
+lex(<<D, Rest/binary>>, #strlen{value = V}) when D >= ?ZERO andalso D =< ?NINE ->
+ lex(Rest, #strlen{value = V * 10 + D - ?ZERO});
+lex(<<":", Rest/binary>>, #strlen{value = V}) ->
+ lex(Rest, #str{remaining = V, pieces_rev = []});
+lex(Chunk, #str{remaining = Len, pieces_rev = PiecesRev}) ->
+ case Chunk of
+ <<Piece:Len/binary, Rest/binary>> ->
+ {Events, FinalState} = lex(Rest, #init{}),
+ {[{str, iolist_to_binary(lists:reverse([Piece | PiecesRev]))} | Events], FinalState};
+ _ ->
+ {[], #str{remaining = Len - size(Chunk), pieces_rev = [Chunk | PiecesRev]}}
+ end;
+lex(<<>>, State) ->
+ {[], State}.
+
+parse_state() ->
+ #parser{lexer = lex_state(), stack = []}.
+
+parse(Chunk) ->
+ Inert = parse_state(),
+ case parse(Chunk, Inert) of
+ {Terms, Inert} -> {ok, Terms, Inert};
+ {Terms, Other} -> {more, Terms, Other}
+ end.
+
+parse(Chunk, #parser{lexer = Lexer, stack = Stack}) ->
+ {Events, NewLexer} = lex(Chunk, Lexer),
+ {Terms, NewStack} = parse_events(Events, Stack),
+ {Terms, #parser{lexer = NewLexer, stack = NewStack}}.
+
+parse_events([open | Rest], Stack) ->
+ parse_events(Rest, [[] | Stack]);
+parse_events([close | Rest], [AccRev]) when is_list(AccRev) ->
+ {Terms, NewStack} = parse_events(Rest, []),
+ {[lists:reverse(AccRev) | Terms], NewStack};
+parse_events([close | Rest], [AccRev, AccRevOuter | Stack]) when is_list(AccRev) ->
+ parse_events(Rest, [[lists:reverse(AccRev) | AccRevOuter] | Stack]);
+parse_events([hint_open | Rest], Stack) ->
+ parse_events(Rest, [hint | Stack]);
+parse_events([{str, Bin} | Rest], [hint | Stack]) ->
+ parse_events(Rest, [{hint, Bin} | Stack]);
+parse_events([hint_close | Rest], Stack = [{hint, _} | _]) ->
+ parse_events(Rest, Stack);
+parse_events([{str, BodyBin} | Rest], [{hint, HintBin} | Stack]) ->
+ {Terms, NewStack} = parse_events(Rest, Stack),
+ {[{HintBin, BodyBin} | Terms], NewStack};
+parse_events([{str, Bin} | Rest], Stack = []) ->
+ {Terms, NewStack} = parse_events(Rest, Stack),
+ {[Bin | Terms], NewStack};
+parse_events([{str, Bin} | Rest], [AccRev | Stack]) when is_list(AccRev) ->
+ parse_events(Rest, [[Bin | AccRev] | Stack]);
+parse_events([], Stack) ->
+ {[], Stack}.
+
+format(Sexp) ->
+ iolist_to_binary(format_iolist(Sexp)).
+
+format_bin(Bin) -> [integer_to_list(size(Bin)), $:, Bin].
+
+format_iolist(Bin) when is_binary(Bin) ->
+ format_bin(Bin);
+format_iolist({H, B}) when is_binary(H) andalso is_binary(B) ->
+ [$[, format_bin(H), $], format_bin(B)];
+format_iolist(Sexps) when is_list(Sexps) ->
+ [$(, [format_iolist(Sexp) || Sexp <- Sexps], $)].

0 comments on commit f92a6e1

Please sign in to comment.
Something went wrong with that request. Please try again.