Skip to content

Commit

Permalink
Merge branch 'develop'. This is v0.6.
Browse files Browse the repository at this point in the history
  • Loading branch information
rvirding committed Jul 24, 2010
2 parents 77b388f + d59e793 commit de757ed
Show file tree
Hide file tree
Showing 11 changed files with 871 additions and 516 deletions.
22 changes: 12 additions & 10 deletions README
Expand Up @@ -14,14 +14,16 @@ of the function. The .beam file in ebin is for R13B.

I will try to make a better fix soon. Sorry about that.

<will be v0.6>
--------------
v0.6
----

Added new example file with core macros implemented in LFE.

Allow literal strings in binaries, both as plain values and as values
with specs, so (binary "abc" ("���" utf-8)) is valid. In the second
case the spec is applied to each character. Works with lists as
well. Add big, little and native as synonyms to big-endian,
little-endian and native-endian.
case the spec is applied to each character. Works with lists as well.
Add big, little and native as synonyms to big-endian, little-endian
and native-endian.

Now have working Makefile, Emakefile and .app file.

Expand Down Expand Up @@ -76,11 +78,11 @@ Parameterized modules.

Added (export all) attribute to module definition.

New records which allow giving default values as in vanilla
Erlang. Records are still compatible with vanilla Erlang but now more
pratical to use. NOTE this change is not backwards compatible as
syntax for (make- ...) and (match- ...) have changed. Also added
general multiple (set- ...) macro.
New records which allow giving default values as in vanilla Erlang.
Records are still compatible with vanilla Erlang but now more pratical
to use. NOTE this change is not backwards compatible as syntax for
(make- ...) and (match- ...) have changed. Also added general multiple
(set- ...) macro.

(eval-when-compile ...) added as a top-level form which allows
functions to be defined when compiling the forms. These are useful for
Expand Down
9 changes: 5 additions & 4 deletions doc/user_guide.txt
Expand Up @@ -127,7 +127,7 @@ Older Scheme inspired macros
(define (name arg ...) ...)
(define name lambda|match-lambda)
(define-syntax name
(syntax-rules (pat exp) ...) | (macro (pat body) ...))
(syntax-rules (pat exp) ...)|(macro (pat body) ...))
(let-syntax ((name ...)
...)
...)
Expand Down Expand Up @@ -267,7 +267,7 @@ A macro is function of one argument which is a called with a list of
the arguments to the macro call. It can be either a lambda or a
match-lambda. The basic forms for defining macros are:

(define-macro name lambda | match-lambda)
(define-macro name lambda|match-lambda)
(let-macro ((name lambda|match-lambda)
...)

Expand All @@ -291,6 +291,9 @@ example:

The macro definitions in a macrolet obey the same rules as defmacro.

Yes, we have the backquote. It is implemented as a macro so it is
expanded at macro expansion time.

Local functions that are only available at compile time and can be
called by macros are defined by:

Expand Down Expand Up @@ -323,8 +326,6 @@ call and do not contain the macro name. So using them we would get:

N.B. These are definitely NOT hygienic.

Yes we have backquote.

*CAVEAT* While it is perfectly legal to define a Core form as a macro
these will silently be ignored by the compiler.

Expand Down
139 changes: 139 additions & 0 deletions examples/core-macros.lfe
@@ -0,0 +1,139 @@
;; Copyright (c) 2008-2010 Robert Virding. All rights reserved.

;; Redistribution and use in source and binary forms, with or without
;; modification, are permitted provided that the following conditions
;; are met:

;; 1. Redistributions of source code must retain the above copyright
;; notice, this list of conditions and the following disclaimer.
;; 2. Redistributions in binary form must reproduce the above copyright
;; notice, this list of conditions and the following disclaimer in the
;; documentation and/or other materials provided with the distribution.

;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
;; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
;; COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
;; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
;; BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
;; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
;; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
;; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
;; ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
;; POSSIBILITY OF SUCH DAMAGE.

;; File : core-macros.lfe
;; Author : Robert Virding
;; Purpose : Some of LFE core macrosas they could have been implemented in LFE.

;; This file contains some of the core LFE macros as they could have
;; been implemented in LFE. They are implemented in lfe_macro.erl
;; today as there is yet no way to compile macros, and to ensure that
;; they are always available. These are shown mostly without comments.
;;
;; For some macros we give two versions, an all-in-one version and a
;; recursive more syntax pattern based expansion. This to show
;; different styles of doing the same thing.

(defmacro caar (x) `(car (car ,x)))
(defmacro cadr (x) `(car (cdr ,x)))
(defmacro cdar (x) `(cdr (car ,x)))
(defmacro cddr (x) `(cdr (cdr ,x)))

(defmacro ++
((e) e)
((e . es) `(call 'erlang '++ ,e (++ . ,es)))
(() ()))

(defmacro :
((m f . as) `(call ',m ',f . ,as)))

(defmacro ? () `(receive (omega omega)))

(defmacro list*
((e) e)
((e . es) `(cons ,e (list* . ,es)))
(() ()))

