changed Makefile
 
@@ -22,6 +22,8 @@ LSRCDIR = src
22
22
INCDIR = include
23
23
EMACSDIR = emacs
24
24
HOSTCC ?= $(CC)
25
+ CFLAGS ?= -Wall -Wextra
26
+ LDFLAGS ?= -Wl,--as-needed
25
27
PREFIX ?= /usr/local
26
28
INSTALL = install
27
29
INSTALL_DIR = $(INSTALL) -m755 -d
 
@@ -73,7 +75,7 @@ ELCS = $(EMACSRCS:.el=.elc)
73
75
.SUFFIXES: .erl .beam
74
76
75
77
$(BINDIR)/%: $(CSRCDIR)/%.c
76
- $(HOSTCC) -o $@ $<
78
+ $(HOSTCC) $(CFLAGS) $(LDFLAGS) -o $@ $<
77
79
78
80
$(EBINDIR)/%.beam: $(SRCDIR)/%.erl
79
81
@$(INSTALL_DIR) $(EBINDIR)
 
@@ -147,6 +149,9 @@ install-bin:
147
149
clean:
148
150
rm -rf $(EBINDIR)/*.beam erl_crash.dump comp_opts.mk
149
151
152
+ clean-all: clean
153
+ rm -rf _build
154
+
150
155
echo:
151
156
@ echo $(ESRCS)
152
157
@ echo $(XSRCS)
 
@@ -217,6 +222,10 @@ TXT7S = $(MAN7_SRCS:.7.md=.txt)
217
222
PDF7S = $(MAN7_SRCS:.7.md=.pdf)
218
223
EPUB7S = $(MAN7_SRCS:.7.md=.epub)
219
224
225
+ # For pandoc for generating PDFs as it omly accepts a few options.
226
+ # xelatex is a reasonable default or wkhtmltopdf.
227
+ PANDOCPDF ?= xelatex
228
+
220
229
# Just generate the docs that are tracked in git
221
230
docs: docs-txt
222
231
 
@@ -269,13 +278,13 @@ docs-pdf: $(PDFDIR) \
269
278
$(addprefix $(PDFDIR)/, $(PDF7S))
270
279
271
280
$(PDFDIR)/%.pdf: $(DOCSRC)/%.1.md
272
- pandoc -f markdown --pdf-engine=xelatex -o $@ $<
281
+ pandoc -f markdown --pdf-engine=$(PANDOCPDF) -o $@ $<
273
282
274
283
$(PDFDIR)/%.pdf: $(DOCSRC)/%.3.md
275
- pandoc -f markdown --pdf-engine=xelatex -o $@ $<
284
+ pandoc -f markdown --pdf-engine=$(PANDOCPDF) -o $@ $<
276
285
277
286
$(PDFDIR)/%.pdf: $(DOCSRC)/%.7.md
278
- pandoc -f markdown --pdf-engine=xelatex -o $@ $<
287
+ pandoc -f markdown --pdf-engine=$(PANDOCPDF) -o $@ $<
279
288
280
289
$(EPUBDIR):
281
290
@$(INSTALL_DIR) $(EPUBDIR)
 
@@ -310,6 +319,10 @@ update-mandb:
310
319
@echo "Updating man page database ..."
311
320
$(MANDB) $(MANINSTDIR)
312
321
322
+ ##############
323
+ ### DOCKER ###
324
+ ##############
325
+
313
326
# Targets for working with Docker
314
327
docker-build:
315
328
docker build -t lfex/lfe:latest .
 
@@ -331,3 +344,14 @@ docker-docs:
331
344
docker-docs-bash:
332
345
docker run -i -v `pwd`/doc:/docs -t lfex/lfe-docs:latest bash
333
346
347
+ ################
348
+ ### RELEASES ###
349
+ ################
350
+
351
+ hex-publish: clean-all compile
352
+ rebar3 hex publish package
353
+
354
+ tags:
355
+ git tag $(shell erl -eval $(GET_VERSION)|tr -d '"')
356
+ git tag v$(shell erl -eval $(GET_VERSION)|tr -d '"')
357
+ git push --tags
changed README.md
 
@@ -24,6 +24,13 @@ $ make compile
24
24
LFE requires Erlang be installed on the system and that the ``erl`` binary is
25
25
in ``$PATH``.
26
26
27
+ ## Running the Tests
28
+
29
+ To run the full suite of tests for LFE, simply use the following:
30
+
31
+ ```sh
32
+ make tests
33
+ ```
27
34
28
35
## Installation
29
36
 
@@ -60,20 +67,27 @@ like so after compiling:
60
67
61
68
```shell
62
69
$ ./bin/lfe
63
- Erlang 17 (erts-6.0) [source] [64-bit] [smp:8:8] ...
70
+ ```
71
+ ```text
72
+ Erlang/OTP 26 [erts-14.0.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace]
64
73
65
- LFE Shell V6.0 (abort with ^G)
66
- >
74
+ ..-~.~_~---..
75
+ ( \\ ) | A Lisp-2+ on the Erlang VM
76
+ |`-.._/_\\_.-': | Type (help) for usage info.
77
+ | g |_ \ |
78
+ | n | | | Docs: https://docs.lfe.io/
79
+ | a / / | Source: https://github.com/lfe/lfe
80
+ \ l |_/ |
81
+ \ r / | LFE v2.1.3 (abort with ^G)
82
+ `-E___.-'
83
+
84
+ lfe>
67
85
```
68
86
69
87
If you have installed LFE, then you may start the REPL from any location:
70
88
71
89
```shell
72
90
$ lfe
73
- Erlang 17 (erts-6.0) [source] [64-bit] [smp:8:8] ...
74
-
75
- LFE Shell V6.0 (abort with ^G)
76
- >
77
91
```
78
92
79
93
Likewise, you may run an LFE shell script in the same style as shell scripts
 
@@ -97,9 +111,9 @@ that will show you how to start using LFE. However, here's a quick taste:
97
111
* start up an LFE REPL as demonstrated above
98
112
* then, do something like this:
99
113
```cl
100
- > (* 2 (+ 1 2 3 4 5 6))
114
+ lfe> (* 2 (+ 1 2 3 4 5 6))
101
115
42
102
- > (* 2 (lists:foldl #'+/2 0 (lists:seq 1 6)))
116
+ lfe> (* 2 (lists:foldl #'+/2 0 (lists:seq 1 6)))
103
117
42
104
118
```
105
119
 
@@ -119,27 +133,12 @@ $ cd lfe
119
133
$ docker build .
120
134
```
121
135
122
- Here are a couple of simple usage examples:
136
+ To bring up the LFE REPL:
123
137
124
138
```bash
125
- $ docker run lfex/lfe
126
- 42
139
+ $ docker run -it lfex/lfe
127
140
```
128
141
129
- ```bash
130
- $ docker run -i -t lfex/lfe lfe
131
- Erlang/OTP 18 [erts-7.0] [source-4d83b58] [64-bit] [smp:8:8] ...
132
-
133
- LFE Shell V7.0 (abort with ^G)
134
- >
135
- ```
136
-
137
- That last command will dump you into the LFE REPL on a running container
138
- of the ``lfex/lfe`` Docker image. For more information on using Docker
139
- with LFE, be sure to read the
140
- [tutorial](https://blog.lfe.io/tutorials/2014/12/07/1837-running-lfe-in-docker/).
141
-
142
-
143
142
## Documentation
144
143
145
144
* [Quick Start](https://lfe.gitbooks.io/quick-start/content/)
 
@@ -169,3 +168,37 @@ the docs, you'll want to read the instructions here:
169
168
[LFE on Slack](https://lfe.slack.com), join by requesting an invite [here](https://erlef.org/slack-invite/lfe)
170
169
171
170
[LFE Forum - Erlang Forums](https://erlangforums.com/lfe)
171
+
172
+ ## Maintainers
173
+
174
+ ### Cutting Releases
175
+
176
+ Steps:
177
+
178
+ 1. Update the version in `src/lfe.app.src`
179
+ 1. Create the release tags
180
+ 1. Create a release on Github
181
+ 1. Publish to hex.pm
182
+
183
+ Once the `app.src` has been updated with the version for the release, you can create and push the tags (to Github) with the following:
184
+
185
+ ``` shell
186
+ make tags
187
+ ```
188
+
189
+ That will create the number-only version as well as the "v"-prefixed version.
190
+
191
+ For now, the process of creating a release on Github is manual:
192
+
193
+ 1. Go to https://github.com/lfe/lfe/releases
194
+ 1. Click "Draft new release"
195
+ 1. Select the correct tag from the drop-down "Choose a tag"
196
+ 1. Click "Generate release notes"
197
+ 1. Click "Publish release"
198
+
199
+ Lastly, to publish LFE to hex.pm, you need to have rebar3 installed on our system and an entry for the hex plugin in your system `rebar.config` file. With that in place, publish a new release to hex.pm requires only the following:
200
+
201
+ ``` shell
202
+ make hex-publish
203
+ ```
204
+
changed hex_metadata.config
 
@@ -2,34 +2,34 @@
2
2
{<<"build_tools">>,[<<"rebar3">>]}.
3
3
{<<"description">>,<<"Lisp Flavored Erlang (LFE)">>}.
4
4
{<<"files">>,
5
- [<<"Emakefile">>,<<"LICENSE">>,<<"Makefile">>,<<"README.md">>,<<"bin">>,
6
- <<"bin/lfe">>,<<"bin/lfe-first-try">>,<<"bin/lfe-test">>,<<"bin/lfec">>,
7
- <<"bin/lfedoc">>,<<"bin/lfeexec">>,<<"bin/lfescript">>,<<"c_src">>,
8
- <<"c_src/lfeexec.c">>,<<"get_comp_opts.escript">>,<<"include">>,
9
- <<"include/cl.lfe">>,<<"include/clj.lfe">>,<<"include/match-spec.lfe">>,
10
- <<"include/scm.lfe">>,<<"rebar.config">>,<<"rebar.config.script">>,
11
- <<"rebar.lock">>,<<"src">>,<<"src/ChangeLog">>,<<"src/NOTES">>,
12
- <<"src/cl.lfe">>,<<"src/clj.lfe">>,<<"src/lfe.app.src">>,<<"src/lfe.erl">>,
13
- <<"src/lfe.hrl">>,<<"src/lfe_abstract_code.erl">>,<<"src/lfe_bits.erl">>,
14
- <<"src/lfe_codegen.erl">>,<<"src/lfe_codelift.erl">>,<<"src/lfe_comp.erl">>,
15
- <<"src/lfe_comp.hrl">>,<<"src/lfe_docs.erl">>,<<"src/lfe_docs.hrl">>,
16
- <<"src/lfe_edlin_expand.erl">>,<<"src/lfe_env.erl">>,<<"src/lfe_eval.erl">>,
17
- <<"src/lfe_eval_bits.erl">>,<<"src/lfe_gen.erl">>,<<"src/lfe_init.erl">>,
18
- <<"src/lfe_internal.erl">>,<<"src/lfe_io.erl">>,<<"src/lfe_io_format.erl">>,
19
- <<"src/lfe_io_pretty.erl">>,<<"src/lfe_io_write.erl">>,
20
- <<"src/lfe_lib.erl">>,<<"src/lfe_lint.erl">>,<<"src/lfe_macro.erl">>,
21
- <<"src/lfe_macro.hrl">>,<<"src/lfe_macro_export.erl">>,
22
- <<"src/lfe_macro_include.erl">>,<<"src/lfe_macro_record.erl">>,
23
- <<"src/lfe_macro_struct.erl">>,<<"src/lfe_ms.erl">>,<<"src/lfe_parse.erl">>,
24
- <<"src/lfe_parse.spell1">>,<<"src/lfe_qlc.erl">>,<<"src/lfe_scan.erl">>,
25
- <<"src/lfe_scan.xrl">>,<<"src/lfe_shell.erl">>,<<"src/lfe_shell_docs.erl">>,
5
+ [<<"Emakefile">>,<<"LICENSE">>,<<"Makefile">>,<<"README.md">>,<<"bin/lfe">>,
6
+ <<"bin/lfe-first-try">>,<<"bin/lfe-test">>,<<"bin/lfec">>,<<"bin/lfedoc">>,
7
+ <<"bin/lfeexec">>,<<"bin/lfescript">>,<<"c_src/lfeexec.c">>,
8
+ <<"get_comp_opts.escript">>,<<"include/cl.lfe">>,<<"include/clj.lfe">>,
9
+ <<"include/match-spec.lfe">>,<<"include/scm.lfe">>,<<"rebar.config">>,
10
+ <<"rebar.config.script">>,<<"rebar.lock">>,<<"src/ChangeLog">>,
11
+ <<"src/NOTES">>,<<"src/cl.lfe">>,<<"src/clj.lfe">>,<<"src/lfe.app.src">>,
12
+ <<"src/lfe.erl">>,<<"src/lfe.hrl">>,<<"src/lfe_abstract_code.erl">>,
13
+ <<"src/lfe_bits.erl">>,<<"src/lfe_codegen.erl">>,<<"src/lfe_codelift.erl">>,
14
+ <<"src/lfe_comp.erl">>,<<"src/lfe_comp.hrl">>,<<"src/lfe_docs.erl">>,
15
+ <<"src/lfe_docs.hrl">>,<<"src/lfe_edlin_expand.erl">>,<<"src/lfe_env.erl">>,
16
+ <<"src/lfe_eval.erl">>,<<"src/lfe_eval_bits.erl">>,<<"src/lfe_gen.erl">>,
17
+ <<"src/lfe_init.erl">>,<<"src/lfe_internal.erl">>,<<"src/lfe_io.erl">>,
18
+ <<"src/lfe_io_format.erl">>,<<"src/lfe_io_pretty.erl">>,
19
+ <<"src/lfe_io_write.erl">>,<<"src/lfe_lib.erl">>,<<"src/lfe_lint.erl">>,
20
+ <<"src/lfe_macro.erl">>,<<"src/lfe_macro.hrl">>,
21
+ <<"src/lfe_macro_export.erl">>,<<"src/lfe_macro_include.erl">>,
22
+ <<"src/lfe_macro_record.erl">>,<<"src/lfe_macro_struct.erl">>,
23
+ <<"src/lfe_ms.erl">>,<<"src/lfe_parse.erl">>,<<"src/lfe_parse.spell1">>,
24
+ <<"src/lfe_qlc.erl">>,<<"src/lfe_scan.erl">>,<<"src/lfe_scan.xrl">>,
25
+ <<"src/lfe_shell.erl">>,<<"src/lfe_shell_docs.erl">>,
26
26
<<"src/lfe_struct.erl">>,<<"src/lfe_translate.erl">>,
27
27
<<"src/lfe_types.erl">>,<<"src/lfescript.erl">>,<<"src/scm.erl">>]}.
28
- {<<"licenses">>,[<<"Apache">>]}.
28
+ {<<"licenses">>,[<<"Apache 2.0">>]}.
29
29
{<<"links">>,
30
30
[{<<"Documentation">>,<<"https://lfe.io/use/#reference">>},
31
31
{<<"Github">>,<<"https://github.com/lfe/lfe">>},
32
32
{<<"Main site">>,<<"https://lfe.io/">>}]}.
33
33
{<<"name">>,<<"lfe">>}.
34
34
{<<"requirements">>,[]}.
35
- {<<"version">>,<<"2.1.2">>}.
35
+ {<<"version">>,<<"2.1.3">>}.
changed rebar.config
 
@@ -9,18 +9,6 @@
9
9
{src_dirs, ["src", "test"]}]},
10
10
{dialyzer, []}]}.
11
11
12
- %% XXX Commenting this out due to weird recursion issues with rebar3_lfe ...
13
- %% Do we remember why we need this? I _thought_ it was to help with
14
- %% publishing LFE to hex.pm; once we remember, we should add a code
15
- %% for future reference.
16
- %% This issue is tracked here:
17
- %% * https://github.com/lfe/lfe/issues/461
18
- %% Long term solution being tracked here:
19
- %% * https://github.com/lfe/lfe/issues/460
20
- %% {plugins, [
21
- %% {rebar3_lfe, "0.3.1"}
22
- %% ]}.
23
-
24
12
{pre_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)", ct,
25
13
"bin/lfescript bin/lfec"
26
14
" -o $REBAR_DEPS_DIR/lfe/test"
changed src/lfe.app.src
 
@@ -1,6 +1,6 @@
1
1
{application,lfe,
2
2
[{description,"Lisp Flavored Erlang (LFE)"},
3
- {vsn,"2.1.2"},
3
+ {vsn,"2.1.3"},
4
4
{modules,[cl,clj,lfe,lfe_abstract_code,lfe_bits,lfe_codegen,
5
5
lfe_codelift,lfe_comp,lfe_docs,lfe_edlin_expand,
6
6
lfe_env,lfe_eval,lfe_eval_bits,lfe_gen,lfe_init,
 
@@ -12,8 +12,7 @@
12
12
lfe_types,lfescript,scm]},
13
13
{registered,[]},
14
14
{applications,[kernel,stdlib,compiler]},
15
- {maintainers,["Robert Virding"]},
16
- {licenses,["Apache"]},
15
+ {licenses,["Apache 2.0"]},
17
16
{links,[{"Github","https://github.com/lfe/lfe"},
18
17
{"Main site","https://lfe.io/"},
19
18
{"Documentation","https://lfe.io/use/#reference"}]},
changed src/lfe.erl
 
@@ -31,6 +31,9 @@
31
31
32
32
-export(['LFE-EXPAND-EXPORTED-MACRO'/3]).
33
33
34
+ %% Metadata
35
+ -export([version/0]).
36
+
34
37
%% 'LFE-EXPAND-EXPORTED-MACRO'(Name, Args, Env) -> {yes,Expansion} | no.
35
38
%% A smart implementation of this where we call the lfe_macro module
36
39
%% to expand and check for us. Using an empty environment ensures
 
@@ -166,3 +169,9 @@ macroexpand(Form, Env) ->
166
169
167
170
'macroexpand-all'(Form) -> 'macroexpand-all'(Form, lfe_env:new()).
168
171
'macroexpand-all'(Form, Env) -> lfe_macro:expand_expr_all(Form, Env).
172
+
173
+ %% Metadata
174
+
175
+ version() ->
176
+ {ok, [App]} = file:consult(code:where_is_file("lfe.app")),
177
+ proplists:get_value(vsn, element(3, App)).
changed src/lfe_bits.erl
 
@@ -1,4 +1,4 @@
1
- %% Copyright (c) 2011-2020 Robert Virding
1
+ %% Copyright (c) 2011-2023 Robert Virding
2
2
%%
3
3
%% Licensed under the Apache License, Version 2.0 (the "License");
4
4
%% you may not use this file except in compliance with the License.
changed src/lfe_codegen.erl
 
@@ -1,4 +1,4 @@
1
- %% Copyright (c) 2008-2020 Robert Virding
1
+ %% Copyright (c) 2008-2023 Robert Virding
2
2
%%
3
3
%% Licensed under the Apache License, Version 2.0 (the "License");
4
4
%% you may not use this file except in compliance with the License.
 
@@ -51,9 +51,12 @@
51
51
imports=orddict:new(), %Imports
52
52
aliases=orddict:new(), %Aliases
53
53
onload=[], %Onload
54
- atts=[], %Attrubutes
55
- defs=[], %Defined top-level functions
56
- opts=[], %Options
54
+ records=[], %Records
55
+ struct=undefined, %Struct definition
56
+ attrs=[], %Attrubutes
57
+ metas=[], %Meta data
58
+ funcs=orddict:new(), %Defined top-level functions
59
+ opts=[], %Compiler options
57
60
file=[], %File name
58
61
func=[], %Current function
59
62
errors=[], %Errors
 
@@ -70,7 +73,7 @@ format_error({illegal_code,Code}) ->
70
73
module(Mfs, #cinfo{opts=Opts,file=File}) ->
71
74
St0 = #lfe_cg{opts=Opts,file=File},
72
75
{AST,St1} = compile_module(Mfs, St0),
73
- %% io:format("imps ~p\n", [St1#lfe_cg.imports]),
76
+ %% io:format("st1 ~p\n", [St1]),
74
77
return_status(AST, St1).
75
78
76
79
return_status(AST, #lfe_cg{module=M,errors=[]}=St) ->
 
@@ -81,89 +84,105 @@ return_status(_AST, St) ->
81
84
compile_module(Mfs, St0) ->
82
85
%% Collect all the module attributes and output them first.
83
86
St1 = collect_mod_defs(Mfs, St0),
84
- Attrs = compile_attributes(St1),
87
+ %% Build the struct functions then __info__ function last.
88
+ St2 = build_struct_def(St1),
89
+ St3 = build_info_func(St2), %Must be last!
90
+ Attrs = compile_attributes(St3),
85
91
%% Now we do the meta, function and record forms in order. Here we
86
92
%% can get translation errors.
87
- %% Forms = compile_forms(Mfs, St1),
88
- {Forms,St2} =
93
+ %% Forms = compile_functions(St1),
94
+ {Functions,St4} =
89
95
try
90
- {compile_forms(Mfs, St1),St1}
96
+ {compile_functions(St3),St3}
91
97
catch
92
98
error:{illegal_code,Line,Code} ->
93
- {[],add_error(Line, {illegal_code,Code}, St1)}
99
+ {[],add_error(Line, {illegal_code,Code}, St3)}
94
100
end,
95
- {Attrs ++ Forms,St2}.
101
+ {Attrs ++ Functions,St4}.
96
102
97
103
%% collect_mod_defs(ModuleForms, State) -> State.
98
- %% Collect the attribute information in define-module and
99
- %% extend-module's which must be first in the output file.
104
+ %% Collect all the information in the module deinition for processing.
100
105
101
106
collect_mod_defs(Mfs, St) ->
102
107
lists:foldl(fun collect_mod_def/2, St, Mfs).
103
108
104
- collect_mod_def({['define-module',Mod,_Metas,Attrs],Line}, St0) ->
109
+ collect_mod_def({['define-module',Mod,Metas,Attrs],Line}, St0) ->
110
+ %% And now add the rest of the attributes and metas.
105
111
St1 = coll_mdef_attrs(Attrs, Line, St0),
106
- St1#lfe_cg{module=Mod,mline=Line};
107
- collect_mod_def({['extend-module',_Metas,Attrs],Line}, St0) ->
108
- coll_mdef_attrs(Attrs, Line, St0);
109
- collect_mod_def({['define-struct',_Fields],Line}, St) ->
110
- %% Export the struct functions.
111
- coll_mdef_attr([export,['__struct__',0],['__struct__',1]], Line, St);
112
+ St2 = coll_mdef_metas(Metas, Line, St1),
113
+ St2#lfe_cg{module=Mod,mline=Line};
114
+ collect_mod_def({['extend-module',Metas,Attrs],Line}, St0) ->
115
+ St1 = coll_mdef_attrs(Attrs, Line, St0),
116
+ coll_mdef_metas(Metas, Line, St1);
117
+ collect_mod_def({['define-type',Type,Def],Line}, St) ->
118
+ coll_mdef_meta([type,[Type,Def]], Line, St);
119
+ collect_mod_def({['define-opaque-type',Type,Def],Line}, St) ->
120
+ coll_mdef_meta([opaque,[Type,Def]], Line, St);
121
+ collect_mod_def({['define-function-spec',Func,Spec],Line}, St) ->
122
+ coll_mdef_meta([spec,[Func,Spec]], Line, St);
123
+ collect_mod_def({['define-record',Name,Fields],Line}, St) ->
124
+ %% io:format("cmd ~p\n", [[record,[Name,Fields]]]),
125
+ coll_mdef_meta([record,[Name,Fields]], Line, St);
126
+ collect_mod_def({['define-struct',Fields],Line}, St) ->
127
+ St#lfe_cg{struct={Fields,Line}};
112
128
collect_mod_def({['define-function',Name,_Meta,Def],Line},
113
- #lfe_cg{defs=Defs}=St) ->
114
- %% Must save all functions for export all.
115
- St#lfe_cg{defs=Defs ++ [{Name,Def,Line}]};
129
+ #lfe_cg{funcs=Funcs0}=St) ->
130
+ %% Must save all the functions.
131
+ Arity = func_arity(Def),
132
+ Funcs1 = orddict:store({Name,Arity}, {Def,Line}, Funcs0),
133
+ St#lfe_cg{funcs=Funcs1};
116
134
collect_mod_def(_Form, St) -> St. %Ignore everything else here
117
135
118
136
%% coll_mdef_attrs(Attributes, Line, State) -> State.
119
- %% Collect all the module attributes.
137
+ %% Collect all the module attributes. Keep the attributes in order.
120
138
121
139
coll_mdef_attrs(Attrs, Line, St) ->
122
140
lists:foldl(fun (A, S) -> coll_mdef_attr(A, Line, S) end, St, Attrs).
123
141
124
142
coll_mdef_attr([export|Es], _Line, St) ->
125
- coll_mdef_exps(Es, St);
143
+ coll_mdef_exports(Es, St);
126
144
coll_mdef_attr([import|Is], _Line, St) ->
127
- coll_mdef_imps(Is, St);
145
+ coll_mdef_imports(Is, St);
128
146
coll_mdef_attr(['module-alias'|As], _Line, St) ->
129
147
coll_mdef_aliases(As, St);
130
148
coll_mdef_attr([on_load,Onload], _Line, St) ->
131
149
coll_mdef_onload(Onload, St);
132
- %% Explicitly ignore any doc or record information here.
150
+ %% Explicitly ignore any doc here.
133
151
coll_mdef_attr([doc|_], _Line, St) -> St;
134
- coll_mdef_attr([record|_], _Line, St) -> St;
152
+ coll_mdef_attr([record|Recs], Line, St) ->
153
+ coll_mdef_records(Recs, Line, St);
135
154
%% Save anything else and get the format right.
136
- coll_mdef_attr([Name,Val], Line, #lfe_cg{atts=As}=St) ->
137
- St#lfe_cg{atts=As ++ [{Name,Val,Line}]};
138
- coll_mdef_attr([Name|Vals], Line, #lfe_cg{atts=As}=St) ->
139
- St#lfe_cg{atts=As ++ [{Name,Vals,Line}]}.
155
+ coll_mdef_attr([Name,Val], Line, #lfe_cg{attrs=Attrs}=St) ->
156
+ St#lfe_cg{attrs=Attrs ++ [{Name,Val,Line}]};
157
+ coll_mdef_attr([Name|Vals], Line, #lfe_cg{attrs=Attrs}=St) ->
158
+ St#lfe_cg{attrs=Attrs ++ [{Name,Vals,Line}]}.
140
159
141
- %% coll_mdef_exps(Export, State) -> State.
160
+ %% coll_mdef_exports(Export, State) -> State.
142
161
%% Collect exports special casing 'all'.
143
162
144
- coll_mdef_exps([all], St) -> St#lfe_cg{exports=all};
145
- coll_mdef_exps(_Exps, #lfe_cg{exports=all}=St) -> St;
146
- coll_mdef_exps(Exps, #lfe_cg{exports=Exps0}=St) ->
163
+ coll_mdef_exports([all], St) -> St#lfe_cg{exports=all};
164
+ coll_mdef_exports(_Exps, #lfe_cg{exports=all}=St) -> St;
165
+ coll_mdef_exports(Exps, #lfe_cg{exports=Exps0}=St) ->
147
166
Exps1 = lists:foldl(fun ([F,A], E) -> ordsets:add_element({F,A}, E) end,
148
167
Exps0, Exps),
149
168
St#lfe_cg{exports=Exps1}.
150
169
151
- %% coll_mdef_imps(Imports, State) -> State.
170
+ %% coll_mdef_imports(Imports, State) -> State.
152
171
%% Collect imports keeping track of local and imported names.
153
172
154
- coll_mdef_imps(Imps, St) ->
155
- lists:foldl(fun (I, S) -> coll_mdef_imp(I, S) end, St, Imps).
173
+ coll_mdef_imports(Imps, St) ->
174
+ lists:foldl(fun (I, S) -> coll_mdef_import(I, S) end, St, Imps).
156
175
157
- coll_mdef_imp(['from',Mod|Fs], St) ->
176
+ coll_mdef_import(['from',Mod|Fs], St) ->
158
177
Ifun = fun ([F,A], Ifs) -> orddict:store({F,A}, {Mod,F}, Ifs) end,
159
- coll_mdef_imp(Ifun, St, Fs);
160
- coll_mdef_imp(['rename',Mod|Fs], St) ->
178
+ coll_mdef_import(Ifun, St, Fs);
179
+ coll_mdef_import(['rename',Mod|Fs], St) ->
161
180
%% Get it right here, R is the renamed local called function, F is
162
181
%% the name in the other module.
163
182
Ifun = fun ([[F,A],R], Ifs) -> orddict:store({R,A}, {Mod,F}, Ifs) end,
164
- coll_mdef_imp(Ifun, St, Fs).
183
+ coll_mdef_import(Ifun, St, Fs).
165
184
166
- coll_mdef_imp(Fun, #lfe_cg{imports=Imps0}=St, Fs) ->
185
+ coll_mdef_import(Fun, #lfe_cg{imports=Imps0}=St, Fs) ->
167
186
Imps1 = lists:foldl(Fun, Imps0, Fs),
168
187
St#lfe_cg{imports=Imps1}.
169
188
 
@@ -175,73 +194,197 @@ coll_mdef_aliases(As, #lfe_cg{aliases=Als0}=St) ->
175
194
Als0, As),
176
195
St#lfe_cg{aliases=Als1}.
177
196
178
- %% coll_mdef_onload(Onload, State) ->
197
+ %% coll_mdef_onload(Onload, State) -> State.
179
198
%% Collect the on_load function name.
180
199
181
200
coll_mdef_onload([Name,Ar], St) ->
182
201
St#lfe_cg{onload={Name,Ar}}.
183
202
203
+ %% coll_mdef_records(Records, Line, State) -> State.
204
+ %% Collect the record definitions.
205
+
206
+ coll_mdef_records(RecordDefs, Line, St) ->
207
+ Fun = fun ([Name,Fields], #lfe_cg{records=Recs}=S) ->
208
+ S#lfe_cg{records=Recs ++ [{Name,Fields,Line}]}
209
+ end,
210
+ lists:foldl(Fun, St, RecordDefs).
211
+
212
+ %% coll_mdef_metas(Metas, Line, State) -> State.
213
+ %% Collect all the module metas. Keep the metas in order.
214
+
215
+ coll_mdef_metas(Metas, Line, St) ->
216
+ lists:foldl(fun (M, S) -> coll_mdef_meta(M, Line, S) end, St, Metas).
217
+
218
+ coll_mdef_meta([type|Tdefs], Line, #lfe_cg{metas=Metas}=St) ->
219
+ St#lfe_cg{metas=Metas ++ [{type,Tdefs,Line}]};
220
+ coll_mdef_meta([opaque|Tdefs], Line, #lfe_cg{metas=Metas}=St) ->
221
+ St#lfe_cg{metas=Metas ++ [{opaque,Tdefs,Line}]};
222
+ coll_mdef_meta([spec|Fspecs], Line, #lfe_cg{metas=Metas}=St) ->
223
+ St#lfe_cg{metas=Metas ++ [{spec,Fspecs,Line}]};
224
+ coll_mdef_meta([record|Rdefs], Line, #lfe_cg{metas=Metas}=St) ->
225
+ St#lfe_cg{metas=Metas ++ [{record,Rdefs,Line}]};
226
+ %% Ignore other metas.
227
+ coll_mdef_meta(_Meta, _Line, St) ->
228
+ St.
229
+
230
+ %% build_struct_def(State) -> State.
231
+ %% build_info_func(State) -> State.
232
+ %% Create functions which are built from the data collected from the
233
+ %% file. Here the __info__ function and the struct definition
234
+ %% functions.
235
+
236
+ build_struct_def(#lfe_cg{struct=undefined}=St) ->
237
+ %% No struct has been defined.
238
+ St;
239
+ build_struct_def(#lfe_cg{module=Mod,struct={Fields,Line},funcs=Funcs0}=St0) ->
240
+ %% The default struct.
241
+ DefStr = comp_struct_map(Mod, Fields),
242
+ %% The default __struct__/0/1 functions.
243
+ StrFun_0 = struct_fun_0(DefStr),
244
+ StrFun_1 = struct_fun_1(DefStr),
245
+ Funcs1 = orddict:store({'__struct__',0}, {StrFun_0,Line}, Funcs0),
246
+ Funcs2 = orddict:store({'__struct__',1}, {StrFun_1,Line}, Funcs1),
247
+ St1 = coll_mdef_exports([['__struct__',0],['__struct__',1]], St0),
248
+ St1#lfe_cg{funcs=Funcs2}.
249
+
250
+ comp_struct_map(Mod, Fields) ->
251
+ Fun = fun ([F,D|_]) -> {F,D};
252
+ ([F]) -> {F,'nil'};
253
+ (F) -> {F,'nil'}
254
+ end,
255
+ KeyVals = lists:map(Fun, Fields),
256
+ maps:from_list([{'__struct__',Mod}|KeyVals]).
257
+
258
+ %% struct_fun_0(DefStr) -> FuncDef.
259
+ %% struct_fun_1(DefStr) -> FuncDef.
260
+ %% Create the bodies __struct__/0/1 functions.
261
+
262
+ struct_fun_0(DefStr) ->
263
+ [lambda,[],DefStr].
264
+
265
+ struct_fun_1(DefStr) ->
266
+ [lambda,[assocs],
267
+ [call,?Q(lists),?Q(foldl),
268
+ ['match-lambda',[[[tuple,x,y],acc],
269
+ [call,?Q(maps),?Q(update),x,y,acc]]],
270
+ DefStr,assocs]].
271
+
272
+ build_info_func(#lfe_cg{module=Mod,mline=Line,funcs=Funcs0}=St0) ->
273
+ %% The default clauses.
274
+ InfoCls = [[[?Q(module)],?Q(Mod)],
275
+ [[?Q(functions)],?Q(info_functions(St0))],
276
+ [[?Q(macros)],[]],
277
+ [[?Q(deprecated)],[]],
278
+ [[?Q(attributes)],
279
+ [call,?Q(erlang),?Q(get_module_info),?Q(Mod),?Q(attributes)]],
280
+ [[?Q(compile)],
281
+ [call,?Q(erlang),?Q(get_module_info),?Q(Mod),?Q(compile)]],
282
+ [[?Q(md5)],
283
+ [call,?Q(erlang),?Q(get_module_info),?Q(Mod),?Q(md5)]]
284
+ ],
285
+ %% The struct clause if relevant.
286
+ StrCls = struct_info_clause(St0),
287
+ %% The function body.
288
+ InfoFun = ['match-lambda' | InfoCls ++ StrCls ],
289
+ Funcs1 = orddict:store({'__info__',1}, {InfoFun,Line}, Funcs0),
290
+ St1 = coll_mdef_exports([['__info__',1]], St0),
291
+ St1#lfe_cg{funcs=Funcs1}.
292
+
293
+ info_functions(#lfe_cg{exports=Exps,funcs=Funcs}) ->
294
+ if Exps =:= all ->
295
+ orddict:fetch_keys(Funcs);
296
+ true -> Exps
297
+ end.
298
+
299
+ struct_info_clause(St) ->
300
+ case St#lfe_cg.struct of
301
+ undefined -> []; %No struct def, no clause
302
+ {Fields,_Line} ->
303
+ Fun = fun ([F|_]) -> #{field => F, required => false};
304
+ (F) -> #{field => F, required => false}
305
+ end,
306
+ KeyVals = lists:map(Fun, Fields),
307
+ [ [[?Q(struct)],[list | KeyVals]] ]
308
+ end.
309
+
184
310
%% compile_attributes(State) -> MdefAST.
185
- %% Compile the module attributes.
311
+ %% Compile the module attributes, metas, records and structs
186
312
187
313
compile_attributes(St) ->
188
314
Exp = comp_export(St),
189
315
Imps = comp_imports(St),
190
316
Onload = comp_onload(St),
191
- Atts = comp_attributes(St),
317
+ Attrs = comp_attributes(St),
318
+ Metas = comp_metas(St),
192
319
Mline = St#lfe_cg.mline,
193
320
%% Collect all the attributes.
194
321
AST = [make_attribute(file, {St#lfe_cg.file,Mline}, Mline),
195
322
make_attribute(module, St#lfe_cg.module, Mline),
196
323
Exp |
197
- Onload ++ Imps ++ Atts],
324
+ Onload ++ Imps ++ Attrs ++ Metas],
198
325
AST.
199
326
200
- %% compile_forms(ModuleForms, State) -> [AST].
201
- %% Compile the function and record forms into Erlang ASTs.
327
+ %% comp_export(State) -> Attribute.
328
+ %% comp_imports(State) -> [Attribute].
329
+ %% comp_on_load(State) -> Attribute.
330
+ %% comp_attributes(State) -> [Attribute].
331
+ %% comp_metas(State) -> [Attribute]
332
+ %% Currently we don't add the import attributes.
202
333
203
- compile_forms(Forms, St) ->
204
- lists:flatmap(fun (F) -> compile_form(F, St) end, Forms).
334
+ comp_export(#lfe_cg{exports=Exps,funcs=Funcs,mline=Line}) ->
335
+ Es = if Exps =:= all ->
336
+ orddict:fetch_keys(Funcs);
337
+ true -> Exps %Already in right format
338
+ end,
339
+ make_attribute(export, Es, Line).
205
340
206
- compile_form({['define-module',_Mod,Metas,_Attrs],Line}, St) ->
207
- comp_mod_metas(Metas, Line, St);
208
- compile_form({['extend-module',Metas,_Attrs],Line}, St) ->
209
- comp_mod_metas(Metas, Line, St);
210
- compile_form({['define-type',Type,Def],Line}, _St) ->
211
- comp_type_def(type, Type, Def, Line);
212
- compile_form({['define-opaque-type',Type,Def],Line}, _St) ->
213
- comp_type_def(opaque, Type, Def, Line);
214
- compile_form({['define-function-spec',Func,Spec],Line}, _St) ->
215
- comp_function_spec(Func, Spec, Line);
216
- compile_form({['define-record',Name,Fields],Line}, _St) ->
217
- comp_record_def(Name, Fields, Line);
218
- compile_form({['define-struct',Fields],Line}, St) ->
219
- comp_struct_def(Fields, Line, St);
220
- compile_form({['define-function',Name,_Meta,Def],Line}, St) ->
221
- comp_function_def(Name, Def, Line, St);
222
- %% Ignore anything else for now. Hopefully there shouldn't be anything
223
- %% else.
224
- compile_form(_Other, _St) -> [].
341
+ comp_imports(_St) -> [].
225
342
226
- %% comp_mod_metas(Metas, Line, State) -> [AST].
343
+ comp_onload(#lfe_cg{onload={Func,Ar},mline=Line}) ->
344
+ [make_attribute(on_load, {Func,Ar}, Line)];
345
+ comp_onload(#lfe_cg{onload=[]}) -> [].
227
346
228
- comp_mod_metas(Metas, Line, _St) ->
229
- lists:flatmap(fun (M) -> comp_mod_meta(M, Line) end, Metas).
347
+ comp_attributes(#lfe_cg{attrs=Atts}) ->
348
+ lists:map(fun comp_attribute/1, Atts).
230
349
231
- comp_mod_meta([type|Tdefs], Line) ->
350
+ comp_attribute({'export-type',Ts,Line}) ->
351
+ Ets = lists:map(fun ([T,A]) -> {T,A} end, Ts),
352
+ make_attribute(export_type, Ets, Line);
353
+ comp_attribute({Name,Val,Line}) ->
354
+ make_attribute(Name, Val, Line).
355
+
356
+ comp_metas(#lfe_cg{metas=Metas,mline=Line}) ->
357
+ %% io:format("cm ~p\n", [Metas]),
358
+ Ms = lists:flatmap(fun (M) -> comp_meta(M, Line) end, Metas),
359
+ %% io:format("cm ~p\n", [Ms]),
360
+ Ms.
361
+
362
+ comp_meta({type,Tdefs,_}, Line) ->
232
363
lists:flatmap(fun (Tdef) -> comp_type_def(type, Tdef, Line) end, Tdefs);
233
- comp_mod_meta([opaque|Tdefs], Line) ->
364
+ comp_meta({opaque,Tdefs,_}, Line) ->
234
365
lists:flatmap(fun (Tdef) -> comp_type_def(opaque, Tdef, Line) end, Tdefs);
235
- comp_mod_meta([spec|Fspecs], Line) ->
366
+ comp_meta({spec,Fspecs,_}, Line) ->
236
367
Fun = fun (Fspec) -> comp_function_spec(Fspec, Line) end,
237
368
lists:flatmap(Fun, Fspecs);
238
- comp_mod_meta([record|Rdefs], Line) ->
369
+ comp_meta({record,Rdefs,_}, Line) ->
239
370
Fun = fun (Rdef) -> comp_record_def(Rdef, Line) end,
240
- lists:flatmap(Fun, Rdefs);
241
- comp_mod_meta(_Meta, _Line) -> [].
371
+ As = lists:flatmap(Fun, Rdefs),
372
+ %% io:format("cmr ~p\n", [As]),
373
+ As;
374
+ comp_meta(_Meta, _Line) -> [].
375
+
376
+ %% compile_functions(State) -> [AST].
377
+
378
+ compile_functions(#lfe_cg{funcs=Funcs0}=St) ->
379
+ Fun = fun (F, B, Fs) -> Fs ++ compile_function(F, B, St) end,
380
+ orddict:fold(Fun, [], Funcs0).
381
+
382
+ compile_function({Name,_Arity}, {Def,Line}, St) ->
383
+ comp_function_def(Name, Def, Line,St).
242
384
243
385
%% comp_type_def(Attr, TypeDef, Line) -> [AST].
244
386
%% comp_type_def(Attr, Type, Def, Line) -> [AST].
387
+ %% Compile a type definition to an attribute.
245
388
246
389
comp_type_def(Attr, [Type,Def], Line) ->
247
390
comp_type_def(Attr, Type, Def, Line).
 
@@ -254,6 +397,7 @@ comp_type_def(Attr, [Type|Args], Def, Line) ->
254
397
255
398
%% comp_function_spec(FuncSpec, Line) -> [AST].
256
399
%% comp_function_spec(Func, Spec, Line) -> [AST].
400
+ %% Compile a function specification to an attribute.
257
401
258
402
comp_function_spec([Func|Spec], Line) ->
259
403
comp_function_spec(Func, Spec, Line).
 
@@ -283,7 +427,9 @@ comp_record_def([Name,Fields], Line) ->
283
427
comp_record_def(Name, Fields, Line).
284
428
285
429
comp_record_def(Name, Fields, Line) ->
430
+ %% io:format("crd ~p ~p\n", [Name,Fields]),
286
431
Fdefs = [ comp_record_field(Fdef, Line) || Fdef <- Fields ],
432
+ %% io:format("cra ~p\n", [make_record_attribute(Name, Fdefs, Line)]),
287
433
[make_record_attribute(Name, Fdefs, Line)].
288
434
289
435
comp_record_field([F,D,T], Line) ->
 
@@ -311,62 +457,6 @@ make_record_attribute(Name, Fdefs, Line) ->
311
457
make_attribute(type, {{record,Name},Fdefs}, Line).
312
458
-endif.
313
459
314
- %% comp_struct_def(Fields, Line, State) -> [Forms].
315
- %% Create the struct definition function
316
-
317
- comp_struct_def(Fields, Line, #lfe_cg{module=Mod}=St) ->
318
- %% The default struct.
319
- DefStr = comp_struct_map(Mod, Fields),
320
- %% The default __struct__/0/1 functions.
321
- Str0 = comp_function_def('__struct__', [lambda,[],DefStr], Line, St),
322
- Str1 = comp_function_def(
323
- '__struct__',
324
- [lambda,[assocs],
325
- [call,?Q(lists),?Q(foldl),
326
- ['match-lambda',[[[tuple,x,y],acc],
327
- [call,?Q(maps),?Q(update),x,y,acc]]],
328
- DefStr,assocs]],
329
- Line, St),
330
- Str0 ++ Str1.
331
-
332
- comp_struct_map(Mod, Fields) ->
333
- Fun = fun ([F,D|_]) -> {F,D};
334
- ([F]) -> {F,'nil'};
335
- (F) -> {F,'nil'}
336
- end,
337
- Args = lists:map(Fun, Fields),
338
- maps:from_list([{'__struct__',Mod}|Args]).
339
-
340
- %% comp_export(State) -> Attribute.
341
- %% comp_imports(State) -> [Attribute].
342
- %% comp_on_load(State) -> Attribute.
343
- %% comp_attributes(State) -> [Attribute].
344
- %% Currently we don't add the import attributes.
345
-
346
- comp_export(#lfe_cg{exports=Exps,defs=Defs,mline=Line}) ->
347
- Es = if Exps =:= all ->
348
- [ {F,func_arity(Def)} || {F,Def,_} <- Defs ];
349
- true -> Exps %Already in right format
350
- end,
351
- make_attribute(export, Es, Line).
352
-
353
- comp_imports(_St) -> [].
354
-
355
- comp_onload(#lfe_cg{onload={Func,Ar},mline=Line}) ->
356
- [make_attribute(on_load, {Func,Ar}, Line)];
357
- comp_onload(#lfe_cg{onload=[]}) -> [].
358
-
359
- comp_attributes(#lfe_cg{atts=Atts}) ->
360
- lists:map(fun comp_attribute/1, Atts).
361
-
362
- %% comp_attribute({spec,[Func|Spec],Line}) ->
363
- %% hd(comp_func_spec(Func, Spec, Line)); %We know!
364
- comp_attribute({'export-type',Ts,Line}) ->
365
- Ets = lists:map(fun ([T,A]) -> {T,A} end, Ts),
366
- make_attribute(export_type, Ets, Line);
367
- comp_attribute({Name,Val,Line}) ->
368
- make_attribute(Name, Val, Line).
369
-
370
460
%% make_attribute(Name, Value, Line) -> Atttribute.
371
461
372
462
make_attribute(Name, Val, Line) ->
changed src/lfe_codelift.erl
 
@@ -25,7 +25,7 @@
25
25
-export([record/3,function/3]).
26
26
27
27
-export([comp_define/1]).
28
- -export([lift_func/2,lift_expr/3,ivars_expr/1]).
28
+ -export([lift_func/2,lift_expr/3,lift_expr/4,ivars_expr/1]).
29
29
30
30
-export([test/1]).
31
31
 
@@ -42,6 +42,10 @@
42
42
fc=0 %Local function index
43
43
}).
44
44
45
+ -record(lift, {type, %Lift type
46
+ name, %New lifted name
47
+ ivars}). %Imported variables
48
+
45
49
%% comp_define(DefForm) -> Funcs
46
50
47
51
comp_define({Name,Def,Line}) ->
 
@@ -54,7 +58,8 @@ comp_define({Name,Def,Line}) ->
54
58
55
59
record(Name, Fs, Line) ->
56
60
St0 = #cl{func=Name,arity=record,line=Line,vc=0,fc=0},
57
- {Lfs,Fncs,St1} = lift_rec_fields(Fs, [], St0),
61
+ Lifts = orddict:new(),
62
+ {Lfs,Fncs,St1} = lift_rec_fields(Fs, Lifts, [], St0),
58
63
{Lfncs,[],_} = lift_loop(Fncs, St1),
59
64
{Lfs,Lfncs}.
60
65
 
@@ -89,7 +94,8 @@ lift_loop(Funcs0, St0) ->
89
94
%% the resulting functions.
90
95
91
96
lift_func({Name,Def0,L}, St0) ->
92
- {Def1,Lds,St1} = lift_expr(Def0, [], St0),
97
+ Lifts = orddict:new(),
98
+ {Def1,Lds,St1} = lift_expr(Def0, Lifts, [], St0),
93
99
{{Name,Def1,L},Lds,St1}.
94
100
95
101
lift_funcs(Defs, St) ->
 
@@ -100,196 +106,248 @@ lift_funcs(Defs, St) ->
100
106
lists:foldl(Fun, {[],[],St}, Defs).
101
107
102
108
%% lift_expr(Expr, LocalDefs, State) -> {AST,LocalDefs,State}.
103
- %% Lambda lift the local functions in an expression.
109
+ %% lift_expr(Expr, LiftedFuncs, LocalDefs, State) -> {AST,LocalDefs,State}.
110
+ %% Lambda lift the local functions in an expression. The Lifts are
111
+ %% the current function lifts which need to be done.
112
+
113
+ lift_expr(Expr, Lds, St) ->
114
+ lift_expr(Expr, [], Lds, St).
104
115
105
116
%% Core data special forms.
106
- lift_expr(?Q(E), Lds, St) -> {?Q(E),Lds,St};
117
+ lift_expr(?Q(E), _Lifts, Lds, St) -> {?Q(E),Lds,St};
107
118
%% Record special forms.
108
- lift_expr(['record',Name|Args], Lds0, St0) ->
109
- {Largs,Lds1,St1} = lift_rec_args(Args, Lds0, St0),
119
+ lift_expr(['record',Name|Args], Lifts, Lds0, St0) ->
120
+ {Largs,Lds1,St1} = lift_rec_args(Args, Lifts, Lds0, St0),
110
121
{['record',Name|Largs],Lds1,St1};
111
122
%% make-record has been deprecated but we sill accept it for now.
112
- lift_expr(['make-record',Name|Args], Lds0, St0) ->
113
- {Largs,Lds1,St1} = lift_rec_args(Args, Lds0, St0),
123
+ lift_expr(['make-record',Name|Args], Lifts, Lds0, St0) ->
124
+ {Largs,Lds1,St1} = lift_rec_args(Args, Lifts, Lds0, St0),
114
125
{['make-record',Name|Largs],Lds1,St1};
115
- lift_expr(['is-record',E,Name], Lds0, St0) ->
116
- {Le,Lds1,St1} = lift_expr(E, Lds0, St0),
126
+ lift_expr(['is-record',E,Name], Lifts, Lds0, St0) ->
127
+ {Le,Lds1,St1} = lift_expr(E, Lifts, Lds0, St0),
117
128
{['is-record',Le,Name],Lds1,St1};
118
- lift_expr(['record-index',_Name,_F]=Ri, Lds, St) ->
129
+ lift_expr(['record-index',_Name,_F]=Ri, _Lifts, Lds, St) ->
119
130
{Ri,Lds,St};
120
- lift_expr(['record-field',E,Name,F], Lds0, St0) ->
121
- {Le,Lds1,St1} = lift_expr(E, Lds0, St0),
131
+ lift_expr(['record-field',E,Name,F], Lifts, Lds0, St0) ->
132
+ {Le,Lds1,St1} = lift_expr(E, Lifts, Lds0, St0),
122
133
{['record-field',Le,Name,F],Lds1,St1};
123
- lift_expr(['record-update',E,Name|Args], Lds0, St0) ->
124
- {Le,Lds1,St1} = lift_expr(E, Lds0, St0),
125
- {Largs,Lds2,St2} = lift_rec_args(Args, Lds1, St1),
134
+ lift_expr(['record-update',E,Name|Args], Lifts, Lds0, St0) ->
135
+ {Le,Lds1,St1} = lift_expr(E, Lifts, Lds0, St0),
136
+ {Largs,Lds2,St2} = lift_rec_args(Args, Lifts, Lds1, St1),
126
137
{['record-update',Le,Name|Largs],Lds2,St2};
127
138
%% Struct special forms.
128
- lift_expr(['struct',Name|Args], Lds0, St0) ->
129
- {Largs,Lds1,St1} = lift_rec_args(Args, Lds0, St0),
139
+ lift_expr(['struct',Name|Args], Lifts, Lds0, St0) ->
140
+ {Largs,Lds1,St1} = lift_rec_args(Args, Lifts, Lds0, St0),
130
141
{['struct',Name|Largs],Lds1,St1};
131
- lift_expr(['is-struct',E], Lds0, St0) ->
132
- {Le,Lds1,St1} = lift_expr(E, Lds0, St0),
142
+ lift_expr(['is-struct',E], Lifts, Lds0, St0) ->
143
+ {Le,Lds1,St1} = lift_expr(E, Lifts, Lds0, St0),
133
144
{['is-struct',Le],Lds1,St1};
134
- lift_expr(['is-struct',E,Name], Lds0, St0) ->
135
- {Le,Lds1,St1} = lift_expr(E, Lds0, St0),
145
+ lift_expr(['is-struct',E,Name], Lifts, Lds0, St0) ->
146
+ {Le,Lds1,St1} = lift_expr(E, Lifts, Lds0, St0),
136
147
{['is-struct',Le,Name],Lds1,St1};
137
- lift_expr(['struct-field',E, Name,F], Lds0, St0) ->
138
- {Le,Lds1,St1} = lift_expr(E, Lds0, St0),
148
+ lift_expr(['struct-field',E, Name,F], Lifts, Lds0, St0) ->
149
+ {Le,Lds1,St1} = lift_expr(E, Lifts, Lds0, St0),
139
150
{['struct-field',Le,Name,F],Lds1,St1};
140
- lift_expr(['struct-update',E,Name|Args], Lds0, St0) ->
141
- {Le,Lds1,St1} = lift_expr(E, Lds0, St0),
142
- {Largs,Lds2,St2} = lift_rec_args(Args, Lds1, St1),
151
+ lift_expr(['struct-update',E,Name|Args], Lifts, Lds0, St0) ->
152
+ {Le,Lds1,St1} = lift_expr(E, Lifts, Lds0, St0),
153
+ {Largs,Lds2,St2} = lift_rec_args(Args, Lifts, Lds1, St1),
143
154
{['struct-update',Le,Name|Largs],Lds2,St2};
144
155
%% Function forms.
145
- lift_expr([function,_,_]=Func, Lds, St) ->
146
- {Func,Lds,St};
147
- lift_expr([function,_,_,_]=Func, Lds, St) ->
156
+ lift_expr([function,Name,Arity], Lifts, Lds, St) ->
157
+ lift_function_ref(Name, Arity, Lifts, Lds, St);
158
+ lift_expr([function,_,_,_]=Func, _Lifts, Lds, St) ->
148
159
{Func,Lds,St};
149
160
%% Core closure special forms.
150
- lift_expr([lambda,Args|Body0], Lds0, St0) ->
151
- {Body1,Lds1,St1} = lift_exprs(Body0, Lds0, St0),
161
+ lift_expr([lambda,Args|Body0], Lifts, Lds0, St0) ->
162
+ {Body1,Lds1,St1} = lift_exprs(Body0, Lifts, Lds0, St0),
152
163
{[lambda,Args|Body1],Lds1,St1};
153
- lift_expr(['match-lambda'|Cls0], Lds0, St0) ->
154
- {Cls1,Lds1,St1} = lift_cls(Cls0, Lds0, St0),
164
+ lift_expr(['match-lambda'|Cls0], Lifts, Lds0, St0) ->
165
+ {Cls1,Lds1,St1} = lift_cls(Cls0, Lifts, Lds0, St0),
155
166
{['match-lambda'|Cls1],Lds1,St1};
156
- lift_expr(['let',Vbs|Body], Lds, St) ->
157
- lift_let(Vbs, Body, Lds, St);
158
- lift_expr(['let-function',Fbs|Body], Lds, St) ->
159
- lift_let_function(Fbs, Body, Lds, St);
160
- lift_expr(['letrec-function',Fbs|Body], Lds, St) ->
161
- lift_letrec_function(Fbs, Body, Lds, St);
167
+ lift_expr(['let',Vbs|Body], Lifts, Lds, St) ->
168
+ lift_let(Vbs, Body, Lifts, Lds, St);
169
+ lift_expr(['let-function',Fbs|Body], Lifts, Lds, St) ->
170
+ lift_let_function(Fbs, Body, Lifts, Lds, St);
171
+ lift_expr(['letrec-function',Fbs|Body], Lifts, Lds, St) ->
172
+ lift_letrec_function(Fbs, Body, Lifts, Lds, St);
162
173
%% Core control special forms.
163
- lift_expr([progn|Body0], Lds0, St0) ->
164
- {Body1,Lds1,St1} = lift_exprs(Body0, Lds0, St0),
174
+ lift_expr([progn|Body0], Lifts, Lds0, St0) ->
175
+ {Body1,Lds1,St1} = lift_exprs(Body0, Lifts, Lds0, St0),
165
176
{[progn|Body1],Lds1,St1};
166
- lift_expr(['if'|Body0], Lds0, St0) ->
167
- {Body1,Lds1,St1} = lift_exprs(Body0, Lds0, St0),
177
+ lift_expr(['if'|Body0], Lifts, Lds0, St0) ->
178
+ {Body1,Lds1,St1} = lift_exprs(Body0, Lifts, Lds0, St0),
168
179
{['if'|Body1],Lds1,St1};
169
- lift_expr(['case',Expr|Cls], Lds, St) ->
170
- lift_case(Expr, Cls, Lds, St);
171
- lift_expr(['catch'|Body0], Lds0, St0) ->
172
- {Body1,Lds1,St1} = lift_exprs(Body0, Lds0, St0),
180
+ lift_expr(['case',Expr|Cls], Lifts, Lds, St) ->
181
+ lift_case(Expr, Cls, Lifts, Lds, St);
182
+ lift_expr(['catch'|Body0], Lifts, Lds0, St0) ->
183
+ {Body1,Lds1,St1} = lift_exprs(Body0, Lifts, Lds0, St0),
173
184
{['catch'|Body1],Lds1,St1};
174
- lift_expr(['try'|Try], Lds, St) ->
175
- lift_try(Try, Lds, St);
176
- lift_expr([funcall|Body0], Lds0, St0) ->
177
- {Body1,Lds1,St1} = lift_exprs(Body0, Lds0, St0),
178
- {[funcall|Body1],Lds1,St1};
185
+ lift_expr(['try'|Try], Lifts, Lds, St) ->
186
+ lift_try(Try, Lifts, Lds, St);
187
+ lift_expr([funcall|Args0], Lifts, Lds0, St0) ->
188
+ {Args1,Lds1,St1} = lift_exprs(Args0, Lifts, Lds0, St0),
189
+ {[funcall|Args1],Lds1,St1};
179
190
%% List/binary comprehensions.
180
- lift_expr(['lc',Qs,E], Lds, St) ->
181
- lift_comp('lc', Qs, E, Lds, St);
182
- lift_expr(['list-comp',Qs,E], Lds, St) ->
183
- lift_comp('list-comp', Qs, E, Lds, St);
184
- lift_expr(['bc',Qs,E], Lds, St) ->
185
- lift_comp('bc', Qs, E, Lds, St);
186
- lift_expr(['binary-comp',Qs,E], Lds, St) ->
187
- lift_comp('binary-comp', Qs, E, Lds, St);
191
+ lift_expr(['lc',Qs,E], Lifts, Lds, St) ->
192
+ lift_comp('lc', Qs, E, Lifts, Lds, St);
193
+ lift_expr(['list-comp',Qs,E], Lifts, Lds, St) ->
194
+ lift_comp('list-comp', Qs, E, Lifts, Lds, St);
195
+ lift_expr(['bc',Qs,E], Lifts, Lds, St) ->
196
+ lift_comp('bc', Qs, E, Lifts, Lds, St);
197
+ lift_expr(['binary-comp',Qs,E], Lifts, Lds, St) ->
198
+ lift_comp('binary-comp', Qs, E, Lifts, Lds, St);
188
199
%% Finally the general cases.
189
- lift_expr([call|Body0], Lds0, St0) ->
190
- {Body1,Lds1,St1} = lift_exprs(Body0, Lds0, St0),
191
- {[call|Body1],Lds1,St1};
192
- lift_expr([Func|Args0], Lds0, St0) when is_atom(Func) ->
193
- {Args1,Lds1,St1} = lift_exprs(Args0, Lds0, St0),
194
- {[Func|Args1],Lds1,St1};
195
- lift_expr(Lit, Lds, St) -> {Lit,Lds,St}.
200
+ lift_expr([call|Args0], Lifts, Lds0, St0) ->
201
+ {Args1,Lds1,St1} = lift_exprs(Args0, Lifts, Lds0, St0),
202
+ {[call|Args1],Lds1,St1};
203
+ lift_expr([Func|Args], Lifts, Lds, St) when is_atom(Func) ->
204
+ lift_func_call(Func, Args, Lifts, Lds, St);
205
+ %% Everything else is a literal.
206
+ lift_expr(Lit, _Lifts, Lds, St) -> {Lit,Lds,St}.
196
207
197
- lift_exprs(Exprs, Lds, St) ->
208
+ lift_func_call(Name, Args0, Lifts, Lds0, St0) ->
209
+ %% Most of the core data special forms can be handled here as well.
210
+ {Args1,Lds1,St1} = lift_exprs(Args0, Lifts, Lds0, St0),
211
+ Arity = length(Args1),
212
+ Call = case lifted_function(Name, Arity, Lifts) of
213
+ {yes,#lift{type=call,name=NewName,ivars=Ivars}} ->
214
+ [NewName | Args1 ++ Ivars];
215
+ {yes,#lift{type=apply,name=NewName,ivars=Ivars}} ->
216
+ [funcall,NewName | Args1 ++ Ivars];
217
+ no ->
218
+ [Name | Args1]
219
+ end,
220
+ {Call,Lds1,St1}.
221
+
222
+ lift_exprs(Exprs, Lifts, Lds, St) ->
198
223
Fun = fun (E0, {Es,Lds0,St0}) ->
199
- {E1,Lds1,St1} = lift_expr(E0, Lds0, St0),
224
+ {E1,Lds1,St1} = lift_expr(E0, Lifts, Lds0, St0),
200
225
{[E1|Es],Lds1,St1}
201
226
end,
202
227
lists:foldr(Fun, {[],Lds,St}, Exprs).
203
228
204
- lift_rec_fields([[F,V|Type]|Fs], Lds0, St0) ->
205
- {Lv,Lds1,St1} = lift_expr(V, Lds0, St0),
206
- {Lfs,Lds2,St2} = lift_rec_fields(Fs, Lds1, St1),
229
+ lift_rec_fields([[F,V|Type]|Fs], Lifts, Lds0, St0) ->
230
+ {Lv,Lds1,St1} = lift_expr(V, Lifts, Lds0, St0),
231
+ {Lfs,Lds2,St2} = lift_rec_fields(Fs, Lifts, Lds1, St1),
207
232
{[[F,Lv|Type]|Lfs],Lds2,St2};
208
- lift_rec_fields([F|Fs], Lds0, St0) ->
209
- {Lfs,Lds1,St1} = lift_rec_fields(Fs, Lds0, St0),
233
+ lift_rec_fields([F|Fs], Lifts, Lds0, St0) ->
234
+ {Lfs,Lds1,St1} = lift_rec_fields(Fs, Lifts, Lds0, St0),
210
235
{[F|Lfs],Lds1,St1};
211
- lift_rec_fields([], Lds, St) -> {[],Lds,St}.
236
+ lift_rec_fields([], _Lifts, Lds, St) -> {[],Lds,St}.
212
237
213
- lift_rec_args([F,V|As], Lds0, St0) ->
214
- {Lv,Lds1,St1} = lift_expr(V, Lds0, St0),
215
- {Las,Lds2,St2} = lift_rec_args(As, Lds1, St1),
238
+ lift_rec_args([F,V|As], Lifts, Lds0, St0) ->
239
+ {Lv,Lds1,St1} = lift_expr(V, Lifts, Lds0, St0),
240
+ {Las,Lds2,St2} = lift_rec_args(As, Lifts, Lds1, St1),
216
241
{[F,Lv|Las],Lds2,St2};
217
- lift_rec_args([], Lds, St) -> {[],Lds,St}.
242
+ lift_rec_args([], _Lifts, Lds, St) -> {[],Lds,St}.
218
243
219
- lift_let(Vbs0, Body0, Lds0, St0) ->
244
+ %% lift_function_ref(Name, Arity, Lifts, LocalDefs, State) ->
245
+ %% {Lifted,LocalDefs,State}.
246
+ %% Check if [function,Name,Arity] needs to tbe lifted and whether
247
+ %% Ivars force it to become a lambda.
248
+
249
+ lift_function_ref(Name, Arity, Lifts, Lds, St) ->
250
+ Lfunc = case lifted_function(Name, Arity, Lifts) of
251
+ {yes,#lift{name=NewName,ivars=Ivars}} ->
252
+ if length(Ivars) > 0 ->
253
+ Vars = new_vars(Arity),
254
+ [lambda,Vars,[funcall,?Q(NewName) | Vars ++ Ivars]];
255
+ true ->
256
+ [function,NewName,Arity]
257
+ end;
258
+ no -> %When not lifted
259
+ [function,Name,Arity]
260
+ end,
261
+ {Lfunc,Lds,St}.
262
+
263
+ %% lift_let(VarBindings, Body, LiftedFuncs, LocalDefines, State) ->
264
+ %% {Let,LocalDefines,State}.
265
+
266
+ lift_let(Vbs0, Body0, Lifts, Lds0, St0) ->
220
267
Fun = fun ([Pat,['when'|_]=G,Expr0], {Ldsa,Sta}) ->
221
- {Expr1,Ldsb,Stb} = lift_expr(Expr0, Ldsa, Sta),
268
+ {Expr1,Ldsb,Stb} = lift_expr(Expr0, Lifts, Ldsa, Sta),
222
269
{[Pat,G,Expr1],{Ldsb,Stb}};
223
270
([Pat,Expr0], {Ldsa,Sta}) ->
224
- {Expr1,Ldsb,Stb} = lift_expr(Expr0, Ldsa, Sta),
271
+ {Expr1,Ldsb,Stb} = lift_expr(Expr0, Lifts, Ldsa, Sta),
225
272
{[Pat,Expr1],{Ldsb,Stb}}
226
273
end,
227
274
{Vbs1,{Lds1,St1}} = lists:mapfoldl(Fun, {Lds0,St0}, Vbs0),
228
- {Body1,Lds2,St2} = lift_exprs(Body0, Lds1, St1),
275
+ {Body1,Lds2,St2} = lift_exprs(Body0, Lifts, Lds1, St1),
229
276
{['let',Vbs1|Body1],Lds2,St2}.
230
277
231
- %% lift_let_function(FuncBindings, LocalDefines, State) ->
278
+ %% lift_let_function(FuncBindings, Body, LiftedFuncs, LocalDefines, State) ->
232
279
%% {LocalBody,LocalDefines,State}.
233
280
%% We can check imported vars separately for each local function as
234
281
%% they do not know of each other.
235
282
236
- lift_let_function(Fbs0, Body0, Lds0, St0) ->
283
+ lift_let_function(Fbs0, Body, Lifts0, Lds0, St0) ->
237
284
%% Build new name function binding and name transform data.
238
285
Line = St0#cl.line,
239
- Nfun = fun ([Name,Def0], Ts, Sta) ->
286
+ Nfun = fun ([Name,Def0], {Ls0,Lda,Sta}) ->
240
287
Ar = func_arity(Def0),
241
- {New,Stb} = new_local_fun_name(Name, Ar, Sta),
242
- %% Get the imported variables.
288
+ %% Get imported variables and append them in definition.
243
289
Ivs = ivars_expr(Def0, [], []),
244
290
Def1 = append_ivars(Def0, Ivs),
245
- {{New,Def1,Line},[{trans,Name,Ar,New,Ivs}|Ts],Stb}
291
+ {Def2,Ldb,Stb} = lift_expr(Def1, Lifts0, Lda, Sta),
292
+ {New,Ls1,Stc} = lift_function(Name, Ar, call, Ivs, Ls0, Stb),
293
+ {{New,Def2,Line},{Ls1,Ldb,Stc}}
246
294
end,
247
295
%% Transform calls in the body.
248
- {Fbs1,Trans,St1} = mapfoldl2(Nfun, [], St0, Fbs0),
249
- Lds1 = Fbs1 ++ Lds0,
250
- %% Apply tranformations to Body.
251
- Bfun = fun ({trans,Name,Ar,New,Ivs}, B) ->
252
- trans_expr(B, Name, Ar, New, Ivs)
253
- end,
254
- Body1 = lists:foldl(Bfun, [progn|Body0], Trans),
255
- lift_expr(Body1, Lds1, St1).
296
+ {Fbs1,{Lifts1,Lds1,St1}} = lists:mapfoldl(Nfun, {Lifts0,Lds0,St0}, Fbs0),
297
+ %% io:format("lf ~p\n ~p\b", [Fbs1,Lds1]),
298
+ Lds2 = Fbs1 ++ Lds1,
299
+ lift_expr([progn | Body], Lifts1, Lds2, St1).
256
300
257
- %% lift_letrec_function(FuncBindings, LocalDefines, State) ->
301
+ %% lift_letrec_function(FuncBindings, Body, LiftedFuncs, LocalDefines, State) ->
258
302
%% {LocalBody,LocalDefines,State}.
259
303
%% We cheat a bit when checking imported vars, we just take the union
260
304
%% of the variables from all the local functions and pass them to all
261
305
%% functions.
262
306
263
- lift_letrec_function(Fbs0, Body0, Lds0, St0) ->
264
- %% Get the imported variables.
307
+ lift_letrec_function(Fbs0, Body, Lifts0, Lds0, St0) ->
308
+ %% Get all the imported variables.
265
309
Ifun = fun ([_,Def], Ivs) -> ivars_expr(Def, [], Ivs) end,
266
310
Ivars = lists:foldl(Ifun, [], Fbs0),
267
- %% Build new name function binding and name transform data.
311
+ %% io:format("lrf ~p\n", [Ivars]),
312
+ %% Lift the local defined functions and get their new names and data.
313
+ Lfun = fun ([Name,Def], {Lsa,Sta}) ->
314
+ Ar = func_arity(Def),
315
+ {New,Lsb,Stb} = lift_function(Name, Ar, call, Ivars, Lsa, Sta),
316
+ {{New,Def},{Lsb,Stb}}
317
+ end,
318
+ {Fbs1,{Lifts1,St1}} = lists:mapfoldl(Lfun, {Lifts0,St0}, Fbs0),
319
+ %% Lift the local functions with the joint lifted local functions.
268
320
Line = St0#cl.line,
269
- Nfun = fun ([Name,Def0], Ts, Sta) ->
270
- Ar = func_arity(Def0),
271
- {New,Stb} = new_local_fun_name(Name, Ar, Sta),
321
+ Efun = fun ({New,Def0}, {Lda,Sta}) ->
272
322
Def1 = append_ivars(Def0, Ivars),
273
- {{New,Def1,Line},[{trans,Name,Ar,New}|Ts],Stb}
323
+ {Def2,Ldb,Stb} = lift_expr(Def1, Lifts1, Lda, Sta),
324
+ {{New,Def2,Line}, {Ldb,Stb}}
274
325
end,
275
- {Fbs1,Trans,St1} = mapfoldl2(Nfun, [], St0, Fbs0),
276
- %% Transform calls in the letrec form.
277
- Tfun = fun ({trans,Name,Ar,New}, Fbs) ->
278
- Ffun = fun ({Nn,Def0,L}) ->
279
- Def1 = trans_expr(Def0, Name, Ar, New, Ivars),
280
- {Nn,Def1,L}
281
- end,
282
- lists:map(Ffun, Fbs)
283
- end,
284
- Fbs2 = lists:foldl(Tfun, Fbs1, Trans),
285
- Lds1 = Fbs2 ++ Lds0,
286
- %% Apply tranformations to Body.
287
- Bfun = fun ({trans,Name,Ar,New}, B) ->
288
- trans_expr(B, Name, Ar, New, Ivars)
289
- end,
290
- Body1 = lists:foldl(Bfun, [progn|Body0], Trans),
291
- {Body2,Lds2,St2} = lift_expr(Body1, Lds1, St1),
292
- {Body2,Lds2,St2}.
326
+ {Fbs2,{Lds1,St2}} = lists:mapfoldl(Efun, {Lds0,St1}, Fbs1),
327
+ Lds2 = Fbs2 ++ Lds1,
328
+ lift_expr([progn | Body], Lifts1, Lds2, St2).
329
+
330
+ %% lift_function(Name, Arity, LiftType, Ivars, Lifts, State) ->
331
+ %% {NewName,Lifts,State}.
332
+ %% lifted_function(Name, Arity, Lifts) -> {yes,Lift} | no.
333
+ %% Lift a function, and check whether a function has been liftes and
334
+ %% return irs lift data.
335
+
336
+ lift_function(Name, Arity, Type, Ivars, Lifts0, St0) ->
337
+ {NewName,St1} = new_local_fun_name(Name, Arity, St0),
338
+ Lift = #lift{type=Type,name=NewName,ivars=Ivars},
339
+ Lifts1 = orddict:store({Name,Arity}, Lift, Lifts0),
340
+ {NewName,Lifts1,St1}.
341
+
342
+ lifted_function(Name, Arity, Lifts) ->
343
+ case orddict:find({Name,Arity}, Lifts) of
344
+ {ok,Value} -> {yes,Value};
345
+ error -> no
346
+ end.
347
+
348
+ func_arity([lambda,Args|_]) -> length(Args);
349
+ func_arity(['match-lambda',[Pats|_]|_]) ->
350
+ length(Pats).
293
351
294
352
append_ivars([lambda,Args|Body], Ivars) ->
295
353
[lambda,Args ++ Ivars|Body];
 
@@ -298,298 +356,76 @@ append_ivars(['match-lambda'|Cls0], Ivars) ->
298
356
Cls1 = lists:map(Fun, Cls0),
299
357
['match-lambda'|Cls1].
300
358
301
- lift_cls(Cls, Lds, St) ->
359
+ lift_cls(Cls, Lifts, Lds, St) ->
302
360
Fun = fun ([Pats,['when'|_]=G|Body0], {Cls0,Lds0,St0}) ->
303
- {Body1,Lds1,St1} = lift_exprs(Body0, Lds0, St0),
361
+ {Body1,Lds1,St1} = lift_exprs(Body0, Lifts, Lds0, St0),
304
362
{[[Pats,G|Body1]|Cls0],Lds1,St1};
305
363
([Pats|Body0], {Cls0,Lds0,St0}) ->
306
- {Body1,Lds1,St1} = lift_exprs(Body0, Lds0, St0),
364
+ {Body1,Lds1,St1} = lift_exprs(Body0, Lifts, Lds0, St0),
307
365
{[[Pats|Body1]|Cls0],Lds1,St1}
308
366
end,
309
367
lists:foldr(Fun, {[],Lds,St}, Cls). %From the right!
310
368
311
- lift_case(Expr0, Cls0, Lds0, St0) ->
312
- {Expr1,Lds1,St1} = lift_expr(Expr0, Lds0, St0),
313
- {Cls1,Lds2,St2} = lift_cls(Cls0, Lds1, St1),
369
+ lift_case(Expr0, Cls0, Lifts, Lds0, St0) ->
370
+ {Expr1,Lds1,St1} = lift_expr(Expr0, Lifts, Lds0, St0),
371
+ {Cls1,Lds2,St2} = lift_cls(Cls0, Lifts, Lds1, St1),
314
372
{['case',Expr1|Cls1],Lds2,St2}.
315
373
316
- %% lift_try(TryBody, LocalDefs, State) -> {TryBody,LocalDefs,State}.
374
+ %% lift_try(TryBody, LiftedFuncs, LocalDefs, State) ->
375
+ %% {TryBody,LocalDefs,State}.
317
376
%% Step down the try body lifting the local functions.
318
377
319
- lift_try(Try0, Lds0, St0) ->
378
+ lift_try(Try0, Lifts, Lds0, St0) ->
320
379
Fun = fun (T0, {L0,S0}) ->
321
- {T1,L1,S1} = lift_try_1(T0, L0, S0),
380
+ {T1,L1,S1} = lift_try_1(T0, Lifts, L0, S0),
322
381
{T1,{L1,S1}}
323
382
end,
324
383
{Try1,{Lds1,St1}} = lists:mapfoldl(Fun, {Lds0,St0}, Try0),
325
384
{['try'|Try1],Lds1,St1}.
326
385
327
- lift_try_1(['case'|Case0], Lds0, St0) ->
328
- {Case1,Lds1,St1} = lift_cls(Case0, Lds0, St0),
386
+ lift_try_1(['case'|Case0], Lifts, Lds0, St0) ->
387
+ {Case1,Lds1,St1} = lift_cls(Case0, Lifts, Lds0, St0),
329
388
{['case'|Case1],Lds1,St1};
330
- lift_try_1(['catch'|Catch0], Lds0, St0) ->
331
- {Catch1,Lds1,St1} = lift_cls(Catch0, Lds0, St0),
389
+ lift_try_1(['catch'|Catch0], Lifts, Lds0, St0) ->
390
+ {Catch1,Lds1,St1} = lift_cls(Catch0, Lifts, Lds0, St0),
332
391
{['catch'|Catch1],Lds1,St1};
333
- lift_try_1(['after'|After0], Lds0, St0) ->
334
- {After1,Lds1,St1} = lift_exprs(After0, Lds0, St0),
392
+ lift_try_1(['after'|After0], Lifts, Lds0, St0) ->
393
+ {After1,Lds1,St1} = lift_exprs(After0, Lifts, Lds0, St0),
335
394
{['after'|After1],Lds1,St1};
336
- lift_try_1(E, Lds, St) -> %The try expression.
337
- lift_expr(E, Lds, St).
395
+ lift_try_1(E, Lifts, Lds, St) -> %The try expression.
396
+ lift_expr(E, Lifts, Lds, St).
338
397
339
- %% lift_comp(Commprehension, Qualifiers, Expr, LocalDefs, State) ->
340
- %% {Comprehension,LocalDefs,State}.
398
+ %% lift_comp(Commprehension, Qualifiers, Expr, LiftedFuncs, LocalDefs, State) ->
399
+ %% {Comprehension,LocalDefs,State}.
341
400
%% Lift comprehensions. Only the expressions in the comprehensions
342
401
%% need to be lifted, no guards or patterns.
343
402
344
- lift_comp(Comp, Qs0, E0, Lds0, St0) ->
403
+ lift_comp(Comp, Qs0, E0, Lifts, Lds0, St0) ->
345
404
%% io:format("lc ~p\n", [[Comp,Qs0,E0]]),
346
- {Qs1,Lds1,St1} = lift_comp_quals(Qs0, Lds0, St0),
347
- {E1,Lds2,St2} = lift_expr(E0, Lds1, St1),
405
+ {Qs1,Lds1,St1} = lift_comp_quals(Qs0, Lifts, Lds0, St0),
406
+ {E1,Lds2,St2} = lift_expr(E0, Lifts, Lds1, St1),
348
407
{[Comp,Qs1,E1],Lds2,St2}.
349
408
350
- lift_comp_quals(Qs, Lds, St) ->
409
+ lift_comp_quals(Qs, Lifts, Lds, St) ->
351
410
lists:foldr(fun (Q0, {Qs0,Lds0,St0}) ->
352
- {Q1,Lds1,St1} = lift_comp_qual(Q0, Lds0, St0),
353
- {[Q1|Qs0],Lds1,St1}
354
- end, {[],Lds,St}, Qs).
411
+ {Q1,Lds1,St1} = lift_comp_qual(Q0, Lifts, Lds0, St0),
412
+ {[Q1|Qs0],Lds1,St1}
413
+ end, {[],Lds,St}, Qs).
355
414
356
- lift_comp_qual(['<-',Pat,E0], Lds0, St0) ->
357
- {E1,Lds1,St1} = lift_expr(E0, Lds0, St0),
415
+ lift_comp_qual(['<-',Pat,E0], Lifts, Lds0, St0) ->
416
+ {E1,Lds1,St1} = lift_expr(E0, Lifts, Lds0, St0),
358
417
{['<-',Pat,E1],Lds1,St1};
359
- lift_comp_qual(['<-',Pat,G,E0], Lds0, St0) ->
360
- {E1,Lds1,St1} = lift_expr(E0, Lds0, St0),
418
+ lift_comp_qual(['<-',Pat,G,E0], Lifts, Lds0, St0) ->
419
+ {E1,Lds1,St1} = lift_expr(E0, Lifts, Lds0, St0),
361
420
{['<-',Pat,G,E1],Lds1,St1};
362
- lift_comp_qual(['<=',Pat,E0], Lds0, St0) ->
363
- {E1,Lds1,St1} = lift_expr(E0, Lds0, St0),
421
+ lift_comp_qual(['<=',Pat,E0], Lifts, Lds0, St0) ->
422
+ {E1,Lds1,St1} = lift_expr(E0, Lifts, Lds0, St0),
364
423
{['<=',Pat,E1],Lds1,St1};
365
- lift_comp_qual(['<=',Pat,G,E0], Lds0, St0) ->
366
- {E1,Lds1,St1} = lift_expr(E0, Lds0, St0),
424
+ lift_comp_qual(['<=',Pat,G,E0], Lifts, Lds0, St0) ->
425
+ {E1,Lds1,St1} = lift_expr(E0, Lifts, Lds0, St0),
367
426
{['<=',Pat,G,E1],Lds1,St1};
368
- lift_comp_qual(Test, Lds, St) ->
369
- lift_expr(Test, Lds, St).
370
-
371
- %% trans_expr(Call, OldName, Arity, NewName, ImportedVars) -> Expr.
372
- %% Translate function call from old Name to New and add imported
373
- %% variables.
374
-
375
- %% Core data special forms.
376
- trans_expr(?Q(E), _, _, _, _) -> ?Q(E);
377
- trans_expr([binary|Segs0], Old, Ar, New, Ivars) ->
378
- Segs1 = trans_bitsegs(Segs0, Old, Ar, New, Ivars),
379
- [binary|Segs1];
380
- %% Record forms.
381
- trans_expr(['record',Rname|Args], Old, Ar, New, Ivars) ->
382
- Targs = trans_rec_args(Args, Old, Ar, New, Ivars),
383
- ['record',Rname|Targs];
384
- %% make-record has been deprecated but we sill accept it for now.
385
- trans_expr(['make-record',Rname|Args], Old, Ar, New, Ivars) ->
386
- Targs = trans_rec_args(Args, Old, Ar, New, Ivars),
387
- ['make-record',Rname|Targs];
388
- trans_expr(['is-record',E,Rname], Old, Ar, New, Ivars) ->
389
- Te = trans_expr(E, Old, Ar, New, Ivars),
390
- ['is-record',Te,Rname];
391
- trans_expr(['record-index',_Name,_F]=Ri, _, _, _, _) ->
392
- Ri; %Nothing to do here
393
- trans_expr(['record-field',E,Rname,F], Old, Ar, New, Ivars) ->
394
- Te = trans_expr(E, Old, Ar, New, Ivars),
395
- ['record-field',Te,Rname,F];
396
- trans_expr(['record-update',E,Rname|Args], Old, Ar, New, Ivars) ->
397
- Te = trans_expr(E, Old, Ar, New, Ivars),
398
- Targs = trans_rec_args(Args, Old, Ar, New, Ivars),
399
- ['record-update',Te,Rname|Targs];
400
- %% Function forms.
401
- trans_expr([function,F,A]=Func, Old, Ar, New, Ivars) ->
402
- if F =:= Old, A =:= Ar ->
403
- %% Must return a function of arity A here which calls the
404
- %% lifted functions! Can access the imported variables.
405
- Vars = new_vars(A),
406
- [lambda,Vars,[New|Vars++Ivars]];
407
- true ->
408
- Func
409
- end;
410
- trans_expr([function,_,_,_]=Func, _, _, _, _) ->
411
- Func; %Nothing to do here
412
- %% Core closure special forms.
413
- trans_expr([lambda,Args|Body0], Name, Ar, New, Ivars) ->
414
- Body1 = trans_exprs(Body0, Name, Ar, New, Ivars),
415
- [lambda,Args|Body1];
416
- trans_expr(['match-lambda'|Cls0], Name, Ar, New, Ivars) ->
417
- Cls1 = trans_cls(Cls0, Name, Ar, New, Ivars),
418
- ['match-lambda'|Cls1];
419
- trans_expr(['let',Vbs|Body], Name, Ar, New, Ivars) ->
420
- trans_let(Vbs, Body, Name, Ar, New, Ivars);
421
- trans_expr(['let-function',Fbs|Body], Name, Ar, New, Ivars) ->
422
- trans_let_function(Fbs, Body, Name, Ar, New, Ivars);
423
- trans_expr(['letrec-function',Fbs|Body], Name, Ar, New, Ivars) ->
424
- trans_letrec_function(Fbs, Body, Name, Ar, New, Ivars);
425
- %% Core control special forms.
426
- trans_expr([progn|Body], Name, Ar, New, Ivars) ->
427
- [progn|trans_exprs(Body, Name, Ar, New, Ivars)];
428
- trans_expr(['if'|Body], Name, Ar, New, Ivars) ->
429
- ['if'|trans_exprs(Body, Name, Ar, New, Ivars)];
430
- trans_expr(['case',Expr|Cls], Name, Ar, New, Ivars) ->
431
- trans_case(Expr, Cls, Name, Ar, New, Ivars);
432
- trans_expr(['receive'|Cls], Name, Ar, New, Ivars) ->
433
- ['receive'|trans_cls(Cls, Name, Ar, New, Ivars)];
434
- trans_expr(['catch'|Body], Name, Ar, New, Ivars) ->
435
- ['catch'|trans_exprs(Body, Name, Ar, New, Ivars)];
436
- trans_expr(['try'|Body], Name, Ar, New, Ivars) ->
437
- trans_try(Body, Name, Ar, New, Ivars);
438
- trans_expr([funcall|Body], Name, Ar, New, Ivars) ->
439
- [funcall|trans_exprs(Body, Name, Ar, New, Ivars)];
440
- %% List/binary comprehensions.
441
- trans_expr(['lc',Qs,E], Name, Ar, New, Ivars) ->
442
- trans_comp('lc', Qs, E, Name, Ar, New, Ivars);
443
- trans_expr(['list-comp',Qs,E], Name, Ar, New, Ivars) ->
444
- trans_comp('list-comp', Qs, E, Name, Ar, New, Ivars);
445
- trans_expr(['bc',Qs,E], Name, Ar, New, Ivars) ->
446
- trans_comp('bc', Qs, E, Name, Ar, New, Ivars);
447
- trans_expr(['binary-comp',Qs,E], Name, Ar, New, Ivars) ->
448
- trans_comp('binary-comp', Qs, E, Name, Ar, New, Ivars);
449
- %% General cases.
450
- trans_expr([call|Body], Name, Ar, New, Ivars) ->
451
- [call|trans_exprs(Body, Name, Ar, New, Ivars)];
452
- trans_expr([Fun|Args0], Name, Ar, New, Ivars) when is_atom(Fun) ->
453
- %% Most of the core data special forms can be handled here as well.
454
- Far = length(Args0),
455
- Args1 = trans_exprs(Args0, Name, Ar, New, Ivars),
456
- if Fun =:= Name,
457
- Far =:= Ar -> [New|Args1 ++ Ivars];
458
- true -> [Fun|Args1]
459
- end;
460
- trans_expr(Lit, _, _, _, _) -> Lit.
461
-
462
- trans_exprs(Exprs, Name, Ar, New, Ivars) ->
463
- Fun = fun (E) -> trans_expr(E, Name, Ar, New, Ivars) end,
464
- lists:map(Fun, Exprs).
465
-
466
- trans_bitsegs(Segs, Name, Ar, New, Ivars) ->
467
- Fun = fun (Seg) -> trans_bitseg(Seg, Name, Ar, New, Ivars) end,
468
- lists:map(Fun, Segs).
469
-
470
- trans_bitseg([Val0|Specs0], Name, Ar, New, Ivars) ->
471
- Val1 = trans_expr(Val0, Name, Ar, New, Ivars),
472
- Fun = fun ([size,E]) -> [size,trans_expr(E, Name, Ar, New, Ivars)] end,
473
- Specs1 = lists:map(Fun, Specs0),
474
- [Val1|Specs1];
475
- trans_bitseg(Seg, Name, Ar, New, Ivars) ->
476
- trans_expr(Seg, Name, Ar, New, Ivars) .
477
-
478
- %% trans_rec_fields(Fields, Name, Arity, NewName, ImportedVars) -> Fields.
479
- %% trans_rec_args(Args, Name, Arity, NewName, ImportedVars) -> Args.
480
-
481
- %% trans_rec_fields([[F,V|Type]|Fs], Name, Ar, New, Ivars) ->
482
- %% Tv = trans_expr(V, Name, Ar, New, Ivars),
483
- %% Tfs = trans_rec_fields(Fs, Name, Ar, New, Ivars),
484
- %% [[F,Tv|Type]|Tfs];
485
- %% trans_rec_fields([F|Fs], Name, Ar, New, Ivars) ->
486
- %% Tfs = trans_rec_fields(Fs, Name, Ar, New, Ivars),
487
- %% [F|Tfs];
488
- %% trans_rec_fields([], _, _, _, _) -> [].
489
-
490
- trans_rec_args([F,V|As], Name, Ar, New, Ivars) ->
491
- Tv = trans_expr(V, Name, Ar, New, Ivars),
492
- Tas = trans_rec_args(As, Name, Ar, New, Ivars),
493
- [F,Tv|Tas];
494
- trans_rec_args([], _, _, _, _) -> [].
495
-
496
- trans_cls(Cls, Name, Ar, New, Ivars) ->
497
- Fun = fun (Cl) -> trans_cl(Cl, Name, Ar, New, Ivars) end,
498
- lists:map(Fun, Cls).
499
-
500
- %% trans_cl(Clause, Name, Arity, NewName, ImportedVars) -> Clause.
501
- %% We know that there are no interesting functions in the guard.
502
-
503
- trans_cl([Pat,['when'|_]=G|Body], Name, Ar, New, Ivars) ->
504
- [Pat,G|trans_exprs(Body, Name, Ar, New, Ivars)];
505
- trans_cl([Pat|Body], Name, Ar, New, Ivars) ->
506
- [Pat|trans_exprs(Body, Name, Ar, New, Ivars)].
507
-
508
- trans_let(Vbs0, Body0, Name, Ar, New, Ivars) ->
509
- Fun = fun ([Pat,['when'|_]=G,Expr0]) ->
510
- Expr1 = trans_expr(Expr0, Name, Ar, New, Ivars),
511
- [Pat,G,Expr1];
512
- ([Pat,Expr0]) ->
513
- Expr1 = trans_expr(Expr0, Name, Ar, New, Ivars),
514
- [Pat,Expr1]
515
- end,
516
- Vbs1 = lists:map(Fun, Vbs0),
517
- Body1 = trans_exprs(Body0, Name, Ar, New, Ivars),
518
- ['let',Vbs1|Body1].
519
-
520
- trans_let_function(Fbs0, Body0, Name, Ar, New, Ivars) ->
521
- Fbs1 = trans_let_fbs(Fbs0, Name, Ar, New, Ivars),
522
- Body1 = trans_exprs(Body0, Name, Ar, New, Ivars),
523
- ['let-function',Fbs1|Body1].
524
-
525
- trans_letrec_function(Fbs0, Body0, Name, Ar, New, Ivars) ->
526
- Fbs1 = trans_let_fbs(Fbs0, Name, Ar, New, Ivars),
527
- Body1 = trans_exprs(Body0, Name, Ar, New, Ivars),
528
- ['letrec-function',Fbs1|Body1].
529
-
530
- trans_let_fbs(Fbs, Name, Ar, New, Ivars) ->
531
- Fun = fun ([F,Def]) -> [F,trans_expr(Def, Name, Ar, New, Ivars)] end,
532
- lists:map(Fun, Fbs).
533
-
534
- trans_case(Expr0, Cls0, Name, Ar, New, Ivars) ->
535
- Expr1 = trans_expr(Expr0, Name, Ar, New, Ivars),
536
- Cls1 = trans_cls(Cls0, Name, Ar, New, Ivars),
537
- ['case',Expr1|Cls1].
538
-
539
- %% trans_try(TryBody, Name, Arity, NewName, ImportedVars) -> Try.
540
- %% Step down the try body doing each section separately.
541
-
542
- trans_try(Try0, Name, Ar, New, Ivars) ->
543
- Fun = fun (T) -> trans_try_1(T, Name, Ar, New, Ivars) end,
544
- Try1 = lists:map(Fun, Try0),
545
- ['try'|Try1].
546
-
547
- trans_try_1(['case'|Case0], Name, Ar, New, Ivars) ->
548
- Case1 = trans_cls(Case0, Name, Ar, New, Ivars),
549
- ['case'|Case1];
550
- trans_try_1(['catch'|Catch0], Name, Ar, New, Ivars) ->
551
- Catch1 = trans_cls(Catch0, Name, Ar, New, Ivars),
552
- ['catch'|Catch1];
553
- trans_try_1(['after'|After0], Name, Ar, New, Ivars) ->
554
- After1 = trans_exprs(After0, Name, Ar, New, Ivars),
555
- ['after'|After1];
556
- trans_try_1(E, Name, Ar, New, Ivars) -> %The try expression.
557
- trans_expr(E, Name, Ar, New, Ivars).
558
-
559
- func_arity([lambda,Args|_]) -> length(Args);
560
- func_arity(['match-lambda',[Pats|_]|_]) ->
561
- length(Pats).
562
-
563
- %% trans_comp(Comprehension, Qualifiers, Expr,
564
- %% OldName, Arity, NewName, ImportedVars) ->
565
- %% Expr.
566
- %% Translate a list/binary comprehenesion.
567
-
568
- trans_comp(Comp, Qs0, E0, Name, Ar, New, Ivars) ->
569
- E1 = trans_expr(E0, Name, Ar, New, Ivars),
570
- Qs1 = trans_comp_quals(Qs0, Name, Ar, New, Ivars),
571
- [Comp,Qs1,E1].
572
-
573
- trans_comp_quals(Qs, Name, Ar, New, Ivars) ->
574
- lists:map(fun (Q) ->
575
- trans_comp_qual(Q, Name, Ar, New, Ivars)
576
- end, Qs).
577
-
578
- trans_comp_qual(['<-',Pat,E0], Name, Ar, New, Ivars) ->
579
- E1 = trans_expr(E0, Name, Ar, New, Ivars),
580
- io:format("tcq ~p ~p\n", [E0,E1]),
581
- ['<-',Pat,E1];
582
- trans_comp_qual(['<-',Pat,Guard,E0], Name, Ar, New, Ivars) ->
583
- E1 = trans_expr(E0, Name, Ar, New, Ivars),
584
- ['<-',Pat,Guard,E1];
585
- trans_comp_qual(['<=',Pat,E0], Name, Ar, New, Ivars) ->
586
- E1 = trans_expr(E0, Name, Ar, New, Ivars),
587
- ['<=',Pat,E1];
588
- trans_comp_qual(['<=',Pat,Guard,E0], Name, Ar, New, Ivars) ->
589
- E1 = trans_expr(E0, Name, Ar, New, Ivars),
590
- ['<=',Pat,Guard,E1];
591
- trans_comp_qual(Test, Name, Ar, New, Ivars) ->
592
- trans_expr(Test, Name, Ar, New, Ivars).
427
+ lift_comp_qual(Test, Lifts, Lds, St) ->
428
+ lift_expr(Test, Lifts, Lds, St).
593
429
594
430
%% new_local_fun_name(Name, Arity, State) -> {FunName,State}.
595
431
%% Create a name for a local function. The name has a similar basic
 
@@ -692,7 +528,8 @@ ivars_expr(Var, Kvars, Ivars) when is_atom(Var) ->
692
528
true -> Ivars;
693
529
false -> ordsets:add_element(Var, Ivars)
694
530
end;
695
- ivars_expr(_Lit, _Kvars, Ivars) -> Ivars. %All literals
531
+ %% Everything else is a literal.
532
+ ivars_expr(_Lit, _Kvars, Ivars) -> Ivars.
696
533
697
534
ivars_exprs(Exprs, Kvars, Ivars) ->
698
535
Fun = fun (E, Ivs) -> ivars_expr(E, Kvars, Ivs) end,
 
@@ -807,9 +644,9 @@ ivars_comp(Qs, E, Kvars0, Ivars0) ->
807
644
808
645
ivars_comp_quals(Qs, Kvars, Ivars) ->
809
646
lists:foldl(fun (Q, {Kvars0,Ivars0}) ->
810
- {Kvars1,Ivars1} = ivars_comp_qual(Q, Kvars0, Ivars0),
811
- {Kvars1,Ivars1}
812
- end, {Kvars,Ivars}, Qs).
647
+ {Kvars1,Ivars1} = ivars_comp_qual(Q, Kvars0, Ivars0),
648
+ {Kvars1,Ivars1}
649
+ end, {Kvars,Ivars}, Qs).
813
650
814
651
ivars_comp_qual(['<-',Pat,Gen], Kvars, Ivars) ->
815
652
ivars_comp_qual(Pat, [], Gen, Kvars, Ivars);
 
@@ -849,11 +686,11 @@ ivars_pats(Pats, Pvars) ->
849
686
850
687
%% mapfoldl2(Fun, Acc1, Acc2, List) -> {List,Acc1,Acc2}.
851
688
852
- mapfoldl2(Fun, A0, B0, [E0|Es0]) ->
853
- {E1,A1,B1} = Fun(E0, A0, B0),
854
- {Es1,A2,B2} = mapfoldl2(Fun, A1, B1, Es0),
855
- {[E1|Es1],A2,B2};
856
- mapfoldl2(_, A, B, []) -> {[],A,B}.
689
+ %% mapfoldl2(Fun, A0, B0, [E0|Es0]) ->
690
+ %% {E1,A1,B1} = Fun(E0, A0, B0),
691
+ %% {Es1,A2,B2} = mapfoldl2(Fun, A1, B1, Es0),
692
+ %% {[E1|Es1],A2,B2};
693
+ %% mapfoldl2(_, A, B, []) -> {[],A,B}.
857
694
858
695
%% test(Which) -> Sexpr.
changed src/lfe_eval.erl
 
@@ -1,4 +1,4 @@
1
- %% Copyright (c) 2008-2021 Robert Virding
1
+ %% Copyright (c) 2008-2023 Robert Virding
2
2
%%
3
3
%% Licensed under the Apache License, Version 2.0 (the "License");
4
4
%% you may not use this file except in compliance with the License.
 
@@ -61,8 +61,6 @@ format_error(function_clause) -> <<"no function clause matching">>;
61
61
format_error({case_clause,Val}) ->
62
62
format_value(Val, <<"no case clause matching ">>);
63
63
format_error(illegal_guard) -> <<"illegal guard expression">>;
64
- format_error(illegal_bitsize) -> <<"illegal bit size">>;
65
- format_error(illegal_bitseg) -> <<"illegal bit segment">>;
66
64
format_error({illegal_pattern,Pat}) ->
67
65
format_value(Pat, <<"illegal pattern ">>);
68
66
format_error({illegal_literal,Lit}) ->
 
@@ -74,6 +72,11 @@ format_error({argument_limit,Arity}) ->
74
72
lfe_io:format1(<<"too many arguments ~w">>, [Arity]);
75
73
format_error({bad_form,Form}) ->
76
74
lfe_io:format1(<<"bad ~w form">>, [Form]);
75
+ %% Binaries
76
+ format_error(illegal_bitsize) -> <<"illegal bit size">>;
77
+ format_error(illegal_bitseg) -> <<"illegal bit segment">>;
78
+ format_error({bad_binary_argument,Arg}) ->
79
+ format_value(Arg, <<"bad binary argument ">>);
77
80
%% Try-catches.
78
81
format_error({try_clause,V}) ->
79
82
format_value(V, <<"no try clause matching ">>);
 
@@ -93,6 +96,9 @@ format_error({undefined_struct_field,Name,Field}) ->
93
96
lfe_io:format1(<<"field ~w undefined in struct ~w">>, [Field,Name]);
94
97
format_error({missing_struct_field_value,Field}) ->
95
98
lfe_io:format1(<<"missing value to field ~w in struct">>, [Field]);
99
+ %% Comprehensions
100
+ format_error({bad_generator,Gen}) ->
101
+ format_value(Gen, <<"bad generator ">>);
96
102
%% Everything we don't recognise or know about.
97
103
format_error(Error) ->
98
104
lfe_io:prettyprint1(Error).
 
@@ -274,9 +280,18 @@ eval_expr(['try'|Body], Env) ->
274
280
eval_try(Body, Env);
275
281
eval_expr([funcall,F|As], Env) ->
276
282
eval_apply_expr(eval_expr(F, Env), eval_list(As, Env), Env);
277
- eval_expr([call|Body], Env) ->
278
- eval_call(Body, Env);
283
+ %% List/binary comprehensions.
284
+ eval_expr(['lc',Qs,E], Env) ->
285
+ eval_list_comp(Qs, E, Env);
286
+ eval_expr(['list-comp',Qs,E], Env) ->
287
+ eval_list_comp(Qs, E, Env);
288
+ eval_expr(['bc',Qs,E], Env) ->
289
+ eval_bin_comp(Qs, E, Env);
290
+ eval_expr(['binary-comp',Qs,E], Env) ->
291
+ eval_bin_comp(Qs, E, Env);
279
292
%% General functions calls.
293
+ eval_expr(['call'|Body], Env) ->
294
+ eval_call(Body, Env);
280
295
eval_expr([Fun|Es], Env) when is_atom(Fun) ->
281
296
%% Note that macros have already been expanded here.
282
297
Ar = length(Es), %Arity
 
@@ -997,6 +1012,159 @@ check_exceptions([Cl|Cls]) ->
997
1012
check_exceptions(Cls);
998
1013
check_exceptions([]) -> ok.
999
1014
1015
+ %% eval_list_comp(Qualifiers, Expression, Env) -> Value.
1016
+ %% Evaluate list comprehensions.
1017
+
1018
+ eval_list_comp(Qs, Expr, Env) ->
1019
+ QualFun = fun eval_lc_qual_loop/5,
1020
+ ValAcc = QualFun(Qs, Expr, Env, [], QualFun),
1021
+ lists:reverse(ValAcc).
1022
+
1023
+ %% eval_bin_comp(Qualifiers, Expression, Env) -> Value.
1024
+ %% Evaluate binary comprehensions.
1025
+
1026
+ eval_bin_comp(Qs, Expr, Env) ->
1027
+ QualFun = fun eval_bc_qual_loop/5,
1028
+ ValAcc = QualFun(Qs, Expr, Env, <<>>, QualFun),
1029
+ ValAcc.
1030
+
1031
+ %% eval_lc_qual_loop(Qualifiers, Expression, Env, ValAcc, QualFun) -> [Val].
1032
+
1033
+ eval_lc_qual_loop([Q|Qs], Expr, Env, Vacc, QualFun) ->
1034
+ case is_comp_generator(Q) of
1035
+ true ->
1036
+ eval_comp_generate(Q, Qs, Expr, Env, Vacc, QualFun);
1037
+ false ->
1038
+ %% We have a test so see if it succeeds.
1039
+ case eval_expr(Q, Env) of
1040
+ true ->
1041
+ eval_lc_qual_loop(Qs, Expr, Env, Vacc, QualFun);
1042
+ _Other ->
1043
+ Vacc
1044
+ end
1045
+ end;
1046
+ eval_lc_qual_loop([], Expr, Env, Vacc, _QualFun) ->
1047
+ Val = eval_expr(Expr, Env),
1048
+ [Val | Vacc].
1049
+
1050
+ %% eval_lc_gen_loop(Pattern, Guard, Generator, Qualifiers, Expression, Env,
1051
+ %% ValAcc, QualFun) -> ValAcc.
1052
+
1053
+ eval_lc_gen_loop(Pat, Guard, [Val|GenVals], Qs, Expr, Env0, Vacc0, QualFun) ->
1054
+ case match_when(Pat, Val, [Guard], Env0) of
1055
+ {yes,_,Vbs} ->
1056
+ Env1 = lfe_env:add_vbindings(Vbs, Env0),
1057
+ Vacc1 = QualFun(Qs, Expr, Env1, Vacc0, QualFun),
1058
+ eval_lc_gen_loop(Pat, Guard, GenVals, Qs, Expr,
1059
+ Env1, Vacc1, QualFun);
1060
+ no ->
1061
+ eval_lc_gen_loop(Pat, Guard, GenVals, Qs, Expr,
1062
+ Env0, Vacc0, QualFun)
1063
+ end;
1064
+ eval_lc_gen_loop(_Pat, _Guard, [], _Qs, _Expr, _Env, Vacc, _QualFun) ->
1065
+ %% No more elements so we are done with this generator.
1066
+ Vacc;
1067
+ eval_lc_gen_loop(_Pat, _Guard, Other, _Qs, _Expr, _Env, _Vacc, _QualFun) ->
1068
+ %% This should be a list.
1069
+ eval_error({bad_generator,Other}).
1070
+
1071
+ %% eval_bc_qual_loop(Qualifiers, Expression, Env, ValAcc, QualFun) -> ValAcc.
1072
+
1073
+ eval_bc_qual_loop([Q|Qs], Expr, Env, Vacc, QualFun) ->
1074
+ case is_comp_generator(Q) of
1075
+ true ->
1076
+ eval_comp_generate(Q, Qs, Expr, Env, Vacc, QualFun);
1077
+ false ->
1078
+ %% We have a test so see if it succeeds.
1079
+ case eval_expr(Q, Env) of
1080
+ true ->
1081
+ eval_bc_qual_loop(Qs, Expr, Env, Vacc, QualFun);
1082
+ _Other ->
1083
+ Vacc
1084
+ end
1085
+ end;
1086
+ eval_bc_qual_loop([], Expr, Env, Vacc, _QualFun) ->
1087
+ Val = eval_expr(Expr, Env),
1088
+ << Vacc/bitstring, Val/bitstring >>.
1089
+
1090
+ %% eval_bc_gen_loop(Pattern, Guard, Generator, Qualifiers, Expression, Env,
1091
+ %% ValAcc, QualFun) -> ValAcc.
1092
+ %% Do a simple test here for the format of the pattern. Match will do
1093
+ %% more test. We calculate the size of the segment patterns in bits
1094
+ %% here so we can step over them without having to do it each time.
1095
+
1096
+ eval_bc_gen_loop([binary|SegPats], Guard, GenBin, Qs, Expr,
1097
+ Env, Vacc, QualFun) ->
1098
+ SegsSize = get_segs_size(SegPats),
1099
+ eval_bc_gen_loop_1(SegPats, SegsSize, Guard, GenBin, Qs, Expr,
1100
+ Env, Vacc, QualFun);
1101
+ eval_bc_gen_loop(Pat, _Guard, _GenBin, _Qs, _Expr, _Env, _Vacc, _QualFun) ->
1102
+ eval_error({illegal_pattern,Pat}).
1103
+
1104
+ %% eval_bc_gen_loop(SegPats, PatSize, Guard, Generator, Qualifiers, Expression,
1105
+ %% Env, ValAcc, QualFun) -> ValAcc.
1106
+
1107
+ eval_bc_gen_loop_1(SegPats, SegsSize, Guard, GenBin0, Qs, Expr, Env0, Vacc0, QualFun)
1108
+ when is_bitstring(GenBin0) ->
1109
+ case GenBin0 of
1110
+ << PatBin:SegsSize/bitstring,GenBin1/bitstring >> ->
1111
+ %% Get the generator bits for matching and the remaining generator.
1112
+ case match_when([binary|SegPats], PatBin, [Guard], Env0) of
1113
+ {yes,_,Vbs} ->
1114
+ Env1 = lfe_env:add_vbindings(Vbs, Env0),
1115
+ Vacc1 = QualFun(Qs, Expr, Env1, Vacc0, QualFun),
1116
+ eval_bc_gen_loop_1(SegPats, SegsSize, Guard, GenBin1, Qs,
1117
+ Expr, Env1, Vacc1, QualFun);
1118
+ no ->
1119
+ %% Didn't match, just step over this part of the generator.
1120
+ eval_bc_gen_loop_1(SegPats, SegsSize, Guard, GenBin1, Qs,
1121
+ Expr, Env0, Vacc0, QualFun)
1122
+ end;
1123
+ _ ->
1124
+ %% Not enough bits so we are done with this generator.
1125
+ Vacc0
1126
+ end;
1127
+ eval_bc_gen_loop_1(_SegPats, _SegsSize, _Guard, GenBin, _Qs, _Expr,
1128
+ _Env, _Vacc, _QualFun) ->
1129
+ %% This should be a binary/bitstring.
1130
+ eval_error({bad_generator,GenBin}).
1131
+
1132
+ get_segs_size(SegPats) ->
1133
+ SizeFun = fun ([_|Specs], Acc) ->
1134
+ {ok,Size,_} = lfe_bits:get_bitspecs(Specs),
1135
+ Acc + Size;
1136
+ (_, Acc) -> %Default is integer
1137
+ Acc + 8
1138
+ end,
1139
+ lists:foldl(SizeFun, 0, SegPats).
1140
+
1141
+ is_comp_generator(['<-',_,_]) -> true;
1142
+ is_comp_generator(['<-',_,['when'|_],_]) -> true;
1143
+ is_comp_generator(['<=',_,_]) -> true;
1144
+ is_comp_generator(['<=',_,['when'|_],_]) -> true;
1145
+ is_comp_generator(_Other) -> false.
1146
+
1147
+ %% eval_comp_generate(Pattern, Qualifiers, Expression, Env, ValAcc, Qualfun) ->
1148
+ %% ValAcc.
1149
+
1150
+ eval_comp_generate(['<-',Pat,Gen], Qs, Expr, Env, Vacc, QualFun) ->
1151
+ GenVals = eval_list_gen(Gen, Env),
1152
+ eval_lc_gen_loop(Pat, [], GenVals, Qs, Expr, Env, Vacc, QualFun);
1153
+ eval_comp_generate(['<-',Pat,['when'|_]=Guard,Gen], Qs, Expr, Env, Vacc, QualFun) ->
1154
+ GenVals = eval_list_gen(Gen, Env),
1155
+ eval_lc_gen_loop(Pat, Guard, GenVals, Qs, Expr, Env, Vacc, QualFun);
1156
+ eval_comp_generate(['<=',Pat,Gen], Qs, Expr, Env, Vacc, QualFun) ->
1157
+ GenBin = eval_bin_gen(Gen, Env),
1158
+ eval_bc_gen_loop(Pat, [], GenBin, Qs, Expr, Env, Vacc, QualFun);
1159
+ eval_comp_generate(['<=',Pat,['when'|_]=Guard,Gen], Qs, Expr, Env, Vacc, QualFun) ->
1160
+ GenBin = eval_bin_gen(Gen, Env),
1161
+ eval_bc_gen_loop(Pat, Guard, GenBin, Qs, Expr, Env, Vacc, QualFun).
1162
+
1163
+ eval_list_gen(Gen, Env) ->
1164
+ eval_expr(Gen, Env).
1165
+
1166
+ eval_bin_gen(Gen, Env) ->
1167
+ eval_expr(Gen, Env).
1000
1168
1001
1169
%% eval_call([Mod,Func|Args], Env) -> Value.
1002
1170
%% Evaluate the module, function and args and then apply the function.
changed src/lfe_eval_bits.erl
 
@@ -1,4 +1,4 @@
1
- %% Copyright (c) 2021 Robert Virding
1
+ %% Copyright (c) 2021-2023 Robert Virding
2
2
%%
3
3
%% Licensed under the Apache License, Version 2.0 (the "License");
4
4
%% you may not use this file except in compliance with the License.
 
@@ -24,7 +24,7 @@
24
24
25
25
-module(lfe_eval_bits).
26
26
27
- -export([expr_bitsegs/2,match_bitsegs/4]).
27
+ -export([expr_bitsegs/2,match_bitsegs/4,format_error/1]).
28
28
29
29
-import(lists, [foldl/3,foldr/3]).
30
30
 
@@ -40,6 +40,15 @@
40
40
41
41
-define(EVAL_ERROR(Error), erlang:raise(error, Error, ?STACKTRACE)).
42
42
43
+ %% Pass most errors on to lfe_eval.
44
+ format_error({bad_binary_argument,Arg}) ->
45
+ format_value(Arg, <<"bad binary argument ">>);
46
+ format_error(Error) ->
47
+ lfe_eval:format_error(Error).
48
+
49
+ format_value(Val, ErrStr) ->
50
+ lfe_io:format1(<<"~s~.P">>, [ErrStr,Val,10]).
51
+
43
52
%% expr_bitsegs(Bitsegs, EvalFun) -> Binary.
44
53
%% Construct a binary from Bitsegs. This code is taken from
45
54
%% eval_bits.erl. Pass in an evaluator function to be used when
 
@@ -93,7 +102,12 @@ eval_bitsegs(Vsps, Eval) ->
93
102
94
103
eval_bitseg(Val, Sz, Ty, Eval) ->
95
104
V = Eval(Val),
96
- eval_exp_bitseg(V, Sz, Eval, Ty).
105
+ try
106
+ eval_exp_bitseg(V, Sz, Eval, Ty)
107
+ catch
108
+ _:_ ->
109
+ eval_error({bad_binary_argument,V})
110
+ end.
97
111
98
112
%% eval_exp_bitseg(Value, Size, EvalSize, {Type,Unit,Sign,Endian}) -> Binary.
99
113
 
@@ -174,12 +188,16 @@ match_bitseg(Pat, Size, Type, Bin0, Bbs0, Pbs0, Env) ->
174
188
end.
175
189
176
190
get_pat_bitsize(all, {Ty,_,_,_}, _, _, _) ->
177
- if Ty =:= binary -> all;
178
- true -> eval_error(illegal_bitsize)
191
+ if Ty =:= binary ->
192
+ all;
193
+ true ->
194
+ eval_error(illegal_bitsize)
179
195
end;
180
196
get_pat_bitsize(undefined, {Ty,_,_,_}, _, _, _) ->
181
- if Ty =:= utf8; Ty =:= utf16; Ty =:= utf32 -> undefined;
182
- true -> eval_error(illegal_bitsize)
197
+ if Ty =:= utf8; Ty =:= utf16; Ty =:= utf32 ->
198
+ undefined;
199
+ true ->
200
+ eval_error(illegal_bitsize)
183
201
end;
184
202
get_pat_bitsize(S, _, _, _, _) when is_integer(S) -> S;
185
203
get_pat_bitsize(S, _, Bbs, _, Env) when is_atom(S) ->
 
@@ -206,7 +224,8 @@ match_bitexpr(S, Val, Bbs, Pbs, _) when is_atom(S) ->
206
224
error -> %Not yet bound
207
225
{yes,store(S, Val, Bbs),store(S, Val, Pbs)}
208
226
end;
209
- match_bitexpr(_, _, _, _, _) -> eval_error(illegal_bitseg).
227
+ match_bitexpr(_, _, _, _, _) ->
228
+ eval_error(illegal_bitseg).
210
229
211
230
%% get_pat_bitseg(Binary, Size, {Type,Unit,Sign,Endian}) -> {Value,RestBinary}.
212
231
%% This function can signal error if impossible to get specified bit
changed src/lfe_lint.erl
 
@@ -1,4 +1,4 @@
1
- %% Copyright (c) 2008-2021 Robert Virding
1
+ %% Copyright (c) 2008-2023 Robert Virding
2
2
%%
3
3
%% Licensed under the Apache License, Version 2.0 (the "License");
4
4
%% you may not use this file except in compliance with the License.
 
@@ -473,9 +473,9 @@ is_func_list(_, _) -> no.
473
473
check_onload_attr([[F,Ar]=LoadF], L, St) when is_atom(F), is_integer(Ar) ->
474
474
Onload = St#lfe_lint.onload,
475
475
if (Onload =:= []) or (Onload =:= LoadF) ->
476
- St#lfe_lint{onload=LoadF};
476
+ St#lfe_lint{onload=LoadF};
477
477
true ->
478
- bad_attr_error(L, on_load, St)
478
+ bad_attr_error(L, on_load, St)
479
479
end;
480
480
check_onload_attr(_Onload, L, St) ->
481
481
bad_attr_error(L, on_load, St).
 
@@ -715,8 +715,13 @@ init_state(St) ->
715
715
end, Env0, St#lfe_lint.imports),
716
716
%% Basic predefines
717
717
Predefs0 = [{module_info,[lambda,[],?Q(dummy)],1},
718
- {module_info,[lambda,[x],?Q(dummy)],1}],
719
- Exps0 = [{module_info,0},{module_info,1}],
718
+ {module_info,[lambda,[x],?Q(dummy)],1},
719
+ {'__info__',[lambda,[x],?Q(dummy)],1},
720
+ {'__struct__',[lambda,[],?Q(dummy)],1},
721
+ {'__struct__',[lambda,[x],?Q(dummy)],1}
722
+ ],
723
+ Exps0 = [{module_info,0},{module_info,1},
724
+ {'__info__',1},{'__struct__',0},{'__struct__',1}],
720
725
Exps1 = add_exports(Exps0, St#lfe_lint.mline, St#lfe_lint.exports),
721
726
{Predefs0,Env1,St#lfe_lint{exports=Exps1}}.
722
727
 
@@ -776,9 +781,9 @@ add_exports(More, L, Exps) ->
776
781
777
782
check_valid_onload(#lfe_lint{mline=L,onload=[F,Ar],env=Env}=St) ->
778
783
case le_hasf(F, Ar, Env) of
779
- true -> St;
780
- false ->
781
- add_error(L, {undefined_onload_function,{F,Ar}}, St)
784
+ true -> St;
785
+ false ->
786
+ add_error(L, {undefined_onload_function,{F,Ar}}, St)
782
787
end;
783
788
check_valid_onload(#lfe_lint{onload=[]}=St) ->
784
789
St.
 
@@ -1490,23 +1495,30 @@ check_comp(Qs, Expr, Env0, L, St0) ->
1490
1495
1491
1496
%% check_comp_quals(Qualifiers, Env, LineNumber, State) ->
1492
1497
%% {Env,State}.
1498
+ %% Note that the explicit guards are now tested as guards.
1493
1499
1494
1500
check_comp_quals([['<-',Pat,E]|Qs], Env0, L, St0) ->
1495
1501
{Pvs,St1} = pattern(Pat, Env0, L, St0),
1496
1502
Env1 = le_addvs(Pvs, Env0),
1497
1503
St2 = check_expr(E, Env1, L, St1),
1498
1504
check_comp_quals(Qs, Env1, L, St2);
1499
- check_comp_quals([['<-',Pat,['when'|G],E]|Qs], Env, L, St) ->
1500
- %% Move guards to qualifiers as tests.
1501
- check_comp_quals([['<-',Pat,E]|G ++ Qs], Env, L, St);
1505
+ check_comp_quals([['<-',Pat,['when'|G],E]|Qs], Env0, L, St0) ->
1506
+ {Pvs,St1} = pattern(Pat, Env0, L, St0),
1507
+ Env1 = le_addvs(Pvs, Env0),
1508
+ St2 = check_guard(G, Env1, L, St1),
1509
+ St3 = check_expr(E, Env1, L, St2),
1510
+ check_comp_quals(Qs, Env1, L, St3);
1502
1511
check_comp_quals([['<=',Pat,E]|Qs], Env0, L, St0) ->
1503
1512
{Pvs,St1} = check_bitstring_pattern(Pat, Env0, L, St0),
1504
1513
Env1 = le_addvs(Pvs, Env0),
1505
1514
St2 = check_expr(E, Env1, L, St1),
1506
1515
check_comp_quals(Qs, Env1, L, St2);
1507
- check_comp_quals([['<=',Pat,['when'|G],E]|Qs], Env, L, St) ->
1508
- %% Move guards to qualifiers as tests.
1509
- check_comp_quals([['<=',Pat,E]|G ++ Qs], Env, L, St);
1516
+ check_comp_quals([['<=',Pat,['when'|G],E]|Qs], Env0, L, St0) ->
1517
+ {Pvs,St1} = check_bitstring_pattern(Pat, Env0, L, St0),
1518
+ Env1 = le_addvs(Pvs, Env0),
1519
+ St2 = check_guard(G, Env1, L, St1),
1520
+ St3 = check_expr(E, Env1, L, St2),
1521
+ check_comp_quals(Qs, Env1, L, St3);
1510
1522
check_comp_quals([Test|Qs], Env, L, St0) ->
1511
1523
St1 = check_expr(Test, Env, L, St0),
1512
1524
check_comp_quals(Qs, Env, L, St1);
changed src/lfe_shell.erl
 
@@ -31,10 +31,13 @@
31
31
run_strings/1,run_strings/2,run_string/1,run_string/2,
32
32
new_state/2,new_state/3,upd_state/3]).
33
33
34
+ %% Useful for the LFE rebar3 plugin
35
+ -export([banner/0,banner/1,banner/2]).
36
+
34
37
%% The shell commands which generally callable.
35
- -export([c/1,c/2,cd/1,ec/1,ec/2,ep/1,ep/2,epp/1,epp/2,help/0,h/1,h/2,h/3,
36
- i/0,i/1,i/3,l/1,ls/1,clear/0,m/0,m/1,pid/3,p/1,p/2,pp/1,pp/2,pwd/0,
37
- q/0,flush/0,regs/0,exit/0]).
38
+ -export([c/1,c/2,cd/1,ec/1,ec/2,ep/1,ep/2,epp/1,epp/2,flush/0,help/0,
39
+ h/1,h/2,h/3,i/0,i/1,i/3,l/1,ls/1,clear/0,m/0,m/1,memory/0,memory/1,
40
+ nregs/0,pid/3,p/1,p/2,pp/1,pp/2,pwd/0,q/0,regs/0,uptime/0,exit/0]).
38
41
39
42
-import(orddict, [store/3,find/2]).
40
43
-import(lists, [reverse/1,foreach/2]).
 
@@ -242,17 +245,23 @@ read_expression_1(Rdr, Eval, St) ->
242
245
read_expression_1(Rdr, start_eval(St), St)
243
246
end.
244
247
245
- make_banner() ->
246
- [io_lib:format(
247
- ?GRN(" ..-~~") ++ ?YLW(".~~_") ++ ?GRN("~~---..") ++ "\n" ++
248
+ banner() ->
249
+ banner(lfe:version()).
250
+
251
+ banner(Vsn) ->
252
+ banner(Vsn, quit_message()).
253
+
254
+ banner(Vsn, QuitMsg) ->
255
+ ?GRN(" ..-~") ++ ?YLW(".~_") ++ ?GRN("~---..") ++ "\n" ++
248
256
?GRN(" ( ") ++ ?YLW("\\\\") ++ ?GRN(" )") ++ " | A Lisp-2+ on the Erlang VM\n" ++
249
257
?GRN(" |`-.._") ++ ?YLW("/") ++ ?GRN("_") ++ ?YLW("\\\\") ++ ?GRN("_.-':") ++ " | Type " ++ ?GRN("(help)") ++ " for usage info.\n" ++
250
258
?GRN(" | ") ++ ?RED("g") ++ ?GRN(" |_ \\") ++ " |\n" ++
251
259
?GRN(" | ") ++ ?RED("n") ++ ?GRN(" | |") ++ " | Docs: " ++ ?BLU("https://docs.lfe.io/") ++ "\n" ++
252
260
?GRN(" | ") ++ ?RED("a") ++ ?GRN(" / /") ++ " | Source: " ++ ?BLU("https://github.com/lfe/lfe") ++ "\n" ++
253
261
?GRN(" \\ ") ++ ?RED("l") ++ ?GRN(" |_/") ++ " |\n" ++
254
- ?GRN(" \\ ") ++ ?RED("r") ++ ?GRN(" /") ++ " | LFE v~s ~s\n" ++
255
- ?GRN(" `-") ++ ?RED("E") ++ ?GRN("___.-'") ++ "\n\n", [get_lfe_version(), get_abort_message()])].
262
+ ?GRN(" \\ ") ++ ?RED("r") ++ ?GRN(" /") ++ " | LFE v" ++
263
+ Vsn ++ " " ++ QuitMsg ++ "\n" ++
264
+ ?GRN(" `-") ++ ?RED("E") ++ ?GRN("___.-'") ++ "\n\n".
256
265
257
266
display_banner() ->
258
267
%% When LFE is called with -noshell, we want to skip the banner. Also, there may be
 
@@ -260,22 +269,18 @@ display_banner() ->
260
269
%% thus we want to support both use cases.
261
270
case init:get_argument(noshell) of
262
271
error -> case init:get_argument(nobanner) of
263
- error -> io:put_chars(make_banner());
272
+ error -> io:put_chars(banner());
264
273
_ -> false
265
274
end;
266
275
_ -> false
267
276
end.
268
277
269
- get_abort_message() ->
278
+ quit_message() ->
270
279
%% We can update this later to check for env variable settings for
271
280
%% shells that require a different control character to abort, such
272
281
%% as jlfe.
273
282
"(abort with ^G)".
274
283
275
- get_lfe_version() ->
276
- {ok, [App]} = file:consult(code:where_is_file("lfe.app")),
277
- proplists:get_value(vsn, element(3, App)).
278
-
279
284
%% new_state(ScriptName, Args [,Env]) -> State.
280
285
%% Generate a new shell state with all the default functions, macros
281
286
%% and variables.
 
@@ -330,6 +335,7 @@ add_shell_functions(Env0) ->
330
335
{h,1,[lambda,[m], [':',lfe_shell,h,m]]},
331
336
{h,2,[lambda,[m,f], [':',lfe_shell,h,m,f]]},
332
337
{h,3,[lambda,[m,f,a], [':',lfe_shell,h,m,f,a]]},
338
+
333
339
{help,0,[lambda,[],[':',lfe_shell,help]]},
334
340
{i,0,[lambda,[],[':',lfe_shell,i]]},
335
341
{i,1,[lambda,[ps],[':',lfe_shell,i,ps]]},
 
@@ -344,6 +350,10 @@ add_shell_functions(Env0) ->
344
350
{q,0,[lambda,[],[':',lfe_shell,exit]]},
345
351
{flush,0,[lambda,[],[':',lfe_shell,flush]]},
346
352
{regs,0,[lambda,[],[':',lfe_shell,regs]]},
353
+ {nregs,0,[lambda,[],[':',lfe_shell,nregs]]},
354
+ {memory,0,[lambda,[],[':',lfe_shell,memory]]},
355
+ {memory,1,[lambda,[t],[':',lfe_shell,memory,t]]},
356
+ {uptime,0,[lambda,[],[':',lfe_shell,uptime]]},
347
357
{exit,0,[lambda,[],[':',lfe_shell,exit]]}
348
358
],
349
359
%% Any errors here will crash shell startup!
 
@@ -827,12 +837,16 @@ help() ->
827
837
"(ls dir) -- list files in directory <dir>\n"
828
838
"(m) -- which modules are loaded\n"
829
839
"(m mod) -- information about module <mod>\n"
840
+ "(memory) -- memory allocation information\n"
841
+ "(memory t) -- memory allocation information of type <t>\n"
830
842
"(p expr) -- print a term\n"
831
843
"(pp expr) -- pretty print a term\n"
832
844
"(pid x y z) -- convert x, y, z to a pid\n"
833
845
"(pwd) -- print working directory\n"
834
846
"(q) -- quit - shorthand for init:stop/0\n"
835
847
"(regs) -- information about registered processes\n"
848
+ "(nregs) -- information about all registered processes\n"
849
+ "(uptime) -- print node uptime\n"
836
850
"\n"
837
851
"LFE shell built-in forms\n\n"
838
852
"(reset-environment) -- reset the environment to its initial state\n"
 
@@ -1018,10 +1032,26 @@ flush() -> c:flush().
1018
1032
1019
1033
regs() -> c:regs().
1020
1034
1035
+ %% nregs() -> ok.
1036
+
1037
+ nregs() -> c:nregs().
1038
+
1021
1039
%% exit() -> ok.
1022
1040
1023
1041
exit() -> c:q().
1024
1042
1043
+ %% memory() -> ok.
1044
+
1045
+ memory() -> c:memory().
1046
+
1047
+ %% memory(Type) -> ok.
1048
+
1049
+ memory(Type) -> c:memory(Type).
1050
+
1051
+ %% uptime() -> ok.
1052
+
1053
+ uptime() -> c:uptime().
1054
+
1025
1055
%% doc(Mod) -> ok | {error,Error}.
1026
1056
%% doc(Mod, Func) -> ok | {error,Error}.
1027
1057
%% doc(Mod, Func, Arity) -> ok | {error,Error}.