Permalink
Browse files

Merge branch 'develop'. This is v0.6.

  • Loading branch information...
2 parents 77b388f + d59e793 commit de757edbc25f4ac661a02f98b26d58ce5a29ec9a @rvirding committed Jul 24, 2010
Showing with 871 additions and 516 deletions.
  1. +12 −10 README
  2. +5 −4 doc/user_guide.txt
  3. +139 −0 examples/core-macros.lfe
  4. +10 −0 src/ChangeLog
  5. +2 −1 src/lfe_comp.erl
  6. +3 −6 src/lfe_macro.erl
  7. +665 −467 src/lfe_scan.erl
  8. +12 −6 src/lfe_scan.xrl
  9. +6 −4 src/lfe_shell.erl
  10. +16 −17 test/guard_SUITE.lfe
  11. +1 −1 test/visual/test_macro.lfe
View
22 README
@@ -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.
@@ -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
View
@@ -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 ...)
...)
...)
@@ -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)
...)
@@ -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:
@@ -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.
View
@@ -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
+ )))
View
@@ -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).
View
@@ -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),
View
@@ -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
@@ -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) ->
@@ -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
Oops, something went wrong.

0 comments on commit de757ed

Please sign in to comment.