Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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
55 lib/macro-js.js
View
@@ -6,7 +6,7 @@ var HOP = $C.HOP;
var prog1 = $C.prog1;
var curry = $C.curry;
-function Unquote(ast) { this.ast = ast; };
+function Unquote(ast, splice) { this.ast = ast; this.splice = splice; };
function Symbol(sym) { this.sym = sym; };
@@ -20,7 +20,11 @@ function quote_ast(ast) {
return [ "name", "undefined" ];
}
else if (ast instanceof Unquote) {
- return ast.ast;
+ if (ast.splice) {
+ return [ "array", [ [ "string", "splice" ], ast.ast ] ];
+ } else {
+ return ast.ast;
+ }
}
else if (ast instanceof Symbol) {
return ast;
@@ -54,6 +58,9 @@ function createParser() {
parser.macro_expand = function(ast) {
return macro_expand(parser, ast);
};
+ parser.splice_list = function(list) {
+ return [ "splice", list ];
+ };
parser.quote = quote_ast;
parser.macros = {};
parser.define_token_reader("`", function(TC, OC) {
@@ -106,8 +113,8 @@ function createParser() {
return quote_ast(PC.statement());
case "unquote":
return new Unquote(cont());
- // case "splice":
- // return new Unquote(cont(), true);
+ case "splice":
+ return new Unquote(cont(), true);
default:
throw new Error("Unsupported macro character: " + tok.macro);
}
@@ -122,24 +129,22 @@ function createParser() {
function read_defmacro_args(PC, OC) {
var args = [];
PC.expect("(");
- get_list();
- function get_list(nested) {
+ get_list(0);
+ function get_list(level) {
var first = true;
var optional = false;
while (!PC.is("punc", ")")) {
if (!first) PC.expect(",");
if (PC.is("punc", "(")) {
PC.next();
- get_list(true);
+ get_list(level + 1);
} else {
if (!PC.is("name")) PC.unexpected();
var a = {
name : PC.tokval(),
optional : optional
};
- if (first && nested) {
- a.nested = true;
- }
+ a.level = level;
PC.next();
if (PC.is("punc", ":")) {
PC.next();
@@ -172,8 +177,8 @@ function read_defmacro_args(PC, OC) {
a.reader = curry(PC.expression, false);
}
if (PC.is("operator", "*")) {
- if (!nested)
- throw new Error("&rest can appear only in nested argument list");
+ if (level == 0)
+ throw new Error("'*' can appear only in nested argument list");
a.rest = true;
a.reader = (function(orig){
return function() {
@@ -265,10 +270,16 @@ function macro_expand(parser, ast) {
return normalize_ast(w.with_walkers({
"macro-expand": function(macro, args) {
var func = parser.macros[macro].func;
- var ret = func.apply(parser, args.map(w.walk));
+ args = args.map(w.walk);
+ var ret = func.apply(parser, args);
ret = replace_symbols(ret);
ret = w.walk(ret);
return ret;
+ },
+ "-other": function() {
+ return this;
+ // if (this[0] instanceof Symbol)
+ // return this;
}
}, function() {
return w.walk(ast);
@@ -302,6 +313,8 @@ function replace_symbols(ast) {
case "function":
case "defun":
ast[1] = normalize_symbol(ast[1]);
+ if (ast[2][0] instanceof Array) ast[2] = ast[2][0];
+ if (ast[2][0] == "splice") ast[2] = ast[2][1];
ast[2] = ast[2].map(function(name){ return normalize_symbol(name) });
ast[3] = ast[3].map(replace_symbols);
return ast;
@@ -355,6 +368,22 @@ function normalize_ast(ast) {
case "with":
return expr;
}
+ },
+ "splice": function(a) {
+ if (w.parent()[0] == "stat" && a[0] == "block") {
+ if (a[1].length > 0 && a[1][0] instanceof Array) {
+ a[1] = a[1][0];
+ }
+ return a[0];
+ } else {
+ for (var i = 0; i < a.length; ++i)
+ this[i] = a[i];
+ this.length = a.length;
+ return this;
+ }
+ },
+ "-other": function() {
+ return this;
}
}, function() {
return w.walk(ast);
5 lib/process.js
View
@@ -216,8 +216,8 @@ function ast_walker(ast) {
if (!(ast instanceof Array))
return ast;
}
- stack.push(ast);
var type = ast[0];
+ stack.push(ast);
var gen = user[type];
if (gen) {
var ret = gen.apply(ast, ast.slice(1));
@@ -226,6 +226,9 @@ function ast_walker(ast) {
}
gen = walkers[type];
if (!gen) {
+ gen = walkers["-other"] || user["-other"];
+ }
+ if (!gen) {
throw new Error("No generator for " + ast);
}
var ret = gen.apply(ast, ast.slice(1));
21 test/macro.js
View
@@ -0,0 +1,21 @@
+#! /usr/bin/env node
+
+global.sys = require("sys");
+global.INSPECT = INSPECT;
+var fs = require("fs");
+
+var macrojs = require("../lib/macro-js");
+var pro = require("../lib/process");
+var p = macrojs.createParser();
+
+fs.readFile(process.argv[2], function(err, data){
+ data = data.toString();
+ var ast = p.parse(data);
+ INSPECT(ast);
+ // sys.puts(pro.gen_code(pro.ast_squeeze(ast), true));
+ sys.puts(pro.gen_code(ast, true));
+});
+
+function INSPECT(obj) {
+ sys.puts(sys.inspect(obj, null, null));
+};
26 test/macro/defun.js
View
@@ -0,0 +1,26 @@
+// -*- espresso -*-
+
+defmacro ensure_ordered(a:name, b:name) {
+ var tmp = this.gensym();
+ return @if (\a > \b) {
+ var \tmp = \a;
+ \a = \b;
+ \b = \tmp;
+ };
+}
+
+defstat defun_region(name:name, (args:name*), b:block) {
+ var p1 = args[0], p2 = args[1];
+ return @function \name (\p1, \p2) {
+ ensure_ordered(p1, p2);
+ \@b
+ };
+}
+
+// ensure_ordered(foo, bar);
+
+defun_region foo(start, stop) {
+ for (var i = start; i <= stop; ++i) {
+ print(getChar(i));
+ }
+}
17 test/macro/literal-obj.js
View
@@ -0,0 +1,17 @@
+// -*- espresso -*-
+
+defmacro mkobj(p1, v1, p2, v2, p3, v3) {
+ var opt = this.gensym();
+ var bar = [ "name", "while" ];
+ return `{
+ \p1: \v1,
+ \p2: \v2,
+ \p3: \(this.quote(v3)),
+ \opt: "And some more",
+ \bar: "even more"
+ };
+};
+
+mkobj(foo, [ 1, 2, 3 ],
+ bar, "some string here",
+ baz, { a: 1, b: 2 });
103 test/macro/test.js
View
@@ -0,0 +1,103 @@
+// -*- espresso -*-
+
+// defmacro test(a:name, b, c:statement) {
+// return [ "block", [ [ "binary", "+", [ "name", a ], b ] ].concat(c) ];
+// }
+
+// test(foo, { parc: "mak" }, {
+// var bar = 10;
+// check(this.out());
+// });
+
+// defmacro order(a:name, b:name) {
+// var tmp = this.gensym();
+// return @{
+// if (\a > \b) {
+// var \tmp = \a;
+// \a = \b;
+// \b = \tmp;
+// }
+// crap();
+// };
+// };
+
+defmacro order(a:name, b:name) {
+ var tmp = this.gensym();
+ return `if (\a > \b) {
+ var \tmp = \a;
+ \a = \b;
+ \b = \tmp;
+ };
+};
+
+// defmacro with_orderd(a:name, b:name, c:statement) {
+// return @{
+// order(\a, \b);
+// \c;
+// };
+// };
+
+defmacro with_orderd(a:name, b:name, c:statement) {
+ var tmp = this.gensym();
+ return `(function(\a, \b){
+ if (\a > \b) {
+ var \tmp = \a;
+ \a = \b;
+ \b = \tmp;
+ }
+ \c;
+ })(\a, \b);
+};
+
+with_orderd(crap, mak, {
+ print("Smallest is " + crap);
+ print("And " + mak + " follows");
+ order(mak, crap);
+ print("Reverse order: " + mak + ", " + crap);
+});
+
+with_orderd(
+ foo, bar,
+ print("order: " + foo + ", " + bar)
+);
+
+// defmacro order(a:name, b:name) {
+// var tmp = this.gensym();
+// return `(function(\tmp){
+// \a = \b;
+// \b = \tmp;
+// })(\a);
+// };
+
+var foo = 10;
+var bar = 20;
+order(foo, bar);
+
+// defmacro qwe (a) {
+// var tmp = this.symbol("crapmak");
+// return @{
+// var \tmp = \a;
+// ++\tmp;
+// };
+// }
+
+// var a = 5;
+// qwe(a);
+
+
+defstat unless(cond, b:statement) {
+ sys.log("********************************************");
+ INSPECT(cond);
+ return @if (!\cond) \b;
+}
+
+unless (foo + bar < 10) {
+ crap();
+ mak();
+}
+
+(function(){
+ unless (foo + bar < 10) unless (bar) return @if (baz) {
+ crap();
+ }
+})();
Please sign in to comment.
Something went wrong with that request. Please try again.