Skip to content

Commit

Permalink
Added new modules lfe_boot and lfe_gen, very cool. Also minor fixes.
Browse files Browse the repository at this point in the history
  • Loading branch information
rvirding committed Sep 28, 2008
1 parent e349850 commit 0aede8c
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 12 deletions.
15 changes: 15 additions & 0 deletions README
Expand Up @@ -5,3 +5,18 @@ code. An LFE evaluator and shell is also included.
This is the first version with the modified internal core forms and
macro intefaces for the new CL inspired style and the older Scheme
inspired style.

Two new modules have been added:

lfe_boot allows you start Erlang with the LFE shell running and still
have ^G enabled and user_drv running. Use it as follows:

erl -noshell -noinput -s lfe_boot start

NOTE order of commands important, must be -noshell -noinput! Add -pa
to find modules if necessary.

lfe_gen is a trial interface for using LFE for dynamic code
generation. LFE is much easier to generate as an Erkang list than
Erlang forms. This module helps defining and compiling a module. Note,
that while it works, this module is very experimental and may change.
Binary file added ebin/lfe_boot.beam
Binary file not shown.
Binary file modified ebin/lfe_comp.beam
Binary file not shown.
Binary file added ebin/lfe_gen.beam
Binary file not shown.
Binary file modified ebin/lfe_io.beam
Binary file not shown.
9 changes: 9 additions & 0 deletions src/ChangeLog
@@ -1,3 +1,12 @@
2008-09-28 <rv@DOUGLAS>

* lfe_gen.erl: Support for dynamic code generation.

* lfe_boot.erl: Start Erlang with the LFE shell running.

* lfe_io.erl (print1_bits): Allow printing of some of the bytes in
a bitstring.

2008-09-27 <rv@DOUGLAS>

* lfe_macro.erl (macro): Apply function of course.
Expand Down
44 changes: 44 additions & 0 deletions src/lfe_boot.erl
@@ -0,0 +1,44 @@
%% Copyright (c) 2008 Robert Virding. All rights reserved.
%%
%% Redistribution and use in source and binary forms, with or without
%% modification, are permitted provided that the following conditions
%% are met:
%%
%% 1. Redistributions of source code must retain the above copyright
%% notice, this list of conditions and the following disclaimer.
%% 2. Redistributions in binary form must reproduce the above copyright
%% notice, this list of conditions and the following disclaimer in the
%% documentation and/or other materials provided with the distribution.
%%
%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
%% "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
%% LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
%% FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
%% COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
%% INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
%% BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
%% LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
%% CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
%% LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
%% ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
%% POSSIBILITY OF SUCH DAMAGE.

%%% File : lfe_boot.erl
%%% Author : Robert Virding
%%% Purpose : Lisp Flavoured Erlang boot module.

%%% This little beauty allows you to start Erlang with the LFE shell
%%% running and still has ^G and user_drv enabled. Use it as follows:
%%%
%%% erl -noshell -noinput -s lfe_boot start
%%%
%%% NOTE order of commands important, must be -noshell -noinput! Add
%%% -pa to find modules if necessary.
%%%
%%% Thanks to Attila Babo for showing me how to do this.

-module(lfe_boot).

-export([start/0]).