;; (defmacro let*
;; ((vbs . b)
;; (: lists foldr
;; (lambda (vb rest) `(let (,vb) ,rest)) `(progn . ,b) vbs)))

(defmacro let*
(((vb . vbs) . b) `(let (,vb) (let* ,vbs . ,b)))
((() . b) `(progn . ,b))
((vb . b) `(let ,vb . b))) ;Pass error to let

(defmacro flet*
(((fb . fbs) . b) `(flet (,fb) (flet* ,fbs . ,b)))
((() . b) `(progn . ,b))
((fb . b) `(flet ,fb . b))) ;Pass error to flet

(defmacro cond
((('else . b)) `(progn . ,b))
(((('?= p e) . b) . cond)
`(case ,e (,p . ,b) (_ (cond . ,cond))))
(((('?= p (= ('when . _) g) e) . b) . cond)
`(case ,e (,p ,g . ,b) (_ (cond . ,cond))))
(((test . b) . cond) `(if ,test (progn . ,b) (cond . ,cond)))
(() `'false))

(defmacro andalso
((e) e)
((e . es) `(if ,e (andalso . ,es) 'false))
(() `'true))

(defmacro orelse
((e) e)
((e . es) `(if ,e 'true (orelse . ,es)))
(() `'false))

;; This version of backquote is almost an exact copy of a quasiquote
;; expander for Scheme by André van Tonder. It is very compact and
;; with some cons/append optimisations we have added produces quite
;; reasonable code.

(defmacro backquote (e) (bq-expand e 0))

(eval-when-compile
(defun bq-expand (exp n)
;; Note that we cannot *use* backquote or any macros using
;; backquote in here! It will cause us to loop.
(fletrec ((bq-app ;Optimise append
([('++ l) r] (bq-app l r)) ;Catch single unquote-splice
([() r] r)
([l ()] l)
([('list l) ('list . r)] (cons 'list (cons l r)))
([('list l) r] (list 'cons l r))
([l r] (list '++ l r)))
(bq-cons ;Optimise cons
([('quote l) ('quote r)] (list 'quote (cons l r)))
([l ('list . r)] (cons 'list (cons l r)))
([l ()] (list 'list l))
([l r] (list 'cons l r))))
(case exp
(('backquote x) ;`(list 'backquote ,(bq-expand x (+ n 1)))
(list 'list (list 'quote 'backquote) (bq-expand x (+ n 1))))
(('unquote x) (when (> n 0))
(bq-cons 'unquote (bq-expand x (- n 1))))
(('unquote x) (when (=:= n 0)) x)
(('unquote-splicing . x) (when (> n 0))
(bq-cons (list 'quote 'unquote-splicing) (bq-expand x (- n 1))))
;; The next two cases handle splicing into a list.
((('unquote . x) . y) (when (=:= n 0))
(bq-app (cons 'list x) (bq-expand y 0)))
((('unquote-splicing . x) . y) (when (=:= n 0))
(bq-app (cons '++ x) (bq-expand y 0)))
((x . y) ;The general list case
(bq-cons (bq-expand x n) (bq-expand y n)))
(_ (when (is_tuple exp))
;; Tuples need some smartness for efficient code to handle
;; when no splicing so as to avoid list_to_tuple.
(case (bq-expand (tuple_to_list exp) n)
(('list . es) (cons tuple es))
((= ('cons . _) e) (list 'list_to_tuple e))))
(_ (when (is_atom exp)) (list 'quote exp))
(_ exp)) ;Self quoting
)))
10 changes: 10 additions & 0 deletions src/ChangeLog
@@ -1,3 +1,13 @@
2010-07-24 Robert Virding <rv@host-90-237-128-188.mobileonline.telia.com>

* lfe_shell.erl (macroexpand, macroexpand_1): Return evaluated
argument if no expansion.

2010-07-12 Robert Virding <rv@host-90-233-145-108.mobileonline.telia.com>

* lfe_scan.xrl: Have separate cases for integer, float and symbol
atoms, catch errors better.

2010-06-07 Robert Virding <rv@stanislaw.local>

* lfe_lint.erl (pat_bitsegs): Allow strings (integer lists).
Expand Down
3 changes: 2 additions & 1 deletion src/lfe_comp.erl
Expand Up @@ -221,7 +221,8 @@ do_passes([], St) -> {ok,St}. %Got to the end, everything ok!

do_save_file(Fun, Ext, St) ->
Name = filename:join(St#comp.odir, St#comp.base ++ ["."|Ext]),
case file:open(Name, [write,delayed_write]) of
%% delayed_write useful here but plays havoc with erjang.
case file:open(Name, [write]) of
{ok,File} ->
Fun(File, St#comp.code),
ok = file:close(File),
Expand Down
9 changes: 3 additions & 6 deletions src/lfe_macro.erl
Expand Up @@ -556,9 +556,6 @@ exp_macro([Mac|Args], Def0, Env, St0) ->
erlang:error({expand_macro,Mac,Error})
end.

%% Exp = lfe_eval:apply(Def1, [Args], Env),
%% {Exp,St1}.

%% exp_predef(Form, Env, State) -> {yes,Form,State} | no.
%% Handle the builtin predefined macros but only one at top-level and
%% only once. Expand must be called on result to fully expand
Expand Down Expand Up @@ -599,9 +596,9 @@ exp_predef(['let*'|Lbody], _, St) ->
{yes,Exp,St};
exp_predef(['flet*'|Lbody], _, St) ->
Exp = case Lbody of
[[Vb|Vbs]|B] -> ['flet',[Vb],['flet*',Vbs|B]];
[[Fb|Fbs]|B] -> ['flet',[Fb],['flet*',Fbs|B]];
[[]|B] -> ['progn'|B];
[Vb|B] -> ['flet',Vb|B] %Pass error to flet for lint.
[Fb|B] -> ['flet',Fb|B] %Pass error to flet for lint.
end,
{yes,Exp,St};
exp_predef(['cond'|Cbody], _, St) ->
Expand Down Expand Up @@ -838,7 +835,7 @@ bq_expand([[unquote|X]|Y], 0) ->
bq_append([list|X], bq_expand(Y, 0));
bq_expand([['unquote-splicing'|X]|Y], 0) ->
bq_append(['++'|X], bq_expand(Y, 0));
bq_expand([X|Y], N) ->
bq_expand([X|Y], N) -> %The general list case
bq_cons(bq_expand(X, N), bq_expand(Y, N));
bq_expand(X, N) when is_tuple(X) ->
%% Straight [list_to_tuple,bq_expand(tuple_to_list(X), N)] inefficient
Expand Down

0 comments on commit de757ed

Please sign in to comment.