Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

some support for splicing argument list, to define a macro that defin…

…es a function
  • Loading branch information...
commit 7137daaff65129d5759356fc5ba9ef4ac68fd0dd 1 parent dae8ed2
Mihai Bazon authored September 25, 2010
55  lib/macro-js.js
@@ -6,7 +6,7 @@ var HOP = $C.HOP;
6 6
 var prog1 = $C.prog1;
7 7
 var curry = $C.curry;
8 8
 
9  
-function Unquote(ast) { this.ast = ast; };
  9
+function Unquote(ast, splice) { this.ast = ast; this.splice = splice; };
10 10
 
11 11
 function Symbol(sym) { this.sym = sym; };
12 12
 
@@ -20,7 +20,11 @@ function quote_ast(ast) {
20 20
                 return [ "name", "undefined" ];
21 21
         }
22 22
         else if (ast instanceof Unquote) {
23  
-                return ast.ast;
  23
+                if (ast.splice) {
  24
+                        return [ "array", [ [ "string", "splice" ], ast.ast ] ];
  25
+                } else {
  26
+                        return ast.ast;
  27
+                }
24 28
         }
25 29
         else if (ast instanceof Symbol) {
26 30
                 return ast;
@@ -54,6 +58,9 @@ function createParser() {
54 58
         parser.macro_expand = function(ast) {
55 59
                 return macro_expand(parser, ast);
56 60
         };
  61
+        parser.splice_list = function(list) {
  62
+                return [ "splice", list ];
  63
+        };
57 64
         parser.quote = quote_ast;
58 65
         parser.macros = {};
59 66
         parser.define_token_reader("`", function(TC, OC) {
@@ -106,8 +113,8 @@ function createParser() {
106 113
                         return quote_ast(PC.statement());
107 114
                     case "unquote":
108 115
                         return new Unquote(cont());
109  
-                    // case "splice":
110  
-                    //     return new Unquote(cont(), true);
  116
+                    case "splice":
  117
+                        return new Unquote(cont(), true);
111 118
                     default:
112 119
                         throw new Error("Unsupported macro character: " + tok.macro);
113 120
                 }
@@ -122,24 +129,22 @@ function createParser() {
122 129
 function read_defmacro_args(PC, OC) {
123 130
         var args = [];
124 131
         PC.expect("(");
125  
-        get_list();
126  
-        function get_list(nested) {
  132
+        get_list(0);
  133
+        function get_list(level) {
127 134
                 var first = true;
128 135
                 var optional = false;
129 136
                 while (!PC.is("punc", ")")) {
130 137
                         if (!first) PC.expect(",");
131 138
                         if (PC.is("punc", "(")) {
132 139
                                 PC.next();
133  
-                                get_list(true);
  140
+                                get_list(level + 1);
134 141
                         } else {
135 142
                                 if (!PC.is("name")) PC.unexpected();
136 143
                                 var a = {
137 144
                                         name     : PC.tokval(),
138 145
                                         optional : optional
139 146
                                 };
140  
-                                if (first && nested) {
141  
-                                        a.nested = true;
142  
-                                }
  147
+                                a.level = level;
143 148
                                 PC.next();
144 149
                                 if (PC.is("punc", ":")) {
145 150
                                         PC.next();
@@ -172,8 +177,8 @@ function read_defmacro_args(PC, OC) {
172 177
                                         a.reader = curry(PC.expression, false);
173 178
                                 }
174 179
                                 if (PC.is("operator", "*")) {
175  
-                                        if (!nested)
176  
-                                                throw new Error("&rest can appear only in nested argument list");
  180
+                                        if (level == 0)
  181
+                                                throw new Error("'*' can appear only in nested argument list");
177 182
                                         a.rest = true;
178 183
                                         a.reader = (function(orig){
179 184
                                                 return function() {
@@ -265,10 +270,16 @@ function macro_expand(parser, ast) {
265 270
         return normalize_ast(w.with_walkers({
266 271
                 "macro-expand": function(macro, args) {
267 272
                         var func = parser.macros[macro].func;
268  
-                        var ret = func.apply(parser, args.map(w.walk));
  273
+                        args = args.map(w.walk);
  274
+                        var ret = func.apply(parser, args);
269 275
                         ret = replace_symbols(ret);
270 276
                         ret = w.walk(ret);
271 277
                         return ret;
  278
+                },
  279
+                "-other": function() {
  280
+                        return this;
  281
+                        // if (this[0] instanceof Symbol)
  282
+                        //         return this;
272 283
                 }
273 284
         }, function() {
274 285
                 return w.walk(ast);
@@ -302,6 +313,8 @@ function replace_symbols(ast) {
302 313
                     case "function":
303 314
                     case "defun":
304 315
                         ast[1] = normalize_symbol(ast[1]);
  316
+                        if (ast[2][0] instanceof Array) ast[2] = ast[2][0];
  317
+                        if (ast[2][0] == "splice") ast[2] = ast[2][1];
305 318
                         ast[2] = ast[2].map(function(name){ return normalize_symbol(name) });
306 319
                         ast[3] = ast[3].map(replace_symbols);
307 320
                         return ast;
@@ -355,6 +368,22 @@ function normalize_ast(ast) {
355 368
                             case "with":
356 369
                                 return expr;
357 370
                         }
  371
+                },
  372
+                "splice": function(a) {
  373
+                        if (w.parent()[0] == "stat" && a[0] == "block") {
  374
+                                if (a[1].length > 0 && a[1][0] instanceof Array) {
  375
+                                        a[1] = a[1][0];
  376
+                                }
  377
+                                return a[0];
  378
+                        } else {
  379
+                                for (var i = 0; i < a.length; ++i)
  380
+                                        this[i] = a[i];
  381
+                                this.length = a.length;
  382
+                                return this;
  383
+                        }
  384
+                },
  385
+                "-other": function() {
  386
+                        return this;
358 387
                 }
359 388
         }, function() {
360 389
                 return w.walk(ast);
5  lib/process.js
@@ -216,8 +216,8 @@ function ast_walker(ast) {
216 216
                         if (!(ast instanceof Array))
217 217
                                 return ast;
218 218
                 }
219  
-                stack.push(ast);
220 219
                 var type = ast[0];
  220
+                stack.push(ast);
221 221
                 var gen = user[type];
222 222
                 if (gen) {
223 223
                         var ret = gen.apply(ast, ast.slice(1));
@@ -226,6 +226,9 @@ function ast_walker(ast) {
226 226
                 }
227 227
                 gen = walkers[type];
228 228
                 if (!gen) {
  229
+                        gen = walkers["-other"] || user["-other"];
  230
+                }
  231
+                if (!gen) {
229 232
                         throw new Error("No generator for " + ast);
230 233
                 }
231 234
                 var ret = gen.apply(ast, ast.slice(1));
21  test/macro.js
... ...
@@ -0,0 +1,21 @@
  1
+#! /usr/bin/env node
  2
+
  3
+global.sys = require("sys");
  4
+global.INSPECT = INSPECT;
  5
+var fs = require("fs");
  6
+
  7
+var macrojs = require("../lib/macro-js");
  8
+var pro = require("../lib/process");
  9
+var p = macrojs.createParser();
  10
+
  11
+fs.readFile(process.argv[2], function(err, data){
  12
+        data = data.toString();
  13
+        var ast = p.parse(data);
  14
+        INSPECT(ast);
  15
+        // sys.puts(pro.gen_code(pro.ast_squeeze(ast), true));
  16
+        sys.puts(pro.gen_code(ast, true));
  17
+});
  18
+
  19
+function INSPECT(obj) {
  20
+        sys.puts(sys.inspect(obj, null, null));
  21
+};
26  test/macro/defun.js
... ...
@@ -0,0 +1,26 @@
  1
+// -*- espresso -*-
  2
+
  3
+defmacro ensure_ordered(a:name, b:name) {
  4
+        var tmp = this.gensym();
  5
+        return @if (\a > \b) {
  6
+                var \tmp = \a;
  7
+                \a = \b;
  8
+                \b = \tmp;
  9
+        };
  10
+}
  11
+
  12
+defstat defun_region(name:name, (args:name*), b:block) {
  13
+        var p1 = args[0], p2 = args[1];
  14
+        return @function \name (\p1, \p2) {
  15
+                ensure_ordered(p1, p2);
  16
+                \@b
  17
+        };
  18
+}
  19
+
  20
+// ensure_ordered(foo, bar);
  21
+
  22
+defun_region foo(start, stop) {
  23
+        for (var i = start; i <= stop; ++i) {
  24
+                print(getChar(i));
  25
+        }
  26
+}
17  test/macro/literal-obj.js
... ...
@@ -0,0 +1,17 @@
  1
+// -*- espresso -*-
  2
+
  3
+defmacro mkobj(p1, v1, p2, v2, p3, v3) {
  4
+        var opt = this.gensym();
  5
+        var bar = [ "name", "while" ];
  6
+        return `{
  7
+                \p1: \v1,
  8
+                \p2: \v2,
  9
+                \p3: \(this.quote(v3)),
  10
+                \opt: "And some more",
  11
+                \bar: "even more"
  12
+        };
  13
+};
  14
+
  15
+mkobj(foo, [ 1, 2, 3 ],
  16
+      bar, "some string here",
  17
+      baz, { a: 1, b: 2 });
103  test/macro/test.js
... ...
@@ -0,0 +1,103 @@
  1
+// -*- espresso -*-
  2
+
  3
+// defmacro test(a:name, b, c:statement) {
  4
+//         return [ "block", [ [ "binary", "+", [ "name", a ], b ] ].concat(c) ];
  5
+// }
  6
+
  7
+// test(foo, { parc: "mak" }, {
  8
+//         var bar = 10;
  9
+//         check(this.out());
  10
+// });
  11
+
  12
+// defmacro order(a:name, b:name) {
  13
+//         var tmp = this.gensym();
  14
+//         return @{
  15
+//                 if (\a > \b) {
  16
+//                         var \tmp = \a;
  17
+//                         \a = \b;
  18
+//                         \b = \tmp;
  19
+//                 }
  20
+//                 crap();
  21
+//         };
  22
+// };
  23
+
  24
+defmacro order(a:name, b:name) {
  25
+        var tmp = this.gensym();
  26
+        return `if (\a > \b) {
  27
+                var \tmp = \a;
  28
+                \a = \b;
  29
+                \b = \tmp;
  30
+        };
  31
+};
  32
+
  33
+// defmacro with_orderd(a:name, b:name, c:statement) {
  34
+//         return @{
  35
+//                 order(\a, \b);
  36
+//                 \c;
  37
+//         };
  38
+// };
  39
+
  40
+defmacro with_orderd(a:name, b:name, c:statement) {
  41
+        var tmp = this.gensym();
  42
+        return `(function(\a, \b){
  43
+                if (\a > \b) {
  44
+                        var \tmp = \a;
  45
+                        \a = \b;
  46
+                        \b = \tmp;
  47
+                }
  48
+                \c;
  49
+        })(\a, \b);
  50
+};
  51
+
  52
+with_orderd(crap, mak, {
  53
+        print("Smallest is " + crap);
  54
+        print("And " + mak + " follows");
  55
+        order(mak, crap);
  56
+        print("Reverse order: " + mak + ", " + crap);
  57
+});
  58
+
  59
+with_orderd(
  60
+        foo, bar,
  61
+        print("order: " + foo + ", " + bar)
  62
+);
  63
+
  64
+// defmacro order(a:name, b:name) {
  65
+//         var tmp = this.gensym();
  66
+//         return `(function(\tmp){
  67
+//                 \a = \b;
  68
+//                 \b = \tmp;
  69
+//         })(\a);
  70
+// };
  71
+
  72
+var foo = 10;
  73
+var bar = 20;
  74
+order(foo, bar);
  75
+
  76
+// defmacro qwe (a) {
  77
+//         var tmp = this.symbol("crapmak");
  78
+//         return @{
  79
+//                 var \tmp = \a;
  80
+//                 ++\tmp;
  81
+//         };
  82
+// }
  83
+
  84
+// var a = 5;
  85
+// qwe(a);
  86
+
  87
+
  88
+defstat unless(cond, b:statement) {
  89
+        sys.log("********************************************");
  90
+        INSPECT(cond);
  91
+        return @if (!\cond) \b;
  92
+}
  93
+
  94
+unless (foo + bar < 10) {
  95
+        crap();
  96
+        mak();
  97
+}
  98
+
  99
+(function(){
  100
+        unless (foo + bar < 10) unless (bar) return @if (baz) {
  101
+                crap();
  102
+        }
  103
+})();

0 notes on commit 7137daa

Please sign in to comment.
Something went wrong with that request. Please try again.