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}.
|