start() -> user_drv:start(['tty_sl -c -e',{lfe_shell,start,[]}]).
8 changes: 4 additions & 4 deletions src/lfe_comp.erl
Expand Up @@ -125,10 +125,10 @@ do_return(Core, Warns, St) ->
forms(Forms) -> forms(Forms, []). %Default options.
forms(Forms, Opts) ->
case forms(Forms, #comp{}, Opts) of
{ok,Core,_,St} ->
{ok,Bin} = compile:forms(Core,
[from_core,return_errors|St#comp.opts]),
{ok,St#comp.mod,Bin};
{ok,Core,Ws,St} ->
{ok,_,Bin} =
compile:forms(Core, [from_core,return_errors|St#comp.opts]),
{ok,St#comp.mod,Bin,Ws};
{error,Es,Ws,_} -> {error,Es,Ws}
end.

Expand Down
114 changes: 114 additions & 0 deletions src/lfe_gen.erl
@@ -0,0 +1,114 @@
%% Copyright (c) 2008 Robert Virding. All rights reserved.
%%
%% Redistribution and use in source and binary forms, with or without
%% modification, are permitted provided that the following conditions
%% are met:
%%
%% 1. Redistributions of source code must retain the above copyright
%% notice, this list of conditions and the following disclaimer.
%% 2. Redistributions in binary form must reproduce the above copyright
%% notice, this list of conditions and the following disclaimer in the
%% documentation and/or other materials provided with the distribution.
%%
%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
%% "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
%% LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
%% FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
%% COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
%% INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
%% BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
%% LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
%% CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
%% LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
%% ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
%% POSSIBILITY OF SUCH DAMAGE.

%%% File : lfe_gen.erl
%%% Author : Robert Virding
%%% Purpose : Lisp Flavoured Erlang dynamic code generator.

-module(lfe_gen).

-export([compile_forms/1]).
-export([new_module/1,add_exports/2,add_imports/2,add_form/2,
print_mod/1,compile_mod/1]).

-import(lists, [map/2,foldl/3,mapfoldl/3]).
-import(ordsets, [add_element/2]).
-import(orddict, [store/3,find/2]).

-record(gen, {name,exps=[],imps=[],atts=[],forms=[]}).

%% compile_forms(Forms) -> {ok,Name,Bin,Warns} | {error,Errors,Warns}.
%% Compile all LFE module forms in one go.

compile_forms(Fs0) ->
%% Tag forms with a "line number", just use their index.
{Fs1,_} = mapfoldl(fun (F, N) -> {{F,N},N+1} end, 1, Fs0),
case lfe_comp:forms(Fs1, []) of
{ok,Mod,Bin,Ws} -> {ok,Mod,Bin,Ws};
{error,Es,Ws} -> {error,Es,Ws}
end.

%% new_module(Name) -> Module.
%% add_exports([{Name,Arity}], Module) -> Module.
%% add_imports({from,Mod,[{Name,Arity}]}, Module) -> Module.
%% add_form(Form, Module) -> Module.
%% print_mod(Module) -> iolist().
%% compile_mod(Mod) -> {ok,Name,Bin,Warns} | {error,Errors,Warns}.
%% The incremental interface to compiling a module.

new_module(Name) ->
#gen{name=Name,forms=[]}.

add_exports(Exps, Mod) ->
Es0 = Mod#gen.exps,
Es1 = foldl(fun ({N,Ar}, Es) when is_atom(N), is_integer(Ar) ->
add_element({N,Ar}, Es)
end, Es0, Exps),
Mod#gen{exps=Es1}.

add_imports({from,M,Is}, Mod) ->
Imps0 = Mod#gen.imps,
Imps1 = collect_imp(fun ({F,A}, Imps) -> store({F,A}, F, Imps) end,
M, Imps0, Is),
Mod#gen{imps=Imps1};
add_imports({rename,M,Is}, Mod) ->
Imps0 = Mod#gen.imps,
Imps1 = collect_imp(fun ({{F,A},R}, Imps) -> store({F,A}, R, Imps) end,
M, Imps0, Is),
Mod#gen{imps=Imps1}.

add_form(Form, Mod) ->
Mod#gen{forms=Mod#gen.forms ++ [Form]}.

compile_mod(Mod) ->
Fs = [build_def(Mod)|Mod#gen.forms],
compile_forms(Fs).

print_mod(Mod) -> %Needs fixing
map(fun (F) -> [lfe_io:prettyprint1(F, 0),io_lib:nl()] end,
[build_def(Mod)|Mod#gen.forms]).

collect_imp(Fun, Mod, Imps, Is) ->
Mimps0 = safe_fetch(Mod, Imps, []),
Mimps1 = foldl(Fun, Mimps0, Is),
store(Mod, Mimps1, Imps).

build_def(Mod) ->
Exps = map(fun ({N,I}) -> [N,I] end, Mod#gen.exps),
Imps = map(fun ({M,Is}) ->
[rename,M|map(fun ({{L,Ar},R}) -> [[L,Ar],R] end,
Is)]
end, Mod#gen.imps),
[defmodule,Mod#gen.name,
[export|Exps],
[import|Imps]].

%% safe_fetch(Key, Dict, Default) -> Value.

safe_fetch(Key, D, Def) ->
case find(Key, D) of
{ok,Val} -> Val;
error -> Def
end.
20 changes: 12 additions & 8 deletions src/lfe_io.erl
Expand Up @@ -146,11 +146,14 @@ print1_symb(Symb) ->
%% Print the bytes in a bitstring. Print bytes except for last which
%% we print as bitstring segement if not 8 bits big.

print1_bits(<<B:8>>) -> integer_to_list(B); %Catch last binary byte
print1_bits(<<B:8,Bits/bitstring>>) ->
[integer_to_list(B),$\s|print1_bits(Bits)];
print1_bits(<<>>) -> [];
print1_bits(Bits) -> %0 < Size < 8
print1_bits(Bits) -> print1_bits(Bits, -1). %Print them all

print1_bits(_, 0) -> "...";
print1_bits(<<B:8>>, _) -> integer_to_list(B); %Catch last binary byte
print1_bits(<<B:8,Bits/bitstring>>, N) ->
[integer_to_list(B),$\s|print1_bits(Bits, N-1)];
print1_bits(<<>>, _) -> [];
print1_bits(Bits, _) -> %0 < Size < 8
N = bit_size(Bits),
<<B:N>> = Bits,
io_lib:format("(~w bitstring (size ~w))", [B,N]).
Expand Down Expand Up @@ -288,7 +291,7 @@ prettyprint1(Tup, I) when is_tuple(Tup) ->
["#(",prettyprint1(hd(List), I+2),pp_tail(tl(List), I+2),")"]
end;
prettyprint1(Bit, _) when is_bitstring(Bit) ->
["#B(",print1_bits(Bit),$)].
["#B(",print1_bits(Bit, 30),$)]. %First 30 bytes

%% split(N, List) -> {List1,List2}.
%% Split a list into two lists, the first containing the first N
Expand Down Expand Up @@ -323,8 +326,7 @@ indent_type('let-syntax') -> 1;
indent_type('syntax-rules') -> 0;
indent_type('macro') -> 0;
%% New style functions.
indent_type('define-function') -> 1;
indent_type('define-macro') -> 1;
indent_type('defmodule') -> 1;
indent_type('defun') -> 1;
indent_type('defmacro') -> 1;
indent_type('defsyntax') -> 1;
Expand All @@ -343,6 +345,8 @@ indent_type('cond') -> 999; %All following forms
indent_type('catch') -> 0;
indent_type('try') -> 1;
indent_type('call') -> 2;
indent_type('define-function') -> 1;
indent_type('define-macro') -> 1;
%% Core macros.
indent_type('let*') -> 1;
indent_type('flet') -> 1;
Expand Down

0 comments on commit 0aede8c

Please sign in to comment.