[pure-lang-svn] SF.net SVN: pure-lang:[607] pure/trunk
Status: Beta
Brought to you by:
agraef
|
From: <ag...@us...> - 2008-08-25 19:56:02
|
Revision: 607
http://pure-lang.svn.sourceforge.net/pure-lang/?rev=607&view=rev
Author: agraef
Date: 2008-08-25 19:56:07 +0000 (Mon, 25 Aug 2008)
Log Message:
-----------
Implement macro substitution facility.
Modified Paths:
--------------
pure/trunk/ChangeLog
pure/trunk/interpreter.cc
pure/trunk/interpreter.hh
Modified: pure/trunk/ChangeLog
===================================================================
--- pure/trunk/ChangeLog 2008-08-25 19:53:35 UTC (rev 606)
+++ pure/trunk/ChangeLog 2008-08-25 19:56:07 UTC (rev 607)
@@ -1,3 +1,22 @@
+2008-08-25 Albert Graef <Dr....@t-...>
+
+ * parser.yy, lexer.ll, interpreter.cc: Added macro substitution
+ facility. Pure macros are meta functions executed at compile time,
+ which are defined by any number of equations (rewriting rules)
+ prefixed with the 'def' keyword, e.g.:
+
+ def foo (bar x) = foo x+1;
+ def foo x = x;
+
+ Only simple, unconditional rules are supported by now, but these
+ are quite powerful already, since, as shown above, the macro
+ parameters can be arbitrary patterns and macro definitions can
+ also be recursive.
+
+ Pure macros are lexically scoped, i.e., symbols on the rhs of a
+ macro definition can never refer to anything outside the macro
+ definition. (These are also known as "hygienic" macros.)
+
2008-08-24 Albert Graef <Dr....@t-...>
* 0.5 release.
Modified: pure/trunk/interpreter.cc
===================================================================
--- pure/trunk/interpreter.cc 2008-08-25 19:53:35 UTC (rev 606)
+++ pure/trunk/interpreter.cc 2008-08-25 19:56:07 UTC (rev 607)
@@ -739,8 +739,8 @@
globals g;
save_globals(g);
compile();
- // promote type tags and substitute constants:
- env vars; expr u = csubst(subst(vars, x));
+ // promote type tags and substitute macros and constants:
+ env vars; expr u = csubst(macsubst(subst(vars, x)));
compile(u);
x = u;
pure_expr *res = doeval(u, e);
@@ -766,8 +766,8 @@
save_globals(g);
compile();
env vars;
- // promote type tags and substitute constants:
- expr rhs = csubst(subst(vars, x));
+ // promote type tags and substitute macros and constants:
+ expr rhs = csubst(macsubst(subst(vars, x)));
expr lhs = bind(vars, pat);
build_env(vars, lhs);
for (env::const_iterator it = vars.begin(); it != vars.end(); ++it) {
@@ -866,8 +866,8 @@
save_globals(g);
compile();
env vars;
- // promote type tags and substitute constants:
- expr rhs = csubst(subst(vars, x));
+ // promote type tags and substitute macros and constants:
+ expr rhs = csubst(macsubst(subst(vars, x)));
expr lhs = bind(vars, pat);
build_env(vars, lhs);
for (env::const_iterator it = vars.begin(); it != vars.end(); ++it) {
@@ -1404,10 +1404,10 @@
assert(!r.lhs.is_null());
closure(r, false);
if (toplevel) {
- // substitute constants:
+ // substitute macros and constants:
expr u = expr(r.lhs),
- v = expr(csubst(r.rhs)),
- w = expr(csubst(r.qual));
+ v = expr(csubst(macsubst(r.rhs))),
+ w = expr(csubst(macsubst(r.qual)));
r = rule(u, v, w);
compile(r.rhs);
compile(r.qual);
@@ -1788,6 +1788,103 @@
}
}
+expr interpreter::fsubst(const env& funs, expr x, uint8_t idx)
+{
+ if (x.is_null()) return x;
+ switch (x.tag()) {
+ // constants:
+ case EXPR::VAR:
+ case EXPR::FVAR:
+ case EXPR::INT:
+ case EXPR::BIGINT:
+ case EXPR::DBL:
+ case EXPR::STR:
+ case EXPR::PTR:
+ return x;
+ // application:
+ case EXPR::APP:
+ if (x.xval1().tag() == EXPR::APP &&
+ x.xval1().xval1().tag() == symtab.catch_sym().f) {
+ expr u = fsubst(funs, x.xval1().xval2(), idx);
+ if (++idx == 0)
+ throw err("error in expression (too many nested closures)");
+ expr v = fsubst(funs, x.xval2(), idx);
+ return expr(symtab.catch_sym().x, u, v);
+ } else {
+ expr u = fsubst(funs, x.xval1(), idx),
+ v = fsubst(funs, x.xval2(), idx);
+ return expr(u, v);
+ }
+ // conditionals:
+ case EXPR::COND: {
+ expr u = fsubst(funs, x.xval1(), idx),
+ v = fsubst(funs, x.xval2(), idx),
+ w = fsubst(funs, x.xval3(), idx);
+ return expr::cond(u, v, w);
+ }
+ // nested closures:
+ case EXPR::LAMBDA: {
+ if (++idx == 0)
+ throw err("error in expression (too many nested closures)");
+ expr u = x.xval1(), v = fsubst(funs, x.xval2(), idx);
+ return expr::lambda(u, v);
+ }
+ case EXPR::CASE: {
+ expr u = fsubst(funs, x.xval(), idx);
+ if (++idx == 0)
+ throw err("error in expression (too many nested closures)");
+ const rulel *r = x.rules();
+ rulel *s = new rulel;
+ for (rulel::const_iterator it = r->begin(); it != r->end(); ++it) {
+ expr u = it->lhs, v = fsubst(funs, it->rhs, idx),
+ w = fsubst(funs, it->qual, idx);
+ s->push_back(rule(u, v, w));
+ }
+ return expr::cases(u, s);
+ }
+ case EXPR::WHEN: {
+ const rulel *r = x.rules();
+ rulel *s = new rulel;
+ for (rulel::const_iterator it = r->begin(); it != r->end(); ++it) {
+ expr u = it->lhs, v = fsubst(funs, it->rhs, idx);
+ s->push_back(rule(u, v));
+ if (++idx == 0)
+ throw err("error in expression (too many nested closures)");
+ }
+ expr u = fsubst(funs, x.xval(), idx);
+ return expr::when(u, s);
+ }
+ case EXPR::WITH: {
+ expr u = fsubst(funs, x.xval(), idx);
+ if (++idx == 0)
+ throw err("error in expression (too many nested closures)");
+ const env *e = x.fenv();
+ env *f = new env;
+ for (env::const_iterator it = e->begin(); it != e->end(); ++it) {
+ int32_t g = it->first;
+ const env_info& info = it->second;
+ const rulel *r = info.rules;
+ rulel s;
+ for (rulel::const_iterator jt = r->begin(); jt != r->end(); ++jt) {
+ expr u = jt->lhs, v = fsubst(funs, jt->rhs, idx),
+ w = fsubst(funs, jt->qual, idx);
+ s.push_back(rule(u, v, w));
+ }
+ (*f)[g] = env_info(info.argc, s, info.temp);
+ }
+ return expr::with(u, f);
+ }
+ default:
+ assert(x.tag() > 0);
+ const symbol& sym = symtab.sym(x.tag());
+ env::const_iterator it = funs.find(sym.f);
+ if (it != funs.end())
+ return expr(EXPR::FVAR, sym.f, idx);
+ else
+ return x;
+ }
+}
+
expr interpreter::csubst(expr x)
{
if (x.is_null()) return x;
@@ -1883,9 +1980,26 @@
}
}
-expr interpreter::fsubst(const env& funs, expr x, uint8_t idx)
+/* Perform simple macro substitutions on a compile time expression. Does
+ applicative-order (depth-first) evaluation using the defined macro
+ substitution rules (which are simple, unconditional term rewriting
+ rules). Everything else but macro applications is considered constant
+ here. When we match a macro call, we perform the corresponding reduction
+ and evaluate the result recursively.
+
+ Note that in contrast to compiled rewriting rules this is essentially a
+ little term rewriting interpreter here, so it's kind of slow compared to
+ compiled code, but for macro substitution it should be good enough. (We
+ can't use compiled code here, since the runtime expression data structure
+ cannot represent special kinds of expressions like anonymous closures, with
+ and when clauses, etc.) */
+
+expr interpreter::macsubst(expr x)
{
+ char test;
if (x.is_null()) return x;
+ if (stackmax > 0 && stackdir*(&test - baseptr) >= stackmax)
+ throw err("recursion too deep in macro expansion");
switch (x.tag()) {
// constants:
case EXPR::VAR:
@@ -1897,63 +2011,245 @@
case EXPR::PTR:
return x;
// application:
+ case EXPR::APP: {
+ expr u = macsubst(x.xval1()),
+ v = macsubst(x.xval2());
+ expr w = expr(u, v);
+ return macval(w);
+ }
+ // conditionals:
+ case EXPR::COND: {
+ expr u = macsubst(x.xval1()),
+ v = macsubst(x.xval2()),
+ w = macsubst(x.xval3());
+ return expr::cond(u, v, w);
+ }
+ // nested closures:
+ case EXPR::LAMBDA: {
+ expr u = x.xval1(), v = macsubst(x.xval2());
+ return expr::lambda(u, v);
+ }
+ case EXPR::CASE: {
+ expr u = macsubst(x.xval());
+ const rulel *r = x.rules();
+ rulel *s = new rulel;
+ for (rulel::const_iterator it = r->begin(); it != r->end(); ++it) {
+ expr u = it->lhs, v = macsubst(it->rhs),
+ w = macsubst(it->qual);
+ s->push_back(rule(u, v, w));
+ }
+ return expr::cases(u, s);
+ }
+ case EXPR::WHEN: {
+ const rulel *r = x.rules();
+ rulel *s = new rulel;
+ for (rulel::const_iterator it = r->begin(); it != r->end(); ++it) {
+ expr u = it->lhs, v = macsubst(it->rhs);
+ s->push_back(rule(u, v));
+ }
+ expr u = macsubst(x.xval());
+ return expr::when(u, s);
+ }
+ case EXPR::WITH: {
+ expr u = macsubst(x.xval());
+ const env *e = x.fenv();
+ env *f = new env;
+ for (env::const_iterator it = e->begin(); it != e->end(); ++it) {
+ int32_t g = it->first;
+ const env_info& info = it->second;
+ const rulel *r = info.rules;
+ rulel s;
+ for (rulel::const_iterator jt = r->begin(); jt != r->end(); ++jt) {
+ expr u = jt->lhs, v = macsubst(jt->rhs),
+ w = macsubst(jt->qual);
+ s.push_back(rule(u, v, w));
+ }
+ (*f)[g] = env_info(info.argc, s, info.temp);
+ }
+ return expr::with(u, f);
+ }
+ default:
+ assert(x.tag() > 0);
+ return macval(x);
+ }
+}
+
+/* Perform a single macro reduction step. */
+
+expr interpreter::varsubst(expr x, uint8_t offs)
+{
+ char test;
+ if (x.is_null()) return x;
+ if (stackmax > 0 && stackdir*(&test - baseptr) >= stackmax)
+ throw err("recursion too deep in macro expansion");
+ switch (x.tag()) {
+ case EXPR::VAR:
+ case EXPR::FVAR:
+ if (((uint32_t)x.vidx()) + offs > 0xff)
+ throw err("error in expression (too many nested closures)");
+ if (x.tag() == EXPR::VAR)
+ return expr(EXPR::VAR, x.vtag(), x.vidx()+offs, x.ttag(), x.vpath());
+ else
+ return expr(EXPR::FVAR, x.vtag(), x.vidx()+offs);
+ // constants:
+ case EXPR::INT:
+ case EXPR::BIGINT:
+ case EXPR::DBL:
+ case EXPR::STR:
+ case EXPR::PTR:
+ return x;
+ // application:
+ case EXPR::APP: {
+ expr u = varsubst(x.xval1(), offs),
+ v = varsubst(x.xval2(), offs);
+ expr w = expr(u, v);
+ return macval(w);
+ }
+ // conditionals:
+ case EXPR::COND: {
+ expr u = varsubst(x.xval1(), offs),
+ v = varsubst(x.xval2(), offs),
+ w = varsubst(x.xval3(), offs);
+ return expr::cond(u, v, w);
+ }
+ // nested closures:
+ case EXPR::LAMBDA: {
+ expr u = x.xval1(), v = varsubst(x.xval2(), offs);
+ return expr::lambda(u, v);
+ }
+ case EXPR::CASE: {
+ expr u = varsubst(x.xval(), offs);
+ const rulel *r = x.rules();
+ rulel *s = new rulel;
+ for (rulel::const_iterator it = r->begin(); it != r->end(); ++it) {
+ expr u = it->lhs, v = varsubst(it->rhs, offs),
+ w = varsubst(it->qual, offs);
+ s->push_back(rule(u, v, w));
+ }
+ return expr::cases(u, s);
+ }
+ case EXPR::WHEN: {
+ const rulel *r = x.rules();
+ rulel *s = new rulel;
+ for (rulel::const_iterator it = r->begin(); it != r->end(); ++it) {
+ expr u = it->lhs, v = varsubst(it->rhs, offs);
+ s->push_back(rule(u, v));
+ }
+ expr u = varsubst(x.xval(), offs);
+ return expr::when(u, s);
+ }
+ case EXPR::WITH: {
+ expr u = varsubst(x.xval(), offs);
+ const env *e = x.fenv();
+ env *f = new env;
+ for (env::const_iterator it = e->begin(); it != e->end(); ++it) {
+ int32_t g = it->first;
+ const env_info& info = it->second;
+ const rulel *r = info.rules;
+ rulel s;
+ for (rulel::const_iterator jt = r->begin(); jt != r->end(); ++jt) {
+ expr u = jt->lhs, v = varsubst(jt->rhs, offs),
+ w = varsubst(jt->qual, offs);
+ s.push_back(rule(u, v, w));
+ }
+ (*f)[g] = env_info(info.argc, s, info.temp);
+ }
+ return expr::with(u, f);
+ }
+ default:
+ assert(x.tag() > 0);
+ return x;
+ }
+}
+
+expr interpreter::macred(expr x, expr y, uint8_t idx)
+{
+ char test;
+ if (y.is_null()) return y;
+ if (stackmax > 0 && stackdir*(&test - baseptr) >= stackmax)
+ throw err("recursion too deep in macro expansion");
+ switch (y.tag()) {
+ // constants:
+ case EXPR::FVAR:
+ case EXPR::INT:
+ case EXPR::BIGINT:
+ case EXPR::DBL:
+ case EXPR::STR:
+ case EXPR::PTR:
+ return y;
+ // lhs variable
+ case EXPR::VAR:
+ if (y.vidx() == idx) {
+ /* Substitute the macro variables, which are the lhs values whose idx
+ match the current idx. Note that the deBruijn indices inside the
+ substituted value must then be shifted by idx, to accommodate for any
+ local environments inside the macro definition. */
+ expr v = varsubst(subterm(x, y.vpath()), idx);
+#if DEBUG>1
+ std::cerr << "macro var: " << y << " = " << v
+ << " (" << (uint32_t)idx << ")" << endl;
+#endif
+ return v;
+ } else
+ return y;
+ // application:
case EXPR::APP:
if (x.xval1().tag() == EXPR::APP &&
x.xval1().xval1().tag() == symtab.catch_sym().f) {
- expr u = fsubst(funs, x.xval1().xval2(), idx);
+ expr u = macred(x, y.xval1().xval2(), idx);
+ expr v = macred(x, y.xval2(), idx);
if (++idx == 0)
throw err("error in expression (too many nested closures)");
- expr v = fsubst(funs, x.xval2(), idx);
return expr(symtab.catch_sym().x, u, v);
} else {
- expr u = fsubst(funs, x.xval1(), idx),
- v = fsubst(funs, x.xval2(), idx);
+ expr u = macred(x, y.xval1(), idx),
+ v = macred(x, y.xval2(), idx);
return expr(u, v);
}
// conditionals:
case EXPR::COND: {
- expr u = fsubst(funs, x.xval1(), idx),
- v = fsubst(funs, x.xval2(), idx),
- w = fsubst(funs, x.xval3(), idx);
+ expr u = macred(x, y.xval1(), idx),
+ v = macred(x, y.xval2(), idx),
+ w = macred(x, y.xval3(), idx);
return expr::cond(u, v, w);
}
// nested closures:
case EXPR::LAMBDA: {
if (++idx == 0)
throw err("error in expression (too many nested closures)");
- expr u = x.xval1(), v = fsubst(funs, x.xval2(), idx);
+ expr u = y.xval1(), v = macred(x, y.xval2(), idx);
return expr::lambda(u, v);
}
case EXPR::CASE: {
- expr u = fsubst(funs, x.xval(), idx);
+ expr u = macred(x, y.xval(), idx);
if (++idx == 0)
throw err("error in expression (too many nested closures)");
- const rulel *r = x.rules();
+ const rulel *r = y.rules();
rulel *s = new rulel;
for (rulel::const_iterator it = r->begin(); it != r->end(); ++it) {
- expr u = it->lhs, v = fsubst(funs, it->rhs, idx),
- w = fsubst(funs, it->qual, idx);
+ expr u = it->lhs, v = macred(x, it->rhs, idx),
+ w = macred(x, it->qual, idx);
s->push_back(rule(u, v, w));
}
return expr::cases(u, s);
}
case EXPR::WHEN: {
- const rulel *r = x.rules();
+ const rulel *r = y.rules();
rulel *s = new rulel;
for (rulel::const_iterator it = r->begin(); it != r->end(); ++it) {
- expr u = it->lhs, v = fsubst(funs, it->rhs, idx);
+ expr u = it->lhs, v = macred(x, it->rhs, idx);
s->push_back(rule(u, v));
if (++idx == 0)
throw err("error in expression (too many nested closures)");
}
- expr u = fsubst(funs, x.xval(), idx);
+ expr u = macred(x, y.xval(), idx);
return expr::when(u, s);
}
case EXPR::WITH: {
- expr u = fsubst(funs, x.xval(), idx);
+ expr u = macred(x, y.xval(), idx);
if (++idx == 0)
throw err("error in expression (too many nested closures)");
- const env *e = x.fenv();
+ const env *e = y.fenv();
env *f = new env;
for (env::const_iterator it = e->begin(); it != e->end(); ++it) {
int32_t g = it->first;
@@ -1961,8 +2257,8 @@
const rulel *r = info.rules;
rulel s;
for (rulel::const_iterator jt = r->begin(); jt != r->end(); ++jt) {
- expr u = jt->lhs, v = fsubst(funs, jt->rhs, idx),
- w = fsubst(funs, jt->qual, idx);
+ expr u = jt->lhs, v = macred(x, jt->rhs, idx),
+ w = macred(x, jt->qual, idx);
s.push_back(rule(u, v, w));
}
(*f)[g] = env_info(info.argc, s, info.temp);
@@ -1970,16 +2266,50 @@
return expr::with(u, f);
}
default:
- assert(x.tag() > 0);
- const symbol& sym = symtab.sym(x.tag());
- env::const_iterator it = funs.find(sym.f);
- if (it != funs.end())
- return expr(EXPR::FVAR, sym.f, idx);
- else
- return x;
+ assert(y.tag() > 0);
+ return y;
}
}
+/* Evaluate a macro call. */
+
+static exprl get_args(expr x)
+{
+ expr y, z;
+ exprl xs;
+ while (x.is_app(y, z)) xs.push_front(z), x = y;
+ return xs;
+}
+
+expr interpreter::macval(expr x)
+{
+ char test;
+ if (x.is_null()) return x;
+ if (stackmax > 0 && stackdir*(&test - baseptr) >= stackmax)
+ throw err("recursion too deep in macro expansion");
+ int32_t f; uint32_t argc = count_args(x, f);
+ if (f <= 0) return x;
+ env::iterator it = macenv.find(f);
+ if (it == macenv.end()) return x;
+ env_info &info = it->second;
+ if (argc != info.argc) return x;
+ if (!info.m)
+ info.m = new matcher(*info.rules, info.argc+1);
+ assert(info.m);
+ exprl args = get_args(x);
+ assert(args.size() == argc);
+ state *st = info.m->match(args);
+ if (st) {
+ assert(!st->r.empty());
+ expr y = macred(x, info.m->r[st->r.front()].rhs);
+#if DEBUG>1
+ std::cerr << "macro expansion: " << x << " -> " << y << endl;
+#endif
+ return macsubst(y);
+ }
+ return x;
+}
+
expr* interpreter::uminop(expr *op, expr *x)
{
if (op->tag() != symtab.sym("-").f) {
Modified: pure/trunk/interpreter.hh
===================================================================
--- pure/trunk/interpreter.hh 2008-08-25 19:53:35 UTC (rev 606)
+++ pure/trunk/interpreter.hh 2008-08-25 19:56:07 UTC (rev 607)
@@ -450,8 +450,12 @@
void promote_ttags(expr f, expr x, expr u, expr v);
expr bind(env& vars, expr x, bool b = true, path p = path());
expr subst(const env& vars, expr x, uint8_t idx = 0);
+ expr fsubst(const env& funs, expr x, uint8_t idx = 0);
expr csubst(expr x);
- expr fsubst(const env& funs, expr x, uint8_t idx = 0);
+ expr macsubst(expr x);
+ expr varsubst(expr x, uint8_t offs);
+ expr macred(expr x, expr y, uint8_t idx = 0);
+ expr macval(expr x);
void closure(expr& l, expr& r, bool b = true);
void closure(rule& r, bool b = true);
expr *uminop(expr *op, expr *x);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|