diff options
author | David Robillard <d@drobilla.net> | 2010-04-08 20:09:16 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2010-04-08 20:09:16 +0000 |
commit | 55b6a3f313670d2cb13847d1f1b04fe3e4b21d63 (patch) | |
tree | 200b7dbe00107507e8111b07747bef2cd3f6a958 /src/resp.hpp | |
parent | 9d9fa6162295f3813d20f7a3ad4e07ccd6087c3c (diff) | |
download | resp-55b6a3f313670d2cb13847d1f1b04fe3e4b21d63.tar.gz resp-55b6a3f313670d2cb13847d1f1b04fe3e4b21d63.tar.bz2 resp-55b6a3f313670d2cb13847d1f1b04fe3e4b21d63.zip |
Tuplr -> Resp (RESource Processing).
git-svn-id: http://svn.drobilla.net/resp/resp@252 ad02d1e2-f140-0410-9f75-f8b11f17cedd
Diffstat (limited to 'src/resp.hpp')
-rw-r--r-- | src/resp.hpp | 727 |
1 files changed, 727 insertions, 0 deletions
diff --git a/src/resp.hpp b/src/resp.hpp new file mode 100644 index 0000000..81574e9 --- /dev/null +++ b/src/resp.hpp @@ -0,0 +1,727 @@ +/* Resp: A programming language + * Copyright (C) 2008-2009 David Robillard <dave@drobilla.net> + * + * Resp is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Resp is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General + * Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Resp. If not, see <http://www.gnu.org/licenses/>. + */ + +/** @file + * @brief Interface and type definitions + */ + +#ifndef RESP_HPP +#define RESP_HPP + +#include <stdarg.h> +#include <stdint.h> +#include <string.h> +#include <iostream> +#include <list> +#include <map> +#include <set> +#include <sstream> +#include <string> +#include <vector> +#include <boost/format.hpp> + +#define FOREACH(IT, i, c) for (IT i = (c).begin(); i != (c).end(); ++i) +#define FOREACHP(IT, i, c) for (IT i = (c)->begin(); i != (c)->end(); ++i) +#define THROW_IF(cond, error, ...) { if (cond) throw Error(error, __VA_ARGS__); } + +using namespace std; +using boost::format; + + +/*************************************************************************** + * Basic Utility Classes * + ***************************************************************************/ + +/// Location in textual code +struct Cursor { + Cursor(const string& n="", unsigned l=1, unsigned c=0) : name(n), line(l), col(c) {} + operator bool() const { return !(line == 1 && col == 0); } + string str() const { return (format("%1%:%2%:%3%") % name % line % col).str(); } + string name; + unsigned line; + unsigned col; +}; + +/// Compiler error +struct Error { + Error(Cursor c, const string& m) : loc(c), msg(m) {} + const string what() const { return (loc ? loc.str() + ": " : "") + "error: " + msg; } + const Cursor loc; + const string msg; +}; + +/// Generic Lexical Environment +template<typename K, typename V> +struct Env : public list< vector< pair<K,V> > > { + typedef vector< pair<K,V> > Frame; + Env() : list<Frame>(1) {} + virtual ~Env() {} + virtual void push(Frame f=Frame()) { list<Frame>::push_front(f); } + virtual void pop() { list<Frame>::pop_front(); } + const V& def(const K& k, const V& v) { + for (typename Frame::iterator b = this->begin()->begin(); b != this->begin()->end(); ++b) + if (b->first == k) + return (b->second = v); + this->front().push_back(make_pair(k, v)); + return v; + } + V* ref(const K& key) { + for (typename Env::iterator f = this->begin(); f != this->end(); ++f) + for (typename Frame::iterator b = f->begin(); b != f->end(); ++b) + if (b->first == key) + return &b->second; + return NULL; + } + bool topLevel(const K& key) const { + for (typename Frame::const_iterator b = this->back().begin(); b != this->back().end(); ++b) + if (b->first == key) + return true; + return false; + } +}; + +template<typename K, typename V> +ostream& operator<<(ostream& out, const Env<K,V>& env) { + out << "(Env" << endl; + for (typename Env<K,V>::const_reverse_iterator f = env.rbegin(); f != env.rend(); ++f) { + out << " (" << endl; + for (typename Env<K,V>::Frame::const_iterator b = f->begin(); b != f->end(); ++b) + cout << " " << b->first << " " << b->second << endl; + out << " )" << endl; + } + out << ")" << endl; + return out; +} + + +/*************************************************************************** + * Lexer: Text (istream) -> S-Expressions (SExp) * + ***************************************************************************/ + +class AST; +AST* readExpression(Cursor& cur, std::istream& in); + + +/*************************************************************************** + * Backend Types * + ***************************************************************************/ + +typedef void* CVal; ///< Compiled value (opaque) +typedef void* CFunc; ///< Compiled function (opaque) + + +/*************************************************************************** + * Garbage Collection * + ***************************************************************************/ + +struct Object; + +/// Garbage collector +struct GC { + typedef std::list<const Object*> Roots; + typedef std::list<Object*> Heap; + GC(size_t pool_size); + ~GC(); + void* alloc(size_t size); + void collect(const Roots& roots); + void addRoot(const Object* obj) { assert(obj); _roots.push_back(obj); } + void lock() { _roots.insert(_roots.end(), _heap.begin(), _heap.end()); } + const Roots& roots() const { return _roots; } +private: + void* _pool; + Heap _heap; + Roots _roots; +}; + +/// Garbage collected object (including AST and runtime data) +struct Object { + enum Tag { OBJECT = 123, AST = 456 }; + + struct Header { + uint32_t mark; + uint32_t tag; + }; + + inline Tag tag() const { return (Tag)header()->tag; } + inline void tag(Tag t) { header()->tag = t; } + inline bool marked() const { return header()->mark != 0; } + inline void mark(bool b) const { header()->mark = (b ? 1 : 0); } + + static void* operator new(size_t size) { return pool.alloc(size); } + static void operator delete(void* ptr) {} + + // Memory used with placement new MUST always be allocated with pool.alloc! + static void* operator new(size_t size, void* ptr) { return ptr; } + + static GC pool; + +private: + /// Always allocated with pool.alloc, so this - sizeof(Header) is a valid Header*. + inline Header* header() const { return (Header*)((char*)this - sizeof(Header)); } +}; + + +/*************************************************************************** + * Abstract Syntax Tree * + ***************************************************************************/ + +struct TEnv; ///< Type-Time Environment +struct Constraints; ///< Type Constraints +struct Subst; ///< Type substitutions +struct CEnv; ///< Compile-Time Environment + +struct AST; +extern ostream& operator<<(ostream& out, const AST* ast); + +/// Base class for all AST nodes +struct AST : public Object { + AST(Cursor c=Cursor()) : loc(c) {} + virtual ~AST() {} + virtual bool value() const { return true; } + virtual bool operator==(const AST& o) const = 0; + virtual bool contains(const AST* child) const { return false; } + virtual void constrain(TEnv& tenv, Constraints& c) const {} + virtual AST* cps(TEnv& tenv, AST* cont) const; + virtual void lift(CEnv& cenv) {} + virtual CVal compile(CEnv& cenv) = 0; + string str() const { ostringstream ss; ss << this; return ss.str(); } + template<typename T> T to() { return dynamic_cast<T>(this); } + template<typename T> T const to() const { return dynamic_cast<T const>(this); } + template<typename T> T as() { + T t = dynamic_cast<T>(this); + return t ? t : throw Error(loc, "internal error: bad cast"); + } + template<typename T> T const as() const { + T const t = dynamic_cast<T const>(this); + return t ? t : throw Error(loc, "internal error: bad cast"); + } + Cursor loc; +}; + +template<typename T> +static T* tup(Cursor c, AST* ast, ...) +{ + va_list args; + va_start(args, ast); + T* ret = new T(c, ast, args); + va_end(args); + return ret; +} + +/// Literal value +template<typename T> +struct ALiteral : public AST { + ALiteral(T v, Cursor c) : AST(c), val(v) {} + bool operator==(const AST& rhs) const { + const ALiteral<T>* r = rhs.to<const ALiteral<T>*>(); + return (r && (val == r->val)); + } + void constrain(TEnv& tenv, Constraints& c) const; + CVal compile(CEnv& cenv); + const T val; +}; + +/// String, e.g. ""a"" +struct AString : public AST, public std::string { + AString(Cursor c, const string& s) : AST(c), std::string(s) {} + bool operator==(const AST& rhs) const { return this == &rhs; } + void constrain(TEnv& tenv, Constraints& c) const; + CVal compile(CEnv& cenv) { return NULL; } +}; + +/// Symbol, e.g. "a" +struct ASymbol : public AST { + bool operator==(const AST& rhs) const { return this == &rhs; } + void constrain(TEnv& tenv, Constraints& c) const; + CVal compile(CEnv& cenv); + const string cppstr; +private: + friend class PEnv; + ASymbol(const string& s, Cursor c) : AST(c), cppstr(s) {} +}; + +/// Tuple (heterogeneous sequence of fixed length), e.g. "(a b c)" +struct ATuple : public AST { + ATuple(Cursor c) : AST(c), _len(0), _vec(0) {} + ATuple(const ATuple& exp) : AST(exp.loc), _len(exp._len) { + _vec = (AST**)malloc(sizeof(AST*) * _len); + memcpy(_vec, exp._vec, sizeof(AST*) * _len); + } + ATuple(Cursor c, AST* ast, va_list args) : AST(c), _len(0), _vec(0) { + if (!ast) return; + push_back(ast); + for (AST* a = va_arg(args, AST*); a; a = va_arg(args, AST*)) + push_back(a); + } + ~ATuple() { free(_vec); } + void push_back(AST* ast) { + AST** newvec = (AST**)realloc(_vec, sizeof(AST*) * (_len + 1)); + newvec[_len++] = ast; + _vec = newvec; + } + const AST* head() const { assert(_len > 0); return _vec[0]; } + AST* head() { assert(_len > 0); return _vec[0]; } + const AST* last() const { return _vec[_len - 1]; } + AST* last() { return _vec[_len - 1]; } + size_t size() const { return _len; } + bool empty() const { return _len == 0; } + + typedef AST** iterator; + typedef AST* const* const_iterator; + const_iterator begin() const { return _vec; } + iterator begin() { return _vec; } + const_iterator end() const { return _vec + _len; } + iterator end() { return _vec + _len; } + + bool value() const { return false; } + bool operator==(const AST& rhs) const { + const ATuple* rt = rhs.to<const ATuple*>(); + if (!rt || rt->size() != size()) return false; + const_iterator l = begin(); + FOREACHP(const_iterator, r, rt) + if (!(*(*l++) == *(*r))) + return false; + return true; + } + bool contains(AST* child) const { + if (*this == *child) return true; + FOREACHP(const_iterator, p, this) + if (**p == *child || (*p)->contains(child)) + return true; + return false; + } + void constrain(TEnv& tenv, Constraints& c) const; + void lift(CEnv& cenv) { FOREACHP(iterator, t, this) (*t)->lift(cenv); } + + CVal compile(CEnv& cenv) { throw Error(loc, "tuple compiled"); } + +private: + size_t _len; + AST** _vec; +}; + +/// Type Expression, e.g. "Int", "(Fn (Int Int) Float)" +struct AType : public ATuple { + enum Kind { VAR, PRIM, EXPR, DOTS }; + AType(ASymbol* s) : ATuple(s->loc), kind(PRIM), id(0) { push_back(s); } + AType(Cursor c, unsigned i) : ATuple(c), kind(VAR), id(i) {} + AType(Cursor c, Kind k=EXPR) : ATuple(c), kind(k), id(0) {} + AType(Cursor c, AST* ast, va_list args) : ATuple(c, ast, args), kind(EXPR), id(0) {} + AType(const AType& copy) : ATuple(copy), kind(copy.kind), id(copy.id) {} + CVal compile(CEnv& cenv) { return NULL; } + const ATuple* prot() const { assert(kind == EXPR); return (*(begin() + 1))->to<const ATuple*>(); } + ATuple* prot() { assert(kind == EXPR); return (*(begin() + 1))->to<ATuple*>(); } + bool concrete() const { + switch (kind) { + case VAR: return false; + case PRIM: return head()->str() != "Nothing"; + case EXPR: + FOREACHP(const_iterator, t, this) { + AType* kid = (*t)->to<AType*>(); + if (kid && !kid->concrete()) + return false; + } + } + return true; + } + bool operator==(const AST& rhs) const { + const AType* rt = rhs.to<const AType*>(); + if (!rt || kind != rt->kind) + return false; + else + switch (kind) { + case VAR: return id == rt->id; + case PRIM: return head()->str() == rt->head()->str(); + case EXPR: return ATuple::operator==(rhs); + } + return false; // never reached + } + Kind kind; + unsigned id; +}; + +/// Type substitution +struct Subst : public list< pair<const AType*,AType*> > { + Subst(AType* s=0, AType* t=0) { if (s && t) { assert(s != t); push_back(make_pair(s, t)); } } + static Subst compose(const Subst& delta, const Subst& gamma); + void add(const AType* from, AType* to) { push_back(make_pair(from, to)); } + const_iterator find(const AType* t) const { + for (const_iterator j = begin(); j != end(); ++j) + if (*j->first == *t) + return j; + return end(); + } + AType* apply(const AType* in) const { + if (in->kind == AType::EXPR) { + AType* out = tup<AType>(in->loc, NULL); + for (ATuple::const_iterator i = in->begin(); i != in->end(); ++i) + out->push_back(apply((*i)->as<AType*>())); + return out; + } else { + const_iterator i = find(in); + if (i != end()) { + AType* out = i->second->as<AType*>(); + if (out->kind == AType::EXPR && !out->concrete()) + out = apply(out->as<AType*>()); + return out; + } else { + return new AType(*in); + } + } + } +}; + +inline ostream& operator<<(ostream& out, const Subst& s) { + for (Subst::const_iterator i = s.begin(); i != s.end(); ++i) + out << i->first << " => " << i->second << endl; + return out; +} + +/// Fn (first-class function with captured lexical bindings) +struct AFn : public ATuple { + AFn(Cursor c, AST* ast, va_list args) : ATuple(c, ast, args) {} + bool operator==(const AST& rhs) const { return this == &rhs; } + void constrain(TEnv& tenv, Constraints& c) const; + AST* cps(TEnv& tenv, AST* cont) const; + void lift(CEnv& cenv); + CVal compile(CEnv& cenv); + const ATuple* prot() const { return (*(begin() + 1))->to<const ATuple*>(); } + ATuple* prot() { return (*(begin() + 1))->to<ATuple*>(); } + /// System level implementations of this (polymorphic) fn + struct Impls : public list< pair<AType*, CFunc> > { + CFunc find(AType* type) const { + for (const_iterator f = begin(); f != end(); ++f) + if (*f->first == *type) + return f->second; + return NULL; + } + }; + Impls impls; + string name; +}; + +/// Function call/application, e.g. "(func arg1 arg2)" +struct ACall : public ATuple { + ACall(const ATuple* exp) : ATuple(*exp) {} + ACall(Cursor c, AST* ast, va_list args) : ATuple(c, ast, args) {} + void constrain(TEnv& tenv, Constraints& c) const; + AST* cps(TEnv& tenv, AST* cont) const; + void lift(CEnv& cenv); + CVal compile(CEnv& cenv); +}; + +/// Definition special form, e.g. "(def x 2)" +struct ADef : public ACall { + ADef(const ATuple* exp) : ACall(exp) {} + ADef(Cursor c, AST* ast, va_list args) : ACall(c, ast, args) {} + const ASymbol* sym() const { + const AST* name = *(begin() + 1); + const ASymbol* sym = name->to<const ASymbol*>(); + if (!sym) { + const ATuple* tup = name->to<const ATuple*>(); + if (tup && !tup->empty()) + return tup->head()->to<const ASymbol*>(); + } + return sym; + } + const AST* body() const { return *(begin() + 2); } + AST* body() { return *(begin() + 2); } + void constrain(TEnv& tenv, Constraints& c) const; + AST* cps(TEnv& tenv, AST* cont) const; + void lift(CEnv& cenv); + CVal compile(CEnv& cenv); +}; + +/// Conditional special form, e.g. "(if cond thenexp elseexp)" +struct AIf : public ACall { + AIf(const ATuple* exp) : ACall(exp) {} + AIf(Cursor c, AST* ast, va_list args) : ACall(c, ast, args) {} + void constrain(TEnv& tenv, Constraints& c) const; + AST* cps(TEnv& tenv, AST* cont) const; + CVal compile(CEnv& cenv); +}; + +struct ACons : public ACall { + ACons(const ATuple* exp) : ACall(exp) {} + void constrain(TEnv& tenv, Constraints& c) const; + CVal compile(CEnv& cenv); +}; + +struct ADot : public ACall { + ADot(const ATuple* exp) : ACall(exp) {} + void constrain(TEnv& tenv, Constraints& c) const; + void lift(CEnv& cenv); + CVal compile(CEnv& cenv); +}; + +/// Primitive (builtin arithmetic function), e.g. "(+ 2 3)" +struct APrimitive : public ACall { + APrimitive(const ATuple* exp) : ACall(exp) {} + bool value() const { + ATuple::const_iterator i = begin(); + for (++i; i != end(); ++i) + if (!(*i)->value()) + return false;; + return true; + } + void constrain(TEnv& tenv, Constraints& c) const; + AST* cps(TEnv& tenv, AST* cont) const; + CVal compile(CEnv& cenv); +}; + + +/*************************************************************************** + * Parser: S-Expressions (SExp) -> AST Nodes (AST) * + ***************************************************************************/ + +/// Parse Time Environment (really just a symbol table) +struct PEnv : private map<const string, ASymbol*> { + PEnv() : symID(0) {} + typedef AST* (*PF)(PEnv&, const AST*, void*); ///< Parse Function + typedef AST* (*MF)(PEnv&, const AST*); ///< Macro Function + struct Handler { Handler(PF f, void* a=0) : func(f), arg(a) {} PF func; void* arg; }; + map<const string, Handler> aHandlers; ///< Atom parse functions + map<const string, Handler> lHandlers; ///< List parse functions + map<const string, MF> macros; ///< Macro functions + void reg(bool list, const string& s, const Handler& h) { + (list ? lHandlers : aHandlers).insert(make_pair(sym(s)->str(), h)); + } + const Handler* handler(bool list, const string& s) const { + const map<const string, Handler>& handlers = list ? lHandlers : aHandlers; + map<string, Handler>::const_iterator i = handlers.find(s); + return (i != handlers.end()) ? &i->second : NULL; + } + void defmac(const string& s, const MF f) { + macros.insert(make_pair(s, f)); + } + MF mac(const AString& s) const { + map<string, MF>::const_iterator i = macros.find(s); + return (i != macros.end()) ? i->second : NULL; + } + string gensymstr(const char* s="_") { return (format("%s%d") % s % symID++).str(); } + ASymbol* gensym(const char* s="_") { return sym(gensymstr(s)); } + ASymbol* sym(const string& s, Cursor c=Cursor()) { + const const_iterator i = find(s); + if (i != end()) { + return i->second; + } else { + ASymbol* sym = new ASymbol(s, c); + insert(make_pair(s, sym)); + return sym; + } + } + ATuple* parseTuple(const ATuple* e) { + ATuple* ret = new ATuple(e->loc); + FOREACHP(ATuple::const_iterator, i, e) + ret->push_back(parse(*i)); + return ret; + } + AST* parse(const AST* exp) { + const ATuple* tup = exp->to<const ATuple*>(); + if (tup) { + if (tup->empty()) throw Error(exp->loc, "call to empty list"); + if (!tup->head()->to<const ATuple*>()) { + MF mf = mac(*tup->head()->to<const AString*>()); + const AST* expanded = (mf ? mf(*this, exp) : exp); + const ATuple* expanded_tup = expanded->to<const ATuple*>(); + const PEnv::Handler* h = handler(true, *expanded_tup->head()->to<const AString*>()); + if (h) + return h->func(*this, expanded, h->arg); + } + ATuple* parsed_tup = parseTuple(tup); + return new ACall(parsed_tup); // Parse as regular call + } + const AString* str = exp->to<const AString*>(); + assert(str); + if (isdigit((*str)[0])) { + const std::string& s = *str; + if (s.find('.') == string::npos) + return new ALiteral<int32_t>(strtol(s.c_str(), NULL, 10), exp->loc); + else + return new ALiteral<float>(strtod(s.c_str(), NULL), exp->loc); + } else if ((*str)[0] == '\"') { + return new AString(exp->loc, str->substr(1, str->length() - 2)); + } else { + const PEnv::Handler* h = handler(false, *str); + if (h) + return h->func(*this, exp, h->arg); + } + return sym(*exp->to<const AString*>(), exp->loc); + } + unsigned symID; +}; + + +/*************************************************************************** + * Typing * + ***************************************************************************/ + +/// Type constraint +struct Constraint : public pair<AType*,AType*> { + Constraint(AType* a, AType* b, Cursor c) : pair<AType*,AType*>(a, b), loc(c) {} + Cursor loc; +}; + +/// Type constraint set +struct Constraints : public list<Constraint> { + void constrain(TEnv& tenv, const AST* o, AType* t); + void replace(AType* s, AType* t); +}; + +inline ostream& operator<<(ostream& out, const Constraints& c) { + for (Constraints::const_iterator i = c.begin(); i != c.end(); ++i) + out << i->first << " : " << i->second << endl; + return out; +} + +/// Type-Time Environment +struct TEnv : public Env<const ASymbol*, AType*> { + TEnv(PEnv& p) + : penv(p) + , varID(1) + , Fn(new AType(penv.sym("Fn"))) + , Tup(new AType(penv.sym("Tup"))) + { + Object::pool.addRoot(Fn); + } + AType* fresh(const ASymbol* sym) { + return def(sym, new AType(sym->loc, varID++)); + } + AType* var(const AST* ast=0) { + if (!ast) + return new AType(Cursor(), varID++); + + const ASymbol* sym = ast->to<const ASymbol*>(); + if (sym) + return *ref(sym); + + Vars::iterator v = vars.find(ast); + if (v != vars.end()) + return v->second; + + return (vars[ast] = new AType(ast->loc, varID++)); + } + AType* named(const string& name) { + return *ref(penv.sym(name)); + } + static Subst buildSubst(AType* fnT, const AType& argsT); + + typedef map<const AST*, AType*> Vars; + + Vars vars; + PEnv& penv; + unsigned varID; + + AType* Fn; + AType* Tup; +}; + +Subst unify(const Constraints& c); + + +/*************************************************************************** + * Code Generation * + ***************************************************************************/ + +/// Compiler backend +struct Engine { + virtual ~Engine() {} + + virtual CFunc startFunction( + CEnv& cenv, + const std::string& name, + const AType* retT, + const ATuple& argsT, + const vector<string> argNames=vector<string>()) = 0; + + virtual void finishFunction(CEnv& cenv, CFunc f, const AType* retT, CVal ret) = 0; + virtual void eraseFunction(CEnv& cenv, CFunc f) = 0; + virtual CFunc compileFunction(CEnv& cenv, AFn* fn, const AType& argsT) = 0; + virtual CVal compileTup(CEnv& cenv, const AType* t, const vector<CVal>& f) = 0; + virtual CVal compileDot(CEnv& cenv, CVal tup, int32_t index) = 0; + virtual CVal compileLiteral(CEnv& cenv, AST* lit) = 0; + virtual CVal compileCall(CEnv& cenv, CFunc f, const vector<CVal>& args) = 0; + virtual CVal compilePrimitive(CEnv& cenv, APrimitive* prim) = 0; + virtual CVal compileIf(CEnv& cenv, AIf* aif) = 0; + virtual CVal compileGlobal(CEnv& cenv, AType* t, const string& sym, CVal val) = 0; + virtual CVal getGlobal(CEnv& cenv, CVal val) = 0; + virtual void writeModule(CEnv& cenv, std::ostream& os) = 0; + + virtual const string call(CEnv& cenv, CFunc f, AType* retT) = 0; +}; + +Engine* resp_new_llvm_engine(); +Engine* resp_new_c_engine(); + +/// Compile-Time Environment +struct CEnv { + CEnv(PEnv& p, TEnv& t, Engine* e, ostream& os=std::cout, ostream& es=std::cerr) + : out(os), err(es), penv(p), tenv(t), _engine(e) + {} + + ~CEnv() { Object::pool.collect(GC::Roots()); } + + typedef Env<const ASymbol*, CVal> Vals; + + Engine* engine() { return _engine; } + void push() { code.push(); tenv.push(); vals.push(); } + void pop() { code.pop(); tenv.pop(); vals.pop(); } + void lock(AST* ast) { Object::pool.addRoot(ast); Object::pool.addRoot(type(ast)); } + AType* type(AST* ast, const Subst& subst = Subst()) const { + ASymbol* sym = ast->to<ASymbol*>(); + if (sym) + return *tenv.ref(sym); + assert(tenv.vars[ast]); + return tsubst.apply(subst.apply(tenv.vars[ast]))->to<AType*>(); + } + void def(const ASymbol* sym, AST* c, AType* t, CVal v) { + code.def(sym, c); + tenv.def(sym, t); + vals.def(sym, v); + } + AST* resolve(AST* ast) { + const ASymbol* sym = ast->to<const ASymbol*>(); + AST** rec = code.ref(sym); + return rec ? *rec : ast; + } + + ostream& out; + ostream& err; + PEnv& penv; + TEnv& tenv; + Vals vals; + Subst tsubst; + + Env<const ASymbol*, AST*> code; + + map<string,string> args; + +private: + Engine* _engine; +}; + + +/*************************************************************************** + * EVAL/REPL/MAIN * + ***************************************************************************/ + +void pprint(std::ostream& out, const AST* ast); +void initLang(PEnv& penv, TEnv& tenv); +int eval(CEnv& cenv, const string& name, istream& is, bool execute); +int repl(CEnv& cenv); + +#endif // RESP_HPP |