Permalink
Browse files

implement quasiquote, unquote, and unquote-splicing for lists

  • Loading branch information...
1 parent 3422222 commit df43c7640e59fdca05a840bf17a5bf447efc17ee @jlongster committed Jan 13, 2012
Showing with 122 additions and 26 deletions.
  1. +2 −1 .gitignore
  2. +2 −1 ast.js
  3. +42 −5 compiler-js.js
  4. +6 −2 compiler.js
  5. +7 −2 compiler.ol
  6. +16 −4 example.ol
  7. +22 −3 grammar.js
  8. +20 −6 grammar.ol
  9. +1 −1 make.js
  10. +4 −1 test.js
View
@@ -1 +1,2 @@
-boot
+boot
+.#*
View
@@ -72,5 +72,6 @@ module.exports = {
node: node,
add_child: add_child,
- pretty_print: pretty_print
+ pretty_print: pretty_print,
+ type_str: type_str
};
View
@@ -172,9 +172,46 @@ function generator() {
}
}
- function write_array(node, parse, quoted) {
+ function write_array(node, parse, context) {
+ // Handle quasiquoting specially here. This is hacky and not
+ // the right place to do it, but it works for now.
+ if(context == 'quasi') {
+ // If it's a list with a term in the front, check if it's
+ // an unquote or unquote-splicing and handle it specially
+ if(node.type == ast.LIST &&
+ node.children[0] &&
+ node.children[0].type == ast.TERM) {
+
+ var term = node.children[0];
+
+ if(term.data.str == 'unquote') {
+ parse_expr(parse, node, node.children[1]);
+ return;
+ }
+ else if(term.data.str == 'unquote-splicing') {
+ var lst = node.children[1];
+ if(lst.type != ast.LIST) {
+ throw ("unquote-splicing expected a list, got " +
+ ast.type_str(lst.type));
+ }
+
+ // Splicing should put all the list elements into
+ // the current element
+ for(var i=0; i<lst.children.length; i++) {
+ if(i > 0) {
+ write(',');
+ }
+
+ parse_expr(parse, lst, lst.children[i]);
+ }
+
+ return;
+ }
+ }
+ }
+
if(node.type == ast.TERM) {
- if(quoted) {
+ if(context == 'quote' || context == 'quasi') {
write_symbol(node);
}
else {
@@ -194,8 +231,8 @@ function generator() {
write(',');
}
- if(quoted) {
- write_array(node.children[i], parse, quoted);
+ if(context == 'quote' || context == 'quasi') {
+ write_array(node.children[i], parse, context);
}
else {
parse_expr(parse, node, node.children[i]);
@@ -273,7 +310,7 @@ function generator() {
'not': function(node, parse) {
write('!');
- parse(node.children[1]);
+ parse_expr(parse, node, node.children[1]);
},
'require': function(node, parse) {
View
@@ -95,7 +95,7 @@ return vector_set_excl(macros,name,func);}
return vector_ref(macros,name);}
;var macrop = function(node){
return (function() {if(eqp(node.type,ast.LIST)) { return (function(name){
-return (function() {if(eqp(node.type,ast.TERM)) { return object_ref(macros,name.data.str);}})()
+return (function() {if(eqp(name.type,ast.TERM)) { return object_ref(macros,name.data.str);}})()
}
)(vector_ref(node.children,0));}})()
}
@@ -146,7 +146,10 @@ return generator.write_set(define_to_setlambda(node),parse);}
)();} else { return (function() {if(equalp(term,"define-macro")) { return (function(){
return parse_macro(node,generator);}
)();} else { return (function() {if(equalp(term,"quote")) { return (function(){
-return generator.write_array(vector_ref(node.children,1),parse,true);}
+return generator.write_array(vector_ref(node.children,1),parse,"quote");}
+)();} else { return (function() {if(equalp(term,"quasiquote")) { return (function(){
+return (function() {if(!eqp(node.type,ast.LIST)) { return parse(node);} else { return generator.write_array(vector_ref(node.children,1),parse,"quasi");}})()
+}
)();} else { return (function() {if(equalp(term,"list")) { return (function(){
return generator.write_array(ast.node(ast.LIST,null,node.children.slice(1)),parse);}
)();} else { return (function() {if(equalp(term,"begin")) { return (function(){
@@ -179,6 +182,7 @@ return generator.write_func_call(node,parse);}
}})()
}})()
}})()
+}})()
}
);install_parser(ast.ROOT,function(node,parse){
return for_each(function(n){
View
@@ -116,7 +116,7 @@
(define (macro? node)
(if (eq? node.type ast.LIST)
(let ((name (vector-ref node.children 0)))
- (if (eq? node.type ast.TERM)
+ (if (eq? name.type ast.TERM)
(object-ref macros name.data.str)))))
(define (parse-macro node generator)
@@ -231,7 +231,12 @@
(generator.write-array
(vector-ref node.children 1)
parse
- true))
+ "quote"))
+
+ ((equal? term "quasiquote")
+ (generator.write-array (vector-ref node.children 1)
+ parse
+ "quasi"))
((equal? term "list")
(generator.write-array
View
@@ -34,18 +34,30 @@
;; macros
;; quasiquote isn't support yet, but will be soon
-(define-macro (helper a b c)
- (list 'bar (list '+ a b c)))
+(define-macro (helper form)
+ (list 'if
+ (list '< (car (cdr form)) 5)
+ (list '+
+ (car (cdr form))
+ (car (cdr (cdr form))))))
+
+(define-macro (helper form)
+ `(if (< ,(car (cdr form)) 5)
+ (+ ,(car (cdr form))
+ ,(car (cdr (cdr form))))))
(define (bar n)
(pp n))
(define (foo)
- (helper 1 2 3))
+ (helper (if 1 2)))
;; ->
;; var bar = function(n){
;; return pp(n);}
;;
;; var foo = function(){
-;; return bar((1+2+3));}
+;; return (function() {if((1<5)) { return (1+2)}})()
+;; }
+
+
View
@@ -8,6 +8,7 @@ var inspect = runtime.inspect;
var eqp = runtime.eqp;
var equalp = runtime.equalp;
var nullp = runtime.nullp;
+var cons = runtime.cons;
var car = runtime.car;
var cdr = runtime.cdr;
var vector_ref = runtime.vector_ref;
@@ -46,12 +47,30 @@ return ""}
);;var term = capture(repeated(any(not_char(("()'"+space_char)))),function(buf,s){
return ast.node(ast.TERM,make_symbol(buf));}
);;var elements = function(lst){
-var capture_quoted = function(buf,node){
+var quoting = function(rule){
+var capt = function(buf,node){
+return (function(special){
return (function(q){
return ast.node(ast.LIST,null,[q,node]);}
-)(ast.node(ast.TERM,make_symbol("quote")));}
+)(ast.node(ast.TERM,make_symbol(special)));}
+)((function() {if(equalp(buf.substring(0,2),",@")) { return (function(){
+return "unquote-splicing"}
+)();} else { return (function() {if(equalp(buf.charAt(0),",")) { return (function(){
+return "unquote"}
+)();} else { return (function() {if(equalp(buf.charAt(0),"'")) { return (function(){
+return "quote"}
+)();} else { return (function() {if(equalp(buf.charAt(0),"`")) { return (function(){
+return "quasiquote"}
+)();}})()
+}})()
+}})()
+}})()
+);}
+;return Y(function(q){
+return capture(all(any(char("'"),char("`"),char(","),all(char(","),char("@"))),any(q,rule)),capt);}
+);}
;return (function(rule){
-return any(capture(all(char("'"),rule),capture_quoted),rule);}
+return any(quoting(rule),rule);}
)(any(lst,number,string,term));}
;var lst = Y(function(lst){
return before(all(char("("),optional(repeated(any(space,comment,after(elements(lst),function(parent,child){
View
@@ -47,13 +47,27 @@
(ast.node ast.TERM (make-symbol buf)))))
(define (elements lst)
- (define (capture_quoted buf node)
- ;; add a "quote" term
- (let ((q (ast.node ast.TERM (make-symbol "quote"))))
- (ast.node ast.LIST null (list q node))))
-
+ (define (quoting rule)
+ (define (capt buf node)
+ (let ((special
+ (cond
+ ((equal? (buf.substring 0 2) ",@") "unquote-splicing")
+ ((equal? (buf.charAt 0) ",") "unquote")
+ ((equal? (buf.charAt 0) "'") "quote")
+ ((equal? (buf.charAt 0) "`") "quasiquote"))))
+ (let ((q (ast.node ast.TERM (make-symbol special))))
+ (ast.node ast.LIST null (list q node)))))
+
+ (Y (lambda (q)
+ (capture (all (any (char "'")
+ (char "`")
+ (char ",")
+ (all (char ",") (char "@")))
+ (any q rule))
+ capt))))
+
(let ((rule (any lst number string term)))
- (any (capture (all (char "'") rule) capture_quoted)
+ (any (quoting rule)
rule)))
(define lst
View
@@ -1,5 +1,5 @@
var outlet = require('./boot/outlet');
var util = require('util');
-var src = require('fs').readFileSync('compiler.ol', 'utf-8');
+var src = require('fs').readFileSync('grammar.ol', 'utf-8');
util.puts(outlet.compile(src, 'nodejs'));
View
@@ -7,9 +7,12 @@ var generator = require('./compiler-js')();
var src = require('fs').readFileSync('example.ol', 'utf-8');
//util.puts(outlet.compile(src, 'nodejs'));
-var compiler = require('./compiler-bootstrap');
+var compiler = require('./compiler');
var reader = require('./parser');
var grammar = require('./grammar');
+// ast.pretty_print(reader(grammar,
+// src,
+// ast.node(ast.ROOT)));
compiler.parse(reader(grammar,
src,
ast.node(ast.ROOT)),

0 comments on commit df43c76

Please sign in to comment.