[pure-lang-svn] SF.net SVN: pure-lang:[605] pure/trunk
Status: Beta
Brought to you by:
agraef
|
From: <ag...@us...> - 2008-08-25 10:25:06
|
Revision: 605
http://pure-lang.svn.sourceforge.net/pure-lang/?rev=605&view=rev
Author: agraef
Date: 2008-08-25 10:25:09 +0000 (Mon, 25 Aug 2008)
Log Message:
-----------
Add macro infrastructure.
Modified Paths:
--------------
pure/trunk/interpreter.cc
pure/trunk/interpreter.hh
pure/trunk/lexer.ll
pure/trunk/parser.yy
pure/trunk/pure.cc
Modified: pure/trunk/interpreter.cc
===================================================================
--- pure/trunk/interpreter.cc 2008-08-24 23:46:59 UTC (rev 604)
+++ pure/trunk/interpreter.cc 2008-08-25 10:25:09 UTC (rev 605)
@@ -773,9 +773,12 @@
for (env::const_iterator it = vars.begin(); it != vars.end(); ++it) {
int32_t f = it->first;
const symbol& sym = symtab.sym(f);
- env::const_iterator jt = globenv.find(f);
- if (jt != globenv.end() && jt->second.t == env_info::cvar) {
+ env::const_iterator jt = globenv.find(f), kt = macenv.find(f);
+ if (kt != macenv.end()) {
restore_globals(g);
+ throw err("symbol '"+sym.s+"' is already defined as a macro");
+ } else if (jt != globenv.end() && jt->second.t == env_info::cvar) {
+ restore_globals(g);
throw err("symbol '"+sym.s+"' is already defined as a constant");
} else if (jt != globenv.end() && jt->second.t == env_info::fun) {
restore_globals(g);
@@ -870,9 +873,12 @@
for (env::const_iterator it = vars.begin(); it != vars.end(); ++it) {
int32_t f = it->first;
const symbol& sym = symtab.sym(f);
- env::const_iterator jt = globenv.find(f);
- if (jt != globenv.end() && jt->second.t == env_info::cvar) {
+ env::const_iterator jt = globenv.find(f), kt = macenv.find(f);
+ if (kt != macenv.end()) {
restore_globals(g);
+ throw err("symbol '"+sym.s+"' is already defined as a macro");
+ } else if (jt != globenv.end() && jt->second.t == env_info::cvar) {
+ restore_globals(g);
throw err("symbol '"+sym.s+"' is already defined as a constant");
} else if (jt != globenv.end() && jt->second.t == env_info::fvar) {
restore_globals(g);
@@ -916,9 +922,12 @@
globals g;
save_globals(g);
symbol& sym = symtab.sym(tag);
- env::const_iterator jt = globenv.find(tag);
- if (jt != globenv.end() && jt->second.t == env_info::cvar) {
+ env::const_iterator jt = globenv.find(tag), kt = macenv.find(tag);
+ if (kt != macenv.end()) {
restore_globals(g);
+ throw err("symbol '"+sym.s+"' is already defined as a macro");
+ } else if (jt != globenv.end() && jt->second.t == env_info::cvar) {
+ restore_globals(g);
throw err("symbol '"+sym.s+"' is already defined as a constant");
} else if (jt != globenv.end() && jt->second.t == env_info::fvar) {
restore_globals(g);
@@ -1289,8 +1298,11 @@
globenv.erase(it);
clearsym(f);
}
+ it = macenv.find(f);
+ if (it != macenv.end())
+ macenv.erase(it);
} else if (f == 0 && temp > 0) {
- // purge all temporary functions and variables
+ // purge all temporary symbols
for (env::iterator it = globenv.begin(); it != globenv.end(); ) {
env::iterator jt = it; ++it;
int32_t f = jt->first;
@@ -1314,6 +1326,30 @@
}
}
}
+ for (env::iterator it = macenv.begin(); it != macenv.end(); ) {
+ env::iterator jt = it; ++it;
+ env_info& info = jt->second;
+ if (info.temp >= temp)
+ macenv.erase(jt);
+ else {
+ // purge temporary rules for non-temporary macros
+ bool d = false;
+ rulel& r = *info.rules;
+ for (rulel::iterator it = r.begin(); it != r.end(); )
+ if (it->temp >= temp) {
+ d = true;
+ it = r.erase(it);
+ } else
+ ++it;
+ if (d) {
+ assert(!r.empty());
+ if (info.m) {
+ delete info.m;
+ info.m = 0;
+ }
+ }
+ }
+ }
if (temp > 1) --temp;
}
}
@@ -1429,6 +1465,48 @@
delete r;
}
+void interpreter::add_macro_rule(rule *r)
+{
+ assert(!r->lhs.is_null() && r->qual.is_null());
+ closure(*r, false);
+ int32_t f; uint32_t argc = count_args(r->lhs, f);
+ if (f <= 0)
+ throw err("error in macro definition (invalid head symbol)");
+ env::iterator it = macenv.find(f), jt = globenv.find(f);
+ const symbol& sym = symtab.sym(f);
+ if (jt != globenv.end()) {
+ if (it->second.t == env_info::cvar)
+ throw err("symbol '"+sym.s+"' is already defined as a constant");
+ else if (it->second.t == env_info::fvar)
+ throw err("symbol '"+sym.s+"' is already defined as a variable");
+ } else if (it != macenv.end()) {
+ if (it->second.argc != argc) {
+ ostringstream msg;
+ msg << "symbol '" << sym.s
+ << "' was previously defined with " << it->second.argc << " args";
+ throw err(msg.str());
+ }
+ }
+ env_info &info = macenv[f];
+ if (info.t == env_info::none)
+ info = env_info(argc, rulel(), temp);
+ assert(info.argc == argc);
+ r->temp = temp;
+ if (override) {
+ rulel::iterator p = info.rules->begin();
+ for (; p != info.rules->end() && p->temp >= temp; p++) ;
+ info.rules->insert(p, *r);
+ } else
+ info.rules->push_back(*r);
+ if ((verbose&verbosity::defs) != 0) cout << "def " << *r << ";\n";
+ if (info.m) {
+ // this will be recomputed the next time the macro is needed
+ delete info.m;
+ info.m = 0;
+ }
+ delete r;
+}
+
void interpreter::closure(expr& l, expr& r, bool b)
{
env vars;
@@ -2187,9 +2265,12 @@
globals g;
save_globals(g);
symbol& sym = symtab.sym(tag);
- env::const_iterator jt = globenv.find(tag);
- if (jt != globenv.end() && jt->second.t == env_info::cvar) {
+ env::const_iterator jt = globenv.find(tag), kt = macenv.find(tag);
+ if (kt != macenv.end()) {
restore_globals(g);
+ throw err("symbol '"+sym.s+"' is already defined as a macro");
+ } else if (jt != globenv.end() && jt->second.t == env_info::cvar) {
+ restore_globals(g);
throw err("symbol '"+sym.s+"' is already defined as a constant");
} else if (jt != globenv.end() && jt->second.t == env_info::fun) {
restore_globals(g);
Modified: pure/trunk/interpreter.hh
===================================================================
--- pure/trunk/interpreter.hh 2008-08-24 23:46:59 UTC (rev 604)
+++ pure/trunk/interpreter.hh 2008-08-25 10:25:09 UTC (rev 605)
@@ -331,6 +331,7 @@
clock_t clocks; // last evaluation time, if stats is set
exprl last; // last processed lhs collection
env globenv; // global function and variable environment
+ env macenv; // global macro environment
funset dirty; // "dirty" function entries which need a recompile
pure_mem *mem; // runtime expression memory
pure_expr *exps; // head of the free list (available expression nodes)
@@ -444,6 +445,7 @@
void add_rule(rulel &rl, rule &r, bool b);
void add_rule(env &e, rule &r, bool toplevel = false);
void add_simple_rule(rulel &rl, rule *r);
+ void add_macro_rule(rule *r);
void promote_ttags(expr f, expr x, expr u);
void promote_ttags(expr f, expr x, expr u, expr v);
expr bind(env& vars, expr x, bool b = true, path p = path());
Modified: pure/trunk/lexer.ll
===================================================================
--- pure/trunk/lexer.ll 2008-08-24 23:46:59 UTC (rev 604)
+++ pure/trunk/lexer.ll 2008-08-25 10:25:09 UTC (rev 605)
@@ -111,11 +111,12 @@
struct env_sym {
const symbol* sym;
- env::const_iterator it;
+ env::const_iterator it, jt;
extmap::const_iterator xt;
env_sym(const symbol& _sym, env::const_iterator _it,
+ env::const_iterator _jt,
extmap::const_iterator _xt)
- : sym(&_sym), it(_it), xt(_xt) { }
+ : sym(&_sym), it(_it), jt(_jt), xt(_xt) { }
};
static bool env_compare(env_sym s, env_sym t)
@@ -172,6 +173,7 @@
int32_t f = it->second.f;
/* Skip non-toplevel symbols. */
if (interp.globenv.find(f) == interp.globenv.end() &&
+ interp.macenv.find(f) == interp.macenv.end() &&
interp.globalvars.find(f) == interp.globalvars.end() &&
interp.externals.find(f) == interp.externals.end()) {
it++;
@@ -361,7 +363,7 @@
uint8_t s_verbose = interpreter::g_verbose;
uint8_t tflag = 0;
bool aflag = false, dflag = false, eflag = false;
- bool cflag = false, fflag = false, vflag = false;
+ bool cflag = false, fflag = false, mflag = false, vflag = false;
bool gflag = false, lflag = false, sflag = false;
const char *s = yytext+4;
if (*s && !isspace(*s)) REJECT;
@@ -372,7 +374,7 @@
// process option arguments
for (arg = args.l.begin(); arg != args.l.end(); arg++) {
const char *s = arg->c_str();
- if (s[0] != '-' || !s[1] || !strchr("acdefghlstv", s[1])) break;
+ if (s[0] != '-' || !s[1] || !strchr("acdefghlmstv", s[1])) break;
while (*++s) {
switch (*s) {
case 'a': aflag = true; break;
@@ -382,6 +384,7 @@
case 'f': fflag = true; break;
case 'g': gflag = true; break;
case 'l': lflag = true; break;
+ case 'm': mflag = true; break;
case 's': sflag = true; break;
case 'v': vflag = true; break;
case 't':
@@ -406,6 +409,7 @@
-h Print this list.\n\
-l Long format, prints definitions along with the summary symbol\n\
information. This implies -s.\n\
+-m Print information about defined macros.\n\
-s Summary format, print just summary information about listed symbols.\n\
-t[level] List only symbols and definitions at the given temporary level\n\
(the current level by default) or above. Level 1 denotes all temporary\n\
@@ -422,10 +426,12 @@
if (eflag) interpreter::g_verbose |= verbosity::envs;
if (aflag) interpreter::g_verbose |= verbosity::code;
if (dflag) interpreter::g_verbose |= verbosity::dump;
- if (!cflag && !fflag && !vflag) cflag = fflag = vflag = true;
+ if (!cflag && !fflag && !mflag && !vflag)
+ cflag = fflag = mflag = vflag = true;
if (lflag) sflag = true;
{
- size_t maxsize = 0, nfuns = 0, nvars = 0, ncsts = 0, nrules = 0;
+ size_t maxsize = 0, nfuns = 0, nmacs = 0, nvars = 0, ncsts = 0,
+ nrules = 0, mrules = 0;
list<env_sym> l; set<int32_t> syms;
for (env::const_iterator it = interp.globenv.begin();
it != interp.globenv.end(); ++it) {
@@ -462,7 +468,8 @@
}
if (!matches) continue;
syms.insert(f);
- l.push_back(env_sym(sym, it, interp.externals.find(f)));
+ l.push_back(env_sym(sym, it, interp.macenv.find(f),
+ interp.externals.find(f)));
if (sym.s.size() > maxsize) maxsize = sym.s.size();
}
if (fflag && tflag == 0) {
@@ -484,11 +491,52 @@
}
}
if (!matches) continue;
- l.push_back(env_sym(sym, interp.globenv.end(), it));
+ l.push_back(env_sym(sym, interp.globenv.end(),
+ interp.macenv.find(f), it));
if (sym.s.size() > maxsize) maxsize = sym.s.size();
}
}
}
+ if (mflag) {
+ // also list any symbols defined as macros, unless they've already been
+ // considered
+ for (env::const_iterator it = interp.macenv.begin();
+ it != interp.macenv.end(); ++it) {
+ int32_t f = it->first;
+ if (syms.find(f) == syms.end()) {
+ const env_info& e = it->second;
+ const symbol& sym = interp.symtab.sym(f);
+ bool matches = e.temp >= tflag;
+ if (!matches && !sflag && args.l.empty()) {
+ // if not in summary mode, also list temporary rules for a
+ // non-temporary symbol
+ rulel::const_iterator r;
+ for (r = e.rules->begin(); r != e.rules->end(); r++)
+ if (r->temp >= tflag) {
+ matches = true;
+ break;
+ }
+ }
+ if (!matches) continue;
+ if (!args.l.empty()) {
+ // see whether we actually want the defined symbol to be listed
+ matches = false;
+ for (arg = args.l.begin(); arg != args.l.end(); ++arg) {
+ if (gflag ? (!fnmatch(arg->c_str(), sym.s.c_str(), 0)) :
+ (*arg == sym.s)) {
+ matches = true;
+ break;
+ }
+ }
+ }
+ if (!matches) continue;
+ syms.insert(f);
+ l.push_back(env_sym(sym, interp.globenv.end(), it,
+ interp.externals.end()));
+ if (sym.s.size() > maxsize) maxsize = sym.s.size();
+ }
+ }
+ }
l.sort(env_compare);
if (!l.empty() && (aflag||dflag)) interp.compile();
// we first dump the entire listing into a string and then output that
@@ -499,9 +547,9 @@
const symbol& sym = *it->sym;
int32_t ftag = sym.f;
map<int32_t,Env>::iterator fenv = interp.globalfuns.find(ftag);
- const env::const_iterator jt = it->it;
+ const env::const_iterator jt = it->it, kt = it->jt;
const extmap::const_iterator xt = it->xt;
- if (jt == interp.globenv.end()) {
+ if (jt == interp.globenv.end() && kt == interp.macenv.end()) {
assert(xt != interp.externals.end());
const ExternInfo& info = xt->second;
sout << info << ";";
@@ -511,7 +559,8 @@
} else
sout << endl;
++nfuns;
- } else if (jt->second.t == env_info::fvar) {
+ } else if (jt != interp.globenv.end() &&
+ jt->second.t == env_info::fvar) {
nvars++;
if (sflag) {
sout << sym.s << string(maxsize-sym.s.size(), ' ')
@@ -522,7 +571,8 @@
} else
sout << "let " << sym.s << " = " << *(pure_expr**)jt->second.val
<< ";\n";
- } else if (jt->second.t == env_info::cvar) {
+ } else if (jt != interp.globenv.end() &&
+ jt->second.t == env_info::cvar) {
ncsts++;
if (sflag) {
sout << sym.s << string(maxsize-sym.s.size(), ' ')
@@ -553,7 +603,7 @@
}
sout << " " << (int)sym.prec << " " << sym.s << ";\n";
}
- if (xt != interp.externals.end()) {
+ if (fflag && xt != interp.externals.end()) {
const ExternInfo& info = xt->second;
sout << info << ";";
if ((!sflag||lflag) && dflag) {
@@ -562,58 +612,85 @@
} else
sout << endl;
}
- uint32_t argc = jt->second.argc;
- const rulel& rules = *jt->second.rules;
- const matcher *m = jt->second.m;
- if (sflag) {
- ++nfuns; nrules += rules.size();
- sout << sym.s << string(maxsize-sym.s.size(), ' ') << " fun";
- if (lflag) {
- sout << " " << rules << ";";
- if (aflag && m) sout << endl << *m;
- if (dflag && fenv != interp.globalfuns.end() && fenv->second.f)
- fenv->second.print(sout);
+ if (mflag && kt != interp.macenv.end()) {
+ uint32_t argc = kt->second.argc;
+ const rulel& rules = *kt->second.rules;
+ const matcher *m = kt->second.m;
+ if (sflag) {
+ ++nmacs; mrules += rules.size();
+ sout << sym.s << string(maxsize-sym.s.size(), ' ') << " mac";
+ if (lflag) {
+ sout << " " << rules << ";";
+ if (aflag && m) sout << endl << *m;
+ } else {
+ sout << " " << argc << " args, " << rules.size() << " rules";
+ }
+ sout << endl;
} else {
- sout << " " << argc << " args, " << rules.size() << " rules";
+ size_t n = 0;
+ for (rulel::const_iterator it = rules.begin();
+ it != rules.end(); ++it) {
+ if (it->temp >= tflag) {
+ sout << "def " << *it << ";\n";
+ ++n;
+ }
+ }
+ if (n > 0) {
+ if (aflag && m) sout << *m << endl;
+ mrules += n;
+ ++nmacs;
+ }
}
- sout << endl;
- } else {
- size_t n = 0;
- for (rulel::const_iterator it = rules.begin();
- it != rules.end(); ++it) {
- if (it->temp >= tflag) {
- sout << *it << ";\n";
- ++n;
+ }
+ if (fflag && jt != interp.globenv.end()) {
+ uint32_t argc = jt->second.argc;
+ const rulel& rules = *jt->second.rules;
+ const matcher *m = jt->second.m;
+ if (sflag) {
+ ++nfuns; nrules += rules.size();
+ sout << sym.s << string(maxsize-sym.s.size(), ' ') << " fun";
+ if (lflag) {
+ sout << " " << rules << ";";
+ if (aflag && m) sout << endl << *m;
+ if (dflag && fenv != interp.globalfuns.end() && fenv->second.f)
+ fenv->second.print(sout);
+ } else {
+ sout << " " << argc << " args, " << rules.size() << " rules";
}
+ sout << endl;
+ } else {
+ size_t n = 0;
+ for (rulel::const_iterator it = rules.begin();
+ it != rules.end(); ++it) {
+ if (it->temp >= tflag) {
+ sout << *it << ";\n";
+ ++n;
+ }
+ }
+ if (n > 0) {
+ if (aflag && m) sout << *m << endl;
+ if (dflag && fenv != interp.globalfuns.end() && fenv->second.f)
+ fenv->second.print(sout);
+ nrules += n;
+ ++nfuns;
+ }
}
- if (n > 0) {
- if (aflag && m) sout << *m << endl;
- if (dflag && fenv != interp.globalfuns.end() && fenv->second.f)
- fenv->second.print(sout);
- nrules += n;
- ++nfuns;
- }
}
}
}
if (sflag) {
- if (fflag && vflag && cflag)
- sout << ncsts << " constants, " << nvars << " variables, "
- << nfuns << " functions, " << nrules << " rules\n";
- else if (fflag && cflag)
- sout << ncsts << " constants, " << nfuns << " functions, "
- << nrules << " rules\n";
- else if (fflag && vflag)
- sout << nvars << " variables, " << nfuns << " functions, "
- << nrules << " rules\n";
- else if (cflag && vflag)
- sout << ncsts << " constants, " << nvars << " variables\n";
- else if (cflag)
- sout << ncsts << " constants\n";
- else if (vflag)
- sout << nvars << " variables\n";
- else if (fflag)
- sout << nfuns << " functions, " << nrules << " rules\n";
+ ostringstream summary;
+ if (cflag)
+ summary << ncsts << " constants, ";
+ if (vflag)
+ summary << nvars << " variables, ";
+ if (mflag)
+ summary << nmacs << " macros (" << mrules << " rules), ";
+ if (fflag)
+ summary << nfuns << " functions (" << nrules << " rules), ";
+ string s = summary.str();
+ if (!s.empty())
+ sout << s.substr(0, s.size()-2) << endl;
}
FILE *fp;
const char *more = getenv("PURE_MORE");
Modified: pure/trunk/parser.yy
===================================================================
--- pure/trunk/parser.yy 2008-08-24 23:46:59 UTC (rev 604)
+++ pure/trunk/parser.yy 2008-08-25 10:25:09 UTC (rev 605)
@@ -279,6 +279,8 @@
{ action(interp.define($2), delete $2); }
| CONST simple_rule
{ action(interp.define_const($2), delete $2); }
+| DEF simple_rule
+{ action(interp.add_macro_rule($2), delete $2); }
| rule
{ rulel *rl = 0;
action(interp.add_rules(interp.globenv,
@@ -632,7 +634,8 @@
catch (err &e) { if (rl) delete rl; interp.error(yyloc, e.what()); } }
;
-/* Same for simple rules (pattern binding in 'when' clauses, no guards). */
+/* Same for simple rules (pattern binding in 'when' clauses or 'let', 'const',
+ 'def', no guards in these cases). */
simple_rule
: expr '=' expr
Modified: pure/trunk/pure.cc
===================================================================
--- pure/trunk/pure.cc 2008-08-24 23:46:59 UTC (rev 604)
+++ pure/trunk/pure.cc 2008-08-25 10:25:09 UTC (rev 605)
@@ -97,6 +97,7 @@
int32_t f = it->second.f;
/* Skip non-toplevel symbols. */
if (interp.globenv.find(f) == interp.globenv.end() &&
+ interp.macenv.find(f) == interp.macenv.end() &&
interp.globalvars.find(f) == interp.globalvars.end() &&
interp.externals.find(f) == interp.externals.end()) {
it++;
@@ -136,6 +137,7 @@
int32_t f = it->second.f;
/* Skip non-toplevel symbols. */
if (interp.globenv.find(f) == interp.globenv.end() &&
+ interp.macenv.find(f) == interp.macenv.end() &&
interp.globalvars.find(f) == interp.globalvars.end() &&
interp.externals.find(f) == interp.externals.end()) {
it++;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|