From 46f45a9f8cad31d7eae1fc8d942c5d9d5f5ae20b Mon Sep 17 00:00:00 2001 From: Providence Salumu Date: Tue, 20 Apr 2021 10:20:05 -0400 Subject: [PATCH 01/40] Avoid std::vector (#400) * wrap bool into Bool struct to avoid std::vector --- lib/hobbes/eval/cmodule.C | 772 +++++++++++++++++++++++--------------- 1 file changed, 462 insertions(+), 310 deletions(-) diff --git a/lib/hobbes/eval/cmodule.C b/lib/hobbes/eval/cmodule.C index 4d5413041..368decb38 100644 --- a/lib/hobbes/eval/cmodule.C +++ b/lib/hobbes/eval/cmodule.C @@ -1,45 +1,53 @@ +#include +#include +#include #include #include #include +#include #include #include -#include -#include #include +#include #include -#include -#include -#include namespace hobbes { -bool fileExists(const std::string& fname) { +bool fileExists(const std::string &fname) { // not the most elegant, but it does the job - FILE* f = fopen(fname.c_str(), "r"); - if (!f) return false; + FILE *f = fopen(fname.c_str(), "r"); + if (!f) + return false; fclose(f); return true; } -bool importObject(cc* e, const std::string& sopath) { +bool importObject(cc *e, const std::string &sopath) { if (!fileExists(sopath)) { return false; } else { - void* h = dlopen(sopath.c_str(), RTLD_NOW); - if (!h) { throw std::runtime_error(std::string("Failed to load .so file: ") + dlerror()); } + void *h = dlopen(sopath.c_str(), RTLD_NOW); + if (!h) { + throw std::runtime_error(std::string("Failed to load .so file: ") + + dlerror()); + } - typedef void (*InitF)(cc*); + typedef void (*InitF)(cc *); InitF initF = reinterpret_cast(dlsym(h, "initialize")); - if (!initF) { dlclose(h); throw std::runtime_error(std::string("Failed to load .so file init: ") + dlerror()); } + if (!initF) { + dlclose(h); + throw std::runtime_error(std::string("Failed to load .so file init: ") + + dlerror()); + } initF(e); return true; } } -bool importScript(cc* e, const std::string& fname) { +bool importScript(cc *e, const std::string &fname) { if (!fileExists(fname)) { return false; } else { @@ -49,26 +57,30 @@ bool importScript(cc* e, const std::string& fname) { } typedef std::vector ModulePaths; -static ModulePaths& modulePaths() { +static ModulePaths &modulePaths() { static thread_local ModulePaths mps; - if (mps.size()==0) { + if (mps.size() == 0) { mps.push_back("."); } return mps; } -void pushModuleDir(const std::string& d) { modulePaths().push_back(d); } -void popModuleDir() { if (modulePaths().size() > 0) modulePaths().resize(modulePaths().size()-1); } +void pushModuleDir(const std::string &d) { modulePaths().push_back(d); } +void popModuleDir() { + if (modulePaths().size() > 0) + modulePaths().resize(modulePaths().size() - 1); +} // import a "module" from a path spec (A.B.C => [.|$MODULEPATH]/A/B/C.*) -void import(cc* e, const std::string& mname) { +void import(cc *e, const std::string &mname) { for (size_t p = modulePaths().size(); p > 0; --p) { - std::string path = modulePaths()[p-1]; - std::string mpath = (path.empty() ? "." : path) + "/" + str::replace(mname, ".", "/"); + std::string path = modulePaths()[p - 1]; + std::string mpath = + (path.empty() ? "." : path) + "/" + str::replace(mname, ".", "/"); if (importObject(e, mpath + ".so")) { return; } else { - for (const auto& p : str::paths(mpath + ".*")) { + for (const auto &p : str::paths(mpath + ".*")) { if (importScript(e, p)) { return; } @@ -78,15 +90,16 @@ void import(cc* e, const std::string& mname) { throw std::runtime_error("No such module to load: " + mname); } -// replace type variable references with expanded aliases or opaque definitions as necessary -ExprPtr applyTypeDefns(const ModulePtr&, cc*, const ExprPtr&); +// replace type variable references with expanded aliases or opaque definitions +// as necessary +ExprPtr applyTypeDefns(const ModulePtr &, cc *, const ExprPtr &); struct appTyDefnF : public switchTyFn { ModulePtr m; - cc* e; - appTyDefnF(const ModulePtr& m, cc* e) : m(m), e(e) { } - MonoTypePtr with(const TVar* v) const { - const auto& tn = v->name(); + cc *e; + appTyDefnF(const ModulePtr &m, cc *e) : m(m), e(e) {} + MonoTypePtr with(const TVar *v) const { + const auto &tn = v->name(); if (isPrimName(tn) || e->isTypeAliasName(tn)) { return e->replaceTypeAliases(Prim::make(tn)); @@ -97,75 +110,90 @@ struct appTyDefnF : public switchTyFn { } } - MonoTypePtr with(const TApp* ap) const { - return e->replaceTypeAliases(TApp::make(switchOf(ap->fn(), *this), switchOf(ap->args(), *this))); + MonoTypePtr with(const TApp *ap) const { + return e->replaceTypeAliases( + TApp::make(switchOf(ap->fn(), *this), switchOf(ap->args(), *this))); } - MonoTypePtr with(const TExpr* x) const { - return TExpr::make(applyTypeDefns(this->m, this->e, translateExprWithOpts(m->options(), x->expr()))); + MonoTypePtr with(const TExpr *x) const { + return TExpr::make(applyTypeDefns( + this->m, this->e, translateExprWithOpts(m->options(), x->expr()))); } }; -MonoTypePtr applyTypeDefns(const ModulePtr& m, cc* e, const MonoTypePtr& t) { +MonoTypePtr applyTypeDefns(const ModulePtr &m, cc *e, const MonoTypePtr &t) { auto ua = e->unappTyDefns.find(t.get()); - if (ua != e->unappTyDefns.end()) return ua->second; + if (ua != e->unappTyDefns.end()) + return ua->second; MonoTypePtr r = switchOf(t, appTyDefnF(m, e)); e->unappTyDefns[t.get()] = r; return r; } -MonoTypes applyTypeDefns(const ModulePtr& m, cc* e, const MonoTypes& ts) { +MonoTypes applyTypeDefns(const ModulePtr &m, cc *e, const MonoTypes &ts) { MonoTypes r; - for (const auto& t : ts) { + for (const auto &t : ts) { r.push_back(applyTypeDefns(m, e, t)); } return r; } -QualTypePtr applyTypeDefns(const ModulePtr& m, cc* e, const QualTypePtr& t) { +QualTypePtr applyTypeDefns(const ModulePtr &m, cc *e, const QualTypePtr &t) { Constraints cs; - for (const auto& c : t->constraints()) { - cs.push_back(ConstraintPtr(new Constraint(c->name(), applyTypeDefns(m, e, c->arguments())))); + for (const auto &c : t->constraints()) { + cs.push_back(ConstraintPtr( + new Constraint(c->name(), applyTypeDefns(m, e, c->arguments())))); } return QualTypePtr(new QualType(cs, applyTypeDefns(m, e, t->monoType()))); } struct appTyDefnEF : public switchExprTyFn { ModulePtr m; - cc* e; - appTyDefnEF(const ModulePtr& m, cc* e) : m(m), e(e) { } - QualTypePtr withTy(const QualTypePtr& t) const { if (t) return applyTypeDefns(this->m, this->e, t); else return t; } + cc *e; + appTyDefnEF(const ModulePtr &m, cc *e) : m(m), e(e) {} + QualTypePtr withTy(const QualTypePtr &t) const { + if (t) + return applyTypeDefns(this->m, this->e, t); + else + return t; + } }; -ExprPtr applyTypeDefns(const ModulePtr& m, cc* e, const ExprPtr& x) { +ExprPtr applyTypeDefns(const ModulePtr &m, cc *e, const ExprPtr &x) { return switchOf(x, appTyDefnEF(m, e)); } struct appTyDefnMF : public switchMDefTyFn { ModulePtr m; - cc* e; - appTyDefnMF(const ModulePtr& m, cc* e) : m(m), e(e) { } - QualTypePtr withTy(const QualTypePtr& t) const { if (t) return applyTypeDefns(this->m, this->e, t); else return t; } + cc *e; + appTyDefnMF(const ModulePtr &m, cc *e) : m(m), e(e) {} + QualTypePtr withTy(const QualTypePtr &t) const { + if (t) + return applyTypeDefns(this->m, this->e, t); + else + return t; + } }; -ModuleDefPtr applyTypeDefns(const ModulePtr& m, cc* e, const ModuleDefPtr& md) { +ModuleDefPtr applyTypeDefns(const ModulePtr &m, cc *e, const ModuleDefPtr &md) { return switchOf(md, appTyDefnMF(m, e)); } -ModuleDefs applyTypeDefns(const ModulePtr& m, cc* e, const ModuleDefs& mds) { +ModuleDefs applyTypeDefns(const ModulePtr &m, cc *e, const ModuleDefs &mds) { ModuleDefs r; - for (const auto& md : mds) { + for (const auto &md : mds) { r.push_back(applyTypeDefns(m, e, md)); } return r; } -ModulePtr applyTypeDefns(cc* e, const ModulePtr& m) { - return ModulePtr(new Module(m->name(), applyTypeDefns(m, e, m->definitions()))); +ModulePtr applyTypeDefns(cc *e, const ModulePtr &m) { + return ModulePtr( + new Module(m->name(), applyTypeDefns(m, e, m->definitions()))); } // index type variables and sanity check names to ensure no duplicates typedef std::map NameIndexing; -NameIndexing nameIndexing(const str::seq& ns) { +NameIndexing nameIndexing(const str::seq &ns) { NameIndexing r; for (size_t i = 0; i < ns.size(); ++i) { if (r.find(ns[i]) != r.end()) { @@ -177,11 +205,11 @@ NameIndexing nameIndexing(const str::seq& ns) { return r; } -NameIndexing nameIndexing(const std::set& ns) { +NameIndexing nameIndexing(const std::set &ns) { return nameIndexing(str::seq(ns.begin(), ns.end())); } -int nameIndex(const NameIndexing& ns, const std::string& vn) { +int nameIndex(const NameIndexing &ns, const std::string &vn) { NameIndexing::const_iterator ni = ns.find(vn); if (ni == ns.end()) { throw std::runtime_error("Undefined type name, '" + vn + "'"); @@ -190,7 +218,7 @@ int nameIndex(const NameIndexing& ns, const std::string& vn) { } } -std::vector nameIndex(const NameIndexing& ns, const str::seq& vns) { +std::vector nameIndex(const NameIndexing &ns, const str::seq &vns) { std::vector r; for (str::seq::const_iterator vn = vns.begin(); vn != vns.end(); ++vn) { r.push_back(nameIndex(ns, *vn)); @@ -198,7 +226,7 @@ std::vector nameIndex(const NameIndexing& ns, const str::seq& vns) { return r; } -MonoTypeSubst substitution(const NameIndexing& ns) { +MonoTypeSubst substitution(const NameIndexing &ns) { MonoTypeSubst s; for (NameIndexing::const_iterator ni = ns.begin(); ni != ns.end(); ++ni) { s[ni->first] = MonoTypePtr(TGen::make(ni->second)); @@ -206,7 +234,7 @@ MonoTypeSubst substitution(const NameIndexing& ns) { return s; } -MonoTypeSubst uvarSubstitution(const NameIndexing& ns) { +MonoTypeSubst uvarSubstitution(const NameIndexing &ns) { MonoTypeSubst s; for (NameIndexing::const_iterator ni = ns.begin(); ni != ns.end(); ++ni) { s[ni->first] = freshTypeVar(); @@ -215,27 +243,32 @@ MonoTypeSubst uvarSubstitution(const NameIndexing& ns) { } // convert functional dependencies into index form -void resolveNames(const NameIndexing& ns, const CFunDepDef& nfdep, FunDeps* out) { +void resolveNames(const NameIndexing &ns, const CFunDepDef &nfdep, + FunDeps *out) { VarIDs lhs = nameIndex(ns, nfdep.first); - for (str::seq::const_iterator vn = nfdep.second.begin(); vn != nfdep.second.end(); ++vn) { + for (str::seq::const_iterator vn = nfdep.second.begin(); + vn != nfdep.second.end(); ++vn) { out->push_back(FunDep(lhs, nameIndex(ns, *vn))); } } -FunDeps resolveNames(const NameIndexing& ns, const CFunDepDefs& nfdeps) { +FunDeps resolveNames(const NameIndexing &ns, const CFunDepDefs &nfdeps) { FunDeps r; - for (CFunDepDefs::const_iterator fd = nfdeps.begin(); fd != nfdeps.end(); ++fd) { + for (CFunDepDefs::const_iterator fd = nfdeps.begin(); fd != nfdeps.end(); + ++fd) { resolveNames(ns, *fd, &r); } return r; } // convert member definitions -TClass::Members resolveMembers(const MonoTypeSubst& s, const MVarTypeDefs& mvtds) { +TClass::Members resolveMembers(const MonoTypeSubst &s, + const MVarTypeDefs &mvtds) { TClass::Members r; - for (const auto& mvtd : mvtds) { + for (const auto &mvtd : mvtds) { if (r.find(mvtd->varName()) != r.end()) { - throw annotated_error(*mvtd, "Duplicate class member name, '" + mvtd->varName() + "'"); + throw annotated_error(*mvtd, "Duplicate class member name, '" + + mvtd->varName() + "'"); } else { r[mvtd->varName()] = requireMonotype(substitute(s, mvtd->varType())); } @@ -244,29 +277,36 @@ TClass::Members resolveMembers(const MonoTypeSubst& s, const MVarTypeDefs& mvtds } // make a type class -void compile(const ModulePtr&, cc* e, const ClassDef* cd) { +void compile(const ModulePtr &, cc *e, const ClassDef *cd) { try { - NameIndexing tns = nameIndexing(cd->vars()); - MonoTypeSubst s = substitution(tns); - Constraints reqs = substitute(s, cd->constraints()); - FunDeps fds = resolveNames(tns, cd->fundeps()); + NameIndexing tns = nameIndexing(cd->vars()); + MonoTypeSubst s = substitution(tns); + Constraints reqs = substitute(s, cd->constraints()); + FunDeps fds = resolveNames(tns, cd->fundeps()); TClass::Members mems = resolveMembers(s, cd->members()); - e->typeEnv()->bind(cd->name(), UnqualifierPtr(new TClass(reqs, cd->name(), tns.size(), mems, mergeFundeps(inferFundeps(e->typeEnv(), reqs), fds), cd->la()))); - } catch (std::exception& ex) { + e->typeEnv()->bind( + cd->name(), + UnqualifierPtr(new TClass( + reqs, cd->name(), tns.size(), mems, + mergeFundeps(inferFundeps(e->typeEnv(), reqs), fds), cd->la()))); + } catch (std::exception &ex) { throw annotated_error(*cd, ex.what()); } } // compile class instance member definitions -MemberMapping compileMembers(const ModulePtr& m, MonoTypeUnifier* u, const TClassPtr& c, const MonoTypes& targs, cc* e, const MVarDefs& ds, bool asfn) { - // Class X => Instance Y, X unify Y applied to class member types should yield instance member types - MonoTypes cargs = freshTypeVars(c->typeVars()); +MemberMapping compileMembers(const ModulePtr &m, MonoTypeUnifier *u, + const TClassPtr &c, const MonoTypes &targs, cc *e, + const MVarDefs &ds, bool asfn) { + // Class X => Instance Y, X unify Y applied to class member types should yield + // instance member types + MonoTypes cargs = freshTypeVars(c->typeVars()); mgu(targs, cargs, u); // compile each member symbol binding MemberMapping ms; - for (const auto& d : ds) { + for (const auto &d : ds) { std::string n = d->varWithArgs()[0]; if (ms.find(n) != ms.end()) { @@ -284,12 +324,14 @@ MemberMapping compileMembers(const ModulePtr& m, MonoTypeUnifier* u, const TClas } mexp = translateExprWithOpts(m, mexp); - // determine how to store this member depending on whether we're making an instance function, - // or if we're generating a new function for a ground instance + // determine how to store this member depending on whether we're making an + // instance function, or if we're generating a new function for a ground + // instance if (asfn) { ms[n] = mexp; } else { - MonoTypePtr expectedMemberType = instantiate(u->substitute(cargs), c->memberType(n)); + MonoTypePtr expectedMemberType = + instantiate(u->substitute(cargs), c->memberType(n)); if (!gendef) { ms[n] = e->normalize(assume(mexp, expectedMemberType, mexp->la())); @@ -304,56 +346,62 @@ MemberMapping compileMembers(const ModulePtr& m, MonoTypeUnifier* u, const TClas } // make a type class instance -void compile(const ModulePtr& m, cc* e, const InstanceDef* id) { +void compile(const ModulePtr &m, cc *e, const InstanceDef *id) { try { UnqualifierPtr tyc = e->typeEnv()->lookupUnqualifier(id->className()); - TClassPtr c = std::dynamic_pointer_cast(tyc); - + TClassPtr c = std::dynamic_pointer_cast(tyc); + if (c.get() == 0) { - throw std::runtime_error("Cannot define overload in '" + id->className() + "', class does not exist."); + throw std::runtime_error("Cannot define overload in '" + id->className() + + "', class does not exist."); } MonoTypeUnifier u(e->typeEnv()); - NameIndexing tns = nameIndexing(tvarNames(id->args())); - MonoTypes targs = id->args(); - bool asfn = id->constraints().size() > 0 || tvarNames(targs).size() > 0; - MemberMapping ms = compileMembers(m, &u, c, targs, e, id->members(), asfn); + NameIndexing tns = nameIndexing(tvarNames(id->args())); + MonoTypes targs = id->args(); + bool asfn = id->constraints().size() > 0 || tvarNames(targs).size() > 0; + MemberMapping ms = compileMembers(m, &u, c, targs, e, id->members(), asfn); // is this a ground instance or an instance function? if (!asfn) { Definitions ds; try { - c->insert(e->typeEnv(), TCInstancePtr(new TCInstance(id->className(), targs, ms, id->la())), &ds); + c->insert( + e->typeEnv(), + TCInstancePtr(new TCInstance(id->className(), targs, ms, id->la())), + &ds); e->drainUnqualifyDefs(ds); } catch (...) { e->drainUnqualifyDefs(ds); throw; } } else { - c->insert(TCInstanceFnPtr(new TCInstanceFn(id->className(), id->constraints(), targs, ms, id->la()))); + c->insert(TCInstanceFnPtr(new TCInstanceFn( + id->className(), id->constraints(), targs, ms, id->la()))); } - } catch (annotated_error&) { + } catch (annotated_error &) { throw; - } catch (std::exception& ex) { + } catch (std::exception &ex) { throw annotated_error(*id, ex.what()); } } // compile import statements -void compile(const ModulePtr&, cc* e, const MImport* mimp) { +void compile(const ModulePtr &, cc *e, const MImport *mimp) { pushModuleDir(mimp->path()); try { import(e, mimp->name()); popModuleDir(); - } catch (std::exception&) { + } catch (std::exception &) { popModuleDir(); throw; } } // compile type definitions -MonoTypePtr forceMonotype(cc* e, const QualTypePtr& qt, const LexicalAnnotation& la) { +MonoTypePtr forceMonotype(cc *e, const QualTypePtr &qt, + const LexicalAnnotation &la) { MonoTypeUnifier u(e->typeEnv()); Definitions ds; while (refine(e->typeEnv(), qt->constraints(), &u, &ds)) { @@ -372,13 +420,15 @@ MonoTypePtr forceMonotype(cc* e, const QualTypePtr& qt, const LexicalAnnotation& } } -void compile(const ModulePtr&, cc* e, const MTypeDef* mtd) { +void compile(const ModulePtr &, cc *e, const MTypeDef *mtd) { switch (mtd->visibility()) { case MTypeDef::Transparent: - e->defineTypeAlias(mtd->name(), mtd->arguments(), forceMonotype(e, mtd->type(), mtd->la())); + e->defineTypeAlias(mtd->name(), mtd->arguments(), + forceMonotype(e, mtd->type(), mtd->la())); break; case MTypeDef::Opaque: - e->defineNamedType(mtd->name(), mtd->arguments(), forceMonotype(e, mtd->type(), mtd->la())); + e->defineNamedType(mtd->name(), mtd->arguments(), + forceMonotype(e, mtd->type(), mtd->la())); break; default: break; @@ -386,13 +436,20 @@ void compile(const ModulePtr&, cc* e, const MTypeDef* mtd) { } // compile regular variable definitions -void compile(const ModulePtr& m, cc* e, const MVarDef* mvd) { - ExprPtr vde = translateExprWithOpts(m, (mvd->varWithArgs().size() == 1) ? mvd->varExpr() : ExprPtr(new Fn(Fn::VarNames(mvd->varWithArgs().begin() + 1, mvd->varWithArgs().end()), mvd->varExpr(), mvd->la()))); - - // make sure that globals with inaccessible names (evaluated for side-effects) have monomorphic type - // (otherwise they'll quietly fail to run) - if (mvd->varWithArgs().size() >= 1 && mvd->varWithArgs()[0].size() > 0 && mvd->varWithArgs()[0][0] == '.') { - requireMonotype(e->typeEnv(), e->unsweetenExpression(mvd->varWithArgs()[0], vde)); +void compile(const ModulePtr &m, cc *e, const MVarDef *mvd) { + ExprPtr vde = translateExprWithOpts( + m, (mvd->varWithArgs().size() == 1) + ? mvd->varExpr() + : ExprPtr(new Fn(Fn::VarNames(mvd->varWithArgs().begin() + 1, + mvd->varWithArgs().end()), + mvd->varExpr(), mvd->la()))); + + // make sure that globals with inaccessible names (evaluated for side-effects) + // have monomorphic type (otherwise they'll quietly fail to run) + if (mvd->varWithArgs().size() >= 1 && mvd->varWithArgs()[0].size() > 0 && + mvd->varWithArgs()[0][0] == '.') { + requireMonotype(e->typeEnv(), + e->unsweetenExpression(mvd->varWithArgs()[0], vde)); } // ok we're fine, define this variable @@ -400,10 +457,10 @@ void compile(const ModulePtr& m, cc* e, const MVarDef* mvd) { } // compile forward-declarations -void compile(const ModulePtr&, cc* e, const MVarTypeDef* vtd) { +void compile(const ModulePtr &, cc *e, const MVarTypeDef *vtd) { try { e->forwardDeclare(vtd->varName(), vtd->varType()); - } catch (std::exception& ex) { + } catch (std::exception &ex) { throw annotated_error(*vtd, ex.what()); } } @@ -413,23 +470,25 @@ struct SafeExpr { using Status = SafeSet::Status; struct UnsafeDefs { UnsafeDefs() = default; - UnsafeDefs(std::string const& var, std::string const& fn_) : var(var), fn(fn_), status(Status::UnSafe) {} - - const std::string& varName() const { return var; } - const std::string& safeFn() const { return fn; } - const std::set& unSafeRefs() const { return closure; } - const Status& varStatus() const { return status; } - const LexicalAnnotation& la() const { return lexAnno; } - const std::string& exprDef() const { return typeDesc; } - - std::string& varName() { return var; } - std::set& unSafeRefs() { return closure; } - Status& varStatus() { return status; } - LexicalAnnotation& la() { return lexAnno; } - std::string& exprDef() { return typeDesc; } - - friend std::ostream& operator<<(std::ostream& os, const UnsafeDefs& s) { - os << s.var << " " << s.status << " " << str::show(s.closure) << ". " << s.typeDesc; + UnsafeDefs(std::string const &var, std::string const &fn_) + : var(var), fn(fn_), status(Status::UnSafe) {} + + const std::string &varName() const { return var; } + const std::string &safeFn() const { return fn; } + const std::set &unSafeRefs() const { return closure; } + const Status &varStatus() const { return status; } + const LexicalAnnotation &la() const { return lexAnno; } + const std::string &exprDef() const { return typeDesc; } + + std::string &varName() { return var; } + std::set &unSafeRefs() { return closure; } + Status &varStatus() { return status; } + LexicalAnnotation &la() { return lexAnno; } + std::string &exprDef() { return typeDesc; } + + friend std::ostream &operator<<(std::ostream &os, const UnsafeDefs &s) { + os << s.var << " " << s.status << " " << str::show(s.closure) << ". " + << s.typeDesc; return os; } @@ -442,7 +501,7 @@ struct SafeExpr { private: std::string var; std::string fn; - Status status { Status::Undefined }; + Status status{Status::Undefined}; std::set closure; LexicalAnnotation lexAnno; std::string typeDesc; @@ -450,22 +509,26 @@ struct SafeExpr { using Map = std::map; - static auto with(std::function const& mapModifier) -> void { + static auto with(std::function const &mapModifier) -> void { instance()._with(mapModifier); }; - template - static auto with(std::string const& n, std::function const& hit, std::function const& miss) -> R { + template + static auto with(std::string const &n, + std::function const &hit, + std::function const &miss) -> R { return instance().template _with(n, hit, miss); } private: - auto _with(std::function const& mapModifier) -> void { + auto _with(std::function const &mapModifier) -> void { mapModifier(map); } - template - auto _with(std::string const& n, std::function const& hit, std::function const& miss) -> R { + template + auto _with(std::string const &n, + std::function const &hit, + std::function const &miss) -> R { auto it = map.find(n); if (it != std::end(map) && it->second.varStatus() != SafeExpr::Status::Safe) return hit(it->second); @@ -473,13 +536,12 @@ private: return miss(); } - static auto instance() -> SafeExpr& { - thread_local SafeExpr ms {Map{{"element" , {"element", "elementM"}}, - {"newArray" , {"newArray", {}}}, - {"newPrim" , {"newPrim", {}}}, - {"newPrimZ" , {"newPrimZ", {}}}, - {"unsafeCast" , {"unsafeCast", {}} - }}}; + static auto instance() -> SafeExpr & { + thread_local SafeExpr ms{Map{{"element", {"element", "elementM"}}, + {"newArray", {"newArray", {}}}, + {"newPrim", {"newPrim", {}}}, + {"newPrimZ", {"newPrimZ", {}}}, + {"unsafeCast", {"unsafeCast", {}}}}}; return ms; } @@ -489,137 +551,191 @@ private: }; struct UnsafeRefs : public SafeExpr::UnsafeDefs { - friend auto operator< (SafeExpr::UnsafeDefs const& l, SafeExpr::UnsafeDefs const& r) -> bool { + friend auto operator<(SafeExpr::UnsafeDefs const &l, + SafeExpr::UnsafeDefs const &r) -> bool { return l.varName() < r.varName(); } - auto stepFn(std::pair, std::set&>& v) -> void { + auto stepFn(std::pair, std::set &> &v) + -> void { if (v.first.empty()) return; auto e = v.first.front(); - SafeExpr::template with(e, [&](const SafeExpr::UnsafeDefs& unsafeDef) { - for (auto &f: unsafeDef.unSafeRefs()) { - if (v.second.find(f) == v.second.end()) { - v.first.push_back(f); - } - } - }, []() {}); + SafeExpr::template with( + e, + [&](const SafeExpr::UnsafeDefs &unsafeDef) { + for (auto &f : unsafeDef.unSafeRefs()) { + if (v.second.find(f) == v.second.end()) { + v.first.push_back(f); + } + } + }, + []() {}); v.first.pop_front(); v.second.insert(e); } void stepAll() { - auto& var = varName(); - std::pair, std::set&> r = { { var }, unSafeRefs() }; + auto &var = varName(); + std::pair, std::set &> r = { + {var}, unSafeRefs()}; while (not r.first.empty()) stepFn(r); unSafeRefs().erase(var); - SafeExpr::template with(var, [&](const SafeExpr::UnsafeDefs& unsafeDef) { - la() = unsafeDef.la(); - exprDef() = unsafeDef.exprDef(); - }, []() {}); + SafeExpr::template with( + var, + [&](const SafeExpr::UnsafeDefs &unsafeDef) { + la() = unsafeDef.la(); + exprDef() = unsafeDef.exprDef(); + }, + []() {}); } - auto show(std::ostream& os) -> void { - os << la().filename() << ", " << la().lineDesc() << ": " << varName() << " is not allowed"; - if (unSafeRefs().size()>0) - os << ", its transitive closure has disabled expressions: " << str::show(unSafeRefs()) ; + auto show(std::ostream &os) -> void { + os << la().filename() << ", " << la().lineDesc() << ": " << varName() + << " is not allowed"; + if (unSafeRefs().size() > 0) + os << ", its transitive closure has disabled expressions: " + << str::show(unSafeRefs()); os << "." << exprDef() << std::endl; } }; -void SafeSet::setUnsafeFn(std::string const& varName) { - SafeExpr::with([varName](SafeExpr::Map& m) { - auto& v = m[varName]; +void SafeSet::setUnsafeFn(std::string const &varName) { + SafeExpr::with([varName](SafeExpr::Map &m) { + auto &v = m[varName]; v.varName() = varName; v.varStatus() = SafeExpr::Status::UnSafe; }); } -void SafeSet::setSafeFn(std::string const& varName) { - SafeExpr::with([varName](SafeExpr::Map& m) { - auto& v = m[varName]; +void SafeSet::setSafeFn(std::string const &varName) { + SafeExpr::with([varName](SafeExpr::Map &m) { + auto &v = m[varName]; v.varName() = varName; v.varStatus() = SafeExpr::Status::Safe; }); } -void SafeSet::forEach(std::function const& fn) { - SafeExpr::with([&](SafeExpr::Map& m) { - for (auto& d : m) { +void SafeSet::forEach( + std::function const &fn) { + SafeExpr::with([&](SafeExpr::Map &m) { + for (auto &d : m) { fn(d.second.varName(), d.second.varStatus(), d.second.desc()); } }); } -std::string const& SafeSet::get(std::string const& binding) { - return SafeExpr::with(binding, - [&binding](SafeExpr::UnsafeDefs const& udefs) -> std::string const& { - return udefs.safeFn().empty() ? binding : udefs.safeFn(); - }, - [&binding]() -> std::string const& { - return binding; - }); +std::string const &SafeSet::get(std::string const &binding) { + return SafeExpr::with( + binding, + [&binding](SafeExpr::UnsafeDefs const &udefs) -> std::string const & { + return udefs.safeFn().empty() ? binding : udefs.safeFn(); + }, + [&binding]() -> std::string const & { return binding; }); } +namespace details { +struct Bool { + static auto mkF() -> Bool { return Bool(0); } + static auto mkT() -> Bool { return Bool(1); } + Bool(Bool const &) = default; + Bool(bool v) : i(v ? 1 : 0) {} + auto operator=(Bool const &) -> Bool & = default; + auto operator=(bool v) -> Bool & { return (*this = Bool(v)); } + operator bool() const { return (i == 0 ? false : true); } + +private: + Bool(int i) : i(i) {} + int i = 0; +}; +} // namespace details -struct buildTransitiveUnsafePragmaClosure : public switchExprC { - buildTransitiveUnsafePragmaClosure(MVarDef const& mvd) : mvd(mvd) { } +struct buildTransitiveUnsafePragmaClosure : public switchExprC { + buildTransitiveUnsafePragmaClosure(MVarDef const &mvd) : mvd(mvd) {} ~buildTransitiveUnsafePragmaClosure() { - SafeExpr::with([&](SafeExpr::Map& m) { + SafeExpr::with([&](SafeExpr::Map &m) { auto iter = m.find(mvd.varWithArgs()[0]); if (iter != m.end()) { - auto& var = iter->second; + auto &var = iter->second; std::stringstream ss; mvd.show(ss); var.exprDef() = ss.str(); } - }); - } - MVarDef const& mvd; - - virtual bool withConst(const Expr*) const { return true; }; - virtual bool with(const Var* v) const { - return SafeExpr::with(v->value(), [&](const SafeExpr::UnsafeDefs&) { - SafeExpr::with([&](SafeExpr::Map& m) { - auto varName=mvd.varWithArgs()[0]; - auto r = m.insert({varName, {}}); - auto& var = r.first->second; - if (r.second) { - var.varName() = varName; - var.la() = mvd.la(); - } - auto &status = var.varStatus(); - if (status != SafeExpr::Status::Safe) { - status = SafeExpr::Status::UnSafe; - var.unSafeRefs().insert(v->value()); - } }); - return true; - }, - []() { return false; }); } - virtual bool with (const Let* v) const { switchOf(v->varExpr(), *this); switchOf(v->bodyExpr(), *this); return true; } - virtual bool with (const LetRec* v) const { + MVarDef const &mvd; + + virtual details::Bool withConst(const Expr *) const { return true; }; + virtual details::Bool with(const Var *v) const { + return SafeExpr::with( + v->value(), + [&](const SafeExpr::UnsafeDefs &) { + SafeExpr::with([&](SafeExpr::Map &m) { + auto varName = mvd.varWithArgs()[0]; + auto r = m.insert({varName, {}}); + auto &var = r.first->second; + if (r.second) { + var.varName() = varName; + var.la() = mvd.la(); + } + auto &status = var.varStatus(); + if (status != SafeExpr::Status::Safe) { + status = SafeExpr::Status::UnSafe; + var.unSafeRefs().insert(v->value()); + } + }); + return true; + }, + []() { return false; }); + } + virtual details::Bool with(const Let *v) const { + switchOf(v->varExpr(), *this); + switchOf(v->bodyExpr(), *this); + return true; + } + virtual details::Bool with(const LetRec *v) const { str::set vns = toSet(v->varNames()); LetRec::Bindings bs; - for (const auto& b : v->bindings()) { + for (const auto &b : v->bindings()) { switchOf(b.second, *this); } switchOf(v->bodyExpr(), *this); return true; } - virtual bool with (const Fn* v) const { switchOf(v->body(), *this); return true; } - virtual bool with (const App* v) const { switchOf(v->fn(), *this); switchOf(v->args(), *this); return true; } - virtual bool with (const Assign* v) const { switchOf(v->left(), *this); switchOf(v->right(), *this); return true; } - virtual bool with (const MkArray* v) const { switchOf(v->values(), *this); return true; } - virtual bool with (const MkVariant* v) const { switchOf(v->value(), *this); return true; } - virtual bool with (const MkRecord* v) const { switchOf(v->fields(), *this); return true; } - virtual bool with (const AIndex*) const { return true; } - virtual bool with (const Case* v) const { - const Case::Bindings& cbs = v->bindings(); + virtual details::Bool with(const Fn *v) const { + switchOf(v->body(), *this); + return true; + } + virtual details::Bool with(const App *v) const { + switchOf(v->fn(), *this); + switchOf(v->args(), *this); + return true; + } + virtual details::Bool with(const Assign *v) const { + switchOf(v->left(), *this); + switchOf(v->right(), *this); + return true; + } + virtual details::Bool with(const MkArray *v) const { + switchOf(v->values(), *this); + return true; + } + virtual details::Bool with(const MkVariant *v) const { + switchOf(v->value(), *this); + return true; + } + virtual details::Bool with(const MkRecord *v) const { + switchOf(v->fields(), *this); + return true; + } + virtual details::Bool with(const AIndex *) const { return true; } + virtual details::Bool with(const Case *v) const { + const Case::Bindings &cbs = v->bindings(); Case::Bindings rcbs; - for (Case::Bindings::const_iterator cb = cbs.begin(); cb != cbs.end(); ++cb) { + for (Case::Bindings::const_iterator cb = cbs.begin(); cb != cbs.end(); + ++cb) { switchOf(cb->exp, *this); } ExprPtr de = v->defaultExpr(); @@ -629,7 +745,7 @@ struct buildTransitiveUnsafePragmaClosure : public switchExprC { switchOf(v->variant(), *this); return true; } - virtual bool with (const Switch* v) const { + virtual details::Bool with(const Switch *v) const { Switch::Bindings rsbs; for (auto sb : v->bindings()) { switchOf(sb.exp, *this); @@ -641,50 +757,64 @@ struct buildTransitiveUnsafePragmaClosure : public switchExprC { switchOf(v->expr(), *this); return true; } - virtual bool with (const Proj* v) const { switchOf(v->record(), *this); return true; } - virtual bool with (const Assump* v) const { switchOf(v->expr(), *this); return true; } - virtual bool with (const Pack* v) const { switchOf(v->expr(), *this); return true; } - virtual bool with (const Unpack* v) const { switchOf(v->package(), *this); switchOf(v->expr(), *this); return true; } + virtual details::Bool with(const Proj *v) const { + switchOf(v->record(), *this); + return true; + } + virtual details::Bool with(const Assump *v) const { + switchOf(v->expr(), *this); + return true; + } + virtual details::Bool with(const Pack *v) const { + switchOf(v->expr(), *this); + return true; + } + virtual details::Bool with(const Unpack *v) const { + switchOf(v->package(), *this); + switchOf(v->expr(), *this); + return true; + } }; // compile pragma defines -void compile(const ModulePtr&, cc*, const MUnsafePragmaDef* mpd) { +void compile(const ModulePtr &, cc *, const MUnsafePragmaDef *mpd) { SafeSet::setUnsafeFn(mpd->symbolValue()); - SafeExpr::with([&](SafeExpr::Map& m){ - auto& v = m[mpd->symbolValue()]; + SafeExpr::with([&](SafeExpr::Map &m) { + auto &v = m[mpd->symbolValue()]; v.la() = mpd->la(); }); } -void compile(const ModulePtr&, cc*, const MSafePragmaDef* mpd) { +void compile(const ModulePtr &, cc *, const MSafePragmaDef *mpd) { SafeSet::setSafeFn(mpd->symbolValue()); - SafeExpr::with([&](SafeExpr::Map& m){ - auto& v = m[mpd->symbolValue()]; + SafeExpr::with([&](SafeExpr::Map &m) { + auto &v = m[mpd->symbolValue()]; v.la() = mpd->la(); }); } -// for now, just treat each definition independently and stick it in the input environment +// for now, just treat each definition independently and stick it in the input +// environment // (this disallows things like mutual recursion) -void compile(cc* e, const ModulePtr& m) { +void compile(cc *e, const ModulePtr &m) { for (auto tmd : m->definitions()) { auto md = applyTypeDefns(m, e, tmd); - if (const MImport* imp = is(md)) { + if (const MImport *imp = is(md)) { compile(m, e, imp); - } else if (const ClassDef* cd = is(md)) { + } else if (const ClassDef *cd = is(md)) { compile(m, e, cd); - } else if (const InstanceDef* id = is(md)) { + } else if (const InstanceDef *id = is(md)) { compile(m, e, id); - } else if (const MTypeDef* td = is(md)) { + } else if (const MTypeDef *td = is(md)) { compile(m, e, td); - } else if (const MVarDef* vd = is(md)) { + } else if (const MVarDef *vd = is(md)) { compile(m, e, vd); - } else if (const MVarTypeDef* vtd = is(md)) { + } else if (const MVarTypeDef *vtd = is(md)) { compile(m, e, vtd); - } else if (const MUnsafePragmaDef* vpd = is(md)) { + } else if (const MUnsafePragmaDef *vpd = is(md)) { (void)vpd; - } else if (const MSafePragmaDef* vpd = is(md)) { + } else if (const MSafePragmaDef *vpd = is(md)) { (void)vpd; } else { throw std::runtime_error("Cannot compile module definition: " + show(md)); @@ -693,110 +823,121 @@ void compile(cc* e, const ModulePtr& m) { // compile unsafe pragma for (auto tmd : m->definitions()) { - if (const MUnsafePragmaDef* vpd = is(tmd)) { - compile(m, e, vpd); + if (const MUnsafePragmaDef *vpd = is(tmd)) { + compile(m, e, vpd); } } // compile safe pragma for (auto tmd : m->definitions()) { - if (const MSafePragmaDef* vpd = is(tmd)) { - compile(m, e, vpd); + if (const MSafePragmaDef *vpd = is(tmd)) { + compile(m, e, vpd); } } // generate unsafe transitive closure for (auto tmd : m->definitions()) { - if (const MVarDef* vd = is(tmd)) { + if (const MVarDef *vd = is(tmd)) { switchOf(vd->varExpr(), buildTransitiveUnsafePragmaClosure(*vd)); } } } -std::vector getDefaultOptions() { - return str::strings(); -} +std::vector getDefaultOptions() { return str::strings(); } // make hobbes run in "safe" mode struct makeSafe : public switchExprC { std::map collectUnsafes; - makeSafe() { } + makeSafe() {} auto show() -> std::string { std::stringstream ss; - for (auto& kv : collectUnsafes) { + for (auto &kv : collectUnsafes) { kv.second.show(ss); } return ss.str(); } - ExprPtr withConst(const Expr* v) const { return ExprPtr(v->clone()); } - - ExprPtr with(const Var* v) const { - return SafeExpr::template with(v->value(), [&, this](const SafeExpr::UnsafeDefs& unsafeDef) { - ExprPtr vc(v->clone()); - if (auto vcc = is(vc.get())) { - if (not unsafeDef.safeFn().empty()) { - const_cast(vcc)->value(unsafeDef.safeFn()); - } else { - auto& entry = const_cast(this)->collectUnsafes[v->value()]; - if (not v->value().empty()) { - entry.varName() = v->value(); - entry.stepAll(); + ExprPtr withConst(const Expr *v) const { return ExprPtr(v->clone()); } + + ExprPtr with(const Var *v) const { + return SafeExpr::template with( + v->value(), + [&, this](const SafeExpr::UnsafeDefs &unsafeDef) { + ExprPtr vc(v->clone()); + if (auto vcc = is(vc.get())) { + if (not unsafeDef.safeFn().empty()) { + const_cast(vcc)->value(unsafeDef.safeFn()); + } else { + auto &entry = + const_cast(this)->collectUnsafes[v->value()]; + if (not v->value().empty()) { + entry.varName() = v->value(); + entry.stepAll(); + } + } } - } - } - return vc; - }, [&]() { return ExprPtr(v->clone()); }); + return vc; + }, + [&]() { return ExprPtr(v->clone()); }); } - ExprPtr with(const Let* v) const { - return ExprPtr(new Let(v->var(), switchOf(v->varExpr(), *this), switchOf(v->bodyExpr(), *this), v->la())); + ExprPtr with(const Let *v) const { + return ExprPtr(new Let(v->var(), switchOf(v->varExpr(), *this), + switchOf(v->bodyExpr(), *this), v->la())); } - ExprPtr with(const LetRec* v) const { + ExprPtr with(const LetRec *v) const { str::set vns = toSet(v->varNames()); LetRec::Bindings bs; - for (const auto& b : v->bindings()) { + for (const auto &b : v->bindings()) { bs.push_back(LetRec::Binding(b.first, switchOf(b.second, *this))); } return ExprPtr(new LetRec(bs, switchOf(v->bodyExpr(), *this), v->la())); } - ExprPtr with(const Fn* v) const { + ExprPtr with(const Fn *v) const { return ExprPtr(new Fn(v->varNames(), switchOf(v->body(), *this), v->la())); } - ExprPtr with(const App* v) const { - return ExprPtr(new App(switchOf(v->fn(), *this), switchOf(v->args(), *this), v->la())); + ExprPtr with(const App *v) const { + return ExprPtr( + new App(switchOf(v->fn(), *this), switchOf(v->args(), *this), v->la())); } - ExprPtr with(const Assign* v) const { - return ExprPtr(new Assign(switchOf(v->left(), *this), switchOf(v->right(), *this), v->la())); + ExprPtr with(const Assign *v) const { + return ExprPtr(new Assign(switchOf(v->left(), *this), + switchOf(v->right(), *this), v->la())); } - ExprPtr with(const MkArray* v) const { + ExprPtr with(const MkArray *v) const { return ExprPtr(new MkArray(switchOf(v->values(), *this), v->la())); } - ExprPtr with(const MkVariant* v) const { - return ExprPtr(new MkVariant(v->label(), switchOf(v->value(), *this), v->la())); + ExprPtr with(const MkVariant *v) const { + return ExprPtr( + new MkVariant(v->label(), switchOf(v->value(), *this), v->la())); } - - ExprPtr with(const MkRecord* v) const { + + ExprPtr with(const MkRecord *v) const { return ExprPtr(new MkRecord(switchOf(v->fields(), *this), v->la())); } - ExprPtr with(const AIndex* v) const { - return fncall(var("atm", v->la()), list(switchOf(v->array(), *this), switchOf(v->index(), *this)), v->la()); + ExprPtr with(const AIndex *v) const { + return fncall( + var("atm", v->la()), + list(switchOf(v->array(), *this), switchOf(v->index(), *this)), + v->la()); } - ExprPtr with(const Case* v) const { - const Case::Bindings& cbs = v->bindings(); + ExprPtr with(const Case *v) const { + const Case::Bindings &cbs = v->bindings(); Case::Bindings rcbs; - for (Case::Bindings::const_iterator cb = cbs.begin(); cb != cbs.end(); ++cb) { - rcbs.push_back(Case::Binding(cb->selector, cb->vname, switchOf(cb->exp, *this))); + for (Case::Bindings::const_iterator cb = cbs.begin(); cb != cbs.end(); + ++cb) { + rcbs.push_back( + Case::Binding(cb->selector, cb->vname, switchOf(cb->exp, *this))); } ExprPtr de = v->defaultExpr(); if (de.get()) { @@ -805,7 +946,7 @@ struct makeSafe : public switchExprC { return ExprPtr(new Case(switchOf(v->variant(), *this), rcbs, de, v->la())); } - ExprPtr with(const Switch* v) const { + ExprPtr with(const Switch *v) const { Switch::Bindings rsbs; for (auto sb : v->bindings()) { rsbs.push_back(Switch::Binding(sb.value, switchOf(sb.exp, *this))); @@ -817,20 +958,21 @@ struct makeSafe : public switchExprC { return ExprPtr(new Switch(switchOf(v->expr(), *this), rsbs, de, v->la())); } - ExprPtr with(const Proj* v) const { + ExprPtr with(const Proj *v) const { return ExprPtr(new Proj(switchOf(v->record(), *this), v->field(), v->la())); } - ExprPtr with(const Assump* v) const { + ExprPtr with(const Assump *v) const { return ExprPtr(new Assump(switchOf(v->expr(), *this), v->ty(), v->la())); } - ExprPtr with(const Pack* v) const { + ExprPtr with(const Pack *v) const { return ExprPtr(new Pack(switchOf(v->expr(), *this), v->la())); } - ExprPtr with(const Unpack* v) const { - return ExprPtr(new Unpack(v->varName(), switchOf(v->package(), *this), switchOf(v->expr(), *this), v->la())); + ExprPtr with(const Unpack *v) const { + return ExprPtr(new Unpack(v->varName(), switchOf(v->package(), *this), + switchOf(v->expr(), *this), v->la())); } }; @@ -839,7 +981,8 @@ struct makeSafeArrays : public makeSafe { using Map = SafeExpr::Map; static auto with(const Var *v) -> ExprPtr { - thread_local Map safeArrayTable{ Map{ { {"element", {"element", "elementM"} } } } }; + thread_local Map safeArrayTable{ + Map{{{"element", {"element", "elementM"}}}}}; ExprPtr vc(v->clone()); if (auto vcc = is(vc.get())) { auto iter = safeArrayTable.find(v->value()); @@ -851,44 +994,53 @@ struct makeSafeArrays : public makeSafe { } }; - ExprPtr with(const Var* v) const { return SafeArray::with(v); } + ExprPtr with(const Var *v) const { return SafeArray::with(v); } }; OptDescs getAllOptions() { OptDescs d; - d["Safe"] = "Interpret hobbes in safe mode"; - d["SafeArrays"] = "Interpret array indexing 'safely' (always bounds-checked and mapped to an optional type in case of out-of-bounds access)"; + d["Safe"] = "Interpret hobbes in safe mode"; + d["SafeArrays"] = + "Interpret array indexing 'safely' (always bounds-checked and mapped to " + "an optional type in case of out-of-bounds access)"; return d; } -ExprPtr translateExprWithOpts(const ModulePtr& m, const ExprPtr& e) { +ExprPtr translateExprWithOpts(const ModulePtr &m, const ExprPtr &e) { return translateExprWithOpts(m->options(), e); } -ExprPtr translateExprWithOpts(const std::vector& opts, const ExprPtr& e, std::function const& exceptionFn) { - auto dispatch = std::map> { - { - "Safe", [&exceptionFn](std::string const&, const ExprPtr& e) -> ExprPtr { - auto ms = makeSafe(); - auto r = switchOf(e, ms); - if (ms.collectUnsafes.size() != 0) { - exceptionFn(ms.show()); - }; - return r; - } - }, - { "SafeArrays", [](std::string const&, const ExprPtr& e) -> ExprPtr { return switchOf(e, makeSafeArrays()); } }, - }; - thread_local auto ignoreFn = [](std::string const& optName, const ExprPtr& e) -> ExprPtr { - throw std::runtime_error("unsupported option, " + optName); return e; +ExprPtr translateExprWithOpts( + const std::vector &opts, const ExprPtr &e, + std::function const &exceptionFn) { + auto dispatch = + std::map>{ + {"Safe", + [&exceptionFn](std::string const &, const ExprPtr &e) -> ExprPtr { + auto ms = makeSafe(); + auto r = switchOf(e, ms); + if (ms.collectUnsafes.size() != 0) { + exceptionFn(ms.show()); + }; + return r; + }}, + {"SafeArrays", + [](std::string const &, const ExprPtr &e) -> ExprPtr { + return switchOf(e, makeSafeArrays()); + }}, + }; + thread_local auto ignoreFn = [](std::string const &optName, + const ExprPtr &e) -> ExprPtr { + throw std::runtime_error("unsupported option, " + optName); + return e; }; ExprPtr r = e; - for (const auto& opt : opts) { + for (const auto &opt : opts) { r = dispatch.insert(std::make_pair(opt, ignoreFn)).first->second(opt, r); } return r; } -} - +} // namespace hobbes From 71d72bcb1d79f048dc70856674641fb700b2a069 Mon Sep 17 00:00:00 2001 From: Providence Salumu Date: Wed, 28 Apr 2021 10:06:38 -0400 Subject: [PATCH 02/40] * Support IP binding for RPC * Support LLVM-12 flake.lock: Update Flake input changes: * Updated 'flake-utils': 'github:numtide/flake-utils/8088c6dbe86a7e6e6396c83e43020e8a1edb08d5' -> 'github:numtide/flake-utils/2ebf2558e5bf978c7fb8ea927dfaed8fefab2e28' * Updated 'nixpkgs': 'github:NixOS/nixpkgs/a3ab47ec9067b5f9fccda506fc8641484c3d8e73' -> 'github:NixOS/nixpkgs/267761cf44498f9e1aa81dbdb92d77d5873dd9f6' llvm12: add infra support gh actions: run on ubuntu-latest gh actions: run on ubuntu-latest gh actions: run on new PR net: fix tests net: fix tests net: throw on socket creation failure --- .github/workflows/build.yml | 6 +- flake.lock | 12 +- flake.nix | 8 +- include/hobbes/eval/jitcc.H | 2 +- include/hobbes/ipc/net.H | 4 +- include/hobbes/net.H | 2 +- include/hobbes/util/llvm.H | 8 +- lib/hobbes/eval/jitcc.C | 2 +- lib/hobbes/ipc/net.C | 337 +++++++++++++++------------- test/Net.C | 429 +++++++++++++++++++++++++++--------- 10 files changed, 538 insertions(+), 272 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 597783e4e..49b9e7fbc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,12 +1,12 @@ name: "Build" -on: [push] +on: [push, pull_request] jobs: linux-clang-build: runs-on: ${{matrix.os}} strategy: matrix: os: [ubuntu-20.04] - clang: [6, 8, 10, 11] + clang: [6, 8, 10, 11, 12] steps: - uses: actions/checkout@v2 with: @@ -32,7 +32,7 @@ jobs: matrix: os: [ubuntu-20.04] gcc: [10] - llvm: [6, 8, 10, 11] + llvm: [6, 8, 10, 11, 12] steps: - uses: actions/checkout@v2 with: diff --git a/flake.lock b/flake.lock index b5e53972e..bb7acad89 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "flake-utils": { "locked": { - "lastModified": 1609935452, - "narHash": "sha256-McwA/tAnnS8LaAdEoONBsdKFHuOpHMxKqpMCU1wL7H4=", + "lastModified": 1619345332, + "narHash": "sha256-qHnQkEp1uklKTpx3MvKtY6xzgcqXDsz5nLilbbuL+3A=", "owner": "numtide", "repo": "flake-utils", - "rev": "8088c6dbe86a7e6e6396c83e43020e8a1edb08d5", + "rev": "2ebf2558e5bf978c7fb8ea927dfaed8fefab2e28", "type": "github" }, "original": { @@ -17,11 +17,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1609899452, - "narHash": "sha256-JXi5v4lygRyZjv238bKoPFrQiTAurwcL3XqOo2ZCOLg=", + "lastModified": 1619586859, + "narHash": "sha256-8DiULA5rhWipZm0Wc9IjqG03jfYSigWFYZWXUVK1ZSI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "a3ab47ec9067b5f9fccda506fc8641484c3d8e73", + "rev": "267761cf44498f9e1aa81dbdb92d77d5873dd9f6", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index af30ac84d..ffc7d13b6 100644 --- a/flake.nix +++ b/flake.nix @@ -11,12 +11,12 @@ inherit system; version = "${nixpkgs.lib.substring 0 8 self.lastModifiedDate}.${self.shortRev or "dirty"}"; src = self; - llvmVersions = [ 6 8 9 10 11 ]; + llvmVersions = [ 6 8 9 10 11 12 ]; gccConstraints = [ { gccVersion = 6; llvmVersions = [ 6 8 9 ]; } - { gccVersion = 8; llvmVersions = [ 6 8 9 10 11 ]; } - { gccVersion = 9; llvmVersions = [ 6 8 9 10 11 ]; } - { gccVersion = 10; llvmVersions = [ 6 8 9 10 11 ]; } + { gccVersion = 8; llvmVersions = [ 6 8 9 10 11 12 ]; } + { gccVersion = 9; llvmVersions = [ 6 8 9 10 11 12 ]; } + { gccVersion = 10; llvmVersions = [ 6 8 9 10 11 12 ]; } ]; }) ]; diff --git a/include/hobbes/eval/jitcc.H b/include/hobbes/eval/jitcc.H index c87ae3add..33f64b033 100644 --- a/include/hobbes/eval/jitcc.H +++ b/include/hobbes/eval/jitcc.H @@ -126,7 +126,7 @@ private: typedef std::vector Modules; Modules modules; -#if LLVM_VERSION_MINOR == 6 || LLVM_VERSION_MINOR == 7 || LLVM_VERSION_MINOR == 8 || LLVM_VERSION_MAJOR == 4 || LLVM_VERSION_MAJOR <= 11 +#if LLVM_VERSION_MINOR == 6 || LLVM_VERSION_MINOR == 7 || LLVM_VERSION_MINOR == 8 || LLVM_VERSION_MAJOR == 4 || LLVM_VERSION_MAJOR <= 12 llvm::legacy::PassManager* mpm; // the set of allocated execution engines (each will own a finalized module from the set of modules) diff --git a/include/hobbes/ipc/net.H b/include/hobbes/ipc/net.H index 4f8b2a9b6..e2ddcf279 100644 --- a/include/hobbes/ipc/net.H +++ b/include/hobbes/ipc/net.H @@ -16,7 +16,7 @@ namespace hobbes { int lookupPort(const std::string&); // create a socket listening on a port -int allocateServer(int port); +int allocateServer(int port, const std::string& host = ""); int allocateServer(const std::string& port); // connect to a host/port @@ -46,11 +46,13 @@ struct Server { }; int installNetREPL(int port, Server*); +int installNetREPL(const std::string& host, int port, Server*); // install a net repl on a unix domain socket (using file paths) int installNetREPL(const std::string& /*filepath*/, Server*); class cc; int installNetREPL(int port, cc*, ReWriteExprFn const& = [](ExprPtr const& e) -> ExprPtr { return e; }); +int installNetREPL(const std::string& host, int port, cc*, ReWriteExprFn const& = [](ExprPtr const& e) -> ExprPtr { return e; }); // install a net repl on a unix domain socket (using file paths) int installNetREPL(const std::string& /*filepath*/, cc*, ReWriteExprFn const& = [](ExprPtr const& e) -> ExprPtr { return e; }); diff --git a/include/hobbes/net.H b/include/hobbes/net.H index 40e6b5bdd..bd7f38ad2 100644 --- a/include/hobbes/net.H +++ b/include/hobbes/net.H @@ -162,7 +162,7 @@ inline addrinfo* lookupAddrInfo(const std::string& host, const std::string& port h.ai_socktype = SOCK_STREAM; struct addrinfo* addrs = 0; - switch (getaddrinfo(host.c_str(), port.empty() ? 0 : port.c_str(), &h, &addrs)) { + switch (getaddrinfo(host.empty()? 0 : host.c_str(), port.empty() ? 0 : port.c_str(), &h, &addrs)) { case 0: return addrs; case EAI_ADDRFAMILY: throw std::runtime_error("Cannot make socket connection to " + host + ":" + port); case EAI_AGAIN: throw std::runtime_error(host + ":" + port + " is temporarily unavailable"); diff --git a/include/hobbes/util/llvm.H b/include/hobbes/util/llvm.H index cf57b8743..0254c508b 100644 --- a/include/hobbes/util/llvm.H +++ b/include/hobbes/util/llvm.H @@ -11,7 +11,7 @@ #include -#if LLVM_VERSION_MAJOR != 3 && LLVM_VERSION_MAJOR != 4 && LLVM_VERSION_MAJOR != 6 && LLVM_VERSION_MAJOR != 8 && LLVM_VERSION_MAJOR != 9 && LLVM_VERSION_MAJOR != 10 && LLVM_VERSION_MAJOR != 11 +#if LLVM_VERSION_MAJOR != 3 && LLVM_VERSION_MAJOR != 4 && LLVM_VERSION_MAJOR != 6 && LLVM_VERSION_MAJOR != 8 && LLVM_VERSION_MAJOR != 9 && LLVM_VERSION_MAJOR != 10 && LLVM_VERSION_MAJOR != 11 && LLVM_VERSION_MAJOR != 12 #error "I don't know how to use this version of LLVM" #endif @@ -32,7 +32,7 @@ #if LLVM_VERSION_MAJOR == 4 || LLVM_VERSION_MAJOR == 6 || LLVM_VERSION_MAJOR <= 8 # include # include -#elif LLVM_VERSION_MAJOR <= 11 +#elif LLVM_VERSION_MAJOR <= 12 # include # include #else @@ -372,7 +372,7 @@ inline llvm::Value* memCopy(llvm::IRBuilder<>* b, llvm::Value* dst, uint32_t dst return b->CreateMemCpy(dst, src, sz, srcAlign); #elif LLVM_VERSION_MAJOR <= 9 return b->CreateMemCpy(dst, dstAlign, src, srcAlign, sz); -#elif LLVM_VERSION_MAJOR <= 11 +#elif LLVM_VERSION_MAJOR <= 12 return b->CreateMemCpy(dst, llvm::MaybeAlign(dstAlign), src, llvm::MaybeAlign(srcAlign), sz); #endif } @@ -586,7 +586,7 @@ inline llvm::Value* fncall(llvm::IRBuilder<>* b, llvm::Value* vfn, llvm::Type* t } #elif LLVM_VERSION_MAJOR <= 10 return b->CreateCall(vfn, args); -#elif LLVM_VERSION_MAJOR <= 11 +#elif LLVM_VERSION_MAJOR <= 12 if (auto *ty = llvm::dyn_cast(tfn)) { return b->CreateCall(ty, vfn, args); } else { diff --git a/lib/hobbes/eval/jitcc.C b/lib/hobbes/eval/jitcc.C index b4a9bf798..3181d6228 100644 --- a/lib/hobbes/eval/jitcc.C +++ b/lib/hobbes/eval/jitcc.C @@ -498,7 +498,7 @@ llvm::Value* jitcc::loadConstant(const std::string& vn) { } else if (llvm::Value* r = refGlobal(vn, cv->second.ref)) { #if LLVM_VERSION_MAJOR <= 10 return hasPointerRep(cv->second.mtype) ? r : builder()->CreateLoad(r); -#elif LLVM_VERSION_MAJOR <= 11 +#elif LLVM_VERSION_MAJOR <= 12 return hasPointerRep(cv->second.mtype) ? r : builder()->CreateAlignedLoad(r->getType()->getPointerElementType(), r, llvm::MaybeAlign(8)); #endif } else { diff --git a/lib/hobbes/ipc/net.C b/lib/hobbes/ipc/net.C index 959ed7b3f..c3959e782 100644 --- a/lib/hobbes/ipc/net.C +++ b/lib/hobbes/ipc/net.C @@ -1,29 +1,30 @@ -#include #include -#include +#include +#include #include +#include #include +#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include #include -#include -#include namespace hobbes { // get the port number associated with a named port -int lookupPort(const std::string& x) { +int lookupPort(const std::string &x) { if (str::is(x)) { return str::to(x); } else { - struct servent* s = getservbyname(x.c_str(), "tcp"); + struct servent *s = getservbyname(x.c_str(), "tcp"); if (s != 0) { return ntohs(s->s_port); } else { @@ -32,70 +33,76 @@ int lookupPort(const std::string& x) { } } -// create a listening socket on a given port -int allocateServer(int port) { - int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (s == -1) { - throw std::runtime_error("Unable to allocate socket: " + std::string(strerror(errno))); - } - - // make sure that we can quickly restart the server if necessary - int ra = 1; - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&ra), sizeof(ra)); - - // bind the new socket to a local address - sockaddr_in laddr; - memset(&laddr, 0, sizeof(laddr)); - - laddr.sin_family = AF_INET; - laddr.sin_port = htons(port); - laddr.sin_addr.s_addr = INADDR_ANY; - - if (bind(s, reinterpret_cast(&laddr), sizeof(laddr)) == -1) { +// create a listening socket on a given port and a given host +int allocateServer(int port, const std::string &host) { + struct addrinfo *addrs = net::lookupAddrInfo(host, std::to_string(port)); + struct addrinfo *p = NULL; + int s; + for (p = addrs; p != 0; p = p->ai_next) { + if (p->ai_family != AF_INET || p->ai_protocol != IPPROTO_TCP) + continue; + s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + + if (s == -1) { + throw std::runtime_error("Unable to allocate socket: " + + std::string(strerror(errno))); + } + // make sure that we can quickly restart the server if necessary + int ra = 1; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&ra), + sizeof(ra)); + if (bind(s, p->ai_addr, p->ai_addrlen) == 0) + break; close(s); - throw std::runtime_error("Unable to bind socket to local address: " + std::string(strerror(errno))); } - + freeaddrinfo(addrs); + if (p == NULL) { + throw std::runtime_error("Unable to bind socket to address: " + + std::string(strerror(errno))); + } // and then start to listen if (listen(s, SOMAXCONN) == -1) { close(s); - throw std::runtime_error("Unable to listen on local address: " + std::string(strerror(errno))); + throw std::runtime_error("Unable to listen on address: " + + std::string(strerror(errno))); } - return s; } -int allocateServer(const std::string& port) { +int allocateServer(const std::string &port) { return allocateServer(lookupPort(port)); } -int allocateFileSocketServer(const std::string& filepath) { +int allocateFileSocketServer(const std::string &filepath) { int s = socket(AF_UNIX, SOCK_STREAM, 0); if (s == -1) { - throw std::runtime_error("Unable to allocate socket: " + std::string(strerror(errno))); + throw std::runtime_error("Unable to allocate socket: " + + std::string(strerror(errno))); } - + sockaddr_un addr; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; unlink(filepath.c_str()); snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", filepath.c_str()); - if (bind(s, reinterpret_cast(&addr), sizeof(addr)) == -1) { + if (bind(s, reinterpret_cast(&addr), sizeof(addr)) == -1) { close(s); - throw std::runtime_error("Unable to bind socket to file: " + filepath + std::string(" : ") + std::string(strerror(errno))); + throw std::runtime_error("Unable to bind socket to file: " + filepath + + std::string(" : ") + std::string(strerror(errno))); } // and then start to listen if (listen(s, SOMAXCONN) == -1) { close(s); - throw std::runtime_error("Unable to listen socket on file: " + filepath + std::string(" : ") + std::string(strerror(errno))); + throw std::runtime_error("Unable to listen socket on file: " + filepath + + std::string(" : ") + std::string(strerror(errno))); } return s; } -int connectSocket(int r, sockaddr* saddr, size_t len) { +int connectSocket(int r, sockaddr *saddr, size_t len) { if (connect(r, saddr, len) == -1) { std::ostringstream ss; ss << "Unable to connect socket: " << strerror(errno) << std::flush; @@ -110,7 +117,8 @@ int connectSocket(int r, sockaddr* saddr, size_t len) { if (select(r + 1, 0, &wd, 0, 0) == -1) { std::ostringstream ss; - ss << "Failed to connect socket while waiting for writeability: " << strerror(errno) << std::flush; + ss << "Failed to connect socket while waiting for writeability: " + << strerror(errno) << std::flush; close(r); throw std::runtime_error(ss.str()); } @@ -120,44 +128,47 @@ int connectSocket(int r, sockaddr* saddr, size_t len) { } // create a connected socket to a remote process -int connectSocket(hostent* host, int port) { +int connectSocket(hostent *host, int port) { int r = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (r == -1) { - throw std::runtime_error("Unable to allocate socket: " + std::string(strerror(errno))); + throw std::runtime_error("Unable to allocate socket: " + + std::string(strerror(errno))); } sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; - addr.sin_addr = *reinterpret_cast(host->h_addr_list[0]); - addr.sin_port = htons(port); + addr.sin_addr = *reinterpret_cast(host->h_addr_list[0]); + addr.sin_port = htons(port); - return connectSocket(r, reinterpret_cast(&addr), sizeof(addr)); + return connectSocket(r, reinterpret_cast(&addr), sizeof(addr)); } -int connectFileSocket(const std::string& filepath) { +int connectFileSocket(const std::string &filepath) { int r = socket(AF_UNIX, SOCK_STREAM, 0); if (r == -1) { - throw std::runtime_error("Unable to allocate socket: " + std::string(strerror(errno))); + throw std::runtime_error("Unable to allocate socket: " + + std::string(strerror(errno))); } - + sockaddr_un addr; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", filepath.c_str()); - return connectSocket(r, reinterpret_cast(&addr), sizeof(addr)); + return connectSocket(r, reinterpret_cast(&addr), sizeof(addr)); } -int connectSocket(const std::string& host, int port) { +int connectSocket(const std::string &host, int port) { if (host.size() > 0 && str::isDigit(host[0])) { - return connectSocket(gethostbyaddr(host.c_str(), host.size(), AF_INET), port); + return connectSocket(gethostbyaddr(host.c_str(), host.size(), AF_INET), + port); } else { return connectSocket(gethostbyname(host.c_str()), port); } } - -int connectSocket(const std::string& hostport) { + +int connectSocket(const std::string &hostport) { str::pair p = str::lsplit(hostport, ":"); if (p.second.size() > 0) return connectSocket(p.first, lookupPort(p.second)); @@ -169,10 +180,12 @@ int connectSocket(const std::string& hostport) { std::string remoteHostname(int c) { struct sockaddr_in sin; socklen_t len = sizeof(sin); - if (getpeername(c, reinterpret_cast(&sin), &len) < 0) { + if (getpeername(c, reinterpret_cast(&sin), &len) < 0) { throw std::runtime_error("Couldn't get peer name for socket"); } else { - if (struct hostent* host = gethostbyaddr(reinterpret_cast(&sin.sin_addr), sizeof(sin.sin_addr), AF_INET)) { + if (struct hostent *host = + gethostbyaddr(reinterpret_cast(&sin.sin_addr), + sizeof(sin.sin_addr), AF_INET)) { return std::string(host->h_name); } else { throw std::runtime_error("Couldn't get host name for socket"); @@ -184,30 +197,34 @@ std::string remoteHostname(int c) { int remotePort(int c) { struct sockaddr_in sin; socklen_t len = sizeof(sin); - if (getpeername(c, reinterpret_cast(&sin), &len) < 0) { + if (getpeername(c, reinterpret_cast(&sin), &len) < 0) { throw std::runtime_error("Couldn't get peer name for socket"); } else { return ntohs(sin.sin_port); } } -void prepareStrExpr(Server* s, int c, exprid eid, const std::string& expr, const MonoTypes& intys, const MonoTypePtr& outty) { +void prepareStrExpr(Server *s, int c, exprid eid, const std::string &expr, + const MonoTypes &intys, const MonoTypePtr &outty) { auto la = LexicalAnnotation::null(); if (intys.size() == 0 || (intys.size() == 1 && isUnit(intys[0]))) { - s->prepare(c, eid, assume(s->readExpr(expr), functy(tuplety(intys), outty), la), tuplety()); + s->prepare(c, eid, + assume(s->readExpr(expr), functy(tuplety(intys), outty), la), + tuplety()); } else { ExprPtr f = assume(s->readExpr(expr), functy(intys, outty), la); Exprs args; for (size_t i = 0; i < intys.size(); ++i) { - args.push_back(proj(var("p", la), ".f"+str::from(i), la)); + args.push_back(proj(var("p", la), ".f" + str::from(i), la)); } - s->prepare(c, eid, fn(str::strings("p"), fncall(f, args, la), la), tuplety(intys)); + s->prepare(c, eid, fn(str::strings("p"), fncall(f, args, la), la), + tuplety(intys)); } } -void evaluateNetREPLRequest(int c, void* d) { - Server* s = reinterpret_cast(d); +void evaluateNetREPLRequest(int c, void *d) { + Server *s = reinterpret_cast(d); try { uint8_t cmd = 0; @@ -222,23 +239,23 @@ void evaluateNetREPLRequest(int c, void* d) { std::string expr; fdread(c, &expr); - + RawData ityd, otyd; fdread(c, &ityd); fdread(c, &otyd); MonoTypePtr itye = decode(ityd); MonoTypes itys; - if (const Record* argl = is(itye)) { + if (const Record *argl = is(itye)) { itys = selectTypes(argl->members()); } else { itys.push_back(itye); } prepareStrExpr(s, c, eid, expr, itys, decode(otyd)); - + // if we got this far, we have a successful result fdwrite(c, uint8_t(1)); - } catch (std::exception& ex) { + } catch (std::exception &ex) { fdwrite(c, uint8_t(0)); fdwrite(c, std::string(ex.what())); } @@ -252,20 +269,20 @@ void evaluateNetREPLRequest(int c, void* d) { fdread(c, &exprd); ExprPtr expr; decode(exprd, &expr); - + RawData tyd; fdread(c, &tyd); MonoTypePtr ty = decode(tyd); - + MonoTypePtr rty = s->prepare(c, eid, expr, ty); - + RawData rtyd; encode(rty, &rtyd); - + // if we got this far, we have a successful result fdwrite(c, uint8_t(1)); fdwrite(c, rtyd); - } catch (std::exception& ex) { + } catch (std::exception &ex) { fdwrite(c, uint8_t(0)); fdwrite(c, std::string(ex.what())); } @@ -279,7 +296,7 @@ void evaluateNetREPLRequest(int c, void* d) { default: throw std::runtime_error("protocol violation: cmd=" + str::from(cmd)); } - } catch (std::exception& ex) { + } catch (std::exception &ex) { // something went wrong, disconnect close(c); unregisterEventHandler(c); @@ -287,37 +304,42 @@ void evaluateNetREPLRequest(int c, void* d) { } } -void registerNetREPL(int s, Server* svr) { +void registerNetREPL(int s, Server *svr) { registerEventHandler( - s, - [](int s, void* d) { - int c = accept(s, 0, 0); - if (c != -1) { - try { - uint32_t version = 0; - fdread(c, &version); - if (version != 0x00010000) { + s, + [](int s, void *d) { + int c = accept(s, 0, 0); + if (c != -1) { + try { + uint32_t version = 0; + fdread(c, &version); + if (version != 0x00010000) { + close(c); + } + + reinterpret_cast(d)->connect(c); + registerEventHandler(c, &evaluateNetREPLRequest, d); + } catch (std::exception &) { close(c); } - - reinterpret_cast(d)->connect(c); - registerEventHandler(c, &evaluateNetREPLRequest, d); - } catch (std::exception&) { - close(c); } - } - }, - svr - ); + }, + svr); } -int installNetREPL(int port, Server* svr) { +int installNetREPL(int port, Server *svr) { int s = allocateServer(port); registerNetREPL(s, svr); return s; } -int installNetREPL(const std::string& filepath, Server* svr) { +int installNetREPL(const std::string &host, int port, Server *svr) { + int s = allocateServer(port, host); + registerNetREPL(s, svr); + return s; +} + +int installNetREPL(const std::string &filepath, Server *svr) { int s = allocateFileSocketServer(filepath); registerNetREPL(s, svr); return s; @@ -325,44 +347,44 @@ int installNetREPL(const std::string& filepath, Server* svr) { class CCServer : public Server { public: - CCServer(cc* c, ReWriteExprFn const& wrExprFn) : c(c), wrExprFn(wrExprFn) { - } - - void connect(int) { } - - ExprPtr readExpr(const std::string& x) { - return this->c->readExpr(x); - } + CCServer(cc *c, ReWriteExprFn const &wrExprFn) : c(c), wrExprFn(wrExprFn) {} + + void connect(int) {} - MonoTypePtr prepare(int c, exprid eid, const ExprPtr& expr, const MonoTypePtr& inty) { - const auto& la = expr->la(); + ExprPtr readExpr(const std::string &x) { return this->c->readExpr(x); } + + MonoTypePtr prepare(int c, exprid eid, const ExprPtr &expr, + const MonoTypePtr &inty) { + const auto &la = expr->la(); // E(readFrom(in)::T) :: ? MonoTypePtr rty = requireMonotype( - this->c->unsweetenExpression( - fncall( - wrExprFn(expr), - list(assume(fncall(var("readFrom", la), list(constant(static_cast(0), la)), la), inty, la)), - la - ) - )->type() - ); + this->c + ->unsweetenExpression(fncall( + wrExprFn(expr), + list(assume(fncall(var("readFrom", la), + list(constant(static_cast(0), la)), la), + inty, la)), + la)) + ->type()); // let x = readFrom(input) :: T in writeTo(output, E(x)) - this->cnetFns[c][eid] = - this->c->compileFn - ( - ".c", - let(".in", assume(fncall(var("readFrom", la), list(var(".c", la)), la), inty, la), fncall(var("writeTo", la), list(var(".c", la), - fncall(wrExprFn(expr), list(var(".in", la)), la)), la), la) - ); + this->cnetFns[c][eid] = this->c->compileFn( + ".c", let(".in", + assume(fncall(var("readFrom", la), list(var(".c", la)), la), + inty, la), + fncall(var("writeTo", la), + list(var(".c", la), + fncall(wrExprFn(expr), list(var(".in", la)), la)), + la), + la)); return rty; } void evaluate(int c, exprid eid) { auto cfns = this->cnetFns[c]; - auto f = cfns.find(eid); + auto f = cfns.find(eid); if (f != cfns.end()) { // perform the call @@ -375,9 +397,10 @@ public: } } - void disconnect(int) { } + void disconnect(int) {} + private: - cc* c; + cc *c; typedef void (*NetFn)(int); // socket -> () typedef std::map NetFns; @@ -386,28 +409,31 @@ private: ReWriteExprFn wrExprFn; }; -int installNetREPL(int port, cc* c, ReWriteExprFn const& wrExprFn) { +int installNetREPL(int port, cc *c, ReWriteExprFn const &wrExprFn) { return installNetREPL(port, new CCServer(c, wrExprFn)); } -int installNetREPL(const std::string& filepath, cc* c, ReWriteExprFn const& wrExprFn) { +int installNetREPL(const std::string &host, int port, cc *c, + ReWriteExprFn const &wrExprFn) { + return installNetREPL(host, port, new CCServer(c, wrExprFn)); +} + +int installNetREPL(const std::string &filepath, cc *c, + ReWriteExprFn const &wrExprFn) { return installNetREPL(filepath, new CCServer(c, wrExprFn)); } // connect to a running net REPL -Client::Client(const std::string& hostport) : hostport(hostport), eid(0), rbno(0), reno(0) { +Client::Client(const std::string &hostport) + : hostport(hostport), eid(0), rbno(0), reno(0) { this->c = connectSocket(hostport); fdwrite(this->c, static_cast(0x00010000)); } -Client::~Client() { - close(this->c); -} +Client::~Client() { close(this->c); } -const std::string& Client::remoteHost() const { - return this->hostport; -} +const std::string &Client::remoteHost() const { return this->hostport; } -exprid Client::remoteExpr(const ExprPtr& expr, const MonoTypePtr& inty) { +exprid Client::remoteExpr(const ExprPtr &expr, const MonoTypePtr &inty) { // have we already exchanged this exprty? ExprTy exprty(expr.get(), inty.get()); auto etid = this->exprTyToID.find(exprty); @@ -436,9 +462,9 @@ exprid Client::remoteExpr(const ExprPtr& expr, const MonoTypePtr& inty) { RawData outtyd; fdread(this->c, &outtyd); - ExprDef& ed = this->exprDefs[rid]; - ed.expr = expr; - ed.inty = inty; + ExprDef &ed = this->exprDefs[rid]; + ed.expr = expr; + ed.inty = inty; ed.outty = decode(outtyd); this->exprTyToID[exprty] = rid; @@ -456,7 +482,8 @@ exprid Client::remoteExpr(const ExprPtr& expr, const MonoTypePtr& inty) { MonoTypePtr Client::input(exprid ex) const { auto ed = this->exprDefs.find(ex); if (ed == this->exprDefs.end()) { - throw std::runtime_error("Remote process has no compiled expression with id=" + str::from(ex)); + throw std::runtime_error( + "Remote process has no compiled expression with id=" + str::from(ex)); } else { return ed->second.inty; } @@ -465,32 +492,41 @@ MonoTypePtr Client::input(exprid ex) const { MonoTypePtr Client::output(exprid ex) const { auto ed = this->exprDefs.find(ex); if (ed == this->exprDefs.end()) { - throw std::runtime_error("Remote process has no compiled expression with id=" + str::from(ex)); + throw std::runtime_error( + "Remote process has no compiled expression with id=" + str::from(ex)); } else { return ed->second.outty; } } -MonoTypePtr Client::output(const ExprPtr& e, const MonoTypePtr& inty) { +MonoTypePtr Client::output(const ExprPtr &e, const MonoTypePtr &inty) { return output(remoteExpr(e, inty)); } -void Client::show(std::ostream& out) const { +void Client::show(std::ostream &out) const { out << this->hostport << "\n\n"; str::seqs cs; cs.resize(4); cs[0].push_back("id"); - for (const auto& ce : this->exprDefs) { cs[0].push_back(str::from(ce.first)); } + for (const auto &ce : this->exprDefs) { + cs[0].push_back(str::from(ce.first)); + } cs[1].push_back("expr"); - for (const auto& ce : this->exprDefs) { cs[1].push_back(hobbes::show(ce.second.expr)); } + for (const auto &ce : this->exprDefs) { + cs[1].push_back(hobbes::show(ce.second.expr)); + } cs[2].push_back("input"); - for (const auto& ce : this->exprDefs) { cs[2].push_back(hobbes::show(ce.second.inty)); } + for (const auto &ce : this->exprDefs) { + cs[2].push_back(hobbes::show(ce.second.inty)); + } cs[3].push_back("output"); - for (const auto& ce : this->exprDefs) { cs[3].push_back(hobbes::show(ce.second.outty)); } + for (const auto &ce : this->exprDefs) { + cs[3].push_back(hobbes::show(ce.second.outty)); + } str::printRightAlignedTable(out, cs); } @@ -501,7 +537,7 @@ size_t Client::appendReadFn(ReadFn f) { return this->reno++; } -char* Client::readValue(size_t x) { +char *Client::readValue(size_t x) { if (x < this->rbno) { // too late, we've already read past this std::cerr << "Can't read remote value out of sequence." << std::endl; @@ -513,7 +549,7 @@ char* Client::readValue(size_t x) { ++this->rbno; } - char* r = this->readFns.front()(this->c); + char *r = this->readFns.front()(this->c); this->readFns.pop(); ++this->rbno; @@ -529,12 +565,11 @@ char* Client::readValue(size_t x) { } size_t Client::unsafeAppendReadFn(size_t p, ReadFn f) { - return reinterpret_cast(p)->appendReadFn(f); -} - -char* Client::unsafeRead(size_t p, size_t x) { - return reinterpret_cast(p)->readValue(x); + return reinterpret_cast(p)->appendReadFn(f); } +char *Client::unsafeRead(size_t p, size_t x) { + return reinterpret_cast(p)->readValue(x); } +} // namespace hobbes diff --git a/test/Net.C b/test/Net.C index d12b74dab..645ac46b8 100644 --- a/test/Net.C +++ b/test/Net.C @@ -1,15 +1,18 @@ +#include "test.H" #include #include #include -#include "test.H" +#include #include #include -#include using namespace hobbes; -static cc& c() { static cc x; return x; } +static cc &c() { + static cc x; + return x; +} // start a basic server to validate RPC communication static int serverPort = -1; @@ -25,7 +28,8 @@ static void runTestServer(int ps, int pe) { lk.unlock(); serverStartup.notify_one(); runEventLoop(); - } catch (std::exception&) { + return; + } catch (std::exception &) { ++serverPort; } } @@ -45,167 +49,392 @@ int testServerPort() { return serverPort; } +// start a basic server with configurable hostname and port to validate RPC +// communication +static int serverPortWithHost = -1; +static std::mutex serverMtxWithHost; +static std::condition_variable serverWithHostStartup; + +static void runTestServerWithHost(int ps, int pe, const std::string &host) { + std::unique_lock lk(serverMtxWithHost); + serverPortWithHost = ps; + while (serverPortWithHost < pe) { + try { + installNetREPL(host, serverPortWithHost, &c()); + lk.unlock(); + serverWithHostStartup.notify_one(); + runEventLoop(); + return; + } catch (std::exception &) { + ++serverPortWithHost; + } + } + serverPortWithHost = -1; +} + +int testServerWithHostPort(const std::string &host = "") { + if (serverPortWithHost < 0) { + std::unique_lock lk(serverMtxWithHost); + std::thread serverWithHostProc( + std::bind(&runTestServerWithHost, 9501, 10500, host)); + serverWithHostProc.detach(); + serverWithHostStartup.wait(lk); + if (serverPortWithHost < 0) { + throw std::runtime_error("Couldn't allocate port for test server"); + } + } + return serverPortWithHost; +} /************************** * types/data for net communication **************************/ typedef std::map NameCounts; -typedef std::pair NC; -bool operator==(const NameCounts& ncs, const std::vector& ncsc) { - for (const auto& nc : ncsc) { auto i = ncs.find(nc.first); if (i == ncs.end() || i->second != nc.second) { return false; } } return ncs.size() == ncsc.size(); +typedef std::pair NC; +bool operator==(const NameCounts &ncs, const std::vector &ncsc) { + for (const auto &nc : ncsc) { + auto i = ncs.find(nc.first); + if (i == ncs.end() || i->second != nc.second) { + return false; + } + } + return ncs.size() == ncsc.size(); } -std::ostream& operator<<(std::ostream& os, const NC& nc) { +std::ostream &operator<<(std::ostream &os, const NC &nc) { os << "(\"" << nc.first << "\", " << nc.second << ")"; return os; } template - std::ostream& operator<<(std::ostream& os, const std::vector& xs) { - os << "["; if (xs.size() > 0) { os << xs[0]; for (size_t i = 1; i < xs.size(); ++i) os << ", " << xs[i]; } os << "]"; - return os; +std::ostream &operator<<(std::ostream &os, const std::vector &xs) { + os << "["; + if (xs.size() > 0) { + os << xs[0]; + for (size_t i = 1; i < xs.size(); ++i) + os << ", " << xs[i]; + } + os << "]"; + return os; +} +std::ostream &operator<<(std::ostream &os, const NameCounts &ncsc) { + os << "{"; + auto nc = ncsc.begin(); + if (nc != ncsc.end()) { + os << "\"" << nc->first << "\" => " << nc->second; + ++nc; + for (; nc != ncsc.end(); ++nc) + os << ", " + << "\"" << nc->first << "\" => " << nc->second; } -std::ostream& operator<<(std::ostream& os, const NameCounts& ncsc) { - os << "{"; auto nc = ncsc.begin(); if (nc != ncsc.end()) { os << "\"" << nc->first << "\" => " << nc->second; ++nc; for(;nc != ncsc.end();++nc) os << ", " << "\"" << nc->first << "\" => " << nc->second; } os << "}"; + os << "}"; return os; } DEFINE_ENUM(Kid, (Jim), (Bob)); -DEFINE_STRUCT( - Group, - (std::string, id), - (Kid, kid), - (double, aa), - (size_t, bb) -); +DEFINE_STRUCT(Group, (std::string, id), (Kid, kid), (double, aa), (size_t, bb)); typedef std::vector Groups; -std::ostream& operator<<(std::ostream& os, const Group& g) { os << "{id=\"" << g.id << "\", kid=" << ((g.kid == Kid::Jim()) ? "|Jim|" : "|Bob|") << ", aa=" << g.aa << ", bb=" << g.bb << "}"; return os; } +std::ostream &operator<<(std::ostream &os, const Group &g) { + os << "{id=\"" << g.id + << "\", kid=" << ((g.kid == Kid::Jim()) ? "|Jim|" : "|Bob|") + << ", aa=" << g.aa << ", bb=" << g.bb << "}"; + return os; +} -DEFINE_VARIANT( - V, - (Bob, int), - (Frank, std::string), - (Nothing, hobbes::unit) -); +DEFINE_VARIANT(V, (Bob, int), (Frank, std::string), (Nothing, hobbes::unit)); // make sure that enums with custom ctor IDs transfer correctly -enum class CustomIDEnum : uint32_t { - Red = 55, - Green = 12, - Blue = 257 -}; -std::ostream& operator<<(std::ostream& os, const CustomIDEnum& e) { +enum class CustomIDEnum : uint32_t { Red = 55, Green = 12, Blue = 257 }; +std::ostream &operator<<(std::ostream &os, const CustomIDEnum &e) { switch (e) { - case CustomIDEnum::Red: os << "|Red|"; break; - case CustomIDEnum::Green: os << "|Green|"; break; - case CustomIDEnum::Blue: os << "|Blue|"; break; - default: os << "???"; break; + case CustomIDEnum::Red: + os << "|Red|"; + break; + case CustomIDEnum::Green: + os << "|Green|"; + break; + case CustomIDEnum::Blue: + os << "|Blue|"; + break; + default: + os << "???"; + break; } return os; } -namespace hobbes { namespace net { -template <> - struct io { - static const bool can_memcpy = true; - static ty::desc type() { - ty::Variant::Ctors cs; - cs.push_back(ty::Variant::Ctor("Red", static_cast(CustomIDEnum::Red), ty::prim("unit"))); - cs.push_back(ty::Variant::Ctor("Green", static_cast(CustomIDEnum::Green), ty::prim("unit"))); - cs.push_back(ty::Variant::Ctor("Blue", static_cast(CustomIDEnum::Blue), ty::prim("unit"))); - return ty::variant(cs); - } - static void write(int s, const CustomIDEnum& x) { io::write(s, static_cast(x)); } - static void read(int s, CustomIDEnum* x) { io::read(s, reinterpret_cast(x)); } +namespace hobbes { +namespace net { +template <> struct io { + static const bool can_memcpy = true; + static ty::desc type() { + ty::Variant::Ctors cs; + cs.push_back(ty::Variant::Ctor( + "Red", static_cast(CustomIDEnum::Red), ty::prim("unit"))); + cs.push_back(ty::Variant::Ctor( + "Green", static_cast(CustomIDEnum::Green), ty::prim("unit"))); + cs.push_back(ty::Variant::Ctor( + "Blue", static_cast(CustomIDEnum::Blue), ty::prim("unit"))); + return ty::variant(cs); + } + static void write(int s, const CustomIDEnum &x) { + io::write(s, static_cast(x)); + } + static void read(int s, CustomIDEnum *x) { + io::read(s, reinterpret_cast(x)); + } - typedef io::async_read_state async_read_state; - static void prepare(async_read_state* o) { io::prepare(o); } - static bool accum(int s, async_read_state* o, CustomIDEnum* x) { return io::accum(s, o, reinterpret_cast(x)); } - }; -}} + typedef io::async_read_state async_read_state; + static void prepare(async_read_state *o) { io::prepare(o); } + static bool accum(int s, async_read_state *o, CustomIDEnum *x) { + return io::accum(s, o, reinterpret_cast(x)); + } +}; +} // namespace net +} // namespace hobbes using rgb_t = int[3]; -DEFINE_STRUCT( - RGB, - (rgb_t, val) -); +DEFINE_STRUCT(RGB, (rgb_t, val)); /************************** * the synchronous client networking API **************************/ DEFINE_NET_CLIENT( - SyncClient, - (add, int(int,int), "\\x y.x+y"), - (doit, std::string(), "\\().\"missiles launched\""), - (misc, NameCounts(std::string,size_t), "\\n c.[(n++\"_\"++show(i), i) | i <- [0L..c]]"), - (grpv, V(Group), "\\_.|Frank=\"frank\"|"), - (nothing, V(), "\\_.|Nothing=()|"), - (recover, Groups(int,int), "\\i e.[{id=\"group_\"++show(k),kid=|Jim|,aa=convert(k),bb=convert(k)}|k<-[i..e]]"), - (eidv, CustomIDEnum(CustomIDEnum), "id"), - (inverse, RGB(RGB), "\\x.do{saelem(x.val,0L)<-255-saelem(x.val,0L);saelem(x.val,1L)<-255-saelem(x.val,1L);saelem(x.val,2L)<-255-saelem(x.val,2L); return x}") -); + SyncClient, (add, int(int, int), "\\x y.x+y"), + (doit, std::string(), "\\().\"missiles launched\""), + (misc, NameCounts(std::string, size_t), + "\\n c.[(n++\"_\"++show(i), i) | i <- [0L..c]]"), + (grpv, V(Group), "\\_.|Frank=\"frank\"|"), + (nothing, V(), "\\_.|Nothing=()|"), + (recover, Groups(int, int), + "\\i " + "e.[{id=\"group_\"++show(k),kid=|Jim|,aa=convert(k),bb=convert(k)}|k<-[i.." + "e]]"), + (eidv, CustomIDEnum(CustomIDEnum), "id"), + (inverse, RGB(RGB), + "\\x.do{saelem(x.val,0L)<-255-saelem(x.val,0L);saelem(x.val,1L)<-255-" + "saelem(x.val,1L);saelem(x.val,2L)<-255-saelem(x.val,2L); return x}")); TEST(Net, syncClientAPI) { SyncClient c("localhost", testServerPort()); - EXPECT_EQ(c.add(1,2), 3); + EXPECT_EQ(c.add(1, 2), 3); EXPECT_EQ(c.doit(), "missiles launched"); - EXPECT_EQ(c.misc("foo", 5), list(NC("foo_0",0),NC("foo_1",1),NC("foo_2",2),NC("foo_3",3),NC("foo_4",4),NC("foo_5",5))); + EXPECT_EQ(c.misc("foo", 5), + list(NC("foo_0", 0), NC("foo_1", 1), NC("foo_2", 2), NC("foo_3", 3), + NC("foo_4", 4), NC("foo_5", 5))); - Group grp = { "id", Kid::Jim(), 4.2, 42 }; + Group grp = {"id", Kid::Jim(), 4.2, 42}; EXPECT_EQ(grp, grp); for (size_t i = 0; i < 10; ++i) { EXPECT_EQ(c.grpv(grp), V::Frank("frank")); } EXPECT_EQ(c.nothing(), V::Nothing(hobbes::unit())); - Groups ros = { {"group_0",Kid::Jim(),0.0,0},{"group_1",Kid::Jim(),1.0,1},{"group_2",Kid::Jim(),2.0,2},{"group_3",Kid::Jim(),3.0,3},{"group_4",Kid::Jim(),4.0,4} }; - EXPECT_EQ(c.recover(0,4), ros); + Groups ros = {{"group_0", Kid::Jim(), 0.0, 0}, + {"group_1", Kid::Jim(), 1.0, 1}, + {"group_2", Kid::Jim(), 2.0, 2}, + {"group_3", Kid::Jim(), 3.0, 3}, + {"group_4", Kid::Jim(), 4.0, 4}}; + EXPECT_EQ(c.recover(0, 4), ros); EXPECT_EQ(c.eidv(CustomIDEnum::Green), CustomIDEnum::Green); - auto inv = c.inverse(RGB{{0,255,0}}); - EXPECT_EQ(std::vector(inv.val,inv.val+3), std::vector({255,0,255})); + auto inv = c.inverse(RGB{{0, 255, 0}}); + EXPECT_EQ(std::vector(inv.val, inv.val + 3), + std::vector({255, 0, 255})); } +TEST(Net, syncClientAPIWithConfiguredHostName) { + SyncClient c("localhost", testServerWithHostPort("localhost")); + EXPECT_EQ(c.add(1, 2), 3); + EXPECT_EQ(c.doit(), "missiles launched"); + EXPECT_EQ(c.misc("foo", 5), + list(NC("foo_0", 0), NC("foo_1", 1), NC("foo_2", 2), NC("foo_3", 3), + NC("foo_4", 4), NC("foo_5", 5))); + + Group grp = {"id", Kid::Jim(), 4.2, 42}; + EXPECT_EQ(grp, grp); + for (size_t i = 0; i < 10; ++i) { + EXPECT_EQ(c.grpv(grp), V::Frank("frank")); + } + EXPECT_EQ(c.nothing(), V::Nothing(hobbes::unit())); + + Groups ros = {{"group_0", Kid::Jim(), 0.0, 0}, + {"group_1", Kid::Jim(), 1.0, 1}, + {"group_2", Kid::Jim(), 2.0, 2}, + {"group_3", Kid::Jim(), 3.0, 3}, + {"group_4", Kid::Jim(), 4.0, 4}}; + EXPECT_EQ(c.recover(0, 4), ros); + + EXPECT_EQ(c.eidv(CustomIDEnum::Green), CustomIDEnum::Green); + + auto inv = c.inverse(RGB{{0, 255, 0}}); + EXPECT_EQ(std::vector(inv.val, inv.val + 3), + std::vector({255, 0, 255})); +} + +TEST(Net, syncClientAPIWithUnConfiguredHostName) { + SyncClient c("localhost", testServerWithHostPort()); + EXPECT_EQ(c.add(1, 2), 3); + EXPECT_EQ(c.doit(), "missiles launched"); + EXPECT_EQ(c.misc("foo", 5), + list(NC("foo_0", 0), NC("foo_1", 1), NC("foo_2", 2), NC("foo_3", 3), + NC("foo_4", 4), NC("foo_5", 5))); + + Group grp = {"id", Kid::Jim(), 4.2, 42}; + EXPECT_EQ(grp, grp); + for (size_t i = 0; i < 10; ++i) { + EXPECT_EQ(c.grpv(grp), V::Frank("frank")); + } + EXPECT_EQ(c.nothing(), V::Nothing(hobbes::unit())); + + Groups ros = {{"group_0", Kid::Jim(), 0.0, 0}, + {"group_1", Kid::Jim(), 1.0, 1}, + {"group_2", Kid::Jim(), 2.0, 2}, + {"group_3", Kid::Jim(), 3.0, 3}, + {"group_4", Kid::Jim(), 4.0, 4}}; + EXPECT_EQ(c.recover(0, 4), ros); + + EXPECT_EQ(c.eidv(CustomIDEnum::Green), CustomIDEnum::Green); + + auto inv = c.inverse(RGB{{0, 255, 0}}); + EXPECT_EQ(std::vector(inv.val, inv.val + 3), + std::vector({255, 0, 255})); +} /************************** * the asynchronous client networking API **************************/ DEFINE_ASYNC_NET_CLIENT( - AsyncClient, - (add, int(int,int), "\\x y.x+y"), - (doit, std::string(), "\\().\"missiles launched\""), - (misc, NameCounts(std::string,size_t), "\\n c.[(n++\"_\"++show(i), i) | i <- [0L..c]]"), - (grpv, V(Group), "\\_.|Frank=\"frank\"|"), - (nothing, V(), "\\().|Nothing=()|"), - (recover, Groups(int,int), "\\i e.[{id=\"group_\"++show(k),kid=|Jim|,aa=convert(k),bb=convert(k)}|k<-[i..e]]"), - (eidv, CustomIDEnum(CustomIDEnum), "id"), - (inverse, RGB(RGB), "\\x.do{saelem(x.val,0L)<-255-saelem(x.val,0L);saelem(x.val,1L)<-255-saelem(x.val,1L);saelem(x.val,2L)<-255-saelem(x.val,2L); return x}") -); -void stepAsyncClient(int, void* p) { reinterpret_cast(p)->step(); } + AsyncClient, (add, int(int, int), "\\x y.x+y"), + (doit, std::string(), "\\().\"missiles launched\""), + (misc, NameCounts(std::string, size_t), + "\\n c.[(n++\"_\"++show(i), i) | i <- [0L..c]]"), + (grpv, V(Group), "\\_.|Frank=\"frank\"|"), + (nothing, V(), "\\().|Nothing=()|"), + (recover, Groups(int, int), + "\\i " + "e.[{id=\"group_\"++show(k),kid=|Jim|,aa=convert(k),bb=convert(k)}|k<-[i.." + "e]]"), + (eidv, CustomIDEnum(CustomIDEnum), "id"), + (inverse, RGB(RGB), + "\\x.do{saelem(x.val,0L)<-255-saelem(x.val,0L);saelem(x.val,1L)<-255-" + "saelem(x.val,1L);saelem(x.val,2L)<-255-saelem(x.val,2L); return x}")); +void stepAsyncClient(int, void *p) { + reinterpret_cast(p)->step(); +} TEST(Net, asyncClientAPI) { AsyncClient c("127.0.0.1", "127.0.0.1", testServerPort()); - c.add(1,2, [](int r) { EXPECT_EQ(r, 3); }); - c.doit([](const std::string& r) { EXPECT_EQ(r, "missiles launched") }); - c.misc("foo", 5, [](const NameCounts& ncs) { EXPECT_EQ(ncs, list(NC("foo_0",0),NC("foo_1",1),NC("foo_2",2),NC("foo_3",3),NC("foo_4",4),NC("foo_5",5))); }); + c.add(1, 2, [](int r) { EXPECT_EQ(r, 3); }); + c.doit([](const std::string &r) { EXPECT_EQ(r, "missiles launched") }); + c.misc("foo", 5, [](const NameCounts &ncs) { + EXPECT_EQ(ncs, list(NC("foo_0", 0), NC("foo_1", 1), NC("foo_2", 2), + NC("foo_3", 3), NC("foo_4", 4), NC("foo_5", 5))); + }); - Group grp = { "id", Kid::Jim(), 4.2, 42 }; + Group grp = {"id", Kid::Jim(), 4.2, 42}; for (size_t i = 0; i < 1000; ++i) { - c.grpv(grp, [](const V& r) { EXPECT_EQ(r, V::Frank("frank")); }); - c.nothing([](const V& r ) { EXPECT_EQ(r, V::Nothing(hobbes::unit())); }); + c.grpv(grp, [](const V &r) { EXPECT_EQ(r, V::Frank("frank")); }); + c.nothing([](const V &r) { EXPECT_EQ(r, V::Nothing(hobbes::unit())); }); } - Groups ros = { {"group_0",Kid::Jim(),0.0,0},{"group_1",Kid::Jim(),1.0,1},{"group_2",Kid::Jim(),2.0,2},{"group_3",Kid::Jim(),3.0,3},{"group_4",Kid::Jim(),4.0,4} }; - c.recover(0,4, [&](const Groups& r) { EXPECT_EQ(r, ros); }); - - c.eidv(CustomIDEnum::Green, [](const CustomIDEnum& x) { EXPECT_EQ(x, CustomIDEnum::Green); }); + Groups ros = {{"group_0", Kid::Jim(), 0.0, 0}, + {"group_1", Kid::Jim(), 1.0, 1}, + {"group_2", Kid::Jim(), 2.0, 2}, + {"group_3", Kid::Jim(), 3.0, 3}, + {"group_4", Kid::Jim(), 4.0, 4}}; + c.recover(0, 4, [&](const Groups &r) { EXPECT_EQ(r, ros); }); + + c.eidv(CustomIDEnum::Green, + [](const CustomIDEnum &x) { EXPECT_EQ(x, CustomIDEnum::Green); }); - c.inverse(RGB{{0,255,0}}, [](const RGB& inv) { EXPECT_EQ(std::vector(inv.val,inv.val+3), std::vector({255,0,255})); }); + c.inverse(RGB{{0, 255, 0}}, [](const RGB &inv) { + EXPECT_EQ(std::vector(inv.val, inv.val + 3), + std::vector({255, 0, 255})); + }); - // run a quick epoll loop to process results asynchronously (expect all results within 30 seconds) + // run a quick epoll loop to process results asynchronously (expect all + // results within 30 seconds) registerEventHandler(c.fd(), &stepAsyncClient, &c); for (size_t s = 0; s < 30 && c.pendingRequests() > 0; ++s) { - runEventLoop(1000*1000); + runEventLoop(1000 * 1000); } EXPECT_EQ(c.pendingRequests(), size_t(0)); } +TEST(Net, asyncClientAPIWithConfiguredHostName) { + AsyncClient c("127.0.0.1", "127.0.0.1", testServerWithHostPort("127.0.0.1")); + c.add(1, 2, [](int r) { EXPECT_EQ(r, 3); }); + c.doit([](const std::string &r) { EXPECT_EQ(r, "missiles launched") }); + c.misc("foo", 5, [](const NameCounts &ncs) { + EXPECT_EQ(ncs, list(NC("foo_0", 0), NC("foo_1", 1), NC("foo_2", 2), + NC("foo_3", 3), NC("foo_4", 4), NC("foo_5", 5))); + }); + + Group grp = {"id", Kid::Jim(), 4.2, 42}; + for (size_t i = 0; i < 1000; ++i) { + c.grpv(grp, [](const V &r) { EXPECT_EQ(r, V::Frank("frank")); }); + c.nothing([](const V &r) { EXPECT_EQ(r, V::Nothing(hobbes::unit())); }); + } + + Groups ros = {{"group_0", Kid::Jim(), 0.0, 0}, + {"group_1", Kid::Jim(), 1.0, 1}, + {"group_2", Kid::Jim(), 2.0, 2}, + {"group_3", Kid::Jim(), 3.0, 3}, + {"group_4", Kid::Jim(), 4.0, 4}}; + c.recover(0, 4, [&](const Groups &r) { EXPECT_EQ(r, ros); }); + + c.eidv(CustomIDEnum::Green, + [](const CustomIDEnum &x) { EXPECT_EQ(x, CustomIDEnum::Green); }); + + c.inverse(RGB{{0, 255, 0}}, [](const RGB &inv) { + EXPECT_EQ(std::vector(inv.val, inv.val + 3), + std::vector({255, 0, 255})); + }); + + // run a quick epoll loop to process results asynchronously (expect all + // results within 30 seconds) + registerEventHandler(c.fd(), &stepAsyncClient, &c); + for (size_t s = 0; s < 30 && c.pendingRequests() > 0; ++s) { + runEventLoop(1000 * 1000); + } + EXPECT_EQ(c.pendingRequests(), size_t(0)); +} + +TEST(Net, asyncClientAPIWithUnConfiguredHostName) { + AsyncClient c("127.0.0.1", "127.0.0.1", testServerWithHostPort()); + c.add(1, 2, [](int r) { EXPECT_EQ(r, 3); }); + c.doit([](const std::string &r) { EXPECT_EQ(r, "missiles launched") }); + c.misc("foo", 5, [](const NameCounts &ncs) { + EXPECT_EQ(ncs, list(NC("foo_0", 0), NC("foo_1", 1), NC("foo_2", 2), + NC("foo_3", 3), NC("foo_4", 4), NC("foo_5", 5))); + }); + + Group grp = {"id", Kid::Jim(), 4.2, 42}; + for (size_t i = 0; i < 1000; ++i) { + c.grpv(grp, [](const V &r) { EXPECT_EQ(r, V::Frank("frank")); }); + c.nothing([](const V &r) { EXPECT_EQ(r, V::Nothing(hobbes::unit())); }); + } + + Groups ros = {{"group_0", Kid::Jim(), 0.0, 0}, + {"group_1", Kid::Jim(), 1.0, 1}, + {"group_2", Kid::Jim(), 2.0, 2}, + {"group_3", Kid::Jim(), 3.0, 3}, + {"group_4", Kid::Jim(), 4.0, 4}}; + c.recover(0, 4, [&](const Groups &r) { EXPECT_EQ(r, ros); }); + + c.eidv(CustomIDEnum::Green, + [](const CustomIDEnum &x) { EXPECT_EQ(x, CustomIDEnum::Green); }); + + c.inverse(RGB{{0, 255, 0}}, [](const RGB &inv) { + EXPECT_EQ(std::vector(inv.val, inv.val + 3), + std::vector({255, 0, 255})); + }); + + // run a quick epoll loop to process results asynchronously (expect all + // results within 30 seconds) + registerEventHandler(c.fd(), &stepAsyncClient, &c); + for (size_t s = 0; s < 30 && c.pendingRequests() > 0; ++s) { + runEventLoop(1000 * 1000); + } + EXPECT_EQ(c.pendingRequests(), size_t(0)); +} From 18850bcd787c849ec0d9c4c2c33d178c9726a0c1 Mon Sep 17 00:00:00 2001 From: Mo Xiaoming <2188767+mo-xiaoming@users.noreply.github.com> Date: Wed, 16 Jun 2021 09:22:07 +0000 Subject: [PATCH 03/40] add language option "IgnoreUnreachableMatches" (#408) --- bin/hi/evaluator.C | 18 +++++++++++++++++- include/hobbes/eval/cc.H | 17 ++++++++++++++--- lib/hobbes/eval/cc.C | 9 +++++++-- lib/hobbes/eval/cmodule.C | 5 +++++ lib/hobbes/lang/module.C | 2 +- lib/hobbes/lang/pat/dfa.C | 19 ++++++------------- test/Main.C | 4 ++-- test/Matching.C | 23 +++++++++++++++-------- 8 files changed, 67 insertions(+), 30 deletions(-) diff --git a/bin/hi/evaluator.C b/bin/hi/evaluator.C index 308ececee..6d944187d 100644 --- a/bin/hi/evaluator.C +++ b/bin/hi/evaluator.C @@ -12,6 +12,12 @@ #include #include +namespace { +void defPrintUnreachableMatches(const hobbes::cc::UnreachableMatches& m) { + std::cout << "warning: " << m.la.filename() << ':' << m.la.lineDesc() << " " << m.lines << std::endl; +} +} // namespace + namespace hi { // allocate a string in global memory @@ -65,11 +71,17 @@ evaluator::evaluator(const Args& args) : silent(args.silent), wwwd(0), opts(args bindArguments(this->ctx, args.scriptNameVals); bindHiDefs(this->ctx); + const bool ignoreUM = (std::find(opts.cbegin(), opts.cend(), std::string("IgnoreUnreachableMatches")) != opts.cend()); + this->ctx.ignoreUnreachableMatches(ignoreUM); + if (ignoreUM) { + this->ctx.setGatherUnreachableMatchesFn(defPrintUnreachableMatches); + } + // start alternate input services if necessary if (args.replPort > 0) { installNetREPL(args.replPort, &this->ctx, [this](ExprPtr const& e) -> ExprPtr { return hobbes::translateExprWithOpts(this->opts, e); }); } - + if (args.httpdPort > 0) { // run a local web server (for diagnostics and alternate queries) if requested this->wwwd = new WWWServer(args.httpdPort, &this->ctx); @@ -314,6 +326,10 @@ void evaluator::searchDefs(const std::string& expr_to_type) { void evaluator::setOption(const std::string& o) { this->opts.push_back(o); + if (o == "IgnoreUnreachableMatches") { + this->ctx.ignoreUnreachableMatches(true); + this->ctx.setGatherUnreachableMatchesFn(defPrintUnreachableMatches); + } } hobbes::ExprPtr evaluator::readExpr(const std::string& x) { diff --git a/include/hobbes/eval/cc.H b/include/hobbes/eval/cc.H index b786142ea..1982f9946 100644 --- a/include/hobbes/eval/cc.H +++ b/include/hobbes/eval/cc.H @@ -101,6 +101,14 @@ public: MonoTypePtr readMonoType(const std::string&); void setReadExprFn(readExprFn); + struct UnreachableMatches { + LexicalAnnotation la; + std::string lines; + }; + typedef void (*gatherUnreachableMatchesFn)(const UnreachableMatches&); + void gatherUnreachableMatches(const UnreachableMatches& m); + void setGatherUnreachableMatchesFn(gatherUnreachableMatchesFn f); + // search for paths from one type to another // (currently just one-step paths, may be useful to consider multi-step paths) SearchEntries search(const MonoTypePtr&, const MonoTypePtr&); @@ -113,6 +121,9 @@ private: readModuleFn readModuleF; readExprDefnFn readExprDefnF; readExprFn readExprF; + + gatherUnreachableMatchesFn gatherUnreachableMatchesF = [](const UnreachableMatches&){}; + public: // type-safe compilation to C++ function pointers template @@ -250,6 +261,8 @@ public: bool buildInterpretedMatches() const; void requireMatchReachability(bool f); bool requireMatchReachability() const; + void ignoreUnreachableMatches(bool f); + bool ignoreUnreachableMatches() const; void alwaysLowerPrimMatchTables(bool); bool alwaysLowerPrimMatchTables() const; void buildColumnwiseMatches(bool f); @@ -261,9 +274,6 @@ public: void regexDFAOverNFAMaxRatio(int f); int regexDFAOverNFAMaxRatio() const; - // allow caller to gather a vector of unreachable rows arising from match compilation - UnreachableMatchRowsPtr unreachableMatchRowsPtr; - // allow low-level functions to be added void bindLLFunc(const std::string&, op*); @@ -290,6 +300,7 @@ private: bool runModInlinePass; bool genInterpretedMatch; bool checkMatchReachability; + bool ignoreUnreachablePatternMatchRows = false; bool lowerPrimMatchTables; bool columnwiseMatches; size_t maxExprDFASize={1000}; diff --git a/lib/hobbes/eval/cc.C b/lib/hobbes/eval/cc.C index 126c83099..03a736179 100644 --- a/lib/hobbes/eval/cc.C +++ b/lib/hobbes/eval/cc.C @@ -44,7 +44,6 @@ cc::cc() : readExprDefnF(&defReadExprDefn), readExprF(&defReadExpr), drainingDefs(false), - unreachableMatchRowsPtr(nullptr), runModInlinePass(true), genInterpretedMatch(false), checkMatchReachability(true), @@ -165,6 +164,9 @@ MonoTypePtr cc::readMonoType(const std::string& x) { } } +void cc::gatherUnreachableMatches(const UnreachableMatches& m) { hlock _; this->gatherUnreachableMatchesF(m); } +void cc::setGatherUnreachableMatchesFn(gatherUnreachableMatchesFn f) { this->gatherUnreachableMatchesF = f; } + ExprPtr cc::unsweetenExpression(const TEnvPtr& te, const ExprPtr& e) { return unsweetenExpression(te, "", e); } @@ -655,6 +657,9 @@ bool cc::buildInterpretedMatches() const { return this->genInterpretedMatch; } void cc::requireMatchReachability(bool f) { this->checkMatchReachability = f; } bool cc::requireMatchReachability() const { return this->checkMatchReachability; } +void cc::ignoreUnreachableMatches(bool f) { this->ignoreUnreachablePatternMatchRows = f; } +bool cc::ignoreUnreachableMatches() const { return this->ignoreUnreachablePatternMatchRows; } + void cc::alwaysLowerPrimMatchTables(bool f) { this->lowerPrimMatchTables = f; } bool cc::alwaysLowerPrimMatchTables() const { return this->lowerPrimMatchTables; } @@ -663,7 +668,7 @@ bool cc::buildColumnwiseMatches() const { return this->columnwiseMatches; } void cc::regexMaxExprDFASize(size_t f) { this->maxExprDFASize = f; } size_t cc::regexMaxExprDFASize() const { return this->maxExprDFASize; } - + void cc::throwOnHugeRegexDFA(bool f) { this->shouldThrowOnHugeRegexDFA = f; } bool cc::throwOnHugeRegexDFA() const { return this-> shouldThrowOnHugeRegexDFA; } diff --git a/lib/hobbes/eval/cmodule.C b/lib/hobbes/eval/cmodule.C index 368decb38..47f879e0e 100644 --- a/lib/hobbes/eval/cmodule.C +++ b/lib/hobbes/eval/cmodule.C @@ -1003,6 +1003,7 @@ OptDescs getAllOptions() { d["SafeArrays"] = "Interpret array indexing 'safely' (always bounds-checked and mapped to " "an optional type in case of out-of-bounds access)"; + d["IgnoreUnreachableMatches"] = "Ignore unreachable pattern match rows"; return d; } @@ -1029,6 +1030,10 @@ ExprPtr translateExprWithOpts( [](std::string const &, const ExprPtr &e) -> ExprPtr { return switchOf(e, makeSafeArrays()); }}, + {"IgnoreUnreachableMatches", + [](std::string const &, const ExprPtr &e) -> ExprPtr { + return e; + }}, }; thread_local auto ignoreFn = [](std::string const &optName, const ExprPtr &e) -> ExprPtr { diff --git a/lib/hobbes/lang/module.C b/lib/hobbes/lang/module.C index 1fa80d4b1..61476b017 100644 --- a/lib/hobbes/lang/module.C +++ b/lib/hobbes/lang/module.C @@ -20,7 +20,7 @@ void Module::show(std::ostream& out) const { } bool isValidOption(const std::string& o) { - return o == "Safe" || o == "SafeArrays"; + return o == "Safe" || o == "SafeArrays" || o == "IgnoreUnreachableMatches"; } void Module::setOption(const std::string& o, const LexicalAnnotation& la) { diff --git a/lib/hobbes/lang/pat/dfa.C b/lib/hobbes/lang/pat/dfa.C index d157ff832..5a18ae133 100644 --- a/lib/hobbes/lang/pat/dfa.C +++ b/lib/hobbes/lang/pat/dfa.C @@ -1133,29 +1133,22 @@ stateidx_t makeDFA(MDFA* dfa, const PatternRows& ps, const LexicalAnnotation& la std::vector unreachableRows; for (size_t r = 0; r < ps.size(); ++r) { size_t fs = finalStates[r]; - + if (dfa->states[fs]->refs == 0) { unreachableRows.push_back(r); } } - + if (unreachableRows.size() > 0) { std::ostringstream fss; fss << "Unreachable row" << (unreachableRows.size() > 1 ? "s" : "") << " in match expression:\n"; for (size_t ur : unreachableRows) { fss << " " << show(ps[ur]) << std::endl; } - throw annotated_error(la, fss.str()); - } - } - - // save unreachable rows for the caller instead of raising an error - if (dfa->c->unreachableMatchRowsPtr) { - for (size_t r = 0; r < ps.size(); ++r) { - size_t fs = finalStates[r]; - - if (dfa->states[fs]->refs == 0) { - dfa->c->unreachableMatchRowsPtr->push_back(std::make_pair(r, ps[r])); + if (dfa->c->ignoreUnreachableMatches()) { + dfa->c->gatherUnreachableMatches({.la = la, .lines = fss.str()}); + } else { + throw annotated_error(la, fss.str()); } } } diff --git a/test/Main.C b/test/Main.C index b6bf3177f..15b37ea50 100644 --- a/test/Main.C +++ b/test/Main.C @@ -75,7 +75,7 @@ int TestCoord::runTestGroups(const Args& args) { std::cout << "---------------------------------------------------------------------" << std::endl << hobbes::describeNanoTime(hobbes::tick()-tt0) << std::endl; - if (failures.size() > 0) { + if (!failures.empty()) { std::cout << "\n\nFAILURE" << (failures.size() == 1 ? "" : "S") << ":" << std::endl << "---------------------------------------------------------------------" << std::endl; for (const auto& failure : failures) { @@ -83,7 +83,7 @@ int TestCoord::runTestGroups(const Args& args) { } } - if (auto path = args.report) { + if (const auto* path = args.report) { std::ofstream outfile(path, std::ios::out | std::ios::trunc); if (outfile) { outfile << toJSON(); diff --git a/test/Matching.C b/test/Matching.C index 8a3e785a0..e3e9bfc8f 100644 --- a/test/Matching.C +++ b/test/Matching.C @@ -136,6 +136,11 @@ TEST(Matching, Regex) { } EXPECT_TRUE(unreachableExn && "failed to determine expected unreachable regex row"); + // verify unreachable rows should not cause error with IgnoreUnreachableMatches option on + c().ignoreUnreachableMatches(true); + EXPECT_EQ(c().compileFn("match \"foo123ooo\" with | '123|foo.*' -> 0 | 'foo.*' -> 1 | _ -> -1")(), 0); + c().ignoreUnreachableMatches(false); + // verify binding in regex matches EXPECT_EQ(makeStdString(c().compileFn*()>("match \"foobar\" with | 'f(?o*)bar' -> os | _ -> \"???\"")()), "oo"); @@ -163,7 +168,7 @@ TEST(Matching, Tests) { // make sure that tests with inaccessible names are rejected EXPECT_EXCEPTION(c().compileFn("\"JIMMY\" matches JIMMY")()); EXPECT_EXCEPTION(c().compileFn("[{x=just(\"JIMMY\")}] matches [{x=|1=JIMMY|}]")()); - + // make sure that tests with inaccessible _ names are allowed EXPECT_TRUE(c().compileFn("\"JIMMY\" matches _")()); EXPECT_TRUE(c().compileFn("[{x=just(\"JIMMY\")}] matches [{x=|1=_|}]")()); @@ -196,7 +201,7 @@ TEST(Matching, matchFromStringToBoolIsBool) { "| _ _ _ _ -> false" )(); EXPECT_TRUE(1 == *reinterpret_cast(&r)); - EXPECT_TRUE(r); + EXPECT_TRUE(r); } #endif @@ -210,7 +215,7 @@ TEST(Matching, matchFromIntToBoolIsBool) { "| _ _ _ _ -> false" ); EXPECT_TRUE(1 == *reinterpret_cast(&r)); - EXPECT_TRUE(r); + EXPECT_TRUE(r); } TEST(Matching, matchFromStringToIntIsCorrect) { @@ -223,7 +228,7 @@ TEST(Matching, matchFromStringToIntIsCorrect) { "| _ _ _ _ -> 0" )(); EXPECT_EQ(uint32_t(86), *reinterpret_cast(&r)); - EXPECT_TRUE(r); + EXPECT_TRUE(r); } TEST(Matching, largeRegexDFAFinishesReasonablyQuickly) { @@ -266,9 +271,9 @@ TEST(Matching, noRaceInterpMatch) { "| _ -> 2" ); size_t wrongMatches = 0; - std::vector ps; + std::vector ps; for (size_t p = 0; p < 10; ++p) { - ps.push_back(new std::thread(([&]() { + ps.emplace_back([&]() { auto t0 = tick(); while (wrongMatches == 0 && size_t(tick()-t0) < 1UL*1000*1000*1000) { if (f("foo") != 0) { @@ -279,9 +284,11 @@ TEST(Matching, noRaceInterpMatch) { } hobbes::resetMemoryPool(); } - }))); + }); + } + for (auto& p : ps) { + p.join(); } - for (auto p : ps) { p->join(); delete p; } EXPECT_EQ(wrongMatches, size_t(0)); c().buildInterpretedMatches(false); } From 36ea90b4d26432629415e10b5d3e8bf184d759d1 Mon Sep 17 00:00:00 2001 From: Mo Xiaoming <2188767+mo-xiaoming@users.noreply.github.com> Date: Sat, 19 Jun 2021 09:56:15 +0000 Subject: [PATCH 04/40] fix few typos in documentation (#405) --- doc/en/examples/simplerepl.rst | 6 +++--- doc/en/language/controlflow.rst | 4 ++-- doc/en/language/polymorphism.rst | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/en/examples/simplerepl.rst b/doc/en/examples/simplerepl.rst index 21f540fce..d59b1cac6 100755 --- a/doc/en/examples/simplerepl.rst +++ b/doc/en/examples/simplerepl.rst @@ -25,7 +25,7 @@ Here's the full code listing. Afterwards we'll dig into all the parts one by one typedef std::pair*> Writer; Writer* getWriter(){ - return hobbes::make(34, hobbes::makeString("Sam")); + return hobbes::make(34, hobbes::makeString("Sam")); } hobbes::array* getWriters(){ @@ -123,7 +123,7 @@ Binding custom datatypes (const hobbes::array*, name) ); - typedef std::pair*> Writer1; + typedef std::pair*> Writer; Writer* getWriter(){ return hobbes::make(34, hobbes::makeString("Sam")); @@ -186,7 +186,7 @@ Function pointers return pf(x, x); } -The basic mechanism by which work is abstracted, and how we can externalise behaviour from Hobbes - allowing us to interact with Hobbes functionality from outside the environment. In this case we expect ``binaryIntFn`` to be called with two items - firstly, a function which takes two ``int``s and returns an ``int``, and secondly an ``int``. +The basic mechanism by which work is abstracted, and how we can externalise behaviour from Hobbes - allowing us to interact with Hobbes functionality from outside the environment. In this case we expect ``binaryIntFn`` to be called with two items - firstly, a function which takes two ``int``\s and returns an ``int``, and secondly an ``int``. The result of the application of the function with the second argument twice is then returned to Hobbes as an ``int``. diff --git a/doc/en/language/controlflow.rst b/doc/en/language/controlflow.rst index d0b950404..c866c5764 100755 --- a/doc/en/language/controlflow.rst +++ b/doc/en/language/controlflow.rst @@ -138,7 +138,7 @@ This matching-and-binding logic can be generalised to arrays, too: :: match [("sam", 2013), ("james", 2012), ("stephen", 2010)] with - | [_ (n, 2012), _] -> show(n) + | [_, (n, 2012), _] -> show(n) | _ -> show("none") And, because of the way character arrays are matched, even to regular expressions: @@ -367,4 +367,4 @@ Finally, let's wrap all that up with a match and a for comprehension: :: > let start=1; end=4 in match [i | i <- [start..end], i % 2 == 0] with | [2, 4] -> "evens" | _ -> "odds" - evens \ No newline at end of file + evens diff --git a/doc/en/language/polymorphism.rst b/doc/en/language/polymorphism.rst index 54f221861..4f8ae0ba4 100755 --- a/doc/en/language/polymorphism.rst +++ b/doc/en/language/polymorphism.rst @@ -42,7 +42,7 @@ The types of the variables are left out, yet Hobbes will quite happily figure ou Hobbes has simply inferred this about those types from the context in which they're used. This is in stark contrast to languates where types are restricted on what interfaces they implement. -Many other type classes are available in the :ref:`Hobbes standard library `. We've already seen an implementation of the equivalence typeclass ``equiv``. Others include ``multiply`` (applied to types which have a ``*``) and ``print`` (for types whose values can be printed). +Many other type classes are available in the :ref:`Hobbes standard library `. We've already seen an implementation of the equivalence typeclass ``Equiv``. Others include ``Multiply`` (applied to types which have a ``*``) and ``Print`` (for types whose values can be printed). .. _type_annotations: @@ -120,4 +120,4 @@ We can take this one step further: Remember that, in our lambda syntax, this can be read as "A function which takes x and returns x.Name" - i.e. the only thing we know about the type of x is that it has a member called Name. Hi will then give names to those two as-yet unnamed types: it calls them 'a' and 'b'. -Note that Hobbes has inferred the type restriction on b: It's whatever type the value of "a.Name" is. This function will work for *any* type that has a member called ``Name``, which can be of any type! \ No newline at end of file +Note that Hobbes has inferred the type restriction on b: It's whatever type the value of "a.Name" is. This function will work for *any* type that has a member called ``Name``, which can be of any type! From 9bd8b61560bd08a45c0f2fca1b3ca4598c5f7638 Mon Sep 17 00:00:00 2001 From: Mo Xiaoming <2188767+mo-xiaoming@users.noreply.github.com> Date: Thu, 24 Jun 2021 03:26:32 +0000 Subject: [PATCH 05/40] fix missing nix logs when build fail (#409) --- .github/workflows/build.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 49b9e7fbc..2cea80578 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,8 +20,12 @@ jobs: - name: nix build hobbesPackages/clang-${{ matrix.clang }}/hobbes run: | nix build .#hobbesPackages/clang-${{ matrix.clang }}/hobbes + - name: nix log hobbesPackages/clang-${{ matrix.clang }}/hobbes + if: ${{ always() }} + run: | nix log .#hobbesPackages/clang-${{ matrix.clang }}/hobbes &> ${{ matrix.os }}-clang-${{ matrix.clang }}-hobbes.log - name: upload log ${{ matrix.os }}-clang-${{ matrix.clang }}-hobbes.log + if: ${{ always() }} uses: actions/upload-artifact@v1 with: name: output-log-file @@ -43,11 +47,15 @@ jobs: install_url: https://github.com/numtide/nix-flakes-installer/releases/download/nix-2.4pre20201221_9fab14a/install extra_nix_config: | experimental-features = nix-command flakes ca-references - - name: nix build hobbesPackages/clang-${{ matrix.clang }}/hobbes + - name: nix build hobbesPackages/gcc-${{ matrix.gcc }}/llvm-${{ matrix.llvm }}/hobbes run: | nix build .#hobbesPackages/gcc-${{ matrix.gcc }}/llvm-${{ matrix.llvm }}/hobbes + - name: nix log hobbesPackages/gcc-${{ matrix.gcc }}/llvm-${{ matrix.llvm }}/hobbes + if: ${{ always() }} + run: | nix log .#hobbesPackages/gcc-${{ matrix.gcc }}/llvm-${{ matrix.llvm }}/hobbes &> ${{ matrix.os }}-gcc-${{ matrix.gcc }}-llvm-${{ matrix.llvm }}-hobbes.log - name: upload log ${{ matrix.os }}-gcc-${{ matrix.gcc }}-llvm-${{ matrix.llvm }}-hobbes.log + if: ${{ always() }} uses: actions/upload-artifact@v1 with: name: output-log-file From ba35780ffe0025342c7a5025ab8d275db83060a8 Mon Sep 17 00:00:00 2001 From: Mo Xiaoming <2188767+mo-xiaoming@users.noreply.github.com> Date: Thu, 24 Jun 2021 05:28:48 +0000 Subject: [PATCH 06/40] Fixes #406 memory leak in varies addEliminator calls (#407) --- include/hobbes/ipc/process.H | 3 ++- include/hobbes/lang/preds/appendsto.H | 6 ++++-- include/hobbes/lang/preds/hasctor.H | 6 ++++-- include/hobbes/lang/preds/hasfield.H | 5 +++-- include/hobbes/lang/preds/subtype.H | 6 +++--- lib/hobbes/db/bindings.C | 2 +- lib/hobbes/db/signals.C | 2 +- lib/hobbes/eval/cc.C | 2 +- lib/hobbes/ipc/process.C | 7 ++++--- lib/hobbes/lang/preds/appendsto.C | 6 +++--- lib/hobbes/lang/preds/hasctor.C | 10 ++++++---- lib/hobbes/lang/preds/hasfield.C | 19 +++++++++---------- lib/hobbes/lang/preds/subtype.C | 4 ++-- 13 files changed, 43 insertions(+), 35 deletions(-) diff --git a/include/hobbes/ipc/process.H b/include/hobbes/ipc/process.H index 0fe22a3cc..e7cb621ac 100644 --- a/include/hobbes/ipc/process.H +++ b/include/hobbes/ipc/process.H @@ -5,6 +5,7 @@ #include #include #include +#include namespace hobbes { @@ -25,7 +26,7 @@ public: SymSet bindings () const; FunDeps dependencies(const ConstraintPtr&) const; private: - ProcManager procman; + std::shared_ptr procman{std::make_shared()}; }; } diff --git a/include/hobbes/lang/preds/appendsto.H b/include/hobbes/lang/preds/appendsto.H index 88879eb69..3fe8780c9 100644 --- a/include/hobbes/lang/preds/appendsto.H +++ b/include/hobbes/lang/preds/appendsto.H @@ -21,6 +21,8 @@ bool dec(const ConstraintPtr&, AppendsTo*); // an "appendsto eliminator" knows how to resolve an "AppendsTo" constraint at a particular (category of) type struct ATEliminator { + virtual ~ATEliminator() = default; + // is this AT instance eliminable? virtual bool satisfied(const TEnvPtr& tenv, const MonoTypePtr& lhs, const MonoTypePtr& rhs, const MonoTypePtr& result) const = 0; @@ -45,7 +47,7 @@ public: static std::string constraintName(); // extend the set of 'appendsto' eliminators dynamically (dangerous?) - void addEliminator(ATEliminator*); + void addEliminator(const std::shared_ptr&); // unqualifier interface bool refine(const TEnvPtr&,const ConstraintPtr&,MonoTypeUnifier*,Definitions*); @@ -57,7 +59,7 @@ public: SymSet bindings () const; FunDeps dependencies(const ConstraintPtr&) const; private: - typedef std::vector ATEliminators; + using ATEliminators = std::vector>; ATEliminators eliminators; ATEliminator* findEliminator(const TEnvPtr&, const AppendsTo*) const; diff --git a/include/hobbes/lang/preds/hasctor.H b/include/hobbes/lang/preds/hasctor.H index 6b9caf719..8660c4b4f 100644 --- a/include/hobbes/lang/preds/hasctor.H +++ b/include/hobbes/lang/preds/hasctor.H @@ -14,6 +14,8 @@ struct HasCtor { // a "has-ctor eliminator" knows how to resolve a "HasCtor" constraint at a particular (category of) type struct HCEliminator { + virtual ~HCEliminator() = default; + // is this HC instance eliminable? virtual bool satisfied(const TEnvPtr& tenv, const HasCtor&, Definitions*) const = 0; @@ -37,7 +39,7 @@ public: static std::string constraintName(); // extend the set of 'hasctor' eliminators dynamically (dangerous?) - void addEliminator(HCEliminator*); + void addEliminator(const std::shared_ptr&); // unqualifier interface bool refine(const TEnvPtr&,const ConstraintPtr&,MonoTypeUnifier*,Definitions*); @@ -49,7 +51,7 @@ public: SymSet bindings () const; FunDeps dependencies(const ConstraintPtr&) const; private: - typedef std::vector HCEliminators; + using HCEliminators = std::vector>; HCEliminators eliminators; HCEliminator* findEliminator(const TEnvPtr&, const HasCtor&, Definitions*) const; diff --git a/include/hobbes/lang/preds/hasfield.H b/include/hobbes/lang/preds/hasfield.H index 5492b366a..a474b4c2b 100644 --- a/include/hobbes/lang/preds/hasfield.H +++ b/include/hobbes/lang/preds/hasfield.H @@ -3,6 +3,7 @@ #define HOBBES_LANG_TYPEPREDS_HASFIELD_HPP_INCLUDED #include +#include namespace hobbes { @@ -56,7 +57,7 @@ public: static std::string constraintName(); // extend the set of 'hasfield' eliminators dynamically (dangerous?) - void addEliminator(HFEliminator*); + void addEliminator(const std::shared_ptr&); // unqualifier interface bool refine(const TEnvPtr&,const ConstraintPtr&,MonoTypeUnifier*,Definitions*); @@ -68,7 +69,7 @@ public: SymSet bindings () const; FunDeps dependencies(const ConstraintPtr&) const; private: - typedef std::vector HFEliminators; + using HFEliminators = std::vector>; HFEliminators eliminators; }; diff --git a/include/hobbes/lang/preds/subtype.H b/include/hobbes/lang/preds/subtype.H index 80586f386..8b5d431d0 100644 --- a/include/hobbes/lang/preds/subtype.H +++ b/include/hobbes/lang/preds/subtype.H @@ -15,7 +15,7 @@ bool dec(const ConstraintPtr&, Subtype*); // a "subtype eliminator" knows how to resolve a "Subtype" constraint at a particular (category of) type struct SubtypeEliminator { - virtual ~SubtypeEliminator(void) = default; + virtual ~SubtypeEliminator() = default; // is this instance eliminable? virtual bool satisfied(const TEnvPtr& tenv, const MonoTypePtr& lhs, const MonoTypePtr& rhs) const = 0; @@ -40,7 +40,7 @@ public: static std::string constraintName(); // extend the set of 'subtype' eliminators dynamically (dangerous?) - void addEliminator(SubtypeEliminator*); + void addEliminator(const std::shared_ptr&); // unqualifier interface bool refine(const TEnvPtr&,const ConstraintPtr&,MonoTypeUnifier*,Definitions*); @@ -52,7 +52,7 @@ public: SymSet bindings () const; FunDeps dependencies(const ConstraintPtr&) const; private: - typedef std::vector SubtypeEliminators; + using SubtypeEliminators = std::vector>; SubtypeEliminators eliminators; SubtypeEliminator* findEliminator(const TEnvPtr&, const Subtype&) const; diff --git a/lib/hobbes/db/bindings.C b/lib/hobbes/db/bindings.C index 9ff40cef3..a66fe61b5 100644 --- a/lib/hobbes/db/bindings.C +++ b/lib/hobbes/db/bindings.C @@ -1106,7 +1106,7 @@ void initStorageFileDefs(FieldVerifier* fv, cc& c) { c.typeEnv()->bind("LoadFile", UnqualifierPtr(new LoadFileP())); // resolve references to values stored in files - fv->addEliminator(new DBFieldLookup()); + fv->addEliminator(std::make_shared()); // read/write top-level values out-of/into a storage file c.bindLLFunc(".DBVLoad", new dbloadVF()); diff --git a/lib/hobbes/db/signals.C b/lib/hobbes/db/signals.C index e02c2f562..7c2ccdb92 100644 --- a/lib/hobbes/db/signals.C +++ b/lib/hobbes/db/signals.C @@ -525,7 +525,7 @@ void initSignalsDefs(FieldVerifier* fv, cc& c) { // add signals for top-level file variables c.bind(".addFileSOSignal", &addFileSOSignal); c.bindLLFunc("signals", new signalsF()); - fv->addEliminator(new AddDBFieldSignal()); + fv->addEliminator(std::make_shared()); c.bind(".addFileSignal", &addFileSignal); c.bindLLFunc("addFileSignal", new addFileSignalF()); diff --git a/lib/hobbes/eval/cc.C b/lib/hobbes/eval/cc.C index 03a736179..3fc8de528 100644 --- a/lib/hobbes/eval/cc.C +++ b/lib/hobbes/eval/cc.C @@ -92,7 +92,7 @@ cc::cc() : // support subtype constraints (including safe upcasting between C++ objects) SubtypeUnqualifier* subuq = new SubtypeUnqualifier(); - subuq->addEliminator(this->objs.get()); + subuq->addEliminator(this->objs); this->tenv->bind(SubtypeUnqualifier::constraintName(), UnqualifierPtr(subuq)); // support constraints on "field projection" (for records, "objects", ...) diff --git a/lib/hobbes/ipc/process.C b/lib/hobbes/ipc/process.C index a5113c81d..10dfd2e47 100644 --- a/lib/hobbes/ipc/process.C +++ b/lib/hobbes/ipc/process.C @@ -1,13 +1,14 @@ #include #include #include +#include namespace hobbes { #define PROCESS_SPAWN "spawn" ProcessP::ProcessP(FieldVerifier* fv) { - fv->addEliminator(&this->procman); + fv->addEliminator(this->procman); } static bool dec(const ConstraintPtr& c, MonoTypePtr* lhs, MonoTypePtr* rhs) { @@ -29,7 +30,7 @@ bool ProcessP::refine(const TEnvPtr&, const ConstraintPtr& cst, MonoTypeUnifier* MonoTypePtr cmdt, pidt; if (dec(cst, &cmdt, &pidt)) { if (const TString* cmd = is(cmdt)) { - mgu(pidt, mkPidTy(this->procman.spawnedPid(cmd->value())), u); + mgu(pidt, mkPidTy(this->procman->spawnedPid(cmd->value())), u); } } return uc != u->size(); @@ -40,7 +41,7 @@ bool ProcessP::satisfied(const TEnvPtr&, const ConstraintPtr& cst, Definitions*) if (dec(cst, &cmdt, &pidt)) { if (const TString* cmd = is(cmdt)) { if (const TLong* pid = pidTy(pidt)) { - return this->procman.isSpawnedPid(cmd->value(), pid->value()); + return this->procman->isSpawnedPid(cmd->value(), pid->value()); } } } diff --git a/lib/hobbes/lang/preds/appendsto.C b/lib/hobbes/lang/preds/appendsto.C index 1ed7b52a6..8bab3e614 100644 --- a/lib/hobbes/lang/preds/appendsto.C +++ b/lib/hobbes/lang/preds/appendsto.C @@ -23,21 +23,21 @@ bool dec(const ConstraintPtr& c, AppendsTo* r) { } AppendsToUnqualifier::AppendsToUnqualifier() { - addEliminator(new ATRecordEliminator()); + addEliminator(std::make_shared()); } std::string AppendsToUnqualifier::constraintName() { return "AppendsTo"; } -void AppendsToUnqualifier::addEliminator(ATEliminator* ate) { +void AppendsToUnqualifier::addEliminator(const std::shared_ptr& ate) { this->eliminators.push_back(ate); } ATEliminator* AppendsToUnqualifier::findEliminator(const TEnvPtr& tenv, const AppendsTo* at) const { for (ATEliminators::const_iterator ate = this->eliminators.begin(); ate != this->eliminators.end(); ++ate) { if ((*ate)->satisfiable(tenv, at->leftType, at->rightType, at->resultType)) { - return *ate; + return ate->get(); } } return 0; diff --git a/lib/hobbes/lang/preds/hasctor.C b/lib/hobbes/lang/preds/hasctor.C index 8a65eb351..f90272511 100644 --- a/lib/hobbes/lang/preds/hasctor.C +++ b/lib/hobbes/lang/preds/hasctor.C @@ -6,6 +6,8 @@ #include +#include + namespace hobbes { #define MSELECT_CTOR_FN "maybeFromCtor" @@ -14,21 +16,21 @@ namespace hobbes { // generic field verification and constraint removal ///////////////////////////////////////////////////// CtorVerifier::CtorVerifier() { - this->eliminators.push_back(new HCVariantEliminator()); + addEliminator(std::make_shared()); } std::string CtorVerifier::constraintName() { return "HasCtor"; } -void CtorVerifier::addEliminator(HCEliminator* hce) { +void CtorVerifier::addEliminator(const std::shared_ptr& hce) { this->eliminators.push_back(hce); } HCEliminator* CtorVerifier::findEliminator(const TEnvPtr& tenv, const HasCtor& hc, Definitions* ds) const { - for (auto hce : this->eliminators) { + for (const auto& hce : this->eliminators) { if (hce->satisfiable(tenv, hc, ds)) { - return hce; + return hce.get(); } } return 0; diff --git a/lib/hobbes/lang/preds/hasfield.C b/lib/hobbes/lang/preds/hasfield.C index 33fde9abd..1200e6346 100644 --- a/lib/hobbes/lang/preds/hasfield.C +++ b/lib/hobbes/lang/preds/hasfield.C @@ -53,13 +53,13 @@ std::string FieldVerifier::constraintName() { } FieldVerifier::FieldVerifier() { - this->eliminators.push_back(new HFRecordEliminator()); - this->eliminators.push_back(new HFSLookupEliminator()); - this->eliminators.push_back(new HFLookupEliminator()); - this->eliminators.push_back(new HFTEnvLookupEliminator()); + this->eliminators.push_back(std::make_shared()); + this->eliminators.push_back(std::make_shared()); + this->eliminators.push_back(std::make_shared()); + this->eliminators.push_back(std::make_shared()); } -void FieldVerifier::addEliminator(HFEliminator* hfe) { +void FieldVerifier::addEliminator(const std::shared_ptr& hfe) { this->eliminators.push_back(hfe); // a hacky way to make sure that the TEnv eliminator is the last one considered, since it's kind of a catch-all @@ -69,8 +69,7 @@ void FieldVerifier::addEliminator(HFEliminator* hfe) { bool FieldVerifier::refine(const TEnvPtr& tenv, const ConstraintPtr& cst, MonoTypeUnifier* s, Definitions* ds) { HasField hf; if (dec(cst, &hf)) { - for (size_t i = 0; i < this->eliminators.size(); ++i) { - auto hfe = this->eliminators[i]; + for (const auto& hfe : this->eliminators) { try { if (hfe->satisfiable(tenv, hf, ds) && hfe->refine(tenv, hf, s, ds)) { return true; @@ -85,7 +84,7 @@ bool FieldVerifier::refine(const TEnvPtr& tenv, const ConstraintPtr& cst, MonoTy bool FieldVerifier::satisfied(const TEnvPtr& tenv, const ConstraintPtr& cst, Definitions* ds) const { HasField hf; if (dec(cst, &hf)) { - for (auto hfe : this->eliminators) { + for (const auto& hfe : this->eliminators) { try { if (hfe->satisfied(tenv, hf, ds)) { return true; @@ -99,7 +98,7 @@ bool FieldVerifier::satisfied(const TEnvPtr& tenv, const ConstraintPtr& cst, Def bool FieldVerifier::satisfiable(const TEnvPtr& tenv, const ConstraintPtr& cst, Definitions* ds) const { HasField hf; if (dec(cst, &hf)) { - for (auto hfe : this->eliminators) { + for (const auto& hfe : this->eliminators) { try { if (hfe->satisfiable(tenv, hf, ds)) { return true; @@ -166,7 +165,7 @@ struct RewriteFnAccess : public switchExprTyFn { ExprPtr FieldVerifier::unqualify(const TEnvPtr& tenv, const ConstraintPtr& cst, const ExprPtr& e, Definitions* ds) const { HasField hf; if (dec(cst, &hf)) { - for (auto hfe : this->eliminators) { + for (const auto& hfe : this->eliminators) { try { if (hfe->satisfied(tenv, hf, ds)) { return hfe->unqualify(tenv, cst, switchOf(e, RewriteFnAccess(hf, *hfe, tenv, ds, cst)), ds); diff --git a/lib/hobbes/lang/preds/subtype.C b/lib/hobbes/lang/preds/subtype.C index 4e07c7125..1ab6db72e 100644 --- a/lib/hobbes/lang/preds/subtype.C +++ b/lib/hobbes/lang/preds/subtype.C @@ -23,14 +23,14 @@ std::string SubtypeUnqualifier::constraintName() { return "Subtype"; } -void SubtypeUnqualifier::addEliminator(SubtypeEliminator* e) { +void SubtypeUnqualifier::addEliminator(const std::shared_ptr& e) { this->eliminators.push_back(e); } SubtypeEliminator* SubtypeUnqualifier::findEliminator(const TEnvPtr& tenv, const Subtype& st) const { for (SubtypeEliminators::const_iterator e = this->eliminators.begin(); e != this->eliminators.end(); ++e) { if ((*e)->satisfiable(tenv, st.lower, st.greater)) { - return *e; + return e->get(); } } return 0; From 76bc9e4a3965eb5e5376495c23fc8f929416e707 Mon Sep 17 00:00:00 2001 From: Mo Xiaoming <2188767+mo-xiaoming@users.noreply.github.com> Date: Wed, 21 Jul 2021 16:41:29 +0000 Subject: [PATCH 07/40] make CMakeLists.txt work with user defined LLVM location (#411) --- CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bf24e5e55..00bde05dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ find_package(Curses REQUIRED) include_directories(${CURSES_INCLUDE_DIRS}) find_package(LLVM REQUIRED CONFIG) -include_directories(${LLVM_INCLUDE_DIRS}) +include_directories(SYSTEM ${LLVM_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) if (${LLVM_PACKAGE_VERSION} VERSION_LESS "10.0") @@ -29,7 +29,8 @@ else() set(jit_lib mcjit) endif() -find_program(llvm-config llvm-config PATHS ${LLVM_TOOLS_BINARY_DIR}) +find_program(llvm-config llvm-config PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH) +find_program(llvm-config llvm-config) if (${LLVM_PACKAGE_VERSION} VERSION_LESS "4.0") execute_process(COMMAND ${llvm-config} --libs x86 ipo ${jit_lib} OUTPUT_VARIABLE llvm_libs From 98933164814d78b10254d0b1018507bcf0f2b7a5 Mon Sep 17 00:00:00 2001 From: Providence Salumu Date: Thu, 22 Jul 2021 19:00:08 -0400 Subject: [PATCH 08/40] fix UB introduced by llvm-9+ (#413) * llvm: fix buggy UB introduced with llvm-9+ * c++: use C++-14 standard --- CMakeLists.txt | 6 +- include/hobbes/eval/cc.H | 420 +++++++++++++++++++---------------- include/hobbes/util/func.H | 162 +++++++------- nix/overlays.nix | 127 ++++++----- test/Matching.C | 437 +++++++++++++++++++++++-------------- 5 files changed, 673 insertions(+), 479 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 00bde05dc..2f811767a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,11 +17,7 @@ find_package(LLVM REQUIRED CONFIG) include_directories(SYSTEM ${LLVM_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) -if (${LLVM_PACKAGE_VERSION} VERSION_LESS "10.0") - set(CMAKE_CXX_STANDARD 11) -else() - set(CMAKE_CXX_STANDARD 14) -endif() +set(CMAKE_CXX_STANDARD 14) if (${LLVM_PACKAGE_VERSION} VERSION_LESS "3.6") set(jit_lib jit) diff --git a/include/hobbes/eval/cc.H b/include/hobbes/eval/cc.H index 1982f9946..18356b21b 100644 --- a/include/hobbes/eval/cc.H +++ b/include/hobbes/eval/cc.H @@ -2,80 +2,95 @@ #ifndef HOBBES_EVAL_CC_HPP_INCLUDED #define HOBBES_EVAL_CC_HPP_INCLUDED +#include +#include #include -#include +#include #include +#include #include -#include -#include #include +#include #include -#include -#include #include #include #include -#include +#include #include -#include #include -#include +#include #include +#include namespace hobbes { // protect access to hobbes/llvm resources between threads class hlock { public: - hlock(); ~hlock(); + hlock(); + ~hlock(); }; class phlock { public: phlock(); void release(); ~phlock(); + private: bool f; }; // parameter parsing for the 'compileFn' family of functions -typedef std::function ExprParser; +typedef std::function ExprParser; -template - struct PArgl { - }; -template <> - struct PArgl { - static str::seq names(const ExprPtr&) { return str::seq(); } - static ExprPtr expr(const ExprParser&, const ExprPtr& e) { return e; } - }; -template <> - struct PArgl { - static str::seq names(const std::string&) { return str::seq(); } - static ExprPtr expr(const ExprParser& p, const std::string& e) { return p(e); } - }; -template <> - struct PArgl { - static str::seq names(char*) { return str::seq(); } - static ExprPtr expr(const ExprParser& p, char* e) { return p(std::string(e)); } - }; -template <> - struct PArgl { - static str::seq names(const char*) { return str::seq(); } - static ExprPtr expr(const ExprParser& p, const char* e) { return p(std::string(e)); } - }; -template - struct PArgl { - static str::seq names(const char* x, const NamesAndExpr& ... args) { str::seq r = PArgl::names(args...); r.insert(r.begin(), std::string(x)); return r; } - static ExprPtr expr(const ExprParser& p, const char*, const NamesAndExpr& ... args) { return PArgl::expr(p, args...); } - }; -template - struct PArgl { - static str::seq names(const std::string& x, const NamesAndExpr& ... args) { str::seq r = PArgl::names(args...); r.insert(r.begin(), x); return r; } - static ExprPtr expr(const ExprParser& p, const std::string&, const NamesAndExpr& ... args) { return PArgl::expr(p, args...); } - }; +template struct PArgl {}; +template <> struct PArgl { + static str::seq names(const ExprPtr &) { return str::seq(); } + static ExprPtr expr(const ExprParser &, const ExprPtr &e) { return e; } +}; +template <> struct PArgl { + static str::seq names(const std::string &) { return str::seq(); } + static ExprPtr expr(const ExprParser &p, const std::string &e) { + return p(e); + } +}; +template <> struct PArgl { + static str::seq names(char *) { return str::seq(); } + static ExprPtr expr(const ExprParser &p, char *e) { + return p(std::string(e)); + } +}; +template <> struct PArgl { + static str::seq names(const char *) { return str::seq(); } + static ExprPtr expr(const ExprParser &p, const char *e) { + return p(std::string(e)); + } +}; +template +struct PArgl { + static str::seq names(const char *x, const NamesAndExpr &...args) { + str::seq r = PArgl::names(args...); + r.insert(r.begin(), std::string(x)); + return r; + } + static ExprPtr expr(const ExprParser &p, const char *, + const NamesAndExpr &...args) { + return PArgl::expr(p, args...); + } +}; +template struct PArgl { + static str::seq names(const std::string &x, const NamesAndExpr &...args) { + str::seq r = PArgl::names(args...); + r.insert(r.begin(), x); + return r; + } + static ExprPtr expr(const ExprParser &p, const std::string &, + const NamesAndExpr &...args) { + return PArgl::expr(p, args...); + } +}; // the main compiler class cc : public typedb { @@ -84,175 +99,205 @@ public: virtual ~cc(); // parse expressions - typedef ModulePtr (*readModuleFileFn)(cc*, const std::string&); - ModulePtr readModuleFile(const std::string&); + typedef ModulePtr (*readModuleFileFn)(cc *, const std::string &); + ModulePtr readModuleFile(const std::string &); void setReadModuleFileFn(readModuleFileFn); - typedef ModulePtr (*readModuleFn)(cc*, const std::string&); - ModulePtr readModule(const std::string&); + typedef ModulePtr (*readModuleFn)(cc *, const std::string &); + ModulePtr readModule(const std::string &); void setReadModuleFn(readModuleFn); - typedef std::pair (*readExprDefnFn)(cc*, const std::string&); - std::pair readExprDefn(const std::string&); + typedef std::pair (*readExprDefnFn)( + cc *, const std::string &); + std::pair readExprDefn(const std::string &); void setReadExprDefnFn(readExprDefnFn); - typedef ExprPtr (*readExprFn)(cc*, const std::string&); - ExprPtr readExpr(const std::string&); - MonoTypePtr readMonoType(const std::string&); + typedef ExprPtr (*readExprFn)(cc *, const std::string &); + ExprPtr readExpr(const std::string &); + MonoTypePtr readMonoType(const std::string &); void setReadExprFn(readExprFn); struct UnreachableMatches { LexicalAnnotation la; std::string lines; }; - typedef void (*gatherUnreachableMatchesFn)(const UnreachableMatches&); - void gatherUnreachableMatches(const UnreachableMatches& m); + typedef void (*gatherUnreachableMatchesFn)(const UnreachableMatches &); + void gatherUnreachableMatches(const UnreachableMatches &m); void setGatherUnreachableMatchesFn(gatherUnreachableMatchesFn f); // search for paths from one type to another // (currently just one-step paths, may be useful to consider multi-step paths) - SearchEntries search(const MonoTypePtr&, const MonoTypePtr&); - SearchEntries search(const ExprPtr&, const MonoTypePtr&); - SearchEntries search(const std::string&, const MonoTypePtr&); - SearchEntries search(const std::string&, const std::string&); + SearchEntries search(const MonoTypePtr &, const MonoTypePtr &); + SearchEntries search(const ExprPtr &, const MonoTypePtr &); + SearchEntries search(const std::string &, const MonoTypePtr &); + SearchEntries search(const std::string &, const std::string &); + private: // parser functions readModuleFileFn readModuleFileF; - readModuleFn readModuleF; - readExprDefnFn readExprDefnF; - readExprFn readExprF; + readModuleFn readModuleF; + readExprDefnFn readExprDefnF; + readExprFn readExprF; - gatherUnreachableMatchesFn gatherUnreachableMatchesF = [](const UnreachableMatches&){}; + gatherUnreachableMatchesFn gatherUnreachableMatchesF = + [](const UnreachableMatches &) {}; public: // type-safe compilation to C++ function pointers - template - typename func::type compileFn(NamesAndExpr ... args) { - static_assert(func::arity == sizeof...(NamesAndExpr)-1, "Formal parameter list and expected function type arity mismatch"); - return rcast::type>( - unsafeCompileFn( - lift::type(*this), - PArgl::names(args...), - PArgl::expr([&](const std::string& x){return this->readExpr(x);}, args...) - ) - ); - } + template + typename func::type compileFn(NamesAndExpr... args) { + static_assert( + func::arity == sizeof...(NamesAndExpr) - 1, + "Formal parameter list and expected function type arity mismatch"); + return rcast::type>(unsafeCompileFn( + lift::type(*this), PArgl::names(args...), + PArgl::expr( + [&](const std::string &x) { return this->readExpr(x); }, args...))); + } + + template + boolSafeFn compileSafeFn(NamesAndExpr &&...args) { + return {this->template compileFn(std::forward(args)...)}; + } // perform type-checking, explicit type annotation, and type class resolution - ExprPtr unsweetenExpression(const TEnvPtr& te, const ExprPtr& e); - ExprPtr unsweetenExpression(const TEnvPtr& te, const std::string& vname, const ExprPtr& e); - ExprPtr unsweetenExpression(const ExprPtr& e); - ExprPtr unsweetenExpression(const std::string& vname, const ExprPtr& e); - ExprPtr normalize(const ExprPtr& e); // unalias + unsweeten + ExprPtr unsweetenExpression(const TEnvPtr &te, const ExprPtr &e); + ExprPtr unsweetenExpression(const TEnvPtr &te, const std::string &vname, + const ExprPtr &e); + ExprPtr unsweetenExpression(const ExprPtr &e); + ExprPtr unsweetenExpression(const std::string &vname, const ExprPtr &e); + ExprPtr normalize(const ExprPtr &e); // unalias + unsweeten // access the LLVM resources - llvm::IRBuilder<>* builder() const; - llvm::Module* module() const; + llvm::IRBuilder<> *builder() const; + llvm::Module *module() const; // dump the contents of the active type environment (useful for debugging) - void dumpTypeEnv(std::function const& = [](std::string const& binding) -> std::string const& { return binding; }) const; - void dumpTypeEnv(str::seq* syms, str::seq* types, std::function const& = [](std::string const& binding) -> std::string const& { return binding; }) const; - std::string showTypeEnv(std::function const& = [](std::string const& binding) -> std::string const& { return binding; }) const; - - const TEnvPtr& typeEnv() const; + void + dumpTypeEnv(std::function const & = + [](std::string const &binding) -> std::string const & { + return binding; + }) const; + void dumpTypeEnv( + str::seq *syms, str::seq *types, + std::function const & = + [](std::string const &binding) -> std::string const & { + return binding; + }) const; + std::string + showTypeEnv(std::function const & = + [](std::string const &binding) -> std::string const & { + return binding; + }) const; + + const TEnvPtr &typeEnv() const; // forward-declare a variable binding - void forwardDeclare(const std::string& vname, const QualTypePtr& qt); + void forwardDeclare(const std::string &vname, const QualTypePtr &qt); // is a variable merely forward-declared, or does it have a definition? - bool hasValueBinding(const std::string& vname); - - // process and define a set of residual definitions produced by type unqualification + bool hasValueBinding(const std::string &vname); + + // process and define a set of residual definitions produced by type + // unqualification bool drainingDefs; LetRec::Bindings drainDefs; - void drainUnqualifyDefs(const Definitions& ds); + void drainUnqualifyDefs(const Definitions &ds); // compile an expression and associate it with a name - void define(const std::string& vname, const ExprPtr& e); - void define(const std::string& vname, const std::string& expr); + void define(const std::string &vname, const ExprPtr &e); + void define(const std::string &vname, const std::string &expr); // shorthand for class instance definitions for classes with 0 or 1 members - void overload(const std::string&, const MonoTypes&); - void overload(const std::string&, const MonoTypes&, const ExprPtr&); - void overload(const std::string&, const MonoTypes&, const std::string&); + void overload(const std::string &, const MonoTypes &); + void overload(const std::string &, const MonoTypes &, const ExprPtr &); + void overload(const std::string &, const MonoTypes &, const std::string &); - // add a type class instance to a known class (wrap up recursive unsweetening/def-draining) - void addInstance(const TClassPtr&, const TCInstancePtr&); + // add a type class instance to a known class (wrap up recursive + // unsweetening/def-draining) + void addInstance(const TClassPtr &, const TCInstancePtr &); // dump the contents of the generated module (useful for debugging) void dumpModule(); // get the x86 machine code for an expression (useful for debugging) typedef std::vector bytes; - bytes machineCodeForExpr(const std::string& expr); + bytes machineCodeForExpr(const std::string &expr); // keep track of C++ classes so that we can perform upcasts where necessary - template - void addObj() { - hlock _; - this->objs->add(); - } + template void addObj() { + hlock _; + this->objs->add(); + } // convenience method for lifting C++ types - template - PolyTypePtr liftType() { - hlock _; - return generalize(lift::type(*this)); - } + template PolyTypePtr liftType() { + hlock _; + return generalize(lift::type(*this)); + } - template - MonoTypePtr liftMonoType() { - return lift::type(*this); - } + template MonoTypePtr liftMonoType() { + return lift::type(*this); + } // bind a C++ value (be sure it stays in scope!) - void bind(const PolyTypePtr& tn, const std::string& vn, void* x); + void bind(const PolyTypePtr &tn, const std::string &vn, void *x); - template - void bind(const std::string& vn, T* x) { - hlock _; - bind(generalize(liftValue::type(*this, x)), vn, rcast(x)); - } + template void bind(const std::string &vn, T *x) { + hlock _; + bind(generalize(liftValue::type(*this, x)), vn, rcast(x)); + } - template - void bindArr(const std::string& vn, T x[N]) { - hlock _; - bind(polytype(qualtype(arrayty(lift::type(*this), N))), vn, rcast(x)); - } + template void bindArr(const std::string &vn, T x[N]) { + hlock _; + bind(polytype(qualtype(arrayty(lift::type(*this), N))), vn, + rcast(x)); + } // simplify binding user functions - template - void bind(const std::string& fn, R (*pfn)(Args...)) { - hlock _; - bindExternFunction(fn, lift::type(*this), rcast(pfn)); - } + template + void bind(const std::string &fn, R (*pfn)(Args...)) { + hlock _; + bindExternFunction(fn, lift::type(*this), rcast(pfn)); + } + private: - typedef std::pair TTyDef; + typedef std::pair TTyDef; typedef std::unordered_map TTyDefs; TTyDefs ttyDefs; + public: // allow the definition of transparent type aliases - // ("transparent" in the sense that all other aspects of compilation see the fully expanded type) - void defineTypeAlias(const std::string& name, const str::seq& argNames, const MonoTypePtr& ty); - bool isTypeAliasName(const std::string& name) const; - MonoTypePtr replaceTypeAliases(const MonoTypePtr& ty) const; + // ("transparent" in the sense that all other aspects of compilation see the + // fully expanded type) + void defineTypeAlias(const std::string &name, const str::seq &argNames, + const MonoTypePtr &ty); + bool isTypeAliasName(const std::string &name) const; + MonoTypePtr replaceTypeAliases(const MonoTypePtr &ty) const; // typedb interface - PolyTypePtr opaquePtrPolyType(const std::type_info& ti, unsigned int sz, bool inStruct); - MonoTypePtr opaquePtrMonoType(const std::type_info& ti, unsigned int sz, bool inStruct); + PolyTypePtr opaquePtrPolyType(const std::type_info &ti, unsigned int sz, + bool inStruct); + MonoTypePtr opaquePtrMonoType(const std::type_info &ti, unsigned int sz, + bool inStruct); - PolyTypePtr generalize(const MonoTypePtr& mt) const; + PolyTypePtr generalize(const MonoTypePtr &mt) const; - MonoTypePtr defineNamedType(const std::string& name, const str::seq& argNames, const MonoTypePtr& ty); - bool isTypeName(const std::string&) const; - MonoTypePtr namedTypeRepresentation(const std::string&) const; + MonoTypePtr defineNamedType(const std::string &name, const str::seq &argNames, + const MonoTypePtr &ty); + bool isTypeName(const std::string &) const; + MonoTypePtr namedTypeRepresentation(const std::string &) const; // an 'unsafe' compilation method - // (the compiled function will conform to the input type description, but this type structure will not be available to C++) - void* unsafeCompileFn(const MonoTypePtr& retTy, const str::seq& names, const MonoTypes& argTys, const ExprPtr& exp); - void* unsafeCompileFn(const MonoTypePtr& fnTy, const str::seq& names, const ExprPtr& exp); - void* unsafeCompileFn(const MonoTypePtr& fnTy, const str::seq& names, const std::string& exp); - void releaseMachineCode(void*); + // (the compiled function will conform to the input type description, but + // this type structure will not be available to C++) + void *unsafeCompileFn(const MonoTypePtr &retTy, const str::seq &names, + const MonoTypes &argTys, const ExprPtr &exp); + void *unsafeCompileFn(const MonoTypePtr &fnTy, const str::seq &names, + const ExprPtr &exp); + void *unsafeCompileFn(const MonoTypePtr &fnTy, const str::seq &names, + const std::string &exp); + void releaseMachineCode(void *); // compile/optimization options void enableModuleInlining(bool f); @@ -272,26 +317,29 @@ public: void throwOnHugeRegexDFA(bool f); bool throwOnHugeRegexDFA() const; void regexDFAOverNFAMaxRatio(int f); - int regexDFAOverNFAMaxRatio() const; + int regexDFAOverNFAMaxRatio() const; // allow low-level functions to be added - void bindLLFunc(const std::string&, op*); + void bindLLFunc(const std::string &, op *); // bind external functions - void bindExternFunction(const std::string& fname, const MonoTypePtr& fty, void* fn); + void bindExternFunction(const std::string &fname, const MonoTypePtr &fty, + void *fn); // allocate global data - void* memalloc(size_t, size_t); - - template - array* makeArray(size_t n) { - auto* r = reinterpret_cast*>(this->memalloc(sizeof(long) + (sizeof(T) * n), std::max(sizeof(long), alignof(T)))); - r->size = n; - if (r->size > 0) { - new (r->data) T[r->size]; - } - return r; + void *memalloc(size_t, size_t); + + template array *makeArray(size_t n) { + auto *r = reinterpret_cast *>( + this->memalloc(sizeof(long) + (sizeof(T) * n), + std::max(sizeof(long), alignof(T)))); + r->size = n; + if (r->size > 0) { + new (r->data) T[r->size]; } + return r; + } + private: // cache for expression search results SearchCache searchCache; @@ -303,61 +351,63 @@ private: bool ignoreUnreachablePatternMatchRows = false; bool lowerPrimMatchTables; bool columnwiseMatches; - size_t maxExprDFASize={1000}; - // abort compilation of regexes which translate into huge dfa transition states + size_t maxExprDFASize = {1000}; + // abort compilation of regexes which translate into huge dfa transition + // states bool shouldThrowOnHugeRegexDFA = false; - int dfaOverNfaMaxRatio = 4; + int dfaOverNfaMaxRatio = 4; // the bound root type-def environment typedef std::map TypeAliasMap; - TEnvPtr tenv; + TEnvPtr tenv; TypeAliasMap typeAliases; - PolyTypePtr lookupVarType(const std::string& vname) const; + PolyTypePtr lookupVarType(const std::string &vname) const; // global variables - void definePolyValue(const std::string& vname, const ExprPtr& unsweetExp); + void definePolyValue(const std::string &vname, const ExprPtr &unsweetExp); // track C++ object relationships ObjsPtr objs; // the JIT engine that compiles our monotyped expressions - jitcc* jit; + jitcc *jit; + public: // compiler-local type structure caches for internal use - std::unordered_map unappTyDefns; + std::unordered_map unappTyDefns; + private: // disable copying - cc(const cc&); - void operator=(const cc&); + cc(const cc &); + void operator=(const cc &); }; #define LIFTCTY(cc, e) (cc).liftMonoType() -template - struct rccF { - static T compile(cc*, const str::seq&, const std::string&) { - throw std::runtime_error("Internal error, unsupported compilation target type"); - } - }; - -template - struct rccF { - typedef R (*cbF)(Args...); - static cbF compile(cc* c, const str::seq& vns, const std::string& expr) { - return rcast(c->unsafeCompileFn(lift::type(*c), vns, expr)); - } - }; +template struct rccF { + static T compile(cc *, const str::seq &, const std::string &) { + throw std::runtime_error( + "Internal error, unsupported compilation target type"); + } +}; -template - T compileTo(cc* c, const str::seq& vns, const std::string& expr) { - return rccF::compile(c, vns, expr); +template struct rccF { + typedef R (*cbF)(Args...); + static cbF compile(cc *c, const str::seq &vns, const std::string &expr) { + return rcast(c->unsafeCompileFn(lift::type(*c), vns, expr)); } +}; +template +T compileTo(cc *c, const str::seq &vns, const std::string &expr) { + return rccF::compile(c, vns, expr); } +} // namespace hobbes + // support binding to C++ class member functions -#define memberfn(e) &hobbes::mfnThunk< decltype(e), decltype(e), e >::fn +#define memberfn(e) &hobbes::mfnThunk::fn #endif diff --git a/include/hobbes/util/func.H b/include/hobbes/util/func.H index 4c3b15ab2..869665225 100644 --- a/include/hobbes/util/func.H +++ b/include/hobbes/util/func.H @@ -2,80 +2,96 @@ #ifndef HOBBES_UTIL_FUNC_HPP_INCLUDED #define HOBBES_UTIL_FUNC_HPP_INCLUDED +#include "ptr.H" + namespace hobbes { -template - struct func { - }; - -template - struct func { - static const std::size_t arity = sizeof...(Args); - typedef R (*type)(Args...); - typedef R result_type; - }; - -template - struct func { - static const std::size_t arity = sizeof...(Args); - typedef R (*type)(Args...); - typedef R result_type; - }; - -template - struct func { - static const std::size_t arity = sizeof...(Args); - typedef R (*type)(C*, Args...); - typedef R result_type; - }; - -template - struct mfnTraits { - }; - -template - struct mfnTraits { - static const int arity = sizeof...(Args); - typedef R result_type; - typedef C class_type; - }; - -template - struct mfnTraits { - static const int arity = sizeof...(Args); - typedef R result_type; - typedef C class_type; - }; - -template - struct mfnThunk { - }; - -template - struct mfnThunk { - static R fn(C* c, Args... args) { - return (c->*f)(args...); - } - }; -template - struct mfnThunk { - static R fn(C* c, Args... args) { - return (c->*f)(args...); - } - }; -template - struct mfnThunk { - static void fn(C* c, Args... args) { - (c->*f)(args...); - } - }; -template - struct mfnThunk { - static void fn(C* c, Args... args) { - (c->*f)(args...); - } - }; - -} +template struct func {}; + +template struct func { + static const std::size_t arity = sizeof...(Args); + typedef R (*type)(Args...); + typedef R result_type; +}; + +template struct func { + static const std::size_t arity = sizeof...(Args); + typedef R (*type)(Args...); + typedef R result_type; +}; + +template +struct func { + static const std::size_t arity = sizeof...(Args); + typedef R (*type)(C *, Args...); + typedef R result_type; +}; + +template struct mfnTraits {}; + +template +struct mfnTraits { + static const int arity = sizeof...(Args); + typedef R result_type; + typedef C class_type; +}; + +template +struct mfnTraits { + static const int arity = sizeof...(Args); + typedef R result_type; + typedef C class_type; +}; + +template struct boolSafeFn : public func { + using Type = typename func::type; + Type fn = nullptr; + boolSafeFn(Type fn) : fn(fn) {} + template auto operator()(Args &&...args) -> decltype(auto) { + return fn(std::forward(args)...); + } +}; + +// smunix: avoid undefined behavior introduced by llvm-9+ +// https://godbolt.org/z/nWWT9jY63 +// https://bugs.llvm.org/show_bug.cgi?id=51163 + +template +struct boolSafeFn : public func { + using Type = typename func::type; + Type fn = nullptr; + boolSafeFn(Type fn) : fn(fn) {} + auto operator()(Args &&...args) -> decltype(auto) { + const bool r = (fn)(std::forward(args)...); + return (0x00 | *rcast(&r)); + } +}; + +template +struct boolSafeFn : public boolSafeFn { + using Type = typename func::type; + boolSafeFn(Type fn) : boolSafeFn(fn) {} +}; + +template struct mfnThunk {}; + +template +struct mfnThunk { + static R fn(C *c, Args... args) { return (c->*f)(args...); } +}; +template +struct mfnThunk { + static R fn(C *c, Args... args) { return (c->*f)(args...); } +}; +template +struct mfnThunk { + static void fn(C *c, Args... args) { (c->*f)(args...); } +}; +template +struct mfnThunk { + static void fn(C *c, Args... args) { (c->*f)(args...); } +}; + +} // namespace hobbes #endif diff --git a/nix/overlays.nix b/nix/overlays.nix index 3a2d1d3e3..813e97a95 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -1,82 +1,93 @@ -{ src, - version, - llvmVersions, - gccConstraints, - system, - debug ? false, -}: final: prev: +{ src, version, llvmVersions, gccConstraints, system, debug ? false, }: +final: prev: with final; let - dbg = if debug == true - then enableDebugging - else (x: x); - + dbg = if debug == true then enableDebugging else (x: x); + nativeBuildInputs = [ cmake ninja python27 ]; - + buildInputs = [ ncurses readline zlib python27 ]; - + doCheck = true; - + doTarget = "test"; - + dontStrip = debug; - + separateDebugInfo = debug; - + meta = with stdenv.lib; { description = "A language and an embedded JIT compiler"; longDescription = '' - Hobbes is a language, embedded compiler, and runtime for efficient - dynamic expression evalution, data storage and analysis. - ''; + Hobbes is a language, embedded compiler, and runtime for efficient + dynamic expression evalution, data storage and analysis. + ''; license = licenses.asl20; maintainers = with maintainers; [ kthielen thmzlt smunix ]; }; - darwinOnly = v : if system == "x86_64-darwin" then v else {}; + darwinOnly = v: if system == "x86_64-darwin" then v else { }; + + linuxOnly = v: if system == "x86_64-linux" then v else { }; + + when = c: m: if c then m else { }; - linuxOnly = v : if system == "x86_64-linux" then v else {}; - - when = c: m: if c then m else {}; - withGCC = { gccVersion ? 10 }: - let gccPkgs = { gccVersion }: builtins.getAttr ("gcc" + (toString gccVersion) + "Stdenv") final; - llvmPkgs = { llvmVersion }: builtins.getAttr ("llvmPackages_" + (toString llvmVersion)) final; - in makeOverridable ({ llvmVersion, stdenv ? (gccPkgs { inherit gccVersion; }) } : stdenv.mkDerivation { - pname = "hobbes-gcc-" + toString gccVersion + "-llvm-" + toString llvmVersion; - inherit version src meta doCheck doTarget dontStrip; - nativeBuildInputs = nativeBuildInputs; - buildInputs = buildInputs ++ [ (llvmPkgs { inherit llvmVersion; }).llvm ]; - postPatch = '' - substituteInPlace CMakeLists.txt \ - --replace "\''${CMAKE_SOURCE_DIR}" "${src}" - ''; - }); - - withCLANG = - let llvmPkgs = { llvmVersion }: builtins.getAttr ("llvmPackages_" + (toString llvmVersion)) final; - in makeOverridable ({ llvmVersion, stdenv ? (llvmPkgs { inherit llvmVersion; }).stdenv } : stdenv.mkDerivation { + let + gccPkgs = { gccVersion }: + builtins.getAttr ("gcc" + (toString gccVersion) + "Stdenv") final; + llvmPkgs = { llvmVersion }: + builtins.getAttr ("llvmPackages_" + (toString llvmVersion)) final; + in makeOverridable + ({ llvmVersion, stdenv ? (gccPkgs { inherit gccVersion; }) }: + stdenv.mkDerivation { + pname = "hobbes-gcc-" + toString gccVersion + "-llvm-" + + toString llvmVersion; + inherit version src meta doCheck doTarget dontStrip; + nativeBuildInputs = nativeBuildInputs; + buildInputs = buildInputs + ++ [ (llvmPkgs { inherit llvmVersion; }).llvm ]; + postPatch = '' + substituteInPlace CMakeLists.txt \ + --replace "\''${CMAKE_SOURCE_DIR}" "${src}" + ''; + }); + + withCLANG = let + llvmPkgs = { llvmVersion }: + builtins.getAttr ("llvmPackages_" + (toString llvmVersion)) final; + in makeOverridable + ({ llvmVersion, stdenv ? (llvmPkgs { inherit llvmVersion; }).stdenv }: + stdenv.mkDerivation { pname = "hobbes-clang-" + (toString llvmVersion); inherit version src meta doCheck doTarget dontStrip; nativeBuildInputs = nativeBuildInputs; buildInputs = buildInputs ++ [ (llvmPkgs { inherit llvmVersion; }).llvm ]; postPatch = '' - substituteInPlace CMakeLists.txt \ - --replace "\''${CMAKE_SOURCE_DIR}" "${src}" - ''; + substituteInPlace CMakeLists.txt \ + --replace "\''${CMAKE_SOURCE_DIR}" "${src}" + ''; }); -in { hobbesPackages = when stdenv.isLinux (recurseIntoAttrs (builtins.listToAttrs (builtins.map (gccConstraint: { - name = "gcc-" + toString gccConstraint.gccVersion; - value = recurseIntoAttrs (builtins.listToAttrs (builtins.map (llvmVersion: { - name = "llvm-" + toString llvmVersion; - value = recurseIntoAttrs ({ hobbes = dbg (callPackage (withGCC { inherit (gccConstraint) gccVersion; }) { inherit llvmVersion; }); }); - }) gccConstraint.llvmVersions)); - }) gccConstraints))) - // recurseIntoAttrs (builtins.listToAttrs ( - builtins.map - (llvmVersion: { name="clang-" + toString llvmVersion; - value = recurseIntoAttrs ({ hobbes = dbg (callPackage withCLANG { inherit llvmVersion; }); }); - }) - llvmVersions)); - } +in { + hobbesPackages = when stdenv.isLinux (recurseIntoAttrs (builtins.listToAttrs + (builtins.map (gccConstraint: { + name = "gcc-" + toString gccConstraint.gccVersion; + value = recurseIntoAttrs (builtins.listToAttrs (builtins.map + (llvmVersion: { + name = "llvm-" + toString llvmVersion; + value = recurseIntoAttrs ({ + hobbes = dbg + (callPackage (withGCC { inherit (gccConstraint) gccVersion; }) { + inherit llvmVersion; + }); + }); + }) gccConstraint.llvmVersions)); + }) gccConstraints))) // recurseIntoAttrs (builtins.listToAttrs (builtins.map + (llvmVersion: { + name = "clang-" + toString llvmVersion; + value = recurseIntoAttrs ({ + hobbes = dbg (callPackage withCLANG { inherit llvmVersion; }); + }); + }) llvmVersions)); +} diff --git a/test/Matching.C b/test/Matching.C index e3e9bfc8f..e5ece1fef 100644 --- a/test/Matching.C +++ b/test/Matching.C @@ -1,161 +1,287 @@ +#include "test.H" #include #include #include -#include "test.H" using namespace hobbes; -static cc& c() { static cc x; return x; } +static cc &c() { + static cc x; + return x; +} TEST(Matching, Basic) { - EXPECT_EQ(c().compileFn("match 1 2 with | 1 2 -> 1 | _ 2 -> 2 | _ _ -> 3")(), 1); - EXPECT_EQ(c().compileFn("match 2 2 with | 1 2 -> 1 | _ 2 -> 2 | _ _ -> 3")(), 2); - EXPECT_EQ(c().compileFn("match 2 3 with | 1 2 -> 1 | _ 2 -> 2 | _ _ -> 3")(), 3); - EXPECT_EQ(c().compileFn("match 2 9 with | 1 2 -> 1 | 2 x -> x | _ _ -> 3")(), 9); + EXPECT_EQ( + c().compileFn("match 1 2 with | 1 2 -> 1 | _ 2 -> 2 | _ _ -> 3")(), + 1); + EXPECT_EQ( + c().compileFn("match 2 2 with | 1 2 -> 1 | _ 2 -> 2 | _ _ -> 3")(), + 2); + EXPECT_EQ( + c().compileFn("match 2 3 with | 1 2 -> 1 | _ 2 -> 2 | _ _ -> 3")(), + 3); + EXPECT_EQ( + c().compileFn("match 2 9 with | 1 2 -> 1 | 2 x -> x | _ _ -> 3")(), + 9); EXPECT_EQ(c().compileFn("match (+) 1 2 with | f x y -> f(x,y)")(), 3); EXPECT_EQ(c().compileFn("let (x, y) = (1, 2) in x + y")(), 3); } TEST(Matching, Strings) { - EXPECT_EQ(c().compileFn("match \"foo\" with | \"fox\" -> 1 | \"for\" -> 2 | _ -> 3")(), 3); + EXPECT_EQ(c().compileFn( + "match \"foo\" with | \"fox\" -> 1 | \"for\" -> 2 | _ -> 3")(), + 3); // verify matching in std::string values (array matching should be overloaded) static std::string stdpatstr = "hello"; c().bind("stdpatstr", &stdpatstr); - EXPECT_EQ(c().compileFn("match stdpatstr with | \"hello\" -> 0 | _ -> 9")(), 0); - EXPECT_EQ(c().compileFn("match stdpatstr with | \"hell\" -> 0 | _ -> 9")(), 9); - - EXPECT_EQ(c().compileFn("match \"abc\" 2 with | _ 2 -> 1 | \"abc\" _ -> 2 | _ 3 -> 3 | _ _ -> 4")(), 1); - EXPECT_EQ(c().compileFn("match \"abc\" 3 with | _ 2 -> 1 | \"abc\" _ -> 2 | _ 3 -> 3 | _ _ -> 4")(), 2); - EXPECT_EQ(c().compileFn("match \"abd\" 3 with | _ 2 -> 1 | \"abc\" _ -> 2 | _ 3 -> 3 | _ _ -> 4")(), 3); - EXPECT_EQ(c().compileFn("match \"abd\" 4 with | _ 2 -> 1 | \"abc\" _ -> 2 | _ 3 -> 3 | _ _ -> 4")(), 4); - EXPECT_EQ( - c().compileFn( - "match \"abc\" \"three\" with | _ \"two\" -> 1 | \"abc\" _ -> 2 | _ \"three\" -> 3 | _ _ -> 4" - )(), - 2 - ); - - EXPECT_TRUE( - c().compileFn( - "let f = (\\x y z.match x y z with | \"aaa\" \"bbb\" _ -> 0 | \"aaa\" \"bbc\" \"ccc\" -> 1 | _ _ _ -> 2) :: ([char],[char],[char])->int in " - "(f(\"aaa\",\"bbb\",\"ccc\") == 0 and f(\"aaa\",\"bbc\",\"ccc\") == 1 and f(\"aaa\",\"bbc\",\"ccd\") == 2 and f(\"aba\",\"bbb\",\"ccdaa\") == 2)" - )() - ); + c().compileFn("match stdpatstr with | \"hello\" -> 0 | _ -> 9")(), + 0); + EXPECT_EQ( + c().compileFn("match stdpatstr with | \"hell\" -> 0 | _ -> 9")(), + 9); + + EXPECT_EQ(c().compileFn("match \"abc\" 2 with | _ 2 -> 1 | \"abc\" _ " + "-> 2 | _ 3 -> 3 | _ _ -> 4")(), + 1); + EXPECT_EQ(c().compileFn("match \"abc\" 3 with | _ 2 -> 1 | \"abc\" _ " + "-> 2 | _ 3 -> 3 | _ _ -> 4")(), + 2); + EXPECT_EQ(c().compileFn("match \"abd\" 3 with | _ 2 -> 1 | \"abc\" _ " + "-> 2 | _ 3 -> 3 | _ _ -> 4")(), + 3); + EXPECT_EQ(c().compileFn("match \"abd\" 4 with | _ 2 -> 1 | \"abc\" _ " + "-> 2 | _ 3 -> 3 | _ _ -> 4")(), + 4); EXPECT_EQ( - c().compileFn( - "((\\a b c.match a b c with | \"aaa\" \"bbb\" \"ccc\" -> 0 | \"aaa\" _ \"ccc\" -> 1 | _ _ _ -> -1) :: ([char],[char],[char]) -> int)(\"aaa\", \"ddd\", \"ccc\")" - )(), - 1 - ); + c().compileFn("match \"abc\" \"three\" with | _ \"two\" -> 1 | " + "\"abc\" _ -> 2 | _ \"three\" -> 3 | _ _ -> 4")(), + 2); + + EXPECT_TRUE(c().compileFn( + "let f = (\\x y z.match x y z with | \"aaa\" \"bbb\" _ -> 0 | \"aaa\" " + "\"bbc\" \"ccc\" -> 1 | _ _ _ -> 2) :: ([char],[char],[char])->int in " + "(f(\"aaa\",\"bbb\",\"ccc\") == 0 and f(\"aaa\",\"bbc\",\"ccc\") == 1 " + "and f(\"aaa\",\"bbc\",\"ccd\") == 2 and f(\"aba\",\"bbb\",\"ccdaa\") == " + "2)")()); + + EXPECT_EQ(c().compileFn( + "((\\a b c.match a b c with | \"aaa\" \"bbb\" \"ccc\" -> 0 | " + "\"aaa\" _ \"ccc\" -> 1 | _ _ _ -> -1) :: " + "([char],[char],[char]) -> int)(\"aaa\", \"ddd\", \"ccc\")")(), + 1); } TEST(Matching, Arrays) { - EXPECT_EQ(c().compileFn("match [1,2,3] with | [1,2,_] -> 1 | [1,2] -> 2 | _ -> 3")(), 1); - EXPECT_EQ(c().compileFn("match [[1],[2]] with | [_,[2]] -> 0 | [[1],_] -> 1 | _ -> 2")(), 0); - EXPECT_EQ(c().compileFn("match [[1],[3]] with | [_,[2]] -> 0 | [[1],_] -> 1 | _ -> 2")(), 1); - EXPECT_EQ(c().compileFn("match [[3],[3]] with | [_,[2]] -> 0 | [[1],_] -> 1 | _ -> 2")(), 2); + EXPECT_EQ(c().compileFn( + "match [1,2,3] with | [1,2,_] -> 1 | [1,2] -> 2 | _ -> 3")(), + 1); + EXPECT_EQ( + c().compileFn( + "match [[1],[2]] with | [_,[2]] -> 0 | [[1],_] -> 1 | _ -> 2")(), + 0); + EXPECT_EQ( + c().compileFn( + "match [[1],[3]] with | [_,[2]] -> 0 | [[1],_] -> 1 | _ -> 2")(), + 1); + EXPECT_EQ( + c().compileFn( + "match [[3],[3]] with | [_,[2]] -> 0 | [[1],_] -> 1 | _ -> 2")(), + 2); } TEST(Matching, Struct) { - EXPECT_EQ(c().compileFn("match (2,2) with | (1,2) -> 1 | (_,2) -> 2 | _ -> 3")(), 2); - EXPECT_EQ(c().compileFn("match ([1,2],\"foo\") 2 with | _ 1 -> 1 | ([3,4],_) _ -> 2 | ([_,2],\"foo\") 2 -> 3 | _ _ -> 4")(), 3); - - EXPECT_EQ(c().compileFn("match (\"abc\", 2) with | (_, 2) -> 1 | (\"abc\", _) -> 2 | (_, 3) -> 3 | _ -> 4")(), 1); - EXPECT_EQ(c().compileFn("match (\"abc\", 3) with | (_, 2) -> 1 | (\"abc\", _) -> 2 | (_, 3) -> 3 | _ -> 4")(), 2); - EXPECT_EQ(c().compileFn("match (\"abd\", 3) with | (_, 2) -> 1 | (\"abc\", _) -> 2 | (_, 3) -> 3 | _ -> 4")(), 3); - EXPECT_EQ(c().compileFn("match (\"abd\", 4) with | (_, 2) -> 1 | (\"abc\", _) -> 2 | (_, 3) -> 3 | _ -> 4")(), 4); + EXPECT_EQ(c().compileFn( + "match (2,2) with | (1,2) -> 1 | (_,2) -> 2 | _ -> 3")(), + 2); + EXPECT_EQ(c().compileFn( + "match ([1,2],\"foo\") 2 with | _ 1 -> 1 | ([3,4],_) _ -> 2 | " + "([_,2],\"foo\") 2 -> 3 | _ _ -> 4")(), + 3); + + EXPECT_EQ(c().compileFn("match (\"abc\", 2) with | (_, 2) -> 1 | " + "(\"abc\", _) -> 2 | (_, 3) -> 3 | _ -> 4")(), + 1); + EXPECT_EQ(c().compileFn("match (\"abc\", 3) with | (_, 2) -> 1 | " + "(\"abc\", _) -> 2 | (_, 3) -> 3 | _ -> 4")(), + 2); + EXPECT_EQ(c().compileFn("match (\"abd\", 3) with | (_, 2) -> 1 | " + "(\"abc\", _) -> 2 | (_, 3) -> 3 | _ -> 4")(), + 3); + EXPECT_EQ(c().compileFn("match (\"abd\", 4) with | (_, 2) -> 1 | " + "(\"abc\", _) -> 2 | (_, 3) -> 3 | _ -> 4")(), + 4); } TEST(Matching, Variant) { - EXPECT_EQ(c().compileFn("match (|0=(1,2,3)| :: (int*int*int)+int) with | |0=(x,y,z)| -> x+y+z | |1=y| -> y")(), 6); - EXPECT_EQ(c().compileFn("match (|bob=3|::|bob:int,frank:[char]|) with | |frank=_| -> 9 | _ -> 2")(), 2); - EXPECT_EQ(c().compileFn("match (|bob=3|::|bob:int,frank:[char]|) with | |bob=_| -> 9 | _ -> 2")(), 9); - - EXPECT_EQ(c().compileFn("match |foo=(\"abc\", 2)| with | |foo=(_, 2)| -> 1 | |foo=(\"abc\", _)| -> 2 | |foo=(_, 3)| -> 3 | |foo=_| -> 4")(), 1); - EXPECT_EQ(c().compileFn("match |foo=(\"abc\", 3)| with | |foo=(_, 2)| -> 1 | |foo=(\"abc\", _)| -> 2 | |foo=(_, 3)| -> 3 | |foo=_| -> 4")(), 2); - EXPECT_EQ(c().compileFn("match |foo=(\"abd\", 3)| with | |foo=(_, 2)| -> 1 | |foo=(\"abc\", _)| -> 2 | |foo=(_, 3)| -> 3 | |foo=_| -> 4")(), 3); - EXPECT_EQ(c().compileFn("match |foo=(\"abd\", 4)| with | |foo=(_, 2)| -> 1 | |foo=(\"abc\", _)| -> 2 | |foo=(_, 3)| -> 3 | |foo=_| -> 4")(), 4); + EXPECT_EQ(c().compileFn("match (|0=(1,2,3)| :: (int*int*int)+int) " + "with | |0=(x,y,z)| -> x+y+z | |1=y| -> y")(), + 6); + EXPECT_EQ(c().compileFn("match (|bob=3|::|bob:int,frank:[char]|) with " + "| |frank=_| -> 9 | _ -> 2")(), + 2); + EXPECT_EQ(c().compileFn("match (|bob=3|::|bob:int,frank:[char]|) with " + "| |bob=_| -> 9 | _ -> 2")(), + 9); + + EXPECT_EQ(c().compileFn( + "match |foo=(\"abc\", 2)| with | |foo=(_, 2)| -> 1 | " + "|foo=(\"abc\", _)| -> 2 | |foo=(_, 3)| -> 3 | |foo=_| -> 4")(), + 1); + EXPECT_EQ(c().compileFn( + "match |foo=(\"abc\", 3)| with | |foo=(_, 2)| -> 1 | " + "|foo=(\"abc\", _)| -> 2 | |foo=(_, 3)| -> 3 | |foo=_| -> 4")(), + 2); + EXPECT_EQ(c().compileFn( + "match |foo=(\"abd\", 3)| with | |foo=(_, 2)| -> 1 | " + "|foo=(\"abc\", _)| -> 2 | |foo=(_, 3)| -> 3 | |foo=_| -> 4")(), + 3); + EXPECT_EQ(c().compileFn( + "match |foo=(\"abd\", 4)| with | |foo=(_, 2)| -> 1 | " + "|foo=(\"abc\", _)| -> 2 | |foo=(_, 3)| -> 3 | |foo=_| -> 4")(), + 4); // ensure match preserves variant constructor order // and that unit matches drive type inference - EXPECT_EQ(c().compileFn("(\\v.match v with | |S|->0 | |F=x|->x)(|F=42|)")(), 42); + EXPECT_EQ( + c().compileFn("(\\v.match v with | |S|->0 | |F=x|->x)(|F=42|)")(), + 42); } TEST(Matching, Efficiency) { - // make sure that we don't produce insane code for reasonable pattern-match expressions - EXPECT_TRUE(c().machineCodeForExpr("(\\xs.match xs with | [1,2,3] -> 1 | [1,2,y] -> y | [] -> 9 | _ -> 10) :: [int] -> int").size() < 150); + // make sure that we don't produce insane code for reasonable pattern-match + // expressions + EXPECT_TRUE( + c().machineCodeForExpr("(\\xs.match xs with | [1,2,3] -> 1 | [1,2,y] -> " + "y | [] -> 9 | _ -> 10) :: [int] -> int") + .size() < 150); } TEST(Matching, Guards) { - EXPECT_EQ(c().compileFn("match 1 2 3 with | 1 2 3 -> 0 | 1 2 y where y < 5 -> 1 | _ _ _ -> 2")(), 0); - EXPECT_EQ(c().compileFn("match 1 2 4 with | 1 2 3 -> 0 | 1 2 y where y < 5 -> 1 | _ _ _ -> 2")(), 1); - EXPECT_EQ(c().compileFn("match 1 2 5 with | 1 2 3 -> 0 | 1 2 y where y < 5 -> 1 | _ _ _ -> 2")(), 2); - - EXPECT_EQ(c().compileFn("match 1 2 5 with | 1 2 3 -> 0 | 1 x y where (x + y) == 7 -> 1 | _ _ _ -> 2")(), 1); + EXPECT_EQ(c().compileFn("match 1 2 3 with | 1 2 3 -> 0 | 1 2 y where " + "y < 5 -> 1 | _ _ _ -> 2")(), + 0); + EXPECT_EQ(c().compileFn("match 1 2 4 with | 1 2 3 -> 0 | 1 2 y where " + "y < 5 -> 1 | _ _ _ -> 2")(), + 1); + EXPECT_EQ(c().compileFn("match 1 2 5 with | 1 2 3 -> 0 | 1 2 y where " + "y < 5 -> 1 | _ _ _ -> 2")(), + 2); + + EXPECT_EQ(c().compileFn("match 1 2 5 with | 1 2 3 -> 0 | 1 x y where " + "(x + y) == 7 -> 1 | _ _ _ -> 2")(), + 1); } TEST(Matching, Regex) { // verify basic regex patterns - EXPECT_EQ(c().compileFn("match \"foo\" with | 'fo*' -> 0 | _ -> 1")(), 0); - EXPECT_EQ(c().compileFn("match \"foo\" with | '(fo)*' -> 0 | _ -> 1")(), 1); - EXPECT_EQ(c().compileFn("match \"fofo\" with | '(fo)*' -> 0 | _ -> 1")(), 0); + EXPECT_EQ( + c().compileFn("match \"foo\" with | 'fo*' -> 0 | _ -> 1")(), 0); + EXPECT_EQ( + c().compileFn("match \"foo\" with | '(fo)*' -> 0 | _ -> 1")(), 1); + EXPECT_EQ( + c().compileFn("match \"fofo\" with | '(fo)*' -> 0 | _ -> 1")(), 0); // verify regex patterns within structures - EXPECT_EQ((c().compileFn("match (\"jimmy\", \"chicken\") with | ('jimmy*', 'ab*') -> 0 | _ -> 1")()), 1); - EXPECT_EQ((c().compileFn("match (\"jimmy\", \"chicken\") with | ('jimmy*', 'ab*') -> 0 | ('j*i*m*y*', 'chicken*') -> 42 | _ -> 1")()), 42); + EXPECT_EQ((c().compileFn("match (\"jimmy\", \"chicken\") with | " + "('jimmy*', 'ab*') -> 0 | _ -> 1")()), + 1); + EXPECT_EQ((c().compileFn( + "match (\"jimmy\", \"chicken\") with | ('jimmy*', 'ab*') -> 0 " + "| ('j*i*m*y*', 'chicken*') -> 42 | _ -> 1")()), + 42); // verify various features of regex syntax - EXPECT_EQ(c().compileFn("match \"aa\" with | 'a?a?' -> 0 | _ -> 1")(), 0); - EXPECT_EQ(c().compileFn("match \"aa\" with | 'a?\\\\' -> 0 | _ -> 1")(), 1); - EXPECT_EQ(c().compileFn("match \"a\\\\\" with | 'a?\\\\' -> 0 | _ -> 1")(), 0); - EXPECT_EQ(c().compileFn("match \"a\\n\" with | 'a?\\\\' -> 0 | _ -> 1")(), 1); - EXPECT_EQ(c().compileFn("match \"a\\n\" with | 'a?\\n' -> 0 | _ -> 1")(), 0); - EXPECT_EQ(c().compileFn("match \"a\\n\" with | '[a-z]\\n' -> 0 | _ -> 1")(), 0); - EXPECT_EQ(c().compileFn("match \"a\\n\" with | '[^a-z]\\n' -> 0 | _ -> 1")(), 1); - EXPECT_EQ(c().compileFn("match \"0\\n\" with | '[^a-z]\\n' -> 0 | _ -> 1")(), 0); - EXPECT_EQ(c().compileFn("match \"8675309\" with | '[0-9]+' -> 0 | _ -> 1")(), 0); + EXPECT_EQ(c().compileFn("match \"aa\" with | 'a?a?' -> 0 | _ -> 1")(), + 0); + EXPECT_EQ( + c().compileFn("match \"aa\" with | 'a?\\\\' -> 0 | _ -> 1")(), 1); + EXPECT_EQ( + c().compileFn("match \"a\\\\\" with | 'a?\\\\' -> 0 | _ -> 1")(), + 0); + EXPECT_EQ( + c().compileFn("match \"a\\n\" with | 'a?\\\\' -> 0 | _ -> 1")(), + 1); + EXPECT_EQ( + c().compileFn("match \"a\\n\" with | 'a?\\n' -> 0 | _ -> 1")(), 0); + EXPECT_EQ( + c().compileFn("match \"a\\n\" with | '[a-z]\\n' -> 0 | _ -> 1")(), + 0); + EXPECT_EQ( + c().compileFn("match \"a\\n\" with | '[^a-z]\\n' -> 0 | _ -> 1")(), + 1); + EXPECT_EQ( + c().compileFn("match \"0\\n\" with | '[^a-z]\\n' -> 0 | _ -> 1")(), + 0); + EXPECT_EQ( + c().compileFn("match \"8675309\" with | '[0-9]+' -> 0 | _ -> 1")(), + 0); EXPECT_TRUE(c().compileFn("\"b\" matches 'a(z)|b'")()); // verify correct match/fallback logic with regexes and multiple columns - EXPECT_EQ(c().compileFn("match \"ab\" 1 with | 'a(b|c)' 1 -> 1 | 'ab' 2 -> 2 | 'ac' 3 -> 3 | _ _ -> 4")(), 1); - EXPECT_EQ(c().compileFn("match \"ab\" 2 with | 'a(b|c)' 1 -> 1 | 'ab' 2 -> 2 | 'ac' 3 -> 3 | _ _ -> 4")(), 2); - EXPECT_EQ(c().compileFn("match \"ac\" 3 with | 'a(b|c)' 1 -> 1 | 'ab' 2 -> 2 | 'ac' 3 -> 3 | _ _ -> 4")(), 3); - EXPECT_EQ(c().compileFn("match \"ab\" 3 with | 'a(b|c)' 1 -> 1 | 'ab' 2 -> 2 | 'ac' 3 -> 3 | _ _ -> 4")(), 4); - EXPECT_EQ(c().compileFn("match \"foo\" 42 with | 'a(b|c)' 1 -> 1 | 'ab' 2 -> 2 | 'ac' 3 -> 3 | _ _ -> 4")(), 4); + EXPECT_EQ(c().compileFn("match \"ab\" 1 with | 'a(b|c)' 1 -> 1 | 'ab' " + "2 -> 2 | 'ac' 3 -> 3 | _ _ -> 4")(), + 1); + EXPECT_EQ(c().compileFn("match \"ab\" 2 with | 'a(b|c)' 1 -> 1 | 'ab' " + "2 -> 2 | 'ac' 3 -> 3 | _ _ -> 4")(), + 2); + EXPECT_EQ(c().compileFn("match \"ac\" 3 with | 'a(b|c)' 1 -> 1 | 'ab' " + "2 -> 2 | 'ac' 3 -> 3 | _ _ -> 4")(), + 3); + EXPECT_EQ(c().compileFn("match \"ab\" 3 with | 'a(b|c)' 1 -> 1 | 'ab' " + "2 -> 2 | 'ac' 3 -> 3 | _ _ -> 4")(), + 4); + EXPECT_EQ(c().compileFn("match \"foo\" 42 with | 'a(b|c)' 1 -> 1 | " + "'ab' 2 -> 2 | 'ac' 3 -> 3 | _ _ -> 4")(), + 4); // verify unreachable row determination bool unreachableExn = false; try { - c().compileFn("match \"foo123ooo\" with | '123|foo.*' -> 0 | 'foo.*' -> 1 | _ -> -1"); - } catch (std::exception&) { + c().compileFn( + "match \"foo123ooo\" with | '123|foo.*' -> 0 | 'foo.*' -> 1 | _ -> -1"); + } catch (std::exception &) { unreachableExn = true; } - EXPECT_TRUE(unreachableExn && "failed to determine expected unreachable regex row"); + EXPECT_TRUE(unreachableExn && + "failed to determine expected unreachable regex row"); - // verify unreachable rows should not cause error with IgnoreUnreachableMatches option on + // verify unreachable rows should not cause error with + // IgnoreUnreachableMatches option on c().ignoreUnreachableMatches(true); - EXPECT_EQ(c().compileFn("match \"foo123ooo\" with | '123|foo.*' -> 0 | 'foo.*' -> 1 | _ -> -1")(), 0); + EXPECT_EQ(c().compileFn("match \"foo123ooo\" with | '123|foo.*' -> 0 " + "| 'foo.*' -> 1 | _ -> -1")(), + 0); c().ignoreUnreachableMatches(false); // verify binding in regex matches - EXPECT_EQ(makeStdString(c().compileFn*()>("match \"foobar\" with | 'f(?o*)bar' -> os | _ -> \"???\"")()), "oo"); + EXPECT_EQ( + makeStdString(c().compileFn *()>( + "match \"foobar\" with | 'f(?o*)bar' -> os | _ -> \"???\"")()), + "oo"); // verify misc expressions - EXPECT_EQ(c().compileFn("match \"Roba\" with | 'Ka|Roba|Raa' -> 1 | _ -> 0")(), 1); + EXPECT_EQ(c().compileFn( + "match \"Roba\" with | 'Ka|Roba|Raa' -> 1 | _ -> 0")(), + 1); // verify regex-as-fn translation EXPECT_TRUE(c().compileFn("'fo*bar'(\"foobar\")")()); EXPECT_TRUE(!c().compileFn("'fo*bar'(\"foobaz\")")()); - EXPECT_EQ(makeStdString(c().compileFn*()>("either('f(?o*)bar'(\"foobar\"),\"\",.os)")()), "oo"); - EXPECT_EQ(makeStdString(c().compileFn*()>("either('f(?o*)bar'(\"foobaz\"),\"\",.os)")()), ""); + EXPECT_EQ(makeStdString(c().compileFn *()>( + "either('f(?o*)bar'(\"foobar\"),\"\",.os)")()), + "oo"); + EXPECT_EQ(makeStdString(c().compileFn *()>( + "either('f(?o*)bar'(\"foobaz\"),\"\",.os)")()), + ""); } TEST(Matching, Support) { - // we now have some support functions that could be used when compiling pattern match expressions and we need to make sure they're correct + // we now have some support functions that could be used when compiling + // pattern match expressions and we need to make sure they're correct EXPECT_EQ(c().compileFn("bsearch([1,3],id,2)")(), 2); EXPECT_EQ(c().compileFn("bsearch([9,10],id,2)")(), 2); EXPECT_EQ(c().compileFn("bsearch([1,2,3,4],id,3)")(), 2); @@ -167,17 +293,23 @@ TEST(Matching, Tests) { // make sure that tests with inaccessible names are rejected EXPECT_EXCEPTION(c().compileFn("\"JIMMY\" matches JIMMY")()); - EXPECT_EXCEPTION(c().compileFn("[{x=just(\"JIMMY\")}] matches [{x=|1=JIMMY|}]")()); + EXPECT_EXCEPTION( + c().compileFn("[{x=just(\"JIMMY\")}] matches [{x=|1=JIMMY|}]")()); // make sure that tests with inaccessible _ names are allowed EXPECT_TRUE(c().compileFn("\"JIMMY\" matches _")()); - EXPECT_TRUE(c().compileFn("[{x=just(\"JIMMY\")}] matches [{x=|1=_|}]")()); + EXPECT_TRUE( + c().compileFn("[{x=just(\"JIMMY\")}] matches [{x=|1=_|}]")()); } TEST(Matching, Functions) { // support irrefutable pattern matches in function heads - EXPECT_EQ(c().compileFn("(\\(a,b) (c,d).a+b+c+d)((1, 2), (3, 4))")(), 10); - EXPECT_EQ(c().compileFn("(\\{bob=a, frank=b} {chicken=c, jimmy=d}.a+b+c+d)({frank=1, bob=2}, {jimmy=3, chicken=4})")(), 10); + EXPECT_EQ(c().compileFn("(\\(a,b) (c,d).a+b+c+d)((1, 2), (3, 4))")(), + 10); + EXPECT_EQ(c().compileFn( + "(\\{bob=a, frank=b} {chicken=c, jimmy=d}.a+b+c+d)({frank=1, " + "bob=2}, {jimmy=3, chicken=4})")(), + 10); // support refutable pattern matches in function heads EXPECT_TRUE(c().compileFn("(\\[1,2,x].x+7)([1,2,3]) === |1=10|")()); @@ -186,96 +318,86 @@ TEST(Matching, Functions) { TEST(Matching, Monadic) { // support irrefutable matching in monadic 'do' sequences - EXPECT_EQ(c().compileFn("do { {x=x, y=y} = {x=1+2, y=3+4}; return x+y }")(), 10); + EXPECT_EQ( + c().compileFn("do { {x=x, y=y} = {x=1+2, y=3+4}; return x+y }")(), + 10); } -#if 0 -// todo: smunix: breaks on LLVM 9,10,11 TEST(Matching, matchFromStringToBoolIsBool) { - bool r = c().compileFn( - "match \"1\" \"2\" \"3\" \"4\" with\n" - "| \"1\" \"2\" \"3\" \"4\" -> true\n" - "| \"1\" \"2\" \"3\" _ -> true\n" - "| \"1\" \"2\" _ _ -> true\n" - "| \"1\" _ _ _ -> true\n" - "| _ _ _ _ -> false" - )(); - EXPECT_TRUE(1 == *reinterpret_cast(&r)); + bool r = c().compileSafeFn("match \"1\" \"2\" \"3\" \"4\" with\n" + "| \"1\" \"2\" \"3\" \"4\" -> true\n" + "| \"1\" \"2\" \"3\" _ -> true\n" + "| \"1\" \"2\" _ _ -> true\n" + "| \"1\" _ _ _ -> true\n" + "| _ _ _ _ -> false")(); + EXPECT_TRUE(1 == *reinterpret_cast(&r)); EXPECT_TRUE(r); } -#endif TEST(Matching, matchFromIntToBoolIsBool) { - bool r = c().compileFn( - "match 1 2 3 4 with\n" - "| 1 2 3 4 -> true\n" - "| 1 2 3 _ -> true\n" - "| 1 2 _ _ -> true\n" - "| 1 _ _ _ -> true\n" - "| _ _ _ _ -> false" - ); - EXPECT_TRUE(1 == *reinterpret_cast(&r)); + bool r = c().compileSafeFn("match 1 2 3 4 with\n" + "| 1 2 3 4 -> true\n" + "| 1 2 3 _ -> true\n" + "| 1 2 _ _ -> true\n" + "| 1 _ _ _ -> true\n" + "| _ _ _ _ -> false")(); + EXPECT_TRUE(1 == *reinterpret_cast(&r)); EXPECT_TRUE(r); } TEST(Matching, matchFromStringToIntIsCorrect) { - int r = c().compileFn( - "match \"1\" \"2\" \"3\" \"4\" with\n" - "| \"1\" \"2\" \"3\" \"4\" -> 86\n" - "| \"1\" \"2\" \"3\" _ -> 75\n" - "| \"1\" \"2\" _ _ -> 30\n" - "| \"1\" _ _ _ -> 9\n" - "| _ _ _ _ -> 0" - )(); - EXPECT_EQ(uint32_t(86), *reinterpret_cast(&r)); + int r = c().compileFn("match \"1\" \"2\" \"3\" \"4\" with\n" + "| \"1\" \"2\" \"3\" \"4\" -> 86\n" + "| \"1\" \"2\" \"3\" _ -> 75\n" + "| \"1\" \"2\" _ _ -> 30\n" + "| \"1\" _ _ _ -> 9\n" + "| _ _ _ _ -> 0")(); + EXPECT_EQ(uint32_t(86), *reinterpret_cast(&r)); EXPECT_TRUE(r); } TEST(Matching, largeRegexDFAFinishesReasonablyQuickly) { auto t0 = tick(); - c().compileFn( - "match \"a\" with\n" - "| '.*MOGUSJGTCA' where false -> ()\n" - "| '.+' where false -> ()\n" - "| '..........' where false -> ()\n" - "| '..AP.+' where false -> ()\n" - "| '..GU.+' where false -> ()\n" - "| '.?%.+' where false -> ()\n" - "| '.?%..AP.+' where false -> ()\n" - "| '.?%..GU.+' where false -> ()\n" - "| '.?%ME.+' where false -> ()\n" - "| '.?&.+' where false -> ()\n" - "| '.?&..AP.+' where false -> ()\n" - "| '.?&..GU.+' where false -> ()\n" - "| '.?&ME.+' where false -> ()\n" - "| '.?[%&].+' where false -> ()\n" - "| '.?[%&].+1==.?[%&].+' where false -> ()\n" - "| '05DVAAAB9' where false -> ()\n" - "| 'IMEAT_AXXBCD_ZM_ABCDEF' where false -> ()\n" - "| 'IMEAT_AXX_UVW_ABCDEF' where false -> ()\n" - "| 'IMEAT_AXXDCB_DE_ABCDEF' where false -> ()\n" - "| 'IMEAT_JWEWQP_DE_ABCDEF' where false -> ()\n" - "| _ -> ()\n" - )(); - - EXPECT_TRUE(size_t(tick()-t0) < 1UL*60*60*1000*1000*1000); + c().compileFn("match \"a\" with\n" + "| '.*MOGUSJGTCA' where false -> ()\n" + "| '.+' where false -> ()\n" + "| '..........' where false -> ()\n" + "| '..AP.+' where false -> ()\n" + "| '..GU.+' where false -> ()\n" + "| '.?%.+' where false -> ()\n" + "| '.?%..AP.+' where false -> ()\n" + "| '.?%..GU.+' where false -> ()\n" + "| '.?%ME.+' where false -> ()\n" + "| '.?&.+' where false -> ()\n" + "| '.?&..AP.+' where false -> ()\n" + "| '.?&..GU.+' where false -> ()\n" + "| '.?&ME.+' where false -> ()\n" + "| '.?[%&].+' where false -> ()\n" + "| '.?[%&].+1==.?[%&].+' where false -> ()\n" + "| '05DVAAAB9' where false -> ()\n" + "| 'IMEAT_AXXBCD_ZM_ABCDEF' where false -> ()\n" + "| 'IMEAT_AXX_UVW_ABCDEF' where false -> ()\n" + "| 'IMEAT_AXXDCB_DE_ABCDEF' where false -> ()\n" + "| 'IMEAT_JWEWQP_DE_ABCDEF' where false -> ()\n" + "| _ -> ()\n")(); + + EXPECT_TRUE(size_t(tick() - t0) < 1UL * 60 * 60 * 1000 * 1000 * 1000); } TEST(Matching, noRaceInterpMatch) { c().alwaysLowerPrimMatchTables(true); c().buildInterpretedMatches(true); - auto f = c().compileFn("x", - "match x with\n" - "| \"foo\" -> 0\n" - "| \"bar\" -> 1\n" - "| _ -> 2" - ); + auto f = c().compileFn("x", "match x with\n" + "| \"foo\" -> 0\n" + "| \"bar\" -> 1\n" + "| _ -> 2"); size_t wrongMatches = 0; std::vector ps; for (size_t p = 0; p < 10; ++p) { ps.emplace_back([&]() { auto t0 = tick(); - while (wrongMatches == 0 && size_t(tick()-t0) < 1UL*1000*1000*1000) { + while (wrongMatches == 0 && + size_t(tick() - t0) < 1UL * 1000 * 1000 * 1000) { if (f("foo") != 0) { ++wrongMatches; } @@ -286,10 +408,9 @@ TEST(Matching, noRaceInterpMatch) { } }); } - for (auto& p : ps) { + for (auto &p : ps) { p.join(); } EXPECT_EQ(wrongMatches, size_t(0)); c().buildInterpretedMatches(false); } - From 3b1d99f246bcdd131ed953c0555da28456b9f0f2 Mon Sep 17 00:00:00 2001 From: Mo Xiaoming <2188767+mo-xiaoming@users.noreply.github.com> Date: Tue, 27 Jul 2021 22:27:00 +0000 Subject: [PATCH 09/40] replace mcjit by orcjit to generate binary code (#414) * Update .gitlab-ci.yml file * Revert "Update .gitlab-ci.yml file" This reverts commit 2f9b62e7ade6de9dea333393f1b577fc1fb6e573 * add ORCJIT, still have unresolved in process symbols * put lock around every explicit getContext() use * module pointers in jitcc might be dangling * add Providence's ci file * logs: add llerrs(x) macros for logging * add missing header for llerr * lock guard IRBuilder access All IRBuilder in llvm.H are input parameters, they are locked on the caller side * redraft globals && fix invalid Value* in vtenv * can see prompt of hi * remove all llerrs except for IR dump * minor refactoring on Globals ConstantList VTEnv * remove dead code & renaming * make every jitcc::module() access locked by withContext tried to add a interface jitcc::withModuleDo, which just make things hard to understand, withModuleDo and withContext does the same thing internally, but with different interfaces, really cumbersome to use * fix duplicate definitions error caused by same .patfs.X name used in multiple module with ExternalLinkage make .patfs.X functions InternalLinkage, since they doesn't seem to be referenced across modules * remove dummy function stubs in jitcc::constants. Functions will be looked up in vtenv and globals anyway, this logic probably never get used * remove dangling Instruction generated by toLLVMConstant * Function should be considered as a Constant like the original logic. for now * minir test fix, missing a pair of parens, function never gets called * fix boolean related failure for llvm >= 9 * change from compileSafeFn -> compileFn as boolean failure has been resolved * some cleanup * fix llvm12 test/Compiler.C crash * ExecutionSession::endSession doesn't exist pre-llvm12, so more ifdef Co-authored-by: Providence Salumu --- .gitlab-ci.yml | 76 ++++ CMakeLists.txt | 4 +- include/hobbes/eval/jitcc.H | 56 ++- include/hobbes/eval/orcjitcc.H | 55 +++ include/hobbes/hobbes.H | 97 +++--- include/hobbes/util/llvm.H | 230 +++++++++++- lib/hobbes/db/bindings.C | 210 ++++++----- lib/hobbes/db/signals.C | 6 +- lib/hobbes/eval/cc.C | 2 + lib/hobbes/eval/cexpr.C | 374 +++++++++++--------- lib/hobbes/eval/func.C | 372 ++++++++++---------- lib/hobbes/eval/jitcc.C | 615 +++++++++++++++++++++++++++++---- lib/hobbes/eval/orcjitcc.C | 96 +++++ lib/hobbes/lang/pat/dfa.C | 42 ++- test/Arrays.C | 2 +- test/Matching.C | 28 +- 16 files changed, 1701 insertions(+), 564 deletions(-) create mode 100644 .gitlab-ci.yml create mode 100644 include/hobbes/eval/orcjitcc.H create mode 100644 lib/hobbes/eval/orcjitcc.C diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 000000000..ca1887ebf --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,76 @@ +# This file is a template, and might need editing before it works on your project. +# To contribute improvements to CI/CD templates, please follow the Development guide at: +# https://docs.gitlab.com/ee/development/cicd/templates.html +# This specific template is located at: +# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml + +# This is a sample GitLab CI/CD configuration file that should run without any modifications. +# It demonstrates a basic 3 stage CI/CD pipeline. Instead of real tests or scripts, +# it uses echo commands to simulate the pipeline execution. +# +# A pipeline is composed of independent jobs that run scripts, grouped into stages. +# Stages run in sequential order, but jobs within stages run in parallel. +# +# For more information, see: https://docs.gitlab.com/ee/ci/yaml/README.html#stages +image: nixpkgs/nix-flakes:latest +stages: # List of stages for jobs, and their order of execution + - build + - test + - deploy + +build-job-gcc10-llvm11: # This job runs in the build stage, which runs first. + stage: build + script: + - echo "Compiling the code..." + - nix build .#hobbesPackages/gcc-10/llvm-11/hobbes + - echo "Compile complete." + after_script: + - echo "nix log .#hobbesPackages/gcc-10/llvm-11/hobbes..." + - mkdir -pv log-job-gcc10-llvm11 + - nix log .#hobbesPackages/gcc-10/llvm-11/hobbes > log-job-gcc10-llvm11/nix.log + - echo "nix log .#hobbesPackages/gcc-10/llvm-11/hobbes complete." + artifacts: + name: "$CI_COMMIT_REF_SLUG" + paths: + - log-job-gcc10-llvm11/ + expire_in: 1 week + when: always + +build-job-clang11: # This job runs in the build stage, which runs first. + stage: build + script: + - mkdir -pv log-clang-11 + - echo "Compiling the code..." + - nix build .#hobbesPackages/clang-11/hobbes; nix log .#hobbesPackages/clang-11/hobbes > log-job-clang-11/nix.log + - echo "Compile complete." + after_script: + - echo "nix log .#hobbesPackages/clang-11/hobbes..." + - mkdir -pv log-job-clang-11 + - nix log .#hobbesPackages/clang-11/hobbes > log-job-clang-11/nix.log + - echo "nix log .#hobbesPackages/clang-11/hobbes complete." + artifacts: + name: "$CI_COMMIT_REF_SLUG" + paths: + - log-job-clang-11/ + expire_in: 1 week + when: always + +unit-test-job-gcc: # This job runs in the test stage. + stage: test # It only starts when the job in the build stage completes successfully. + script: + - echo "Running unit tests... This will take about 60 seconds." + - sleep 60 + - echo "Code coverage is 90%" + +lint-test-job: # This job also runs in the test stage. + stage: test # It can run at the same time as unit-test-job (in parallel). + script: + - echo "Linting code... This will take about 10 seconds." + - sleep 10 + - echo "No lint issues found." + +deploy-job: # This job runs in the deploy stage. + stage: deploy # It only runs when *both* jobs in the test stage complete successfully. + script: + - echo "Deploying application..." + - echo "Application successfully deployed." diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f811767a..dc8b250d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,8 +21,10 @@ set(CMAKE_CXX_STANDARD 14) if (${LLVM_PACKAGE_VERSION} VERSION_LESS "3.6") set(jit_lib jit) -else() +elseif(${LLVM_PACKAGE_VERSION} VERSION_LESS "11.0") set(jit_lib mcjit) +else() + set(jit_lib mcjit orcjit) endif() find_program(llvm-config llvm-config PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH) diff --git a/include/hobbes/eval/jitcc.H b/include/hobbes/eval/jitcc.H index 33f64b033..d75a28e4c 100644 --- a/include/hobbes/eval/jitcc.H +++ b/include/hobbes/eval/jitcc.H @@ -10,10 +10,17 @@ #include #include +#if LLVM_VERSION_MAJOR >= 11 +#include +#endif #include #include #include +namespace llvm { +class GlobalVariable; +} + namespace hobbes { // an operation, which can emit some specialized assembly code @@ -29,6 +36,13 @@ struct op { virtual llvm::Value* apply(jitcc* ev, const MonoTypes& tys, const MonoTypePtr& rty, const Exprs& es) = 0; }; +#if LLVM_VERSION_MAJOR >= 11 +class ORCJIT; +class Globals; +class VTEnv; +class ConstantList; +#endif + // a JIT compiler for monotyped expressions class jitcc { public: @@ -42,14 +56,16 @@ public: // get the address of a bound symbol void* getSymbolAddress(const std::string&); +#if LLVM_VERSION_MAJOR < 11 // print all module contents void dump() const; +#endif // define a global from a primitive expression void defineGlobal(const std::string& vname, const ExprPtr& unsweetExp); // define a global on some existing memory - void bindGlobal(const std::string& vn, const MonoTypePtr& ty, void* v); + void bindGlobal(const std::string& vn, const MonoTypePtr& ty, void* x); // is there a definition of the named symbol? bool isDefined(const std::string&) const; @@ -115,17 +131,26 @@ private: TEnvPtr tenv; // produce some machine code for a compiled function - void* getMachineCode(llvm::Function*, llvm::JITEventListener* listener = 0); + void* getMachineCode(llvm::Function*, llvm::JITEventListener* listener = nullptr); +#if LLVM_VERSION_MAJOR >= 11 + std::unique_ptr currentModule; +#else // the current non-finalized module // (new definitions will be accumulated here) // (may be null, to lazily allocate modules) - llvm::Module* currentModule; + llvm::Module* currentModule = nullptr; +#endif +#if LLVM_VERSION_MAJOR < 11 // the set of allocated modules typedef std::vector Modules; Modules modules; +#endif +#if LLVM_VERSION_MAJOR >= 11 + +#else #if LLVM_VERSION_MINOR == 6 || LLVM_VERSION_MINOR == 7 || LLVM_VERSION_MINOR == 8 || LLVM_VERSION_MAJOR == 4 || LLVM_VERSION_MAJOR <= 12 llvm::legacy::PassManager* mpm; @@ -142,19 +167,24 @@ private: llvm::legacy::FunctionPassManager* fpm; #else #error "This version of LLVM is not supported" +#endif #endif // support incremental construction of LLVM assembly sequences - llvm::IRBuilder<>* irbuilder; + std::unique_ptr> irbuilder; // the bound root function environment typedef std::map FuncEnv; FuncEnv fenv; // keep track of variables and local scopes during compilation +#if LLVM_VERSION_MAJOR >= 11 + std::unique_ptr vtenv; +#else typedef std::map VarBindings; typedef std::vector VarBindingStack; VarBindingStack vtenv; +#endif bool ignoreLocalScope; // compile sets of mutually-recursive functions (as a special case, single-function compilation) @@ -173,6 +203,9 @@ private: void unsafeCompileFunctions(UCFS*); // keep track of global variables +#if LLVM_VERSION_MAJOR >= 11 + std::unique_ptr globals; +#else struct Global { MonoTypePtr type; void* value; @@ -183,6 +216,7 @@ private: }; typedef std::map Globals; Globals globals; +#endif // keep track of global data (in case we need to dynamically allocate global variables of any type) region globalData; @@ -190,6 +224,9 @@ private: void popGlobalRegion(size_t x); // keep track of global constants +#if LLVM_VERSION_MAJOR >= 11 + std::unique_ptr constants; +#else struct Constant { llvm::Constant* value; llvm::Type* type; @@ -198,24 +235,35 @@ private: }; typedef std::map Constants; Constants constants; +#endif llvm::Value* loadConstant(const std::string&); // keep some interned strings, helpful for global constants and debug info typedef std::unordered_map InternConstVars; InternConstVars internConstVars; +#if LLVM_VERSION_MAJOR >= 11 + llvm::GlobalVariable* lookupGlobalVar(const std::string&); +#else // try to load a symbol as a global (may return nullptr if this can't be done) llvm::GlobalVariable* maybeRefGlobal(const std::string&); llvm::GlobalVariable* refGlobal(const std::string&, llvm::GlobalVariable*); +#endif +#if LLVM_VERSION_MAJOR < 11 // pass through a value if it's not a global or if it's a global in the current module // else wrap it in an extern decl llvm::Value* maybeRefGlobalV(llvm::Value*); +#endif // keep track of monotyped definitions as expressions // (in case we want to inline them later) typedef std::map GlobalExprs; GlobalExprs globalExprs; + +#if LLVM_VERSION_MAJOR >= 11 + std::unique_ptr orcjit; +#endif }; // shorthand for compilation over a sequence of expressions diff --git a/include/hobbes/eval/orcjitcc.H b/include/hobbes/eval/orcjitcc.H new file mode 100644 index 000000000..57debbf4f --- /dev/null +++ b/include/hobbes/eval/orcjitcc.H @@ -0,0 +1,55 @@ +#ifndef HOBBES_EVAL_ORCJITCC_HPP_INCLUDED +#define HOBBES_EVAL_ORCJITCC_HPP_INCLUDED + +#include + +#if LLVM_VERSION_MAJOR >= 11 +#include +#include +#include +#include +#include +#include +#include + +namespace hobbes { + +class ORCJIT { +public: + ORCJIT(std::unique_ptr tm, const llvm::DataLayout& dl); + ORCJIT(const ORCJIT&) = delete; + ORCJIT(ORCJIT&&) = delete; + ORCJIT& operator=(const ORCJIT&) = delete; + ORCJIT& operator=(ORCJIT&&) = delete; + ~ORCJIT(); + + static llvm::Expected> create(); + + llvm::Error addModule(std::unique_ptr m); + + llvm::Expected lookup(llvm::StringRef name); + + llvm::Error addExternalSymbol(llvm::StringRef name, void* ptr); + +private: + std::unique_ptr targetMachine; + + llvm::orc::ExecutionSession execSession; + + llvm::DataLayout dataLayout; + llvm::orc::MangleAndInterner mangle; + + llvm::orc::RTDyldObjectLinkingLayer objectLayer; + llvm::orc::IRCompileLayer compileLayer; + llvm::orc::IRTransformLayer optLayer; + + llvm::orc::JITDylib& mainJD; + + static llvm::Expected + optimizeModule(llvm::orc::ThreadSafeModule tsm, const llvm::orc::MaterializationResponsibility&); + +}; +} // namespace hobbes + +#endif +#endif diff --git a/include/hobbes/hobbes.H b/include/hobbes/hobbes.H index b42f203b7..8019945e0 100644 --- a/include/hobbes/hobbes.H +++ b/include/hobbes/hobbes.H @@ -2,24 +2,41 @@ #ifndef HOBBES_MAIN_HPP_INCLUDED #define HOBBES_MAIN_HPP_INCLUDED -#include #include #include -#include -#include #include #include -#include +#include +#include +#include #include +#include + +#include +#include +#include + +#define llerrs(x) \ + do { \ + llvm::errs() << "file:" << __FILE__ << "(" << __LINE__ << ")" \ + << ", func:" << __PRETTY_FUNCTION__ << ": " << x << '\n'; \ + } while (false) namespace hobbes { +LLVM_NODISCARD inline std::string createUniqueName(llvm::StringRef prefix) { + static llvm::StringMap m; + return llvm::formatv("{0}{1}", prefix, llvm::to_string(m[prefix]++)); +} + // type aliases for common types DEFINE_TYPE_ALIAS_AS(timespanT, timespan, int64_t); -inline uint64_t microseconds(const timespanT& ts) { return ts.value; } -inline uint64_t milliseconds(const timespanT& ts) { return microseconds(ts) / 1000; } -inline uint64_t seconds (const timespanT& ts) { return milliseconds(ts) / 1000; } +inline uint64_t microseconds(const timespanT &ts) { return ts.value; } +inline uint64_t milliseconds(const timespanT &ts) { + return microseconds(ts) / 1000; +} +inline uint64_t seconds(const timespanT &ts) { return milliseconds(ts) / 1000; } DEFINE_TYPE_ALIAS_AS(timeT, time, int64_t); DEFINE_TYPE_ALIAS_AS(datetimeT, datetime, int64_t); @@ -31,50 +48,50 @@ datetimeT datetimeAt(datetimeT, timeT); timespanT gmtoffset(datetimeT); // allocate some memory in the calling thread's memory pool -char* memalloc(size_t, size_t); +char *memalloc(size_t, size_t); // string representations, I/O -const array* makeString(const std::string& x); -std::string makeStdString(const array* x); +const array *makeString(const std::string &x); +std::string makeStdString(const array *x); -const array* makeString(region& m, const char* s); -const array* makeString(region& m, const std::string& s); -const array* makeString(region& m, const char* s, size_t len); -const array* makeString(const char* s, size_t len); +const array *makeString(region &m, const char *s); +const array *makeString(region &m, const std::string &s); +const array *makeString(region &m, const char *s, size_t len); +const array *makeString(const char *s, size_t len); -inline std::ostream& operator<<(std::ostream& out, const array* x) { +inline std::ostream &operator<<(std::ostream &out, const array *x) { out.write(x->data, x->size); return out; } // allocate an array at some type, with some length -template - array* defInitArray(array* xs) { - if (xs->size > 0) { - new (xs->data) T[xs->size]; - } - return xs; +template array *defInitArray(array *xs) { + if (xs->size > 0) { + new (xs->data) T[xs->size]; } + return xs; +} -template - array* makeArray(region& m, long n) { - array* r = reinterpret_cast*>(m.malloc(sizeof(long) + (sizeof(T) * n), std::max(sizeof(long), alignof(T)))); - r->size = n; - return defInitArray(r); - } +template array *makeArray(region &m, long n) { + array *r = reinterpret_cast *>( + m.malloc(sizeof(long) + (sizeof(T) * n), + std::max(sizeof(long), alignof(T)))); + r->size = n; + return defInitArray(r); +} -template - array* makeArray(long n) { - array* r = reinterpret_cast*>(memalloc(sizeof(long) + (sizeof(T) * n), std::max(sizeof(long), alignof(T)))); - r->size = n; - return defInitArray(r); - } +template array *makeArray(long n) { + array *r = reinterpret_cast *>( + memalloc(sizeof(long) + (sizeof(T) * n), + std::max(sizeof(long), alignof(T)))); + r->size = n; + return defInitArray(r); +} // allocate ... something -template - T* make(const Args& ... args) { - return new (memalloc(sizeof(T), alignof(T))) T(args...); - } +template T *make(const Args &...args) { + return new (memalloc(sizeof(T), alignof(T))) T(args...); +} // resets the thread-local memory pool for expressions // (subsequent allocations will reuse previously-used memory) @@ -90,11 +107,11 @@ public: std::string showMemoryPool(); // control the set of regions used for dynamic allocation -size_t addThreadRegion(const std::string&, region*); -size_t findThreadRegion(const std::string&); +size_t addThreadRegion(const std::string &, region *); +size_t findThreadRegion(const std::string &); void removeThreadRegion(size_t); size_t setThreadRegion(size_t); -} +} // namespace hobbes #endif diff --git a/include/hobbes/util/llvm.H b/include/hobbes/util/llvm.H index 0254c508b..771aec681 100644 --- a/include/hobbes/util/llvm.H +++ b/include/hobbes/util/llvm.H @@ -3,6 +3,9 @@ #define HOBBES_UTIL_LLVM_HPP_INCLUDED #include +#if LLVM_VERSION_MAJOR >= 11 +#include +#endif #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" @@ -29,7 +32,7 @@ #include #include #include -#if LLVM_VERSION_MAJOR == 4 || LLVM_VERSION_MAJOR == 6 || LLVM_VERSION_MAJOR <= 8 +#if LLVM_VERSION_MAJOR == 4 || LLVM_VERSION_MAJOR == 6 || LLVM_VERSION_MAJOR <= 8 # include # include #elif LLVM_VERSION_MAJOR <= 12 @@ -54,12 +57,228 @@ # include #endif +#if LLVM_VERSION_MAJOR >= 11 +# include +#endif + #pragma GCC diagnostic pop namespace hobbes { typedef __int128 int128_t; + +#if LLVM_VERSION_MAJOR >= 11 +inline llvm::orc::ThreadSafeContext& threadSafeContext() { + static auto c = llvm::orc::ThreadSafeContext(std::make_unique()); + return c; +} + +template auto withContext(Fn fn) -> decltype(auto) { + auto lk = threadSafeContext().getLock(); + return fn(*threadSafeContext().getContext()); +} + +typedef std::vector Types; +typedef std::vector Constants; +typedef std::vector Values; + +// type utilities +inline llvm::Type* voidType() { + return withContext([](llvm::LLVMContext& c) { return llvm::Type::getVoidTy(c); }); +} + +inline llvm::Type* boolType() { + return withContext([](llvm::LLVMContext& c) { return llvm::Type::getInt1Ty(c); }); +} + +inline llvm::Type* charType() { + return withContext([](llvm::LLVMContext& c) { return llvm::Type::getInt8Ty(c); }); +} + +inline llvm::Type* byteType() { + return charType(); +} + +inline llvm::Type* shortType() { + return withContext([](llvm::LLVMContext& c) { return llvm::Type::getInt16Ty(c); }); +} + +inline llvm::Type* intType() { + return withContext([](llvm::LLVMContext& c) { return llvm::Type::getInt32Ty(c); }); +} + +inline llvm::Type* longType() { + return withContext([](llvm::LLVMContext& c) { return llvm::Type::getInt64Ty(c); }); +} + +inline llvm::Type* int128Type() { + return withContext([](llvm::LLVMContext& c) { return llvm::Type::getIntNTy(c, 128); }); +} + +inline llvm::Type* floatType() { + return withContext([](llvm::LLVMContext& c) { return llvm::Type::getFloatTy(c); }); +} + +inline llvm::Type* doubleType() { + return withContext([](llvm::LLVMContext& c) { return llvm::Type::getDoubleTy(c); }); +} + +inline llvm::PointerType* ptrType(llvm::Type* ty) { + return llvm::PointerType::getUnqual(ty); +} + +inline llvm::ArrayType* arrayType(llvm::Type* ty, size_t sz) { + // we can be a little dishonest in describing the type of arrays of unit, since LLVM barfs on arrays of unit + // and we should never need to look at the "data" in an array of unit values _anyway_! + return llvm::ArrayType::get(ty->isVoidTy() ? boolType() : ty, static_cast(sz)); +} + +inline llvm::StructType* packedRecordType(const Types& tys) { + return withContext([&tys](llvm::LLVMContext& c) { return llvm::StructType::get(c, tys, true); }); +} + +inline llvm::StructType* recordType(const Types& tys) { + return withContext([&tys](llvm::LLVMContext& c) { return llvm::StructType::get(c, tys); }); +} + +inline llvm::StructType* recordType(llvm::Type* t0) { + return recordType(list(t0)); +} + +inline llvm::StructType* recordType(llvm::Type* t0, llvm::Type* t1) { + return recordType(list(t0, t1)); +} + +inline llvm::StructType* recordType(llvm::Type* t0, llvm::Type* t1, llvm::Type* t2) { + return recordType(list(t0, t1, t2)); +} + +inline llvm::StructType* recordType(llvm::Type* t0, llvm::Type* t1, llvm::Type* t2, llvm::Type* t3) { + return recordType(list(t0, t1, t2, t3)); +} + +inline llvm::StructType* recordType(llvm::Type* t0, llvm::Type* t1, llvm::Type* t2, llvm::Type* t3, llvm::Type* t4) { + return recordType(list(t0, t1, t2, t3, t4)); +} + +inline llvm::StructType* recordType(llvm::Type* t0, llvm::Type* t1, llvm::Type* t2, llvm::Type* t3, llvm::Type* t4, llvm::Type* t5) { + return recordType(list(t0, t1, t2, t3, t4, t5)); +} + +inline llvm::StructType* recordType(llvm::Type* t0, llvm::Type* t1, llvm::Type* t2, llvm::Type* t3, llvm::Type* t4, llvm::Type* t5, llvm::Type* t6) { + return recordType(list(t0, t1, t2, t3, t4, t5, t6)); +} + +inline llvm::FunctionType* functionType(const Types& argTys, llvm::Type* rty) { + return llvm::FunctionType::get(rty, argTys, false); +} + +inline llvm::StructType* varArrayType(llvm::Type* elemty, size_t sz = 1) { + return recordType(longType(), arrayType(elemty, sz)); +} + +// casting +inline llvm::Value* cast(llvm::IRBuilder<>* b, llvm::Type* ty, llvm::Value* v) { + return b->CreateBitCast(v, ty); +} + +inline llvm::Constant* ccast(llvm::Type* ty, llvm::Constant* v) { + return llvm::ConstantExpr::getBitCast(v, ty); +} + +// constant utilities +inline llvm::Constant* cvalue(bool x) { + return llvm::Constant::getIntegerValue(boolType(), llvm::APInt(1, x ? 1 : 0, false)); +} + +inline llvm::Constant* cvalue(char x) { + return llvm::Constant::getIntegerValue(charType(), llvm::APInt(8, x, true)); +} + +inline llvm::Constant* cvalue(unsigned char x) { + return llvm::Constant::getIntegerValue(charType(), llvm::APInt(8, x, false)); +} + +inline llvm::Constant* cvalue(short x) { + return llvm::Constant::getIntegerValue(shortType(), llvm::APInt(16, x, false)); +} + +inline llvm::Constant* cvalue(int x) { + return llvm::Constant::getIntegerValue(intType(), llvm::APInt(32, x, true)); +} + +inline llvm::Constant* cvalue(unsigned int x) { + return llvm::Constant::getIntegerValue(intType(), llvm::APInt(32, x, true)); +} + +inline llvm::Constant* cvalue(long x) { + return llvm::Constant::getIntegerValue(longType(), llvm::APInt(64, x, true)); +} + +inline llvm::Constant* cvalue(int128_t x) { + return llvm::Constant::getIntegerValue(int128Type(), llvm::APInt(128, x, true)); +} + +inline llvm::Constant* cvalue(float x) { + return withContext( + [x](llvm::LLVMContext& c) { return llvm::ConstantFP::get(c, llvm::APFloat(x)); }); +} + +inline llvm::Constant* cvalue(double x) { + return withContext( + [x](llvm::LLVMContext& c) { return llvm::ConstantFP::get(c, llvm::APFloat(x)); }); +} + +// constant int utilities (different than constants to LLVM!) +inline llvm::ConstantInt* civalue(bool x) { + return withContext([x](llvm::LLVMContext& c) { + return llvm::ConstantInt::get(llvm::IntegerType::get(c, 1), static_cast(x ? 1 : 0)); + }); +} + +inline llvm::ConstantInt* civalue(char x) { + return withContext([x](llvm::LLVMContext& c) { + return llvm::ConstantInt::get(llvm::IntegerType::get(c, 8), static_cast(x)); + }); +} + +inline llvm::ConstantInt* civalue(unsigned char x) { + return withContext([x](llvm::LLVMContext& c) { + return llvm::ConstantInt::get(llvm::IntegerType::get(c, 8), static_cast(x)); + }); +} + +inline llvm::ConstantInt* civalue(short x) { + return withContext([x](llvm::LLVMContext& c) { + return llvm::ConstantInt::get(llvm::IntegerType::get(c, 16), static_cast(x)); + }); +} + +inline llvm::ConstantInt* civalue(int x) { + return withContext([x](llvm::LLVMContext& c) { + return llvm::ConstantInt::get(llvm::IntegerType::get(c, 32), static_cast(x)); + }); +} + +inline llvm::ConstantInt* civalue(unsigned int x) { + return withContext([x](llvm::LLVMContext& c) { + return llvm::ConstantInt::get(llvm::IntegerType::get(c, 32), static_cast(x)); + }); +} + +inline llvm::ConstantInt* civalue(long x) { + return withContext([x](llvm::LLVMContext& c) { + return llvm::ConstantInt::get(llvm::IntegerType::get(c, 64), static_cast(x)); + }); +} + +inline llvm::ConstantInt* civalue(int128_t x) { + return withContext([x](llvm::LLVMContext& c) { + return llvm::ConstantInt::get(llvm::IntegerType::get(c, 128), x); // static_cast(x)); + }); +} +#else // keep one context per thread to avoid global locking // NOTE: temporarily reverting to one global context // this is because we have some cases where we partially compile in one thread and then resume compiling in another thread @@ -69,6 +288,10 @@ inline llvm::LLVMContext& context() { return ctx; } +template auto withContext(Fn fn) -> decltype(auto) { + return fn(context()); +} + typedef std::vector Types; typedef std::vector Constants; typedef std::vector Values; @@ -251,6 +474,7 @@ inline llvm::ConstantInt* civalue(int128_t x) { return llvm::ConstantInt::get(llvm::IntegerType::get(context(), 128), x); //static_cast(x)); } +#endif // an intermediate representation for records typedef std::pair FieldValue; typedef std::vector RecordValue; @@ -530,6 +754,7 @@ inline llvm::ExecutionEngine* makeExecutionEngine(llvm::Module* m, llvm::Section } #endif +#if LLVM_VERSION_MAJOR < 11 inline llvm::Function* externDecl(llvm::Function* remoteFn, llvm::Module* thisModule) { if (llvm::Function* ef = thisModule->getFunction(remoteFn->getName())) { return ef; @@ -537,7 +762,9 @@ inline llvm::Function* externDecl(llvm::Function* remoteFn, llvm::Module* thisMo return llvm::Function::Create(remoteFn->getFunctionType(), llvm::Function::ExternalLinkage, remoteFn->getName(), thisModule); } } +#endif +#if LLVM_VERSION_MAJOR < 11 const size_t FUNCTION_SIZE_THRESHOLD = 64; inline llvm::Function* cloneFunction(llvm::Function *f, llvm::Module *targetMod) { using namespace llvm; @@ -568,6 +795,7 @@ inline llvm::Function* cloneFunction(llvm::Function *f, llvm::Module *targetMod) CloneFunctionInto(newF, f, vmap, false, returns); return newF; } +#endif inline llvm::Value* fncall(llvm::IRBuilder<>* b, llvm::Value* vfn, llvm::Type* tfn, const Values& args) { (void)tfn; diff --git a/lib/hobbes/db/bindings.C b/lib/hobbes/db/bindings.C index a66fe61b5..448f223c3 100644 --- a/lib/hobbes/db/bindings.C +++ b/lib/hobbes/db/bindings.C @@ -189,13 +189,15 @@ class dbloadVF : public op { llvm::Function* f = c->lookupFunction(".dbloado"); if (!f) { throw std::runtime_error("Expected 'dbloado' function as call"); } - llvm::Value* allocv = fncall(c->builder(), f, f->getFunctionType(), list(db, off)); + return withContext([&](auto&) -> llvm::Value* { + llvm::Value* allocv = fncall(c->builder(), f, f->getFunctionType(), list(db, off)); - if (hasPointerRep(rty)) { - return c->builder()->CreateBitCast(allocv, toLLVM(rty, true)); - } else { - return c->builder()->CreateLoad(c->builder()->CreateBitCast(allocv, ptrType(toLLVM(rty, true)))); - } + if (hasPointerRep(rty)) { + return c->builder()->CreateBitCast(allocv, toLLVM(rty, true)); + } else { + return c->builder()->CreateLoad(c->builder()->CreateBitCast(allocv, ptrType(toLLVM(rty, true)))); + } + }); } PolyTypePtr type(typedb&) const { @@ -223,19 +225,21 @@ class dbstoreVF : public op { llvm::Function* f = c->lookupFunction(".dbloado"); if (!f) { throw std::runtime_error("Expected 'dbloado' function as call"); } - llvm::Value* allocv = fncall(c->builder(), f, f->getFunctionType(), list(db, off)); + return withContext([&](auto&) -> llvm::Value* { + llvm::Value* allocv = fncall(c->builder(), f, f->getFunctionType(), list(db, off)); - if (hasPointerRep(sty)) { - allocv = c->builder()->CreateBitCast(allocv, toLLVM(sty, true)); - } else { - allocv = c->builder()->CreateBitCast(allocv, ptrType(toLLVM(sty, true))); - } + if (hasPointerRep(sty)) { + allocv = c->builder()->CreateBitCast(allocv, toLLVM(sty, true)); + } else { + allocv = c->builder()->CreateBitCast(allocv, ptrType(toLLVM(sty, true))); + } - if (isLargeType(sty)) { - return memCopy(c->builder(), allocv, 8, outv, 8, sizeOf(sty)); - } else { - return c->builder()->CreateStore(outv, allocv); - } + if (isLargeType(sty)) { + return memCopy(c->builder(), allocv, 8, outv, 8, sizeOf(sty)); + } else { + return c->builder()->CreateStore(outv, allocv); + } + }); } PolyTypePtr type(typedb&) const { @@ -260,29 +264,31 @@ struct dbloadF : public op { return cvalue(true); } - // are we loading an array or a non-array? - if (storedAsDArray(rty)) { - llvm::Function* f = c->lookupFunction(".dbloaddarr"); - if (!f) { throw std::runtime_error("Expected 'dbloaddarr' function as call"); } + return withContext([&](auto&) -> llvm::Value* { + // are we loading an array or a non-array? + if (storedAsDArray(rty)) { + llvm::Function* f = c->lookupFunction(".dbloaddarr"); + if (!f) { throw std::runtime_error("Expected 'dbloaddarr' function as call"); } - return c->builder()->CreateBitCast(fncall(c->builder(), f, f->getFunctionType(), list(db, off)), toLLVM(rty, true)); - } else if (const Array* t = storedAsArray(rty)) { - llvm::Function* f = c->lookupFunction(".dbloadarr"); - if (!f) { throw std::runtime_error("Expected 'dbloadarr' function as call"); } + return c->builder()->CreateBitCast(fncall(c->builder(), f, f->getFunctionType(), list(db, off)), toLLVM(rty, true)); + } else if (const Array* t = storedAsArray(rty)) { + llvm::Function* f = c->lookupFunction(".dbloadarr"); + if (!f) { throw std::runtime_error("Expected 'dbloadarr' function as call"); } - return c->builder()->CreateBitCast(fncall(c->builder(), f, f->getFunctionType(), list(db, off, cvalue(static_cast(storageSizeOf(t->type()))))), toLLVM(rty, true)); - } else { - llvm::Function* f = c->lookupFunction(".dbloadv"); - if (!f) { throw std::runtime_error("Expected 'dbloadv' function as call"); } + return c->builder()->CreateBitCast(fncall(c->builder(), f, f->getFunctionType(), list(db, off, cvalue(static_cast(storageSizeOf(t->type()))))), toLLVM(rty, true)); + } else { + llvm::Function* f = c->lookupFunction(".dbloadv"); + if (!f) { throw std::runtime_error("Expected 'dbloadv' function as call"); } - llvm::Value* allocv = fncall(c->builder(), f, f->getFunctionType(), list(db, off, cvalue(static_cast(storageSizeOf(rty))))); + llvm::Value* allocv = fncall(c->builder(), f, f->getFunctionType(), list(db, off, cvalue(static_cast(storageSizeOf(rty))))); - if (hasPointerRep(rty)) { - return c->builder()->CreateBitCast(allocv, toLLVM(rty, true)); - } else { - return c->builder()->CreateLoad(c->builder()->CreateBitCast(allocv, ptrType(toLLVM(rty, true)))); + if (hasPointerRep(rty)) { + return c->builder()->CreateBitCast(allocv, toLLVM(rty, true)); + } else { + return c->builder()->CreateLoad(c->builder()->CreateBitCast(allocv, ptrType(toLLVM(rty, true)))); + } } - } + }); } PolyTypePtr type(typedb&) const { @@ -303,29 +309,31 @@ struct dbloadPF : public op { return cvalue(true); } - // are we loading an array or a non-array? - if (storedAsDArray(rty)) { - llvm::Function* f = c->lookupFunction(".dbloaddarr"); - if (!f) { throw std::runtime_error("Expected 'dbloaddarr' function as call"); } + return withContext([&](auto&) -> llvm::Value* { + // are we loading an array or a non-array? + if (storedAsDArray(rty)) { + llvm::Function* f = c->lookupFunction(".dbloaddarr"); + if (!f) { throw std::runtime_error("Expected 'dbloaddarr' function as call"); } - return c->builder()->CreateBitCast(fncall(c->builder(), f, f->getFunctionType(), list(db, off)), toLLVM(rty, true)); - } else if (const Array* a = storedAsArray(rty)) { - llvm::Function* f = c->lookupFunction(".dbloadarr"); - if (!f) { throw std::runtime_error("Expected 'dbloadarr' function as call"); } + return c->builder()->CreateBitCast(fncall(c->builder(), f, f->getFunctionType(), list(db, off)), toLLVM(rty, true)); + } else if (const Array* a = storedAsArray(rty)) { + llvm::Function* f = c->lookupFunction(".dbloadarr"); + if (!f) { throw std::runtime_error("Expected 'dbloadarr' function as call"); } - return c->builder()->CreateBitCast(fncall(c->builder(), f, f->getFunctionType(), list(db, off, cvalue(static_cast(storageSizeOf(a->type()))))), toLLVM(rty, true)); - } else { - llvm::Function* f = c->lookupFunction(".dbloadv"); - if (!f) { throw std::runtime_error("Expected 'dbloadv' function as call"); } + return c->builder()->CreateBitCast(fncall(c->builder(), f, f->getFunctionType(), list(db, off, cvalue(static_cast(storageSizeOf(a->type()))))), toLLVM(rty, true)); + } else { + llvm::Function* f = c->lookupFunction(".dbloadv"); + if (!f) { throw std::runtime_error("Expected 'dbloadv' function as call"); } - llvm::Value* allocv = fncall(c->builder(), f, f->getFunctionType(), list(db, off, cvalue(static_cast(storageSizeOf(rty))))); + llvm::Value* allocv = fncall(c->builder(), f, f->getFunctionType(), list(db, off, cvalue(static_cast(storageSizeOf(rty))))); - if (hasPointerRep(rty)) { - return c->builder()->CreateBitCast(allocv, toLLVM(rty, true)); - } else { - return c->builder()->CreateLoad(c->builder()->CreateBitCast(allocv, ptrType(toLLVM(rty, true)))); + if (hasPointerRep(rty)) { + return c->builder()->CreateBitCast(allocv, toLLVM(rty, true)); + } else { + return c->builder()->CreateLoad(c->builder()->CreateBitCast(allocv, ptrType(toLLVM(rty, true)))); + } } - } + }); } PolyTypePtr type(typedb&) const { @@ -376,32 +384,34 @@ void dbunloadarr(long db, long ptr, long sz) { struct dbunloadF : public op { llvm::Value* apply(jitcc* c, const MonoTypes& tys, const MonoTypePtr&, const Exprs& es) { llvm::Value* db = c->compile(es[0]); - llvm::Value* val = c->builder()->CreatePtrToInt(c->compile(es[1]), toLLVM(primty("long"), true)); + return withContext([&](auto&) -> llvm::Value* { + llvm::Value* val = c->builder()->CreatePtrToInt(c->compile(es[1]), toLLVM(primty("long"), true)); - // sure you can unload a unit value ... - if (isUnit(tys[1])) { - return cvalue(true); - } + // sure you can unload a unit value ... + if (isUnit(tys[1])) { + return cvalue(true); + } - // are we unloading an array or a non-array? - if (storedAsDArray(tys[1])) { - llvm::Function* f = c->lookupFunction(".dbunloaddarr"); - if (!f) { throw std::runtime_error("Expected 'dbunloaddarr' function as call"); } + // are we unloading an array or a non-array? + if (storedAsDArray(tys[1])) { + llvm::Function* f = c->lookupFunction(".dbunloaddarr"); + if (!f) { throw std::runtime_error("Expected 'dbunloaddarr' function as call"); } - return fncall(c->builder(), f, f->getFunctionType(), list(db, val)); - } else if (const Array* a = storedAsArray(tys[1])) { - llvm::Function* f = c->lookupFunction(".dbunloadarr"); - if (!f) { throw std::runtime_error("Expected 'dbunloadarr' function as call"); } + return fncall(c->builder(), f, f->getFunctionType(), list(db, val)); + } else if (const Array* a = storedAsArray(tys[1])) { + llvm::Function* f = c->lookupFunction(".dbunloadarr"); + if (!f) { throw std::runtime_error("Expected 'dbunloadarr' function as call"); } - return fncall(c->builder(), f, f->getFunctionType(), list(db, val, cvalue(static_cast(storageSizeOf(a->type()))))); - } else if (!hasPointerRep(tys[1])) { - return cvalue(true); - } else { - llvm::Function* f = c->lookupFunction(".dbunloadv"); - if (!f) { throw std::runtime_error("Expected 'dbunloadv' function as call"); } + return fncall(c->builder(), f, f->getFunctionType(), list(db, val, cvalue(static_cast(storageSizeOf(a->type()))))); + } else if (!hasPointerRep(tys[1])) { + return cvalue(true); + } else { + llvm::Function* f = c->lookupFunction(".dbunloadv"); + if (!f) { throw std::runtime_error("Expected 'dbunloadv' function as call"); } - return fncall(c->builder(), f, f->getFunctionType(), list(db, val, cvalue(static_cast(storageSizeOf(tys[1]))))); - } + return fncall(c->builder(), f, f->getFunctionType(), list(db, val, cvalue(static_cast(storageSizeOf(tys[1]))))); + } + }); } PolyTypePtr type(typedb&) const { @@ -428,7 +438,9 @@ struct dballocF : public op { if (!f) { throw std::runtime_error("Expected 'dballoc' function as call"); } size_t sz = storageSizeOf(frefType(rty)); - return fncall(c->builder(), f, f->getFunctionType(), list(db, cvalue(static_cast(sz)), cvalue(static_cast(alignment(frefType(rty)))))); + return withContext([&](auto&) { + return fncall(c->builder(), f, f->getFunctionType(), list(db, cvalue(static_cast(sz)), cvalue(static_cast(alignment(frefType(rty)))))); + }); } PolyTypePtr type(typedb&) const { @@ -454,14 +466,16 @@ struct dbstoreF : public op { if (!dblf) { throw std::runtime_error("Expected 'dbloadv' function as call"); } size_t sz = storageSizeOf(frefType(rty)); - llvm::Value* id = fncall(c->builder(), f, f->getFunctionType(), list(db, cvalue(static_cast(sz)), cvalue(static_cast(alignment(frefType(rty)))))); + return withContext([&](auto&) { + llvm::Value* id = fncall(c->builder(), f, f->getFunctionType(), list(db, cvalue(static_cast(sz)), cvalue(static_cast(alignment(frefType(rty)))))); - if (!isUnit(tys[0])) { - llvm::Value* p = fncall(c->builder(), dblf, dblf->getFunctionType(), list(db, id, cvalue(static_cast(sz)))); - memCopy(c->builder(), p, 8, c->builder()->CreateBitCast(v, ptrType(charType())), 8, sz); - } + if (!isUnit(tys[0])) { + llvm::Value* p = fncall(c->builder(), dblf, dblf->getFunctionType(), list(db, id, cvalue(static_cast(sz)))); + memCopy(c->builder(), p, 8, c->builder()->CreateBitCast(v, ptrType(charType())), 8, sz); + } - return id; + return id; + }); } } @@ -488,14 +502,16 @@ struct dbstorePF : public op { if (!dblf) { throw std::runtime_error("Expected 'dbloadv' function as call"); } size_t sz = storageSizeOf(frefType(rty)); - llvm::Value* id = fncall(c->builder(), f, f->getFunctionType(), list(db, cvalue(static_cast(sz)), cvalue(static_cast(alignment(frefType(rty)))))); + return withContext([&](auto&) { + llvm::Value* id = fncall(c->builder(), f, f->getFunctionType(), list(db, cvalue(static_cast(sz)), cvalue(static_cast(alignment(frefType(rty)))))); - if (!isUnit(tys[1])) { - llvm::Value* p = fncall(c->builder(), dblf, dblf->getFunctionType(), list(db, id, cvalue(static_cast(sz)))); - memCopy(c->builder(), p, 8, c->builder()->CreateBitCast(v, ptrType(charType())), 8, sz); - } + if (!isUnit(tys[1])) { + llvm::Value* p = fncall(c->builder(), dblf, dblf->getFunctionType(), list(db, id, cvalue(static_cast(sz)))); + memCopy(c->builder(), p, 8, c->builder()->CreateBitCast(v, ptrType(charType())), 8, sz); + } - return id; + return id; + }); } } @@ -523,7 +539,9 @@ struct dballocArrF : public op { if (!f) { throw std::runtime_error("Expected 'dballocarr' function as call"); } size_t elemsz = storageSizeOf(arrType(frt.first)); - return fncall(c->builder(), f, f->getFunctionType(), list(db, cvalue(static_cast(elemsz)), len)); + return withContext([&](auto&) { + return fncall(c->builder(), f, f->getFunctionType(), list(db, cvalue(static_cast(elemsz)), len)); + }); } PolyTypePtr type(typedb&) const { @@ -543,7 +561,9 @@ struct dballocArrPF : public op { if (!f) { throw std::runtime_error("Expected 'dballocarr' function as call"); } size_t elemsz = storageSizeOf(arrType(frefType(rty))); - return fncall(c->builder(), f, f->getFunctionType(), list(db, cvalue(static_cast(elemsz)), len)); + return withContext([&](auto&) { + return fncall(c->builder(), f, f->getFunctionType(), list(db, cvalue(static_cast(elemsz)), len)); + }); } PolyTypePtr type(typedb&) const { @@ -570,7 +590,9 @@ struct dbarrCapacityF : public op { if (!f) { throw std::runtime_error("Expected 'dbdarrcapacity' function as call"); } size_t elemsz = storageSizeOf(darrType(frt.first)); - return fncall(c->builder(), f, f->getFunctionType(), list(db, cvalue(static_cast(elemsz)), off)); + return withContext([&](auto&) { + return fncall(c->builder(), f, f->getFunctionType(), list(db, cvalue(static_cast(elemsz)), off)); + }); } PolyTypePtr type(typedb&) const { @@ -590,7 +612,9 @@ struct dbarrCapacityPF : public op { if (!f) { throw std::runtime_error("Expected 'dbdarrcapacity' function as call"); } size_t elemsz = storageSizeOf(darrType(frefType(tys[1]))); - return fncall(c->builder(), f, f->getFunctionType(), list(db, cvalue(static_cast(elemsz)), off)); + return withContext([&](auto&) { + return fncall(c->builder(), f, f->getFunctionType(), list(db, cvalue(static_cast(elemsz)), off)); + }); } PolyTypePtr type(typedb&) const { @@ -635,7 +659,9 @@ struct signalUpdateF : public op { llvm::Function* f = c->lookupFunction(".dbsignalupdate"); if (!f) { throw std::runtime_error("Expected 'dbsignalupdate' function as call"); } - return fncall(c->builder(), f, f->getFunctionType(), list(db)); + return withContext([&](auto&) { + return fncall(c->builder(), f, f->getFunctionType(), list(db)); + }); } PolyTypePtr type(typedb&) const { diff --git a/lib/hobbes/db/signals.C b/lib/hobbes/db/signals.C index 7c2ccdb92..1509f63cf 100644 --- a/lib/hobbes/db/signals.C +++ b/lib/hobbes/db/signals.C @@ -266,12 +266,14 @@ struct addFileSignalF : public op { if (isDArr) { sz = sizeof(long); - off = c->builder()->CreateAdd(off, cvalue(static_cast(sizeof(long)))); + off = withContext([c, off](auto&) { return c->builder()->CreateAdd(off, cvalue(static_cast(sizeof(long)))); }); } else { sz = storageSizeOf(refty); } - return fncall(c->builder(), f, f->getFunctionType(), list(db, off, cvalue(static_cast(sz)), cvalue(static_cast(isDArr ? BROffsetType::DArray : BROffsetType::Value)), sfn)); + return withContext([&](auto&) { + return fncall(c->builder(), f, f->getFunctionType(), list(db, off, cvalue(static_cast(sz)), cvalue(static_cast(isDArr ? BROffsetType::DArray : BROffsetType::Value)), sfn)); + }); } PolyTypePtr type(typedb&) const { diff --git a/lib/hobbes/eval/cc.C b/lib/hobbes/eval/cc.C index 3fc8de528..3c8ece766 100644 --- a/lib/hobbes/eval/cc.C +++ b/lib/hobbes/eval/cc.C @@ -557,8 +557,10 @@ const TEnvPtr& cc::typeEnv() const { } void cc::dumpModule() { +#if LLVM_VERSION_MAJOR < 11 hlock _; this->jit->dump(); +#endif } cc::bytes cc::machineCodeForExpr(const std::string& expr) { diff --git a/lib/hobbes/eval/cexpr.C b/lib/hobbes/eval/cexpr.C index 812fea360..1e94f0352 100644 --- a/lib/hobbes/eval/cexpr.C +++ b/lib/hobbes/eval/cexpr.C @@ -6,6 +6,8 @@ #include #include #include +#include +#include namespace hobbes { @@ -144,10 +146,12 @@ public: } // it's a standard function call, invoke it in the standard way - return fncall(builder(), - compile(v->fn()), - toLLVM(requireMonotype(this->c->typeEnv(), v->fn())), - compileArgs(this->c, v->args())); + return withContext([this, v](auto&) { + return fncall(builder(), + compile(v->fn()), + toLLVM(requireMonotype(this->c->typeEnv(), v->fn())), + compileArgs(this->c, v->args())); + }); } llvm::Value* with(const Assign* v) const { @@ -158,11 +162,13 @@ public: llvm::Value* lhs = compileRef(v->left()); llvm::Value* rhs = compile(v->right()); - if (isLargeType(rty)) { - memCopy(builder(), lhs, 8, rhs, 8, sizeOf(rty)); - } else { - builder()->CreateStore(rhs, lhs); - } + withContext([&](auto&) { + if (isLargeType(rty)) { + memCopy(builder(), lhs, 8, rhs, 8, sizeOf(rty)); + } else { + builder()->CreateStore(rhs, lhs); + } + }); return with(rcast(0)); } else { @@ -186,26 +192,28 @@ public: llvm::Type* elemTy = toLLVM(aty->type(), isStoredPtr); llvm::Value* p = compileAllocStmt(sizeof(long) + sizeOf(aty->type()) * vs.size(), std::max(sizeof(long), alignment(aty->type())), ptrType(llvmVarArrType(elemTy))); - // store the array length - llvm::Value* alenp = structOffset(builder(), p, 0); - builder()->CreateStore(llvm::Constant::getIntegerValue(longType(), llvm::APInt(64, vs.size(), true)), alenp); - - // store the array contents - if (!isUnit(aty->type())) { - llvm::Value* adatap = structOffset(builder(), p, 1); - - for (size_t i = 0; i < vs.size(); ++i) { - llvm::Value* ev = vs[i]; - llvm::Value* ap = offset(builder(), adatap, 0, i); - - // we only memcopy into an array if the data is large and isn't an opaque pointer (always write opaque pointers as pointers) - if (!isStoredPtr && isLargeType(aty->type())) { - memCopy(builder(), ap, 8, ev, 8, sizeOf(aty->type())); - } else { - builder()->CreateStore(ev, ap); + withContext([&](auto&) { + // store the array length + llvm::Value* alenp = structOffset(builder(), p, 0); + builder()->CreateStore(llvm::Constant::getIntegerValue(longType(), llvm::APInt(64, vs.size(), true)), alenp); + + // store the array contents + if (!isUnit(aty->type())) { + llvm::Value* adatap = structOffset(builder(), p, 1); + + for (size_t i = 0; i < vs.size(); ++i) { + llvm::Value* ev = vs[i]; + llvm::Value* ap = offset(builder(), adatap, 0, i); + + // we only memcopy into an array if the data is large and isn't an opaque pointer (always write opaque pointers as pointers) + if (!isStoredPtr && isLargeType(aty->type())) { + memCopy(builder(), ap, 8, ev, 8, sizeOf(aty->type())); + } else { + builder()->CreateStore(ev, ap); + } } } - } + }); return p; } @@ -220,24 +228,26 @@ public: llvm::Value* tg = cvalue(vty->id(v->label())); llvm::Value* tv = compile(v->value()); - // store the variant tag - builder()->CreateStore(tg, builder()->CreateBitCast(p, ptrType(intType()))); + return withContext([&](auto&) { + // store the variant tag + builder()->CreateStore(tg, builder()->CreateBitCast(p, ptrType(intType()))); - // store the variant value - MonoTypePtr valty = requireMonotype(v->value()->type()); - llvm::Value* pp = offset(builder(), p, vty->payloadOffset()); + // store the variant value + MonoTypePtr valty = requireMonotype(v->value()->type()); + llvm::Value* pp = offset(builder(), p, vty->payloadOffset()); - if (isLargeType(valty)) { - memCopy(builder(), pp, 8, tv, 8, sizeOf(valty)); - } else if (isUnit(valty)) { - // don't store unit values - } else { - // store data for this case inline in the variant - // (functions should be stored as pointers) - builder()->CreateStore(tv, builder()->CreateBitCast(pp, ptrType(toLLVM(valty, is(valty))))); - } + if (isLargeType(valty)) { + memCopy(builder(), pp, 8, tv, 8, sizeOf(valty)); + } else if (isUnit(valty)) { + // don't store unit values + } else { + // store data for this case inline in the variant + // (functions should be stored as pointers) + builder()->CreateStore(tv, builder()->CreateBitCast(pp, ptrType(toLLVM(valty, is(valty))))); + } - return builder()->CreateBitCast(p, toLLVM(mvty, true)); + return builder()->CreateBitCast(p, toLLVM(mvty, true)); + }); } llvm::Value* with(const MkRecord* v) const { @@ -262,11 +272,13 @@ public: llvm::Value* fp = structFieldPtr(p, rty->alignedIndex(rv->first)); MonoTypePtr fty = rty->member(rv->first); - if (isLargeType(fty)) { - memCopy(builder(), fp, 8, fv, 8, sizeOf(fty)); - } else { - builder()->CreateStore(fv, fp); - } + withContext([&](auto&) { + if (isLargeType(fty)) { + memCopy(builder(), fp, 8, fv, 8, sizeOf(fty)); + } else { + builder()->CreateStore(fv, fp); + } + }); } return p; @@ -281,14 +293,16 @@ public: return with(rcast(0)); } - llvm::Value* ard = structOffset(builder(), ar, 1); // get the array's data pointer - llvm::Value* p = offset(builder(), ard, 0, ir); // and index into it + return withContext([&](auto&) -> llvm::Value* { + llvm::Value* ard = structOffset(builder(), ar, 1); // get the array's data pointer + llvm::Value* p = offset(builder(), ard, 0, ir); // and index into it - if (isLargeType(aity)) { - return p; - } else { - return builder()->CreateLoad(p, false); - } + if (isLargeType(aity)) { + return p; + } else { + return builder()->CreateLoad(p, false); + } + }); } // apply a case expression's default expression across every constructor not accounted for @@ -315,18 +329,24 @@ public: // compile the variant and pull out the tag and value llvm::Value* var = compile(v->variant()); - llvm::Value* ptag = builder()->CreateBitCast(var, ptrType(intType())); - llvm::Value* tag = builder()->CreateLoad(ptag, false); + llvm::Value* ptag = withContext([this, var](auto&) { return builder()->CreateBitCast(var, ptrType(intType())); }); + llvm::Value* tag = withContext([this, ptag](auto&) { return builder()->CreateLoad(ptag, false); }); std::vector idxs; idxs.push_back(cvalue(0)); idxs.push_back(cvalue(vty->payloadOffset())); - llvm::Value* pval = builder()->CreateGEP(var, idxs); - - llvm::Function* thisFn = builder()->GetInsertBlock()->getParent(); - llvm::BasicBlock* failBlock = llvm::BasicBlock::Create(context(), "casefail", thisFn); - llvm::BasicBlock* mergeBlock = llvm::BasicBlock::Create(context(), "casemerge", thisFn); - llvm::SwitchInst* s = builder()->CreateSwitch(tag, failBlock, v->bindings().size()); + llvm::Value* pval = withContext([&, this](auto&) { return builder()->CreateGEP(var, idxs); }); + + llvm::Function* thisFn = withContext([this](auto&) { return builder()->GetInsertBlock()->getParent(); }); + llvm::BasicBlock* failBlock = withContext([thisFn](llvm::LLVMContext& c) { + return llvm::BasicBlock::Create(c, "casefail", thisFn); + }); + llvm::BasicBlock* mergeBlock = withContext([thisFn](llvm::LLVMContext& c) { + return llvm::BasicBlock::Create(c, "casemerge", thisFn); + }); + llvm::SwitchInst* s = withContext([&](auto&) { + return builder()->CreateSwitch(tag, failBlock, v->bindings().size()); + }); typedef std::pair MergeLink; typedef std::vector MergeLinks; @@ -334,34 +354,37 @@ public: for (Case::Bindings::const_iterator b = v->bindings().begin(); b != v->bindings().end(); ++b) { unsigned int caseID = vty->id(b->selector); - llvm::BasicBlock* caseBlock = llvm::BasicBlock::Create(context(), "case_" + str::from(caseID), thisFn); + withContext([&](llvm::LLVMContext& c) { + llvm::BasicBlock* caseBlock = llvm::BasicBlock::Create(c, "case_" + str::from(caseID), thisFn); - builder()->SetInsertPoint(caseBlock); - try { - MonoTypePtr valty = vty->payload(b->selector); + builder()->SetInsertPoint(caseBlock); + try { + MonoTypePtr valty = vty->payload(b->selector); - if (isUnit(valty)) { - beginScope(b->vname, cvalue(true)); // this is unit, so should never be looked at - } else { - // otherwise the data here is available inline - // (and functions are stored as pointers) - llvm::Type* lty = toLLVM(valty, is(valty)); - llvm::Value* pointval = builder()->CreateBitCast(pval, ptrType(lty)); - llvm::Value* val = isLargeType(valty) ? pointval : builder()->CreateLoad(pointval, false); + if (isUnit(valty)) { + beginScope(b->vname, cvalue(true)); // this is unit, so should never be looked at + } else { + // otherwise the data here is available inline + // (and functions are stored as pointers) + llvm::Type* lty = toLLVM(valty, is(valty)); + llvm::Value* pointval = builder()->CreateBitCast(pval, ptrType(lty)); + llvm::Value* val = isLargeType(valty) ? pointval : builder()->CreateLoad(pointval, false); - beginScope(b->vname, val); - } + beginScope(b->vname, val); + } - llvm::Value* caseValue = switchOf(b->exp, compileExpF("", this->c)); - mergeLinks.push_back(MergeLink(caseValue, builder()->GetInsertBlock())); - builder()->CreateBr(mergeBlock); - endScope(); - } catch (...) { - endScope(); - throw; - } + llvm::Value* caseValue = switchOf(b->exp, compileExpF("", this->c)); + mergeLinks.push_back(MergeLink(caseValue, builder()->GetInsertBlock())); + builder()->CreateBr(mergeBlock); + endScope(); + } catch (...) { + endScope(); + throw; + } - s->addCase(llvm::ConstantInt::get(llvm::IntegerType::get(context(), 32), scast(caseID)), caseBlock); + s->addCase(llvm::ConstantInt::get(llvm::IntegerType::get(c, 32), + scast(caseID)), caseBlock); + }); } // fill in the default (failure) target for variant matching @@ -371,26 +394,28 @@ public: auto ltxts = v->la().lines(v->la().p0.first-1, v->la().p1.first); auto ltxt = ltxts.size() > 0 ? ltxts[0] : "???"; - builder()->SetInsertPoint(failBlock); - fncall(builder(), f, f->getFunctionType(), list( - this->c->internConstString(v->la().filename()), - cvalue(scast(v->la().p0.first)), - this->c->internConstString(ltxt), - builder()->CreateBitCast(var, ptrType(charType())) - )); - builder()->CreateUnreachable(); - - // now if the result type is unit, it can be trivially constructed, else merge potential branch results - builder()->SetInsertPoint(mergeBlock); - if (isUnit(casety)) { - return cvalue(true); - } else { - llvm::PHINode* pn = builder()->CreatePHI(toLLVM(casety, true), mergeLinks.size()); - for (MergeLinks::const_iterator ml = mergeLinks.begin(); ml != mergeLinks.end(); ++ml) { - pn->addIncoming(ml->first, ml->second); + return withContext([&](auto&) -> llvm::Value* { + builder()->SetInsertPoint(failBlock); + fncall(builder(), f, f->getFunctionType(), list( + this->c->internConstString(v->la().filename()), + cvalue(scast(v->la().p0.first)), + this->c->internConstString(ltxt), + builder()->CreateBitCast(var, ptrType(charType())) + )); + builder()->CreateUnreachable(); + + // now if the result type is unit, it can be trivially constructed, else merge potential branch results + builder()->SetInsertPoint(mergeBlock); + if (isUnit(casety)) { + return cvalue(true); + } else { + llvm::PHINode* pn = builder()->CreatePHI(toLLVM(casety, true), mergeLinks.size()); + for (MergeLinks::const_iterator ml = mergeLinks.begin(); ml != mergeLinks.end(); ++ml) { + pn->addIncoming(ml->first, ml->second); + } + return pn; } - return pn; - } + }); } llvm::Value* with(const Switch* v) const { @@ -399,49 +424,59 @@ public: // prepare to switch on the discriminant llvm::Value* e = compile(v->expr()); - llvm::Function* thisFn = builder()->GetInsertBlock()->getParent(); - llvm::BasicBlock* failBlock = llvm::BasicBlock::Create(context(), "casefail", thisFn); - llvm::BasicBlock* mergeBlock = llvm::BasicBlock::Create(context(), "casemerge", thisFn); - llvm::SwitchInst* s = builder()->CreateSwitch(e, failBlock, v->bindings().size()); + llvm::Function* thisFn = withContext([this](auto&) { + return builder()->GetInsertBlock()->getParent(); + }); + llvm::BasicBlock* failBlock = withContext([thisFn](llvm::LLVMContext& c) { + return llvm::BasicBlock::Create(c, "casefail", thisFn); + }); + llvm::BasicBlock* mergeBlock = withContext([thisFn](llvm::LLVMContext& c) { + return llvm::BasicBlock::Create(c, "casemerge", thisFn); + }); + llvm::SwitchInst* s = withContext([&](auto&) { + return builder()->CreateSwitch(e, failBlock, v->bindings().size()); + }); typedef std::pair MergeLink; typedef std::vector MergeLinks; MergeLinks mergeLinks; - size_t i = 0; - for (auto b : v->bindings()) { - size_t caseID = i++; - llvm::BasicBlock* caseBlock = llvm::BasicBlock::Create(context(), "case_" + str::from(caseID), thisFn); + return withContext([&](auto& c) -> llvm::Value* { + size_t i = 0; + for (auto b : v->bindings()) { + size_t caseID = i++; + llvm::BasicBlock* caseBlock = llvm::BasicBlock::Create(c, "case_" + str::from(caseID), thisFn); - builder()->SetInsertPoint(caseBlock); - llvm::Value* caseValue = compile(b.exp); - mergeLinks.push_back(MergeLink(caseValue, builder()->GetInsertBlock())); - builder()->CreateBr(mergeBlock); + builder()->SetInsertPoint(caseBlock); + llvm::Value* caseValue = compile(b.exp); + mergeLinks.push_back(MergeLink(caseValue, builder()->GetInsertBlock())); + builder()->CreateBr(mergeBlock); - s->addCase(toLLVMConstantInt(b.value), caseBlock); - } + s->addCase(toLLVMConstantInt(b.value), caseBlock); + } - // fill in the default (failure) target - if (v->defaultExpr()) { - builder()->SetInsertPoint(failBlock); - llvm::Value* defValue = compile(v->defaultExpr()); - mergeLinks.push_back(MergeLink(defValue, builder()->GetInsertBlock())); - builder()->CreateBr(mergeBlock); - } else { - builder()->CreateUnreachable(); - } + // fill in the default (failure) target + if (v->defaultExpr()) { + builder()->SetInsertPoint(failBlock); + llvm::Value* defValue = compile(v->defaultExpr()); + mergeLinks.push_back(MergeLink(defValue, builder()->GetInsertBlock())); + builder()->CreateBr(mergeBlock); + } else { + builder()->CreateUnreachable(); + } - // now just merge each of the case blocks to a final value - builder()->SetInsertPoint(mergeBlock); - if (isUnit(casety)) { - return cvalue(true); - } else { - llvm::PHINode* pn = builder()->CreatePHI(toLLVM(casety, true), mergeLinks.size()); - for (MergeLinks::const_iterator ml = mergeLinks.begin(); ml != mergeLinks.end(); ++ml) { - pn->addIncoming(ml->first, ml->second); + // now just merge each of the case blocks to a final value + builder()->SetInsertPoint(mergeBlock); + if (isUnit(casety)) { + return cvalue(true); + } else { + llvm::PHINode* pn = builder()->CreatePHI(toLLVM(casety, true), mergeLinks.size()); + for (MergeLinks::const_iterator ml = mergeLinks.begin(); ml != mergeLinks.end(); ++ml) { + pn->addIncoming(ml->first, ml->second); + } + return pn; } - return pn; - } + }); } llvm::Value* with(const Proj* v) const { @@ -461,17 +496,19 @@ public: // switched to using packed records and manually-determined padding llvm::Value* rp = structFieldPtr(rec, rty->alignedIndex(v->field())); - if (OpaquePtr* op = is(fty)) { - if (op->storedContiguously()) { - return builder()->CreateBitCast(rp, ptrType(byteType())); + return withContext([&](auto&) -> llvm::Value* { + if (OpaquePtr* op = is(fty)) { + if (op->storedContiguously()) { + return builder()->CreateBitCast(rp, ptrType(byteType())); + } else { + return builder()->CreateLoad(rp, false); + } + } else if (isLargeType(fty)) { + return rp; } else { return builder()->CreateLoad(rp, false); } - } else if (isLargeType(fty)) { - return rp; - } else { - return builder()->CreateLoad(rp, false); - } + }); } llvm::Value* with(const Assump* v) const { @@ -483,7 +520,7 @@ public: llvm::Value* ev = compile(v->expr()); llvm::Type* et = toLLVM(requireMonotype(v->type()), true); - return builder()->CreateBitCast(ev, et); + return withContext([&](auto&) { return builder()->CreateBitCast(ev, et); }); } llvm::Value* with(const Unpack* v) const { @@ -507,11 +544,16 @@ private: llvm::Value* compileConstArray(const MonoTypePtr& ty, const Values& vs) const { auto elemTy = is(ty) ? ptrType(toLLVM(ty)) : toLLVM(ty); - return tryMkConstVarArray(builder(), this->c->module(), elemTy, vs, is(ty)); // take care to refer to global array constants by reference (a bit awkward!) + return withContext([&](auto&) { + // take care to refer to global array constants by reference (a bit awkward!) + return tryMkConstVarArray(builder(), this->c->module(), elemTy, vs, is(ty)); + }); } llvm::Value* compileConstRecord(const RecordValue& vs, const Record* rty) const { - return tryMkConstRecord(builder(), this->c->module(), vs, rty); + return withContext([&](auto&) { + return tryMkConstRecord(builder(), this->c->module(), vs, rty); + }); } llvm::Value* compile(const ExprPtr& e) const { @@ -544,7 +586,7 @@ private: } llvm::Value* structFieldPtr(llvm::Value* r, unsigned int i) const { - return structOffset(builder(), r, i); + return withContext([=](auto&) { return structOffset(builder(), r, i); }); } RecordValue compileRecordFields(const MkRecord::FieldDefs& fs) const { @@ -573,14 +615,18 @@ private: throw annotated_error(*e, "Failed to get reference to global variable: " + gv->value()); } - return isLargeType(vty) ? builder()->CreateLoad(vl) : vl; + return withContext([&](auto&) { return isLargeType(vty) ? builder()->CreateLoad(vl) : vl; }); } else if (const AIndex* ai = is(e)) { MonoTypePtr aity = requireMonotype(ai->type()); llvm::Value* ar = compile(ai->array()); llvm::Value* ir = compile(ai->index()); - llvm::Value* ard = structOffset(builder(), ar, 1); // get the array's 'data' pointer - llvm::Value* p = offset(builder(), ard, 0, ir); // and index into it + llvm::Value* ard = withContext([this, ar](auto&) { + return structOffset(builder(), ar, 1); // get the array's 'data' pointer + }); + llvm::Value* p = withContext([&](auto&) { + return offset(builder(), ard, 0, ir); // and index into it + }); return p; } else if (const Proj* rp = is(e)) { @@ -597,8 +643,10 @@ private: if (OpaquePtr* op = is(fty)) { if (op->storedContiguously()) { - llvm::PointerType* bty = llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(context())); - return builder()->CreateBitCast(p, bty); + return withContext([&](llvm::LLVMContext& c) { + llvm::PointerType* bty = llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(c)); + return builder()->CreateBitCast(p, bty); + }); } } @@ -609,7 +657,7 @@ private: llvm::Value* ar = compile(ap->args()[0]); llvm::Value* i = compile(ap->args()[1]); - return offset(builder(), ar, 0, i); + return withContext([&](auto&) { return offset(builder(), ar, 0, i); }); } } } @@ -645,7 +693,14 @@ public: llvm::Constant* with(const Double* v) const { return cvalue(v->value()); } llvm::Constant* with(const Var* v) const { - return llvm::dyn_cast(this->c->lookupVar(v->value(), requireMonotype(v->type()))); + // possible instructions created during compilation + // remove them otherwise they may become dangling instructions + llvm::Value* x = this->c->lookupVar(v->value(), requireMonotype(v->type())); + if (auto* inst = llvm::dyn_cast(x)) { + inst->eraseFromParent(); + return nullptr; + } + return llvm::dyn_cast(x); } llvm::Constant* with(const Let*) const { @@ -695,8 +750,8 @@ public: llvm::StructType* saty = varArrayType(elemTy, cs.size()); llvm::StructType* caty = varArrayType(elemTy); - return - ccast(ptrType(caty), + return withContext([&](auto&) { + return ccast(ptrType(caty), new llvm::GlobalVariable( *this->c->module(), saty, @@ -705,6 +760,7 @@ public: constArray(this->c->module(), cs, elemTy) ) ); + }); } llvm::Constant* with(const MkVariant*) const { @@ -724,7 +780,7 @@ public: return 0; } } - return constantRecord(this->c->module(), rcs, rty); + return withContext([&](auto&) { return constantRecord(this->c->module(), rcs, rty); }); } llvm::Constant* with(const AIndex*) const { diff --git a/lib/hobbes/eval/func.C b/lib/hobbes/eval/func.C index 10da22bde..a399bbdc0 100644 --- a/lib/hobbes/eval/func.C +++ b/lib/hobbes/eval/func.C @@ -15,7 +15,7 @@ namespace hobbes { public: \ llvm::Value* apply(jitcc* c, const MonoTypes&, const MonoTypePtr&, const Exprs& es) { \ llvm::Value* x = c->compile(es[0]); \ - return c->builder()->mem(x, "t"); \ + return withContext([&](auto&) { return c->builder()->mem(x, "t"); }); \ } \ PolyTypePtr type(typedb&) const { \ return polytype(prim()); \ @@ -28,7 +28,7 @@ namespace hobbes { llvm::Value* apply(jitcc* c, const MonoTypes&, const MonoTypePtr&, const Exprs& es) { \ llvm::Value* left = c->compile(es[0]); \ llvm::Value* right = c->compile(es[1]); \ - return c->builder()->mem(left, right, "t"); \ + return withContext([&](auto&) { return c->builder()->mem(left, right, "t"); }); \ } \ PolyTypePtr type(typedb&) const { \ return polytype(prim()); \ @@ -40,7 +40,7 @@ namespace hobbes { public: \ llvm::Value* apply(jitcc* c, const MonoTypes&, const MonoTypePtr&, const Exprs& es) { \ llvm::Value* e = c->compile(es[0]); \ - return c->builder()->CreateCast(cflag, e, toLLVM(prim()), "t"); \ + return withContext([&](auto&) { return c->builder()->CreateCast(cflag, e, toLLVM(prim()), "t"); }); \ } \ PolyTypePtr type(typedb&) const { \ return polytype(prim()); \ @@ -52,7 +52,7 @@ namespace hobbes { public: \ llvm::Value* apply(jitcc* c, const MonoTypes&, const MonoTypePtr&, const Exprs& es) { \ llvm::Value* x = c->compile(es[0]); \ - return c->builder()->mem(x, a0, "t"); \ + return withContext([&](auto&) { return c->builder()->mem(x, a0, "t"); }); \ } \ PolyTypePtr type(typedb&) const { \ return polytype(prim()); \ @@ -64,7 +64,7 @@ namespace hobbes { public: \ llvm::Value* apply(jitcc* c, const MonoTypes&, const MonoTypePtr&, const Exprs& es) { \ llvm::Value* x = c->compile(es[0]); \ - return c->builder()->mem(x, a0, a1, "t"); \ + return withContext([&](auto&) { return c->builder()->mem(x, a0, a1, "t"); }); \ } \ PolyTypePtr type(typedb&) const { \ return polytype(prim()); \ @@ -224,45 +224,47 @@ BOP(dgte, CreateFCmpOGE, double, double, bool); class ifexp : public op { public: llvm::Value* apply(jitcc* c, const MonoTypes& tys, const MonoTypePtr&, const Exprs& es) { - llvm::Function* thisFn = c->builder()->GetInsertBlock()->getParent(); - llvm::Value* cond = c->compile(es[0]); + return withContext([&](llvm::LLVMContext& ctx) -> llvm::Value* { + llvm::Function* thisFn = c->builder()->GetInsertBlock()->getParent(); + llvm::Value* cond = c->compile(es[0]); - // for a condition, we need a 'then' branch, an 'else' branch, and a 'merge' block joining the two - llvm::BasicBlock* thenBlock = llvm::BasicBlock::Create(context(), "then", thisFn); - llvm::BasicBlock* elseBlock = llvm::BasicBlock::Create(context(), "else"); - llvm::BasicBlock* mergeBlock = llvm::BasicBlock::Create(context(), "ifmerge"); + // for a condition, we need a 'then' branch, an 'else' branch, and a 'merge' block joining the two + llvm::BasicBlock* thenBlock = llvm::BasicBlock::Create(ctx, "then", thisFn); + llvm::BasicBlock* elseBlock = llvm::BasicBlock::Create(ctx, "else"); + llvm::BasicBlock* mergeBlock = llvm::BasicBlock::Create(ctx, "ifmerge"); - // compile 'then' branch flowing to 'merge' block - c->builder()->CreateCondBr(cond, thenBlock, elseBlock); - c->builder()->SetInsertPoint(thenBlock); + // compile 'then' branch flowing to 'merge' block + c->builder()->CreateCondBr(cond, thenBlock, elseBlock); + c->builder()->SetInsertPoint(thenBlock); - llvm::Value* thenExp = c->compile(es[1]); - c->builder()->CreateBr(mergeBlock); - thenBlock = c->builder()->GetInsertBlock(); // reset block pointer, in case compiling 'then' expression changed the active block + llvm::Value* thenExp = c->compile(es[1]); + c->builder()->CreateBr(mergeBlock); + thenBlock = c->builder()->GetInsertBlock(); // reset block pointer, in case compiling 'then' expression changed the active block - // compile the 'else' branch - thisFn->getBasicBlockList().push_back(elseBlock); - c->builder()->SetInsertPoint(elseBlock); + // compile the 'else' branch + thisFn->getBasicBlockList().push_back(elseBlock); + c->builder()->SetInsertPoint(elseBlock); - llvm::Value* elseExp = c->compile(es[2]); - c->builder()->CreateBr(mergeBlock); - elseBlock = c->builder()->GetInsertBlock(); // reset block pointer, in case compiling 'else' expression changed the active block + llvm::Value* elseExp = c->compile(es[2]); + c->builder()->CreateBr(mergeBlock); + elseBlock = c->builder()->GetInsertBlock(); // reset block pointer, in case compiling 'else' expression changed the active block - // finally, merge blocks - thisFn->getBasicBlockList().push_back(mergeBlock); - c->builder()->SetInsertPoint(mergeBlock); + // finally, merge blocks + thisFn->getBasicBlockList().push_back(mergeBlock); + c->builder()->SetInsertPoint(mergeBlock); - // and the final value is the phi merge of the two possible branches - // (unless we're returning unit) - if (isUnit(tys[1])) { - return cvalue(true); - } else { - llvm::PHINode* pn = c->builder()->CreatePHI(toLLVM(tys[1], true), 2); - pn->addIncoming(thenExp, thenBlock); - pn->addIncoming(elseExp, elseBlock); + // and the final value is the phi merge of the two possible branches + // (unless we're returning unit) + if (isUnit(tys[1])) { + return cvalue(true); + } else { + llvm::PHINode* pn = c->builder()->CreatePHI(toLLVM(tys[1], true), 2); + pn->addIncoming(thenExp, thenBlock); + pn->addIncoming(elseExp, elseBlock); - return pn; - } + return pn; + } + }); } PolyTypePtr type(typedb&) const { @@ -276,7 +278,9 @@ public: class alenexp : public op { public: llvm::Value* apply(jitcc* c, const MonoTypes&, const MonoTypePtr&, const Exprs& es) { - return c->builder()->CreateLoad(structOffset(c->builder(), c->compile(es[0]), 0), false, "at"); + return withContext([c, &es](auto&) { + return c->builder()->CreateLoad(structOffset(c->builder(), c->compile(es[0]), 0), false, "at"); + }); } PolyTypePtr type(typedb&) const { @@ -293,32 +297,34 @@ class aconcatexp : public op { public: llvm::Value* apply(jitcc* c, const MonoTypes& tys, const MonoTypePtr&, const Exprs& es) { Array* aty = is(tys[0]); - if (aty == 0) { + if (aty == nullptr) { throw annotated_error(*es[0], "Internal compiler error -- can't make array out of non-array type: " + show(tys[0])); } - llvm::Value* a0 = c->compile(es[0]); - llvm::Value* c0 = c->builder()->CreateLoad(structOffset(c->builder(), a0, 0)); - llvm::Value* d0 = structOffset(c->builder(), a0, 1); - llvm::Value* a1 = c->compile(es[1]); - llvm::Value* c1 = c->builder()->CreateLoad(structOffset(c->builder(), a1, 0)); - llvm::Value* d1 = structOffset(c->builder(), a1, 1); + return withContext([&](auto&) { + llvm::Value* a0 = c->compile(es[0]); + llvm::Value* c0 = c->builder()->CreateLoad(structOffset(c->builder(), a0, 0)); + llvm::Value* d0 = structOffset(c->builder(), a0, 1); + llvm::Value* a1 = c->compile(es[1]); + llvm::Value* c1 = c->builder()->CreateLoad(structOffset(c->builder(), a1, 0)); + llvm::Value* d1 = structOffset(c->builder(), a1, 1); - llvm::Value* aclen = c->builder()->CreateAdd(c0, c1); - llvm::Value* mlen = c->builder()->CreateAdd(cvalue(static_cast(sizeof(long))), c->builder()->CreateMul(aclen, cvalue(static_cast(sizeOf(aty->type()))))); + llvm::Value* aclen = c->builder()->CreateAdd(c0, c1); + llvm::Value* mlen = c->builder()->CreateAdd(cvalue(static_cast(sizeof(long))), c->builder()->CreateMul(aclen, cvalue(static_cast(sizeOf(aty->type()))))); - llvm::Value* cmdata = c->compileAllocStmt(mlen, cvalue(std::max(sizeof(long), alignment(aty->type()))), toLLVM(tys[0])); - c->builder()->CreateStore(aclen, structOffset(c->builder(), cmdata, 0)); + llvm::Value* cmdata = c->compileAllocStmt(mlen, cvalue(std::max(sizeof(long), alignment(aty->type()))), toLLVM(tys[0])); + c->builder()->CreateStore(aclen, structOffset(c->builder(), cmdata, 0)); - if (!isUnit(aty->type())) { - // hack to acknowledge the fact that opaque pointers are stored as pointers within arrays - long elemSize = is(aty->type()) ? sizeof(void*) : static_cast(sizeOf(aty->type())); + if (!isUnit(aty->type())) { + // hack to acknowledge the fact that opaque pointers are stored as pointers within arrays + long elemSize = is(aty->type()) ? sizeof(void*) : static_cast(sizeOf(aty->type())); - llvm::Value* od = structOffset(c->builder(), cmdata, 1); - memCopy(c->builder(), offset(c->builder(), od, 0), 8, d0, 8, c->builder()->CreateMul(c0, cvalue(elemSize))); - memCopy(c->builder(), offset(c->builder(), od, c0), 8, d1, 8, c->builder()->CreateMul(c1, cvalue(elemSize))); - } - return cmdata; + llvm::Value* od = structOffset(c->builder(), cmdata, 1); + memCopy(c->builder(), offset(c->builder(), od, 0), 8, d0, 8, c->builder()->CreateMul(c0, cvalue(elemSize))); + memCopy(c->builder(), offset(c->builder(), od, c0), 8, d1, 8, c->builder()->CreateMul(c1, cvalue(elemSize))); + } + return cmdata; + }); } PolyTypePtr type(typedb&) const { @@ -340,7 +346,7 @@ class asetlen : public op { llvm::Value* av = c->compile(es[0]); llvm::Value* nc = c->compile(es[1]); - c->builder()->CreateStore(nc, structOffset(c->builder(), av, 0)); + withContext([&](auto&) { c->builder()->CreateStore(nc, structOffset(c->builder(), av, 0)); }); return cvalue(true); } @@ -380,13 +386,15 @@ class saelem : public op { return cvalue(true); } - llvm::Value* p = offset(c->builder(), c->compile(es[0]), 0, c->compile(es[1])); + return withContext([&](auto&) -> llvm::Value* { + llvm::Value* p = offset(c->builder(), c->compile(es[0]), 0, c->compile(es[1])); - if (isLargeType(rty)) { - return p; - } else { - return c->builder()->CreateLoad(p, false); - } + if (isLargeType(rty)) { + return p; + } else { + return c->builder()->CreateLoad(p, false); + } + }); } PolyTypePtr type(typedb&) const { @@ -407,12 +415,14 @@ class saacopy : public op { llvm::Value* farr = c->compile(es[0]); llvm::Value* varr = c->compile(es[1]); - llvm::Value* vard = structOffset(c->builder(), varr, 1); // get the var-length array's 'data' pointer + withContext([&](auto&) { + llvm::Value* vard = structOffset(c->builder(), varr, 1); // get the var-length array's 'data' pointer - llvm::Value* len = c->compile(es[2]); - llvm::Value* lenb = c->builder()->CreateMul(len, cvalue(static_cast(sizeOf(aty->type())))); + llvm::Value* len = c->compile(es[2]); + llvm::Value* lenb = c->builder()->CreateMul(len, cvalue(static_cast(sizeOf(aty->type())))); - memCopy(c->builder(), farr, 8, vard, 8, lenb); + memCopy(c->builder(), farr, 8, vard, 8, lenb); + }); return cvalue(true); } @@ -491,7 +501,9 @@ public: if (isUnit(rty)) { return cvalue(true); } else { - return c->builder()->CreateBitCast(r, toLLVM(rty, true)); + return withContext([&](auto&) { + return c->builder()->CreateBitCast(r, toLLVM(rty, true)); + }); } } @@ -513,7 +525,9 @@ public: if (isUnit(rty)) { return cvalue(true); } else if (!hasPointerRep(rty)) { - return c->builder()->CreateLoad(c->compileAllocStmt(sizeOf(rty), alignment(rty), ptrType(toLLVM(rty, true)), this->zeroMem)); + return withContext([&](auto&) { + return c->builder()->CreateLoad(c->compileAllocStmt(sizeOf(rty), alignment(rty), ptrType(toLLVM(rty, true)), this->zeroMem)); + }); } else { return c->compileAllocStmt(sizeOf(rty), alignment(rty), toLLVM(rty, true), this->zeroMem); } @@ -537,9 +551,11 @@ public: } llvm::Value* aclen = c->compile(es[0]); - llvm::Value* mlen = c->builder()->CreateAdd(cvalue(static_cast(sizeof(long))), c->builder()->CreateMul(aclen, cvalue(static_cast(sizeOf(aty->type()))))); + llvm::Value* mlen = withContext([&](auto&) { + return c->builder()->CreateAdd(cvalue(static_cast(sizeof(long))), c->builder()->CreateMul(aclen, cvalue(static_cast(sizeOf(aty->type()))))); + }); llvm::Value* cmdata = c->compileAllocStmt(mlen, cvalue(std::max(sizeof(long), alignment(aty->type()))), toLLVM(rty)); - c->builder()->CreateStore(aclen, structOffset(c->builder(), cmdata, 0)); + withContext([&](auto&) { c->builder()->CreateStore(aclen, structOffset(c->builder(), cmdata, 0)); }); return cmdata; } @@ -558,7 +574,7 @@ public: llvm::Value* apply(jitcc* c, const MonoTypes&, const MonoTypePtr&, const Exprs& es) { llvm::Value* p = c->compile(es[0]); llvm::Value* o = c->compile(es[1]); - return c->builder()->CreateGEP(p, o); + return withContext([&](auto&) { return c->builder()->CreateGEP(p, o); }); } PolyTypePtr type(typedb&) const { @@ -573,16 +589,14 @@ public: class adjvtblptr : public op { public: llvm::Value* apply(jitcc* c, const MonoTypes&, const MonoTypePtr&, const Exprs& es) { - llvm::Type* tppchar = - llvm::PointerType::getUnqual( - llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(context())) - ); + llvm::Type* tppchar = llvm::PointerType::getUnqual(llvm::PointerType::getUnqual( + withContext([](llvm::LLVMContext& ctx) { return llvm::Type::getInt8Ty(ctx); }))); llvm::Value* p = c->compile(es[0]); llvm::Value* o = c->compile(es[1]); - return - c->builder()->CreateGEP( + return withContext([&](auto&) { + return c->builder()->CreateGEP( p, c->builder()->CreateLoad( c->builder()->CreateGEP( @@ -593,6 +607,7 @@ public: ) ) ); + }); } PolyTypePtr type(typedb&) const { @@ -761,13 +776,15 @@ public: } static llvm::Value* payloadValue(jitcc* c, const MonoTypePtr& mty, llvm::Value* pval) { - if (isUnit(mty)) { - return cvalue(true); - } else if (isLargeType(mty)) { - return c->builder()->CreateBitCast(pval, toLLVM(mty, true)); - } else { - return c->builder()->CreateLoad(c->builder()->CreateBitCast(pval, llvm::PointerType::getUnqual(toLLVM(mty, true))), false); - } + return withContext([&](auto&) -> llvm::Value* { + if (isUnit(mty)) { + return cvalue(true); + } else if (isLargeType(mty)) { + return c->builder()->CreateBitCast(pval, toLLVM(mty, true)); + } else { + return c->builder()->CreateLoad(c->builder()->CreateBitCast(pval, llvm::PointerType::getUnqual(toLLVM(mty, true))), false); + } + }); } llvm::Value* apply(jitcc* c, const MonoTypes& tys, const MonoTypePtr&, const Exprs& es) { @@ -789,72 +806,74 @@ public: // compile the variant, head-handler and tail-handler llvm::Value* var = c->compile(es[0]); - // if the tail is 0, we can only possibly match the head - if (isVoid(vty->tailType())) { - // get an offset to the payload data - std::vector idxs; - idxs.push_back(cvalue(0)); - idxs.push_back(cvalue(vty->payloadOffset())); - llvm::Value* pval = c->builder()->CreateGEP(var, idxs); + return withContext([&](llvm::LLVMContext& ctx) -> llvm::Value* { + // if the tail is 0, we can only possibly match the head + if (isVoid(vty->tailType())) { + // get an offset to the payload data + std::vector idxs; + idxs.push_back(cvalue(0)); + idxs.push_back(cvalue(vty->payloadOffset())); + llvm::Value* pval = c->builder()->CreateGEP(var, idxs); + + // invoke the head case function with the payload value + return callWith(c, es[1], vheadm.type, payloadValue(c, vheadm.type, pval)); + } else { + // pull out the variant tag + llvm::Value* ptag = c->builder()->CreateBitCast(var, ptrType(intType())); + llvm::Value* tag = c->builder()->CreateLoad(ptag, false); - // invoke the head case function with the payload value - return callWith(c, es[1], vheadm.type, payloadValue(c, vheadm.type, pval)); - } else { - // pull out the variant tag - llvm::Value* ptag = c->builder()->CreateBitCast(var, ptrType(intType())); - llvm::Value* tag = c->builder()->CreateLoad(ptag, false); + // compare the tag data to the head tag id + llvm::Value* htagv = cvalue(static_cast(vheadm.id)); + llvm::Value* ishtag = c->builder()->CreateICmpEQ(tag, htagv); - // compare the tag data to the head tag id - llvm::Value* htagv = cvalue(static_cast(vheadm.id)); - llvm::Value* ishtag = c->builder()->CreateICmpEQ(tag, htagv); + // get an offset to the payload data + std::vector idxs; + idxs.push_back(cvalue(0)); + idxs.push_back(cvalue(vty->payloadOffset())); + llvm::Value* pval = c->builder()->CreateGEP(var, idxs); - // get an offset to the payload data - std::vector idxs; - idxs.push_back(cvalue(0)); - idxs.push_back(cvalue(vty->payloadOffset())); - llvm::Value* pval = c->builder()->CreateGEP(var, idxs); + // either invoke the head case function, or the tail case function + llvm::Function* thisFn = c->builder()->GetInsertBlock()->getParent(); - // either invoke the head case function, or the tail case function - llvm::Function* thisFn = c->builder()->GetInsertBlock()->getParent(); + // for a condition, we need a 'then' branch, an 'else' branch, and a 'merge' block joining the two + llvm::BasicBlock* thenBlock = llvm::BasicBlock::Create(ctx, "then", thisFn); + llvm::BasicBlock* elseBlock = llvm::BasicBlock::Create(ctx, "else"); + llvm::BasicBlock* mergeBlock = llvm::BasicBlock::Create(ctx, "ifmerge"); - // for a condition, we need a 'then' branch, an 'else' branch, and a 'merge' block joining the two - llvm::BasicBlock* thenBlock = llvm::BasicBlock::Create(context(), "then", thisFn); - llvm::BasicBlock* elseBlock = llvm::BasicBlock::Create(context(), "else"); - llvm::BasicBlock* mergeBlock = llvm::BasicBlock::Create(context(), "ifmerge"); + // compile 'then' branch flowing to 'merge' block + c->builder()->CreateCondBr(ishtag, thenBlock, elseBlock); + c->builder()->SetInsertPoint(thenBlock); - // compile 'then' branch flowing to 'merge' block - c->builder()->CreateCondBr(ishtag, thenBlock, elseBlock); - c->builder()->SetInsertPoint(thenBlock); + llvm::Value* thenExp = callWith(c, es[1], vheadm.type, payloadValue(c, vheadm.type, pval)); - llvm::Value* thenExp = callWith(c, es[1], vheadm.type, payloadValue(c, vheadm.type, pval)); + c->builder()->CreateBr(mergeBlock); + thenBlock = c->builder()->GetInsertBlock(); // reset block pointer, in case compiling 'then' expression changed the active block - c->builder()->CreateBr(mergeBlock); - thenBlock = c->builder()->GetInsertBlock(); // reset block pointer, in case compiling 'then' expression changed the active block + // compile the 'else' branch + thisFn->getBasicBlockList().push_back(elseBlock); + c->builder()->SetInsertPoint(elseBlock); - // compile the 'else' branch - thisFn->getBasicBlockList().push_back(elseBlock); - c->builder()->SetInsertPoint(elseBlock); + llvm::Value* elseExp = callWith(c, es[2], vty->tailType(), var); + c->builder()->CreateBr(mergeBlock); + elseBlock = c->builder()->GetInsertBlock(); // reset block pointer, in case compiling 'else' expression changed the active block - llvm::Value* elseExp = callWith(c, es[2], vty->tailType(), var); - c->builder()->CreateBr(mergeBlock); - elseBlock = c->builder()->GetInsertBlock(); // reset block pointer, in case compiling 'else' expression changed the active block + // finally, merge blocks + thisFn->getBasicBlockList().push_back(mergeBlock); + c->builder()->SetInsertPoint(mergeBlock); - // finally, merge blocks - thisFn->getBasicBlockList().push_back(mergeBlock); - c->builder()->SetInsertPoint(mergeBlock); - - // and the final value is the phi merge of the two possible branches - // (if it's a non-trivial type) - if (isUnit(resultType)) { - return cvalue(true); - } else { - llvm::PHINode* pn = c->builder()->CreatePHI(toLLVM(resultType, true), 2); - pn->addIncoming(thenExp, thenBlock); - pn->addIncoming(elseExp, elseBlock); + // and the final value is the phi merge of the two possible branches + // (if it's a non-trivial type) + if (isUnit(resultType)) { + return cvalue(true); + } else { + llvm::PHINode* pn = c->builder()->CreatePHI(toLLVM(resultType, true), 2); + pn->addIncoming(thenExp, thenBlock); + pn->addIncoming(elseExp, elseBlock); - return pn; + return pn; + } } - } + }); } PolyTypePtr type(typedb&) const { @@ -905,17 +924,19 @@ char stdstrelem(const std::string& x, size_t i) { return x[i]; } class packLongF : public op { llvm::Value* apply(jitcc* c, const MonoTypes&, const MonoTypePtr&, const Exprs& es) { - llvm::Value* c0 = c->builder()->CreateShl(c->builder()->CreateIntCast(c->compile(es[0]), longType(), false), 56); - llvm::Value* c1 = c->builder()->CreateShl(c->builder()->CreateIntCast(c->compile(es[1]), longType(), false), 48); - llvm::Value* c2 = c->builder()->CreateShl(c->builder()->CreateIntCast(c->compile(es[2]), longType(), false), 40); - llvm::Value* c3 = c->builder()->CreateShl(c->builder()->CreateIntCast(c->compile(es[3]), longType(), false), 32); - llvm::Value* c4 = c->builder()->CreateShl(c->builder()->CreateIntCast(c->compile(es[4]), longType(), false), 24); - llvm::Value* c5 = c->builder()->CreateShl(c->builder()->CreateIntCast(c->compile(es[5]), longType(), false), 16); - llvm::Value* c6 = c->builder()->CreateShl(c->builder()->CreateIntCast(c->compile(es[6]), longType(), false), 8); - llvm::Value* c7 = c->builder()->CreateIntCast(c->compile(es[7]), longType(), false); - - return - c->builder()->CreateOr(c0,c->builder()->CreateOr(c1,c->builder()->CreateOr(c2,c->builder()->CreateOr(c3,c->builder()->CreateOr(c4,c->builder()->CreateOr(c5,c->builder()->CreateOr(c6,c7))))))); + return withContext([&](auto&) { + llvm::Value* c0 = c->builder()->CreateShl(c->builder()->CreateIntCast(c->compile(es[0]), longType(), false), 56); + llvm::Value* c1 = c->builder()->CreateShl(c->builder()->CreateIntCast(c->compile(es[1]), longType(), false), 48); + llvm::Value* c2 = c->builder()->CreateShl(c->builder()->CreateIntCast(c->compile(es[2]), longType(), false), 40); + llvm::Value* c3 = c->builder()->CreateShl(c->builder()->CreateIntCast(c->compile(es[3]), longType(), false), 32); + llvm::Value* c4 = c->builder()->CreateShl(c->builder()->CreateIntCast(c->compile(es[4]), longType(), false), 24); + llvm::Value* c5 = c->builder()->CreateShl(c->builder()->CreateIntCast(c->compile(es[5]), longType(), false), 16); + llvm::Value* c6 = c->builder()->CreateShl(c->builder()->CreateIntCast(c->compile(es[6]), longType(), false), 8); + llvm::Value* c7 = c->builder()->CreateIntCast(c->compile(es[7]), longType(), false); + + return + c->builder()->CreateOr(c0,c->builder()->CreateOr(c1,c->builder()->CreateOr(c2,c->builder()->CreateOr(c3,c->builder()->CreateOr(c4,c->builder()->CreateOr(c5,c->builder()->CreateOr(c6,c7))))))); + }); } PolyTypePtr type(typedb& db) const { @@ -926,22 +947,24 @@ class packLongF : public op { class packIntF : public op { llvm::Value* apply(jitcc* c, const MonoTypes&, const MonoTypePtr&, const Exprs& es) { - llvm::Value* c0 = c->builder()->CreateIntCast(c->compile(es[0]), intType(), false); - llvm::Value* c1 = c->builder()->CreateIntCast(c->compile(es[1]), intType(), false); - llvm::Value* c2 = c->builder()->CreateIntCast(c->compile(es[2]), intType(), false); - llvm::Value* c3 = c->builder()->CreateIntCast(c->compile(es[3]), intType(), false); - - return - c->builder()->CreateOr( - c->builder()->CreateShl(c0, 24), + return withContext([&](auto&) { + llvm::Value* c0 = c->builder()->CreateIntCast(c->compile(es[0]), intType(), false); + llvm::Value* c1 = c->builder()->CreateIntCast(c->compile(es[1]), intType(), false); + llvm::Value* c2 = c->builder()->CreateIntCast(c->compile(es[2]), intType(), false); + llvm::Value* c3 = c->builder()->CreateIntCast(c->compile(es[3]), intType(), false); + + return c->builder()->CreateOr( - c->builder()->CreateShl(c1, 16), + c->builder()->CreateShl(c0, 24), c->builder()->CreateOr( - c->builder()->CreateShl(c2, 8), - c3 + c->builder()->CreateShl(c1, 16), + c->builder()->CreateOr( + c->builder()->CreateShl(c2, 8), + c3 + ) ) - ) - ); + ); + }); } PolyTypePtr type(typedb& db) const { @@ -952,14 +975,16 @@ class packIntF : public op { class packShortF : public op { llvm::Value* apply(jitcc* c, const MonoTypes&, const MonoTypePtr&, const Exprs& es) { - llvm::Value* c0 = c->builder()->CreateIntCast(c->compile(es[0]), shortType(), false); - llvm::Value* c1 = c->builder()->CreateIntCast(c->compile(es[1]), shortType(), false); + return withContext([&](auto&) { + llvm::Value* c0 = c->builder()->CreateIntCast(c->compile(es[0]), shortType(), false); + llvm::Value* c1 = c->builder()->CreateIntCast(c->compile(es[1]), shortType(), false); - return - c->builder()->CreateOr( - c->builder()->CreateShl(c0, 8), - c1 - ); + return + c->builder()->CreateOr( + c->builder()->CreateShl(c0, 8), + c1 + ); + }); } PolyTypePtr type(typedb& db) const { @@ -970,11 +995,10 @@ class packShortF : public op { class cptrrefbyF : public op { llvm::Value* apply(jitcc* c, const MonoTypes&, const MonoTypePtr&, const Exprs& es) { - return - c->builder()->CreateLoad( - offset(c->builder(), c->compile(es[0]), c->compile(es[1])), - false - ); + return withContext([&](auto&) { + return c->builder()->CreateLoad( + offset(c->builder(), c->compile(es[0]), c->compile(es[1])), false); + }); } PolyTypePtr type(typedb& db) const { diff --git a/lib/hobbes/eval/jitcc.C b/lib/hobbes/eval/jitcc.C index 3181d6228..263e41793 100644 --- a/lib/hobbes/eval/jitcc.C +++ b/lib/hobbes/eval/jitcc.C @@ -2,12 +2,25 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wctor-dtor-privacy" +#if LLVM_VERSION_MAJOR >= 11 +#include +#else #if LLVM_VERSION_MINOR == 3 or LLVM_VERSION_MINOR == 5 #include "llvm/ExecutionEngine/JIT.h" #else @@ -21,6 +34,7 @@ #if LLVM_VERSION_MAJOR == 4 || LLVM_VERSION_MAJOR == 6 #include "llvm/Transforms/Scalar/GVN.h" #endif +#endif #include "llvm/Object/ELFObjectFile.h" #include "llvm/ExecutionEngine/JITEventListener.h" @@ -28,23 +42,262 @@ #pragma GCC diagnostic pop namespace hobbes { +#if LLVM_VERSION_MAJOR >= 11 +class ConstantList { + using VarFnTy = std::function; + struct Constant { + MonoTypePtr mtype; + variant varOrFunc; + VarFnTy fn; + }; + llvm::StringMap constants; + +public: + ConstantList() = default; + ConstantList(const ConstantList&) = delete; + ConstantList(ConstantList&&) = delete; + ConstantList& operator=(const ConstantList&) = delete; + ConstantList& operator=(ConstantList&&) = delete; + ~ConstantList() = default; + + LLVM_NODISCARD bool contains(llvm::StringRef name) const { + return constants.find(name) != constants.end(); + } + + /// Creates const global variable definition + /// + /// \p initVal is the initializer for this constant, must not be null + /// or it can be a function + void createDefinition(const std::string& name, llvm::Module& m, llvm::Constant* initVal, + const MonoTypePtr& mtype); + + /// Gets constant by generating load inst or possibly recreating decl + LLVM_NODISCARD llvm::Value* loadConstant(llvm::StringRef name, llvm::Module& m, + llvm::IRBuilder<>& builder); +}; + +void ConstantList::createDefinition(const std::string& name, llvm::Module& m, + llvm::Constant* initVal, const MonoTypePtr& mtype) { + assert(!contains(name)); + + llvm::Type* type = toLLVM(mtype); + if (is(mtype) != nullptr) { + constants[name] = Constant{.mtype = mtype, .varOrFunc = initVal, .fn = VarFnTy()}; + } else { + constants[name] = Constant{ + .mtype = mtype, + .varOrFunc = llvm::WeakTrackingVH(new llvm::GlobalVariable( + m, type, /*isConstant=*/true, llvm::GlobalVariable::ExternalLinkage, initVal, name)), + .fn = [&, type, name](llvm::Module& m) -> llvm::GlobalVariable* { + return prepgv(new llvm::GlobalVariable(m, type, /*isConstant=*/true, + llvm::GlobalVariable::ExternalLinkage, + /*initializer=*/nullptr, name)); + }}; + } +} + +llvm::Value* ConstantList::loadConstant(llvm::StringRef name, llvm::Module& m, + llvm::IRBuilder<>& builder) { + auto it = constants.find(name); + if (it == constants.end()) { + return nullptr; + } + + if (is(it->second.mtype) != nullptr) { + return *it->second.varOrFunc.get(); + } + + return withContext([&](auto&) -> llvm::Value* { + if (!it->second.varOrFunc.get()->pointsToAliveValue()) { + it->second.varOrFunc = llvm::WeakTrackingVH(it->second.fn(m)); + } + + auto* g = llvm::cast( + static_cast(*it->second.varOrFunc.get())); + + if (is(it->second.mtype) != nullptr) { + return builder.CreateLoad(g); + } + if (hasPointerRep(it->second.mtype)) { + return g; + } + return builder.CreateAlignedLoad(g->getType()->getPointerElementType(), g, llvm::MaybeAlign(8)); + }); +} + +class VTEnv { +public: + using FunFnTy = std::function; + +private: + using VarBindings = llvm::StringMap; + using VarBindingStack = llvm::SmallVector; + VarBindingStack vtenv; + llvm::StringMap vtenvFuns; + +public: + VTEnv() = default; + VTEnv(const VTEnv&) = delete; + VTEnv(VTEnv&&) = delete; + VTEnv& operator=(const VTEnv&) = delete; + VTEnv& operator=(VTEnv&&) = delete; + ~VTEnv() = default; + + LLVM_NODISCARD bool contains(llvm::StringRef name) const { + return std::any_of(vtenv.rbegin(), vtenv.rend(), + [name](const auto& vb) { return vb.find(name) != vb.end(); }); + } + + /// Gets \p name by looking up from inner to outer scope + /// + /// Possibly recreating decl + LLVM_NODISCARD llvm::Value* getOrCreateDecl(llvm::StringRef name, llvm::Module& m); + + /// Adds variable \p name to current scope + void add(llvm::StringRef name, llvm::Value* v) { + this->vtenv.back()[name] = v; + } + + /// Adds function \p name to current scope + /// + /// It stores function prototype for decl recreating + void add(llvm::StringRef name, FunFnTy f, llvm::Function* fp) { + this->vtenv.back()[name] = fp; + vtenvFuns[name] = std::move(f); + } + + /// Create a new inner scope + void pushScope() { + vtenv.push_back(VarBindings()); + } + + /// Destroys the inner scope + void popScope() { + vtenv.pop_back(); + } +}; + +llvm::Value* VTEnv::getOrCreateDecl(llvm::StringRef name, llvm::Module& m) { + for (auto vb = vtenv.rbegin(); vb != vtenv.rend(); ++vb) { + auto it = vb->find(name); + if (it == vb->end()) { + continue; + } + if (!it->second.pointsToAliveValue()) { + assert(vtenvFuns.find(name) != vtenvFuns.end()); + it->second = vtenvFuns[name](m); + } + return it->second; + } + return nullptr; +} + +class Globals { +private: + using FunFnTy = std::function; + using VarFnTy = std::function; + struct Global { + variant protoTypes; + llvm::WeakTrackingVH handle; + }; + llvm::StringMap globals; + LLVM_NODISCARD bool isFunc(decltype(globals)::iterator it) const { + return it->second.protoTypes.get() != nullptr; + } + +public: + Globals() = default; + Globals(const Globals&) = delete; + Globals(Globals&&) = delete; + Globals& operator=(const Globals&) = delete; + Globals& operator=(Globals&&) = delete; + ~Globals() = default; + + LLVM_NODISCARD bool contains(llvm::StringRef name) const { + return globals.find(name) != globals.end(); + } + + /// Gets a global variable \p name by possibly recreating decl in current module + LLVM_NODISCARD llvm::GlobalVariable* getOrCreateVarDecl(llvm::StringRef name, llvm::Module& m); + /// Gets a global function \p name by possibly recreating decl in current module + LLVM_NODISCARD llvm::Function* getOrCreateFuncDecl(llvm::StringRef name, llvm::Module& m); + + /// Creates a global variable decl for \p name with type \p ty + /// + /// It stores variable prototype for decl recreating + void add(const std::string& name, llvm::Module& m, llvm::Type* ty); + /// Creates a global function decl for \p name with type \p ty if \p existingF is null + /// + /// It stores function prototype for decl recreating + void add(const std::string& name, llvm::Module& m, llvm::FunctionType* ty, + llvm::Function* existingF); +}; + +llvm::GlobalVariable* Globals::getOrCreateVarDecl(llvm::StringRef name, llvm::Module& m) { + auto it = globals.find(name); + if (it == globals.end() || isFunc(it)) { + return nullptr; + } + if (!it->second.handle.pointsToAliveValue()) { + it->second.handle = (*it->second.protoTypes.get())(m); + } + return llvm::cast(static_cast(it->second.handle)); +} + +llvm::Function* Globals::getOrCreateFuncDecl(llvm::StringRef name, llvm::Module& m) { + auto it = globals.find(name); + if (it == globals.end() || !isFunc(it)) { + return nullptr; + } + if (!it->second.handle.pointsToAliveValue()) { + it->second.handle = (*it->second.protoTypes.get())(m); + } + return llvm::cast(static_cast(it->second.handle)); +} + +void Globals::add(const std::string& name, llvm::Module& m, llvm::Type* ty) { + Global g; + g.protoTypes = VarFnTy([ty, name](llvm::Module& m) { + return prepgv(new llvm::GlobalVariable(m, ty, /*isConstant=*/false, + llvm::GlobalValue::ExternalLinkage, + /*initializer=*/nullptr, name), + sizeof(void*)); + }); + g.handle = (*g.protoTypes.get())(m); + globals[name] = g; +} + +void Globals::add(const std::string& name, llvm::Module& m, llvm::FunctionType* ty, + llvm::Function* existingF) { + Global g; + g.protoTypes = FunFnTy([ty, name](llvm::Module& m) { + return llvm::Function::Create(ty, llvm::Function::ExternalLinkage, name, m); + }); + if (existingF != nullptr) { + g.handle = existingF; + } else { + g.handle = (*g.protoTypes.get())(m); + } + globals[name] = g; +} +#endif // this should be moved out of here eventually bool isFileType(const MonoTypePtr&); -#if LLVM_VERSION_MINOR >= 6 || LLVM_VERSION_MAJOR == 4 || LLVM_VERSION_MAJOR == 6 || LLVM_VERSION_MAJOR >= 8 +#if (LLVM_VERSION_MINOR >= 6 || LLVM_VERSION_MAJOR == 4 || LLVM_VERSION_MAJOR == 6 || LLVM_VERSION_MAJOR >= 8) && LLVM_VERSION_MAJOR < 11 class jitmm : public llvm::SectionMemoryManager { public: - jitmm(jitcc* jit) : jit(jit) { } + explicit jitmm(jitcc* jit) : jit(jit) { } // link symbols across modules :T uint64_t getSymbolAddress(const std::string& n) override { if (uint64_t laddr = reinterpret_cast(this->jit->getSymbolAddress(n))) { return laddr; } - if (n.size() > 0 && n[0] == '_') { + if (!n.empty() && n[0] == '_') { uint64_t sv = reinterpret_cast(this->jit->getSymbolAddress(n.substr(1))); - if (sv) return sv; + if (sv != 0U) return sv; } if (uint64_t baddr = llvm::SectionMemoryManager::getSymbolAddress(n)) { return baddr; @@ -57,8 +310,38 @@ private: }; #endif +#if LLVM_VERSION_MAJOR >= 11 +jitcc::jitcc(const TEnvPtr& tenv) + : tenv(tenv), vtenv(std::make_unique()), ignoreLocalScope(false), + globals(std::make_unique()), globalData(32768 /* min global page size = 32K */), + constants(std::make_unique()) { + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmParser(); + llvm::InitializeNativeTargetAsmPrinter(); + + this->orcjit = llvm::cantFail(ORCJIT::create(), "orcjit init failed"); + + // allocate an IR builder with an initial dummy basic-block to write into + this->irbuilder = withContext([](llvm::LLVMContext& c) { + auto r = std::make_unique>(c); + r->SetInsertPoint(llvm::BasicBlock::Create(c, "dummy")); + return r; + }); + + // make sure we've always got one frame for variable defs + this->pushScope(); +} + +jitcc::~jitcc() { + // release low-level functions + for (auto f : this->fenv) { + delete f.second; + } +} +#else + jitcc::jitcc(const TEnvPtr& tenv) : - tenv(tenv), currentModule(0), irbuilder(0), + tenv(tenv), ignoreLocalScope(false), globalData(32768 /* min global page size = 32K */) { @@ -67,8 +350,11 @@ jitcc::jitcc(const TEnvPtr& tenv) : llvm::InitializeNativeTargetAsmPrinter(); // allocate an IR builder with an initial dummy basic-block to write into - this->irbuilder = new llvm::IRBuilder<>(context()); - this->irbuilder->SetInsertPoint(llvm::BasicBlock::Create(context(), "dummy")); + this->irbuilder = withContext([](llvm::LLVMContext& c) { + auto r = std::make_unique>(c); + r->SetInsertPoint(llvm::BasicBlock::Create(c, "dummy")); + return r; + }); // make sure we've always got one frame for variable defs this->vtenv.push_back(VarBindings()); @@ -120,26 +406,67 @@ jitcc::~jitcc() { #elif LLVM_VERSION_MINOR == 3 or LLVM_VERSION_MINOR == 5 delete this->eengine; #endif - - delete this->irbuilder; } +#endif const TEnvPtr& jitcc::typeEnv() const { return this->tenv; } llvm::IRBuilder<>* jitcc::builder() const { - return this->irbuilder; + return this->irbuilder.get(); } +#if LLVM_VERSION_MAJOR >= 11 llvm::Module* jitcc::module() { - if (!this->currentModule) { - this->currentModule = new llvm::Module("jitModule" + str::from(this->modules.size()), context()); + if (this->currentModule == nullptr) { + this->currentModule = withContext([](llvm::LLVMContext& c) { + auto m = std::make_unique(createUniqueName("jitModule"), c); + return m; + }); + } + return this->currentModule.get(); +} +#else +llvm::Module* jitcc::module() { + if (this->currentModule == nullptr) { + this->currentModule = withContext([this](llvm::LLVMContext& c) { + return new llvm::Module("jitModule" + str::from(this->modules.size()), c); + }); this->modules.push_back(this->currentModule); } return this->currentModule; } +#endif + +#if LLVM_VERSION_MAJOR >= 11 +void* jitcc::getMachineCode(llvm::Function* f, llvm::JITEventListener* /*listener*/) { + const std::string fname = f->getName().str(); + auto sym = orcjit->lookup(fname); + if (auto e = sym.takeError()) { + llvm::consumeError(std::move(e)); + } else { + return llvm::jitTargetAddressToPointer(sym->getAddress()); + } + + withContext([&](auto&) { + const std::string name = this->currentModule->getName().str(); + if (auto e = orcjit->addModule(std::move(this->currentModule))) { + llvm::logAllUnhandledErrors(std::move(e), llvm::errs()); + throw std::runtime_error("cannot add module " + name); + } + }); + sym = orcjit->lookup(fname); + if (auto e = sym.takeError()) { + logAllUnhandledErrors(std::move(e), llvm::errs()); + throw std::runtime_error( + "Internal compiler error, no current module and no machine code for (" + fname + ")"); + } + + return llvm::jitTargetAddressToPointer(sym->getAddress()); +} +#else void* jitcc::getSymbolAddress(const std::string& vn) { // do we have a global with this name? auto gd = this->globals.find(vn); @@ -156,7 +483,7 @@ void* jitcc::getSymbolAddress(const std::string& vn) { } } } -#elif LLVM_VERSION_MINOR >= 6 || LLVM_VERSION_MAJOR == 4 +#elif LLVM_VERSION_MINOR >= 6 || LLVM_VERSION_MAJOR == 4 for (auto ee : this->eengines) { if (uint64_t faddr = ee->getFunctionAddress(vn)) { return reinterpret_cast(faddr); @@ -275,6 +602,7 @@ void* jitcc::getMachineCode(llvm::Function* f, llvm::JITEventListener* listener) } #endif } +#endif #if LLVM_VERSION_MINOR >= 7 || LLVM_VERSION_MAJOR == 4 || LLVM_VERSION_MAJOR == 6 || LLVM_VERSION_MAJOR >= 8 // get the machine code produced for a given expression @@ -283,7 +611,7 @@ class LenWatch : public llvm::JITEventListener { public: std::string fname; size_t sz; - LenWatch(const std::string& fname) : fname(fname), sz(0) { } + explicit LenWatch(const std::string& fname) : fname(fname), sz(0) { } size_t size() const { return this->sz; } void NotifyObjectEmitted(const llvm::object::ObjectFile& o, const llvm::RuntimeDyld::LoadedObjectInfo&) { for (auto s : o.symbols()) { @@ -353,6 +681,23 @@ jitcc::bytes jitcc::machineCodeForExpr(const ExprPtr& e) { return r; } +#if LLVM_VERSION_MAJOR >= 11 +bool jitcc::isDefined(const std::string& vn) const { + if (this->globals->contains(vn)) { + return true; + } + if (this->constants->contains(vn)) { + return true; + } + if (lookupOp(vn) != nullptr) { + return true; + } + if (this->vtenv->contains(vn)) { + return true; + } + return false; +} +#else bool jitcc::isDefined(const std::string& vn) const { if (this->globals.find(vn) != this->globals.end()) { return true; @@ -369,6 +714,7 @@ bool jitcc::isDefined(const std::string& vn) const { return false; } } +#endif llvm::Value* jitcc::compile(const ExprPtr& exp) { return toLLVM(this, exp); @@ -387,6 +733,30 @@ op* jitcc::lookupOp(const std::string& vn) const { return (f == this->fenv.end()) ? 0 : f->second; } +#if LLVM_VERSION_MAJOR >= 11 +void jitcc::bindGlobal(const std::string& vn, const MonoTypePtr& ty, void* x) { + assert(not this->globals->contains(vn)); + + void* value = x; + if (is(ty) != nullptr) { + withContext([&](auto&) { + this->globals->add(vn, *this->module(), + llvm::cast(toLLVM(ty, /*asArg=*/false)), + /*existingF=*/nullptr); + }); + } else { + if (hasPointerRep(ty) || isFileType(ty)) { + void** p = reinterpret_cast(this->globalData.malloc(sizeof(void*))); + *p = x; + value = p; + } + + withContext( + [&](auto&) { return this->globals->add(vn, *this->module(), toLLVM(ty, /*asArg=*/true)); }); + } + llvm::cantFail(orcjit->addExternalSymbol(vn, value)); +} +#else void jitcc::bindGlobal(const std::string& vn, const MonoTypePtr& ty, void* x) { Global g; g.type = ty; @@ -419,14 +789,16 @@ void jitcc::bindGlobal(const std::string& vn, const MonoTypePtr& ty, void* x) { vn ), sizeof(void*)); - + #if LLVM_VERSION_MINOR == 3 or LLVM_VERSION_MINOR == 5 this->eengine->addGlobalMapping(g.ref.var, g.value); #endif } this->globals[vn] = g; } +#endif +#if LLVM_VERSION_MAJOR < 11 llvm::Value* jitcc::maybeRefGlobalV(llvm::Value* v) { llvm::Module* thisMod = module(); @@ -448,7 +820,13 @@ llvm::Value* jitcc::maybeRefGlobalV(llvm::Value* v) { return v; } } +#endif +#if LLVM_VERSION_MAJOR >= 11 +llvm::GlobalVariable* jitcc::lookupGlobalVar(const std::string& vn) { + return withContext([&](auto&) { return this->globals->getOrCreateVarDecl(vn, *this->module()); }); +} +#else llvm::GlobalVariable* jitcc::maybeRefGlobal(const std::string& vn) { auto gv = this->globals.find(vn); if (gv != this->globals.end() && !is(gv->second.type)) { @@ -456,7 +834,9 @@ llvm::GlobalVariable* jitcc::maybeRefGlobal(const std::string& vn) { } return 0; } +#endif +#if LLVM_VERSION_MAJOR < 11 llvm::GlobalVariable* jitcc::refGlobal(const std::string& vn, llvm::GlobalVariable* gv) { llvm::Module* mod = module(); @@ -477,41 +857,60 @@ llvm::GlobalVariable* jitcc::refGlobal(const std::string& vn, llvm::GlobalVariab sizeof(void*)); } } +#endif llvm::GlobalVariable* jitcc::lookupVarRef(const std::string& vn) { // if any local variables shadow this global, hide it +#if LLVM_VERSION_MAJOR >= 11 + if (this->vtenv->contains(vn)) { + return nullptr; + } +#else for (auto vbs : this->vtenv) { if (vbs.find(vn) != vbs.end()) { return 0; } } +#endif // now if we've got a global with this name, we can get a pointer to it +#if LLVM_VERSION_MAJOR >= 11 + return lookupGlobalVar(vn); +#else return maybeRefGlobal(vn); +#endif } +#if LLVM_VERSION_MAJOR >= 11 +llvm::Value* jitcc::loadConstant(const std::string& vn) { + return withContext( + [&](auto&) { return this->constants->loadConstant(vn, *this->module(), *builder()); }); +} +#else llvm::Value* jitcc::loadConstant(const std::string& vn) { auto cv = this->constants.find(vn); if (cv != this->constants.end()) { - if (is(cv->second.mtype)) { - return builder()->CreateLoad(refGlobal(vn, cv->second.ref)); - } else if (llvm::Value* r = refGlobal(vn, cv->second.ref)) { -#if LLVM_VERSION_MAJOR <= 10 - return hasPointerRep(cv->second.mtype) ? r : builder()->CreateLoad(r); + return withContext([&](auto&) -> llvm::Value* { + if (is(cv->second.mtype)) { + return builder()->CreateLoad(refGlobal(vn, cv->second.ref)); + } else if (llvm::Value* r = refGlobal(vn, cv->second.ref)) { +#if LLVM_VERSION_MAJOR <= 10 + return hasPointerRep(cv->second.mtype) ? r : builder()->CreateLoad(r); #elif LLVM_VERSION_MAJOR <= 12 - return hasPointerRep(cv->second.mtype) ? r : builder()->CreateAlignedLoad(r->getType()->getPointerElementType(), r, llvm::MaybeAlign(8)); + return hasPointerRep(cv->second.mtype) ? r : builder()->CreateAlignedLoad(r->getType()->getPointerElementType(), r, llvm::MaybeAlign(8)); #endif - } else { - return cv->second.value; - } + } else { + return cv->second.value; + } + }); } - return 0; + return nullptr; } +#endif void jitcc::defineGlobal(const std::string& vn, const ExprPtr& ue) { std::string vname = vn.empty() ? (".global" + freshName()) : vn; this->globalExprs[vn] = ue; - typedef void (*Thunk)(); MonoTypePtr uety = requireMonotype(this->tenv, ue); @@ -523,6 +922,10 @@ void jitcc::defineGlobal(const std::string& vn, const ExprPtr& ue) { resetMemoryPool(); } else if (llvm::Constant* c = toLLVMConstant(this, vname, ue)) { // make a global constant ... +#if LLVM_VERSION_MAJOR >= 11 + withContext( + [&](auto&) { return this->constants->createDefinition(vname, *module(), c, uety); }); +#else Constant& cv = this->constants[vname]; cv.value = c; cv.type = toLLVM(uety); @@ -534,6 +937,7 @@ void jitcc::defineGlobal(const std::string& vn, const ExprPtr& ue) { } else { cv.ref = new llvm::GlobalVariable(*module(), cv.type, true, llvm::GlobalVariable::ExternalLinkage, c, vname); } +#endif } else { // make some space for this global data ... if (isLargeType(uety)) { @@ -545,16 +949,18 @@ void jitcc::defineGlobal(const std::string& vn, const ExprPtr& ue) { } // compile an initializer function for this expression - llvm::BasicBlock* ibb = this->builder()->GetInsertBlock(); + llvm::BasicBlock* ibb = withContext([this](auto&) { return this->builder()->GetInsertBlock(); }); llvm::Function* initfn = allocFunction("." + vname + "_init", MonoTypes(), primty("unit")); - if (initfn == 0) { + if (initfn == nullptr) { throw annotated_error(*ue, "Failed to allocate initializer function for '" + vname + "'."); } - llvm::BasicBlock* bb = llvm::BasicBlock::Create(context(), "entry", initfn); - this->builder()->SetInsertPoint(bb); + withContext([&](llvm::LLVMContext& c) { + llvm::BasicBlock* bb = llvm::BasicBlock::Create(c, "entry", initfn); + this->builder()->SetInsertPoint(bb); - compile(assign(var(vname, uety, ue->la()), ue, ue->la())); - this->builder()->CreateRetVoid(); + compile(assign(var(vname, uety, ue->la()), ue, ue->la())); + this->builder()->CreateRetVoid(); + }); // compile and run this function, it should then perform the global variable assignment // (make sure that any allocation happens in the global context iff we need it) @@ -571,8 +977,10 @@ void jitcc::defineGlobal(const std::string& vn, const ExprPtr& ue) { // clean up releaseMachineCode(reinterpret_cast(f)); - this->builder()->SetInsertPoint(ibb); + withContext([this, ibb](auto&) { this->builder()->SetInsertPoint(ibb); }); +#if LLVM_VERSION_MAJOR < 11 initfn->eraseFromParent(); +#endif } } @@ -603,6 +1011,14 @@ llvm::Value* jitcc::lookupVar(const std::string& vn, const MonoTypePtr& vty) { } // try to find this variable up the local variable stack (unless we're ignoring local scope) +#if LLVM_VERSION_MAJOR >= 11 + if (!this->ignoreLocalScope) { + if (auto* fn = + withContext([&](auto&) { return this->vtenv->getOrCreateDecl(vn, *this->module()); })) { + return fn; + } + } +#else if (!this->ignoreLocalScope) { for (size_t i = 0; i < this->vtenv.size(); ++i) { const VarBindings& vbs = this->vtenv[this->vtenv.size() - (i + 1)]; @@ -612,10 +1028,15 @@ llvm::Value* jitcc::lookupVar(const std::string& vn, const MonoTypePtr& vty) { } } } +#endif // try to find this variable as a global +#if LLVM_VERSION_MAJOR >= 11 + if (llvm::GlobalVariable* gv = lookupGlobalVar(vn)) { +#else if (llvm::GlobalVariable* gv = maybeRefGlobal(vn)) { - return builder()->CreateLoad(gv); +#endif + return withContext([this, gv](auto&) { return builder()->CreateLoad(gv); }); } // maybe it's a function? @@ -647,6 +1068,19 @@ llvm::Value* jitcc::internConstString(const std::string& x) { return lookupVar(vn, arrayty(primty("char"))); } +#if LLVM_VERSION_MAJOR >= 11 +void jitcc::pushScope() { + this->vtenv->pushScope(); +} + +void jitcc::bindScope(const std::string& vn, llvm::Value* v) { + this->vtenv->add(vn, v); +} + +void jitcc::popScope() { + this->vtenv->popScope(); +} +#else void jitcc::pushScope() { this->vtenv.push_back(VarBindings()); } @@ -658,6 +1092,7 @@ void jitcc::bindScope(const std::string& vn, llvm::Value* v) { void jitcc::popScope() { this->vtenv.pop_back(); } +#endif llvm::Value* jitcc::compileAtGlobalScope(const ExprPtr& exp) { this->ignoreLocalScope = true; @@ -671,10 +1106,17 @@ llvm::Value* jitcc::compileAtGlobalScope(const ExprPtr& exp) { } } +#if LLVM_VERSION_MAJOR >= 11 +llvm::Function* jitcc::lookupFunction(const std::string& fn) { + return withContext( + [&](auto&) { return this->globals->getOrCreateFuncDecl(fn, *this->module()); }); +} +#else llvm::Function* jitcc::lookupFunction(const std::string& fn) { llvm::Module* thisMod = module(); - for (auto m : this->modules) { + for (size_t i = 0; imodules.size(); ++i) { + auto m = this->modules[i]; if (llvm::Function* f = m->getFunction(fn)) { if (m == thisMod) { return f; @@ -685,7 +1127,7 @@ llvm::Function* jitcc::lookupFunction(const std::string& fn) { } return 0; } - +#endif llvm::Function* jitcc::compileFunction(const std::string& name, const str::seq& argns, const MonoTypes& argtys, const ExprPtr& exp) { UCFS fs; fs.push_back(UCF(name, argns, argtys, exp)); @@ -726,7 +1168,7 @@ void jitcc::unsafeCompileFunctions(UCFS* ufs) { UCFS& fs = *ufs; // save our current write context to restore later - llvm::BasicBlock* ibb = this->builder()->GetInsertBlock(); + llvm::BasicBlock* ibb = withContext([this](auto&) { return this->builder()->GetInsertBlock(); }); // prepare the environment for these mutually-recursive definitions for (size_t f = 0; f < fs.size(); ++f) { @@ -735,7 +1177,11 @@ void jitcc::unsafeCompileFunctions(UCFS* ufs) { throw std::runtime_error("Failed to allocate function"); } +#if LLVM_VERSION_MAJOR >= 11 + this->bindScope(fs[f].name, fval); +#else this->vtenv.back()[fs[f].name] = fval; +#endif fs[f].result = fval; } @@ -744,57 +1190,76 @@ void jitcc::unsafeCompileFunctions(UCFS* ufs) { llvm::Function* fval = fs[f].result; const UCF& ucf = fs[f]; MonoTypePtr rty = requireMonotype(this->tenv, ucf.exp); - llvm::BasicBlock* bb = llvm::BasicBlock::Create(context(), "entry", fval); + llvm::BasicBlock* bb = withContext( + [fval](llvm::LLVMContext& c) { return llvm::BasicBlock::Create(c, "entry", fval); }); - this->builder()->SetInsertPoint(bb); + withContext([this, bb](auto&) { return this->builder()->SetInsertPoint(bb); }); // set argument names for safe referencing here +#if LLVM_VERSION_MAJOR >= 11 + this->pushScope(); +#else this->vtenv.push_back(VarBindings()); +#endif llvm::Function::arg_iterator a = fval->arg_begin(); for (unsigned int i = 0; i < ucf.argns.size(); ++i) { if (isUnit(ucf.argtys[i])) { +#if LLVM_VERSION_MAJOR >= 11 + this->bindScope(ucf.argns[i], cvalue(true)); // this should never even be seen +#else this->vtenv.back()[ucf.argns[i]] = cvalue(true); // this should never even be seen +#endif } else { a->setName(ucf.argns[i]); llvm::Value* argv = &*a; if (is(ucf.argtys[i])) { - argv = cast(this->builder(), ptrType(toLLVM(ucf.argtys[i], false)), argv); + argv = withContext([&](auto&) { + return cast(this->builder(), ptrType(toLLVM(ucf.argtys[i], false)), argv); + }); } +#if LLVM_VERSION_MAJOR >= 11 + this->bindScope(ucf.argns[i], argv); +#else this->vtenv.back()[ucf.argns[i]] = argv; +#endif ++a; } } - try { - // compile the function body - llvm::Value* cexp = compile(ucf.exp); - if (isUnit(rty)) { - this->builder()->CreateRetVoid(); - } else { - this->builder()->CreateRet(cexp); - } + withContext([&](auto&) { + try { + // compile the function body + llvm::Value* cexp = compile(ucf.exp); + if (isUnit(rty)) { + this->builder()->CreateRetVoid(); + } else { + this->builder()->CreateRet(cexp); + } #if LLVM_VERSION_MINOR == 3 or LLVM_VERSION_MINOR == 5 this->fpm->run(*fval); #endif - // and we're done - this->vtenv.pop_back(); - if (ibb != 0) { this->builder()->SetInsertPoint(ibb); } - } catch (...) { - if (ibb != 0) { this->builder()->SetInsertPoint(ibb); } - this->vtenv.pop_back(); - throw; - } + // and we're done + this->popScope(); + if (ibb != 0) { this->builder()->SetInsertPoint(ibb); } + } catch (...) { + if (ibb != 0) { this->builder()->SetInsertPoint(ibb); } + this->popScope(); + throw; + } + }); } } llvm::Value* jitcc::compileAllocStmt(llvm::Value* sz, llvm::Value* asz, llvm::Type* mty, bool zeroMem) { llvm::Function* f = lookupFunction(zeroMem ? "mallocz" : "malloc"); if (!f) throw std::runtime_error("Expected heap allocation function as call."); - return builder()->CreateBitCast(fncall(builder(), f, f->getFunctionType(), list(sz, asz)), mty); + return withContext([&](auto&) { + return builder()->CreateBitCast(fncall(builder(), f, f->getFunctionType(), list(sz, asz)), mty); + }); } llvm::Value* jitcc::compileAllocStmt(size_t sz, size_t asz, llvm::Type* mty, bool zeroMem) { @@ -804,6 +1269,37 @@ llvm::Value* jitcc::compileAllocStmt(size_t sz, size_t asz, llvm::Type* mty, boo void jitcc::releaseMachineCode(void*) { } +#if LLVM_VERSION_MAJOR >= 11 +llvm::Function* jitcc::allocFunction(const std::string& fname, const MonoTypes& argl, const MonoTypePtr& rty) { + const auto f = [=](llvm::Module& m) { + llvm::Type* retType = toLLVM(rty, true); + auto* f = llvm::Function::Create( + llvm::FunctionType::get(retType, toLLVM(argl, true), false), + fname.find(".patfs.") == 0 ? llvm::Function::InternalLinkage + : llvm::Function::ExternalLinkage, + fname, m); + // https://bugs.llvm.org/show_bug.cgi?id=51163 + // for a llvm version >=9, zeroext has to be added to functions return boolean + // otherwise, 255 will be returned as true + if (retType == boolType()) { + f->addAttribute(llvm::AttributeList::ReturnIndex, llvm::Attribute::ZExt); + } + return f; + }; + llvm::Function* ret = withContext([&](auto&) { return f(*this->module()); }); + + if (fname.find(".rfn.t") != std::string::npos) { + this->vtenv->add(fname, f, ret); + } else if (!this->globals->contains(fname)) { + withContext([&](auto&) { + return this->globals->add( + fname, *this->module(), + llvm::FunctionType::get(toLLVM(rty, true), toLLVM(argl, true), false), ret); + }); + } + return ret; +} +#else llvm::Function* jitcc::allocFunction(const std::string& fname, const MonoTypes& argl, const MonoTypePtr& rty) { return llvm::Function::Create( @@ -813,6 +1309,7 @@ llvm::Function* jitcc::allocFunction(const std::string& fname, const MonoTypes& module() ); } +#endif void* jitcc::reifyMachineCodeForFn(const MonoTypePtr&, const str::seq& names, const MonoTypes& tys, const ExprPtr& exp) { return getMachineCode(compileFunction("", names, tys, exp)); @@ -841,7 +1338,9 @@ Values compileArgs(jitcc* c, const Exprs& es) { if (is(et)) { // variable-length arrays need to be cast to a single type to pass LLVM's check - r.push_back(c->builder()->CreateBitCast(ev, toLLVM(et))); + r.push_back(withContext([&](auto&) { + return c->builder()->CreateBitCast(ev, toLLVM(et)); + })); } else if (isUnit(et)) { // no need to pass unit anywhere } else { diff --git a/lib/hobbes/eval/orcjitcc.C b/lib/hobbes/eval/orcjitcc.C new file mode 100644 index 000000000..b21082863 --- /dev/null +++ b/lib/hobbes/eval/orcjitcc.C @@ -0,0 +1,96 @@ +#include + +#include + +#if LLVM_VERSION_MAJOR >= 11 +#include +#include + +#include + +namespace hobbes { + +ORCJIT::ORCJIT(std::unique_ptr tm, + const llvm::DataLayout &dl) + : targetMachine(std::move(tm)), dataLayout(dl), + mangle(execSession, dataLayout), + objectLayer( + execSession, + []() { return std::make_unique(); }), + compileLayer(execSession, objectLayer, + std::make_unique(*targetMachine)), + optLayer(execSession, compileLayer, optimizeModule), + mainJD(execSession.createBareJITDylib(createUniqueName("main"))) { + mainJD.addGenerator( + cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( + dataLayout.getGlobalPrefix()))); +} + +#if LLVM_VERSION_MAJOR >= 12 +ORCJIT::~ORCJIT() { + // https://repo.hca.bsc.es/gitlab/rferrer/llvm-epi/-/commit/0aec49c8531bc5282b095730d34681455826bc2c + // newly added in llvm12, has to be called to destroy objectLayer associated memory manager + llvm::cantFail(execSession.endSession()); +} +#else +ORCJIT::~ORCJIT() = default; +#endif + +llvm::Expected> ORCJIT::create() { + auto jtmb = llvm::orc::JITTargetMachineBuilder::detectHost(); + if (!jtmb) { + return jtmb.takeError(); + } + + auto tm = jtmb->createTargetMachine(); + if (!tm) { + return tm.takeError(); + } + + auto dl = jtmb->getDefaultDataLayoutForTarget(); + if (!dl) { + return dl.takeError(); + } + + return std::make_unique(std::move(*tm), *dl); +} + +llvm::Error ORCJIT::addModule(std::unique_ptr m) { + return withContext([&](auto&) { + m->setDataLayout(dataLayout); + return optLayer.add(mainJD, llvm::orc::ThreadSafeModule(std::move(m), threadSafeContext())); + }); +} + +llvm::Expected ORCJIT::lookup(llvm::StringRef name) { + return execSession.lookup({&mainJD}, mangle(name.str())); +} + +llvm::Error ORCJIT::addExternalSymbol(llvm::StringRef name, void *ptr) { + return mainJD.define(llvm::orc::absoluteSymbols( + {{mangle(name), llvm::JITEvaluatedSymbol::fromPointer(ptr)}})); +} + +llvm::Expected +ORCJIT::optimizeModule(llvm::orc::ThreadSafeModule tsm, + const llvm::orc::MaterializationResponsibility &) { + tsm.withModuleDo([](llvm::Module &m) { + auto fpm = llvm::legacy::FunctionPassManager(&m); + fpm.add(llvm::createReassociatePass()); + fpm.add(llvm::createNewGVNPass()); + fpm.add(llvm::createCFGSimplificationPass()); + fpm.add(llvm::createTailCallEliminationPass()); + fpm.doInitialization(); + for (auto &f : m) { + fpm.run(f); + } + + auto mpm = llvm::legacy::PassManager(); + mpm.add(llvm::createFunctionInliningPass()); + mpm.run(m); + }); + + return tsm; +} +} // namespace hobbes +#endif diff --git a/lib/hobbes/lang/pat/dfa.C b/lib/hobbes/lang/pat/dfa.C index 5a18ae133..b4da60eec 100644 --- a/lib/hobbes/lang/pat/dfa.C +++ b/lib/hobbes/lang/pat/dfa.C @@ -1,4 +1,5 @@ - +#include +#include #include #include #include @@ -1411,14 +1412,18 @@ struct makePrimDFASF : public switchMState { } if (x->jumps().size() > 0 && is(x->jumps().begin()->first)) { - llvm::SwitchInst* s = this->dfa->c->builder()->CreateSwitch(this->dfa->c->builder()->CreateBitCast(arg(x->switchVar()), longType()), blockForState(x->defaultState()), x->jumps().size()); + llvm::SwitchInst* s = withContext([&](auto&) { + return this->dfa->c->builder()->CreateSwitch(this->dfa->c->builder()->CreateBitCast(arg(x->switchVar()), longType()), blockForState(x->defaultState()), x->jumps().size()); + }); for (const auto& jmp : x->jumps()) { if (const Double* d = is(jmp.first)) { s->addCase(civalue(asLongRep(d->value())), blockForState(jmp.second)); } } } else { - llvm::SwitchInst* s = this->dfa->c->builder()->CreateSwitch(arg(x->switchVar()), blockForState(x->defaultState()), x->jumps().size()); + llvm::SwitchInst* s = withContext([&](auto&) { + return this->dfa->c->builder()->CreateSwitch(arg(x->switchVar()), blockForState(x->defaultState()), x->jumps().size()); + }); for (const auto& jmp : x->jumps()) { s->addCase(toLLVMConstantInt(jmp.first), blockForState(jmp.second)); } @@ -1431,11 +1436,11 @@ struct makePrimDFASF : public switchMState { if (ei == this->dfa->exprIdxs.end()) { throw std::runtime_error("Internal error, primitive match DFA returns non-indexed expression"); } else { - this->dfa->c->builder()->CreateRet(cvalue(static_cast(ei->second))); + withContext([&](auto&) { this->dfa->c->builder()->CreateRet(cvalue(static_cast(ei->second))); }); } return unitv; } - + UnitV with(const LoadVars*) const { throw std::runtime_error("Internal error, not a primitive match table (load vars)"); } @@ -1449,13 +1454,15 @@ struct makePrimDFASF : public switchMState { if (b != this->branches->end()) { return b->second; } else { - llvm::BasicBlock* obb = this->dfa->c->builder()->GetInsertBlock(); - llvm::BasicBlock* bb = llvm::BasicBlock::Create(context(), ".pmst" + freshName(), obb->getParent()); - this->dfa->c->builder()->SetInsertPoint(bb); - switchOf(this->dfa->states[s], *this); - (*this->branches)[s] = bb; - this->dfa->c->builder()->SetInsertPoint(obb); - return bb; + return withContext([&](llvm::LLVMContext& ctx) { + llvm::BasicBlock* obb = this->dfa->c->builder()->GetInsertBlock(); + llvm::BasicBlock* bb = llvm::BasicBlock::Create(ctx, ".pmst" + freshName(), obb->getParent()); + this->dfa->c->builder()->SetInsertPoint(bb); + switchOf(this->dfa->states[s], *this); + (*this->branches)[s] = bb; + this->dfa->c->builder()->SetInsertPoint(obb); + return bb; + }); } } }; @@ -1468,10 +1475,13 @@ llvm::Function* makePrimMatchDFAFunc(const std::string& fname, MDFA* dfa, statei } } - llvm::Function* result = llvm::Function::Create(llvm::FunctionType::get(intType(), atys, false), llvm::Function::ExternalLinkage, fname, dfa->c->module()); - llvm::BasicBlock* bb = llvm::BasicBlock::Create(context(), "entry", result); + llvm::Function* result = withContext([&](auto&) { + return llvm::Function::Create(llvm::FunctionType::get(intType(), atys, false), + llvm::Function::ExternalLinkage, fname, dfa->c->module()); + }); + llvm::BasicBlock* bb = withContext([result](llvm::LLVMContext& ctx) { return llvm::BasicBlock::Create(ctx, "entry", result); }); - dfa->c->builder()->SetInsertPoint(bb); + withContext([dfa, bb](auto&) { dfa->c->builder()->SetInsertPoint(bb); }); Args fargs; llvm::Function::arg_iterator a = result->arg_begin(); @@ -1506,7 +1516,7 @@ public: } llvm::Value* apply(jitcc* c, const MonoTypes&, const MonoTypePtr&, const Exprs& es) { - return fncall(c->builder(), this->vfn, this->vfn->getFunctionType(), compileArgs(c, es)); + return withContext([&](auto&) { return fncall(c->builder(), this->vfn, this->vfn->getFunctionType(), compileArgs(c, es)); }); } PolyTypePtr type(typedb&) const { diff --git a/test/Arrays.C b/test/Arrays.C index 2568ad8fa..bcb5ee57f 100644 --- a/test/Arrays.C +++ b/test/Arrays.C @@ -46,7 +46,7 @@ TEST(Arrays, Streams) { )); EXPECT_TRUE((c().compileFn( "takeS(10, [s | |even='12(?[4-9]+)'| <- [if (x%2 == 0) then |even=show(x)| else |odd=x|::|even:[char],odd:int| | x <- [0..], x > 20]]) == [\"4\", \"6\", \"8\", \"44\", \"46\", \"48\", \"54\", \"56\", \"58\", \"64\"]" - ))); + )())); } TEST(Arrays, WithStdVector) { diff --git a/test/Matching.C b/test/Matching.C index e5ece1fef..b5205b71e 100644 --- a/test/Matching.C +++ b/test/Matching.C @@ -324,25 +324,21 @@ TEST(Matching, Monadic) { } TEST(Matching, matchFromStringToBoolIsBool) { - bool r = c().compileSafeFn("match \"1\" \"2\" \"3\" \"4\" with\n" - "| \"1\" \"2\" \"3\" \"4\" -> true\n" - "| \"1\" \"2\" \"3\" _ -> true\n" - "| \"1\" \"2\" _ _ -> true\n" - "| \"1\" _ _ _ -> true\n" - "| _ _ _ _ -> false")(); - EXPECT_TRUE(1 == *reinterpret_cast(&r)); - EXPECT_TRUE(r); + EXPECT_TRUE(c().compileFn("match \"1\" \"2\" \"3\" \"4\" with\n" + "| \"1\" \"2\" \"3\" \"4\" -> true\n" + "| \"1\" \"2\" \"3\" _ -> true\n" + "| \"1\" \"2\" _ _ -> true\n" + "| \"1\" _ _ _ -> true\n" + "| _ _ _ _ -> false")); } TEST(Matching, matchFromIntToBoolIsBool) { - bool r = c().compileSafeFn("match 1 2 3 4 with\n" - "| 1 2 3 4 -> true\n" - "| 1 2 3 _ -> true\n" - "| 1 2 _ _ -> true\n" - "| 1 _ _ _ -> true\n" - "| _ _ _ _ -> false")(); - EXPECT_TRUE(1 == *reinterpret_cast(&r)); - EXPECT_TRUE(r); + EXPECT_TRUE(c().compileFn("match 1 2 3 4 with\n" + "| 1 2 3 4 -> true\n" + "| 1 2 3 _ -> true\n" + "| 1 2 _ _ -> true\n" + "| 1 _ _ _ -> true\n" + "| _ _ _ _ -> false")); } TEST(Matching, matchFromStringToIntIsCorrect) { From e00dab5471108e99d354ee2a1eca3e3bb466369c Mon Sep 17 00:00:00 2001 From: Mo Xiaoming <2188767+mo-xiaoming@users.noreply.github.com> Date: Wed, 4 Aug 2021 18:41:51 +0000 Subject: [PATCH 10/40] instead of reinterpret_cast, memcpy/alignas should be used to get proper type punning and alignment (#415) --- include/hobbes/db/series.H | 4 ++-- include/hobbes/mc/encode.H | 11 ++++++----- include/hobbes/reflect.H | 5 +++-- lib/hobbes/lang/type.C | 5 +++-- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/include/hobbes/db/series.H b/include/hobbes/db/series.H index 48f82acd5..4c7c274f4 100644 --- a/include/hobbes/db/series.H +++ b/include/hobbes/db/series.H @@ -170,8 +170,8 @@ public: private: StorageMode sm; union { - char rss[sizeof(RawStoredSeries)]; - char css[sizeof(CompressedStoredSeries)]; + alignas(RawStoredSeries) char rss[sizeof(RawStoredSeries)]; + alignas(CompressedStoredSeries) char css[sizeof(CompressedStoredSeries)]; } storage; }; diff --git a/include/hobbes/mc/encode.H b/include/hobbes/mc/encode.H index afd72930f..c3ae43c21 100644 --- a/include/hobbes/mc/encode.H +++ b/include/hobbes/mc/encode.H @@ -55,7 +55,7 @@ #include #include -#include +#include #include namespace hobbes { namespace mc { @@ -143,7 +143,7 @@ public: // add a label reference at the current write position (assuming a 32-bit displacement) void addLabelRef(const std::string& lbl) { this->labelRefs[lbl].push_back(this->sz); - *reinterpret_cast(allocate(sizeof(uint32_t))) = 0; + std::memset(allocate(sizeof(uint32_t)), 0, sizeof(uint32_t)); } // define a label at the current write position @@ -230,7 +230,8 @@ private: if (!canLowerTo(dist)) { throw std::runtime_error("Can't resolve label reference to '" + d->first + "' in program with jump distance greater than 32-bits"); } - *reinterpret_cast(this->mem + pc) = static_cast(dist); + const auto dist32 = static_cast(dist); + std::memcpy(this->mem + pc, &dist32, sizeof(dist32)); } } } @@ -1550,7 +1551,7 @@ inline void emitValue(buffer* b, const MODRMCode& modrm) { if (O == 1) { *b->allocate(1) = static_cast(modrm.disp); } else if (O == 2 || (O == 0 && thd_233(modrm.modrm) == 5) || (O == 0 && hasSIB && thd_233(modrm.sib) == 5)) { - *reinterpret_cast(b->allocate(4)) = modrm.disp; + std::memcpy(b->allocate(4), &modrm.disp, sizeof(modrm.disp)); } } @@ -1622,7 +1623,7 @@ public: // mov rax, faddr (*b)[0] = REXW().byte; (*b)[1] = 0xb8; - *reinterpret_cast(&(*b)[2]) = faddr; + std::memcpy(&(*b)[2], &faddr, sizeof(faddr)); // call rax Reg rax; diff --git a/include/hobbes/reflect.H b/include/hobbes/reflect.H index 2a150be62..b575156cf 100644 --- a/include/hobbes/reflect.H +++ b/include/hobbes/reflect.H @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -1362,7 +1362,8 @@ inline bool operator!=(const desc& t0, const desc& t1) { template T readValue(const bytes& bs, size_t* i) { assert((bs.size() >= (*i + sizeof(T))) && "Invalid type encoding, expected data not available"); - T result = *reinterpret_cast(&bs[*i]); + T result; + std::memcpy(&result, &bs[*i], sizeof(T)); *i += sizeof(T); return result; } diff --git a/lib/hobbes/lang/type.C b/lib/hobbes/lang/type.C index 02d34d29d..f1d8acc09 100644 --- a/lib/hobbes/lang/type.C +++ b/lib/hobbes/lang/type.C @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include @@ -2362,7 +2362,8 @@ template template struct readF { static T read(const bytes& in, unsigned int* n) { - T r = *reinterpret_cast(&(in[*n])); + T r; + std::memcpy(&r, &in[*n], sizeof(T)); *n += sizeof(T); return r; } From 30574be2455852c3d9d98d1e554873e61481d7b7 Mon Sep 17 00:00:00 2001 From: Mo Xiaoming <2188767+mo-xiaoming@users.noreply.github.com> Date: Wed, 4 Aug 2021 18:46:00 +0000 Subject: [PATCH 11/40] Make jit lazy (#416) * enable concurrent compilation inside LLJIT * add lazy jit * make function calls and declaration which return bool consistent with definitions (zeroext) * use angle brackets on include headers --- include/hobbes/eval/orcjitcc.H | 54 ++--- include/hobbes/util/llvm.H | 6 +- lib/hobbes/eval/jitcc.C | 392 +++++++++++++++++++-------------- lib/hobbes/eval/orcjitcc.C | 141 ++++++------ 4 files changed, 330 insertions(+), 263 deletions(-) diff --git a/include/hobbes/eval/orcjitcc.H b/include/hobbes/eval/orcjitcc.H index 57debbf4f..8a5b9b937 100644 --- a/include/hobbes/eval/orcjitcc.H +++ b/include/hobbes/eval/orcjitcc.H @@ -4,50 +4,44 @@ #include #if LLVM_VERSION_MAJOR >= 11 -#include -#include -#include -#include -#include +#include #include +#include +#include + #include +namespace llvm { +class Module; +namespace orc { +class LLLazyJIT; +class MaterializationResponsibility; +class MangleAndInterner; +} // namespace orc +} // namespace llvm + namespace hobbes { class ORCJIT { public: - ORCJIT(std::unique_ptr tm, const llvm::DataLayout& dl); - ORCJIT(const ORCJIT&) = delete; - ORCJIT(ORCJIT&&) = delete; - ORCJIT& operator=(const ORCJIT&) = delete; - ORCJIT& operator=(ORCJIT&&) = delete; + ORCJIT(); + ORCJIT(const ORCJIT &) = delete; + ORCJIT(ORCJIT &&) = delete; + ORCJIT &operator=(const ORCJIT &) = delete; + ORCJIT &operator=(ORCJIT &&) = delete; ~ORCJIT(); - static llvm::Expected> create(); - llvm::Error addModule(std::unique_ptr m); - llvm::Expected lookup(llvm::StringRef name); + LLVM_NODISCARD llvm::Expected + lookup(llvm::StringRef name); - llvm::Error addExternalSymbol(llvm::StringRef name, void* ptr); + llvm::Error addExternalNonCallableSymbol(llvm::StringRef name, void *ptr); + llvm::Error addExternalCallableSymbol(llvm::StringRef name, void *ptr); private: - std::unique_ptr targetMachine; - - llvm::orc::ExecutionSession execSession; - - llvm::DataLayout dataLayout; - llvm::orc::MangleAndInterner mangle; - - llvm::orc::RTDyldObjectLinkingLayer objectLayer; - llvm::orc::IRCompileLayer compileLayer; - llvm::orc::IRTransformLayer optLayer; - - llvm::orc::JITDylib& mainJD; - - static llvm::Expected - optimizeModule(llvm::orc::ThreadSafeModule tsm, const llvm::orc::MaterializationResponsibility&); - + std::unique_ptr jit; + std::unique_ptr mangle; }; } // namespace hobbes diff --git a/include/hobbes/util/llvm.H b/include/hobbes/util/llvm.H index 771aec681..70f58688f 100644 --- a/include/hobbes/util/llvm.H +++ b/include/hobbes/util/llvm.H @@ -816,7 +816,11 @@ inline llvm::Value* fncall(llvm::IRBuilder<>* b, llvm::Value* vfn, llvm::Type* t return b->CreateCall(vfn, args); #elif LLVM_VERSION_MAJOR <= 12 if (auto *ty = llvm::dyn_cast(tfn)) { - return b->CreateCall(ty, vfn, args); + auto *inst = b->CreateCall(ty, vfn, args); + if (ty->getReturnType() == boolType()) { + inst->addAttribute(llvm::AttributeList::ReturnIndex, llvm::Attribute::ZExt); + } + return inst; } else { throw std::runtime_error("fncall(...) invoked on non-function type (internal error)"); } diff --git a/lib/hobbes/eval/jitcc.C b/lib/hobbes/eval/jitcc.C index 263e41793..6bc76d480 100644 --- a/lib/hobbes/eval/jitcc.C +++ b/lib/hobbes/eval/jitcc.C @@ -1,17 +1,23 @@ -#include -#include +#include +#include #include +#include +#include #include #include #include #include #include +#include #include #include +#include +#include #include #include #include +#include #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" @@ -22,263 +28,310 @@ #include #else #if LLVM_VERSION_MINOR == 3 or LLVM_VERSION_MINOR == 5 -#include "llvm/ExecutionEngine/JIT.h" +#include #else -#include "llvm/ExecutionEngine/MCJIT.h" +#include #endif #if LLVM_VERSION_MINOR >= 8 || LLVM_VERSION_MAJOR == 4 || LLVM_VERSION_MAJOR == 6 -#include "llvm/Analysis/BasicAliasAnalysis.h" +#include #endif #if LLVM_VERSION_MAJOR == 4 || LLVM_VERSION_MAJOR == 6 -#include "llvm/Transforms/Scalar/GVN.h" +#include #endif #endif -#include "llvm/Object/ELFObjectFile.h" -#include "llvm/ExecutionEngine/JITEventListener.h" +#include +#include #pragma GCC diagnostic pop +#if LLVM_VERSION_MAJOR >= 11 +namespace { +LLVM_NODISCARD llvm::Function *createFnDecl(llvm::Function *f, llvm::Module &m, + llvm::StringRef name) { + if (f->getReturnType() == hobbes::boolType()) { + f->addAttribute(llvm::AttributeList::ReturnIndex, llvm::Attribute::ZExt); + } + if (f->getName() != name) { + f->eraseFromParent(); + return m.getFunction(name); + } + return f; +} + +LLVM_NODISCARD llvm::GlobalVariable * +createGVDecl(llvm::GlobalVariable *gv, llvm::Module &m, llvm::StringRef name) { + if (gv->getName() != name) { + gv->eraseFromParent(); + return m.getGlobalVariable(name); + } + return gv; +} +} // namespace +#endif + namespace hobbes { #if LLVM_VERSION_MAJOR >= 11 class ConstantList { - using VarFnTy = std::function; + using VarDeclFnTy = std::function; + enum class Ty : std::int8_t { + Function, + GlobalVar, + Array, + HasPointerRep, + Other, + }; struct Constant { - MonoTypePtr mtype; - variant varOrFunc; - VarFnTy fn; + // function is a constant + // globalvariable returned by a function + variant value; + Ty ty = Ty::Other; }; llvm::StringMap constants; public: ConstantList() = default; - ConstantList(const ConstantList&) = delete; - ConstantList(ConstantList&&) = delete; - ConstantList& operator=(const ConstantList&) = delete; - ConstantList& operator=(ConstantList&&) = delete; + ConstantList(const ConstantList &) = delete; + ConstantList(ConstantList &&) = delete; + ConstantList &operator=(const ConstantList &) = delete; + ConstantList &operator=(ConstantList &&) = delete; ~ConstantList() = default; LLVM_NODISCARD bool contains(llvm::StringRef name) const { return constants.find(name) != constants.end(); } - /// Creates const global variable definition - /// - /// \p initVal is the initializer for this constant, must not be null - /// or it can be a function - void createDefinition(const std::string& name, llvm::Module& m, llvm::Constant* initVal, - const MonoTypePtr& mtype); + void storeFnAddr(const std::string &name, llvm::Constant *funcAddr); + void createGVDef(const std::string &name, llvm::Module &m, + llvm::Constant *initVal, const MonoTypePtr &mtype); /// Gets constant by generating load inst or possibly recreating decl - LLVM_NODISCARD llvm::Value* loadConstant(llvm::StringRef name, llvm::Module& m, - llvm::IRBuilder<>& builder); + LLVM_NODISCARD llvm::Value *loadConstant(llvm::StringRef name, + llvm::Module &m, + llvm::IRBuilder<> &builder); }; -void ConstantList::createDefinition(const std::string& name, llvm::Module& m, - llvm::Constant* initVal, const MonoTypePtr& mtype) { - assert(!contains(name)); +void ConstantList::storeFnAddr(const std::string &name, + llvm::Constant *funcAddr) { + constants[name] = Constant{.value = funcAddr, .ty = Ty::Function}; +} + +void ConstantList::createGVDef(const std::string &name, llvm::Module &m, + llvm::Constant *initVal, + const MonoTypePtr &mtype) { + llvm::Type *type = toLLVM(mtype); + new llvm::GlobalVariable(m, type, /*isConstant=*/true, + llvm::GlobalVariable::ExternalLinkage, initVal, + name); + + const auto vf = [&, type, name](llvm::Module &m) -> llvm::GlobalVariable * { + return createGVDecl( + prepgv(new llvm::GlobalVariable(m, type, /*isConstant=*/true, + llvm::GlobalVariable::ExternalLinkage, + /*initializer=*/nullptr, name)), + m, name); + }; + const auto tf = [&mtype] { + if (is(mtype) != nullptr) { + return Ty::Array; + } + if (hasPointerRep(mtype)) { + return Ty::HasPointerRep; + } + return Ty::Other; + }; - llvm::Type* type = toLLVM(mtype); - if (is(mtype) != nullptr) { - constants[name] = Constant{.mtype = mtype, .varOrFunc = initVal, .fn = VarFnTy()}; - } else { - constants[name] = Constant{ - .mtype = mtype, - .varOrFunc = llvm::WeakTrackingVH(new llvm::GlobalVariable( - m, type, /*isConstant=*/true, llvm::GlobalVariable::ExternalLinkage, initVal, name)), - .fn = [&, type, name](llvm::Module& m) -> llvm::GlobalVariable* { - return prepgv(new llvm::GlobalVariable(m, type, /*isConstant=*/true, - llvm::GlobalVariable::ExternalLinkage, - /*initializer=*/nullptr, name)); - }}; - } + constants[name] = Constant{ + .value = VarDeclFnTy(vf), + .ty = tf(), + }; } -llvm::Value* ConstantList::loadConstant(llvm::StringRef name, llvm::Module& m, - llvm::IRBuilder<>& builder) { - auto it = constants.find(name); +llvm::Value *ConstantList::loadConstant(llvm::StringRef name, llvm::Module &m, + llvm::IRBuilder<> &builder) { + const auto it = constants.find(name); if (it == constants.end()) { return nullptr; } - if (is(it->second.mtype) != nullptr) { - return *it->second.varOrFunc.get(); + if (it->second.ty == Ty::Function) { + return *it->second.value.get(); } - return withContext([&](auto&) -> llvm::Value* { - if (!it->second.varOrFunc.get()->pointsToAliveValue()) { - it->second.varOrFunc = llvm::WeakTrackingVH(it->second.fn(m)); - } - - auto* g = llvm::cast( - static_cast(*it->second.varOrFunc.get())); + return withContext([&](auto &) -> llvm::Value * { + auto *g = llvm::cast( + static_cast((*it->second.value.get())(m))); - if (is(it->second.mtype) != nullptr) { + switch (it->second.ty) { + case Ty::Array: return builder.CreateLoad(g); - } - if (hasPointerRep(it->second.mtype)) { + case Ty::HasPointerRep: return g; + default: + return builder.CreateAlignedLoad(g->getType()->getPointerElementType(), g, + llvm::MaybeAlign(8)); } - return builder.CreateAlignedLoad(g->getType()->getPointerElementType(), g, llvm::MaybeAlign(8)); }); } class VTEnv { public: - using FunFnTy = std::function; + using FnDeclFnTy = std::function; private: - using VarBindings = llvm::StringMap; - using VarBindingStack = llvm::SmallVector; + using ValOrFnTy = variant; + using VarBindingStack = llvm::SmallVector, 8>; VarBindingStack vtenv; - llvm::StringMap vtenvFuns; public: VTEnv() = default; - VTEnv(const VTEnv&) = delete; - VTEnv(VTEnv&&) = delete; - VTEnv& operator=(const VTEnv&) = delete; - VTEnv& operator=(VTEnv&&) = delete; + VTEnv(const VTEnv &) = delete; + VTEnv(VTEnv &&) = delete; + VTEnv &operator=(const VTEnv &) = delete; + VTEnv &operator=(VTEnv &&) = delete; ~VTEnv() = default; LLVM_NODISCARD bool contains(llvm::StringRef name) const { - return std::any_of(vtenv.rbegin(), vtenv.rend(), - [name](const auto& vb) { return vb.find(name) != vb.end(); }); + return std::any_of(vtenv.rbegin(), vtenv.rend(), [name](const auto &vb) { + return vb.find(name) != vb.end(); + }); } /// Gets \p name by looking up from inner to outer scope /// /// Possibly recreating decl - LLVM_NODISCARD llvm::Value* getOrCreateDecl(llvm::StringRef name, llvm::Module& m); - - /// Adds variable \p name to current scope - void add(llvm::StringRef name, llvm::Value* v) { - this->vtenv.back()[name] = v; + LLVM_NODISCARD llvm::Value *getOrCreateDecl(llvm::StringRef name, + llvm::Module &m); + + /// Adds \p name to current scope + void add(llvm::StringRef name, llvm::Value *v) { + // do not allow value overwritten function prototype + // otherwise some decls will not created correctly + if (this->vtenv.back().find(name) == this->vtenv.back().end()) { + this->vtenv.back()[name] = llvm::WeakTrackingVH(v); + } } /// Adds function \p name to current scope /// /// It stores function prototype for decl recreating - void add(llvm::StringRef name, FunFnTy f, llvm::Function* fp) { - this->vtenv.back()[name] = fp; - vtenvFuns[name] = std::move(f); + void add(const std::string &name, FnDeclFnTy f) { + this->vtenv.back()[name] = FnDeclFnTy( + [name, f = std::move(f)](llvm::Module &m) -> llvm::Function * { + return createFnDecl(f(m), m, name); + }); } /// Create a new inner scope - void pushScope() { - vtenv.push_back(VarBindings()); - } + void pushScope() { vtenv.emplace_back(); } /// Destroys the inner scope - void popScope() { - vtenv.pop_back(); - } + void popScope() { vtenv.pop_back(); } }; -llvm::Value* VTEnv::getOrCreateDecl(llvm::StringRef name, llvm::Module& m) { +llvm::Value *VTEnv::getOrCreateDecl(llvm::StringRef name, llvm::Module &m) { for (auto vb = vtenv.rbegin(); vb != vtenv.rend(); ++vb) { - auto it = vb->find(name); + const auto it = vb->find(name); if (it == vb->end()) { continue; } - if (!it->second.pointsToAliveValue()) { - assert(vtenvFuns.find(name) != vtenvFuns.end()); - it->second = vtenvFuns[name](m); + + if (auto *const f = it->second.get()) { + return (*f)(m); } - return it->second; + + auto *p = it->second.get(); + if (!p->pointsToAliveValue()) { + throw std::runtime_error((name + " has been invalidated").str()); + } + return *p; } return nullptr; } class Globals { private: - using FunFnTy = std::function; - using VarFnTy = std::function; - struct Global { - variant protoTypes; - llvm::WeakTrackingVH handle; - }; - llvm::StringMap globals; + using FnDeclFnTy = std::function; + using VarDeclFnTy = std::function; + llvm::StringMap> globals; + LLVM_NODISCARD bool isFunc(decltype(globals)::iterator it) const { - return it->second.protoTypes.get() != nullptr; + return it->second.get() != nullptr; } public: Globals() = default; - Globals(const Globals&) = delete; - Globals(Globals&&) = delete; - Globals& operator=(const Globals&) = delete; - Globals& operator=(Globals&&) = delete; + Globals(const Globals &) = delete; + Globals(Globals &&) = delete; + Globals &operator=(const Globals &) = delete; + Globals &operator=(Globals &&) = delete; ~Globals() = default; LLVM_NODISCARD bool contains(llvm::StringRef name) const { return globals.find(name) != globals.end(); } - /// Gets a global variable \p name by possibly recreating decl in current module - LLVM_NODISCARD llvm::GlobalVariable* getOrCreateVarDecl(llvm::StringRef name, llvm::Module& m); - /// Gets a global function \p name by possibly recreating decl in current module - LLVM_NODISCARD llvm::Function* getOrCreateFuncDecl(llvm::StringRef name, llvm::Module& m); + /// Gets a global variable \p name by possibly recreating decl in current + /// module + LLVM_NODISCARD llvm::GlobalVariable *getOrCreateVarDecl(llvm::StringRef name, + llvm::Module &m); + /// Gets a global function \p name by possibly recreating decl in current + /// module + LLVM_NODISCARD llvm::Function *getOrCreateFuncDecl(llvm::StringRef name, + llvm::Module &m); /// Creates a global variable decl for \p name with type \p ty /// /// It stores variable prototype for decl recreating - void add(const std::string& name, llvm::Module& m, llvm::Type* ty); - /// Creates a global function decl for \p name with type \p ty if \p existingF is null + void add(const std::string &name, llvm::Type *ty); + /// Creates a global function decl for \p name with type \p ty if \p existingF + /// is null /// /// It stores function prototype for decl recreating - void add(const std::string& name, llvm::Module& m, llvm::FunctionType* ty, - llvm::Function* existingF); + void add(const std::string &name, llvm::FunctionType *ty); }; -llvm::GlobalVariable* Globals::getOrCreateVarDecl(llvm::StringRef name, llvm::Module& m) { - auto it = globals.find(name); +llvm::GlobalVariable *Globals::getOrCreateVarDecl(llvm::StringRef name, + llvm::Module &m) { + const auto it = globals.find(name); if (it == globals.end() || isFunc(it)) { return nullptr; } - if (!it->second.handle.pointsToAliveValue()) { - it->second.handle = (*it->second.protoTypes.get())(m); - } - return llvm::cast(static_cast(it->second.handle)); + + auto *p = (*it->second.get())(m); + return llvm::cast(static_cast(p)); } -llvm::Function* Globals::getOrCreateFuncDecl(llvm::StringRef name, llvm::Module& m) { - auto it = globals.find(name); +llvm::Function *Globals::getOrCreateFuncDecl(llvm::StringRef name, + llvm::Module &m) { + const auto it = globals.find(name); if (it == globals.end() || !isFunc(it)) { return nullptr; } - if (!it->second.handle.pointsToAliveValue()) { - it->second.handle = (*it->second.protoTypes.get())(m); - } - return llvm::cast(static_cast(it->second.handle)); + + auto *p = (*it->second.get())(m); + return llvm::cast(static_cast(p)); } -void Globals::add(const std::string& name, llvm::Module& m, llvm::Type* ty) { - Global g; - g.protoTypes = VarFnTy([ty, name](llvm::Module& m) { - return prepgv(new llvm::GlobalVariable(m, ty, /*isConstant=*/false, - llvm::GlobalValue::ExternalLinkage, - /*initializer=*/nullptr, name), - sizeof(void*)); +void Globals::add(const std::string &name, llvm::Type *ty) { + globals[name] = VarDeclFnTy([ty, name](llvm::Module &m) { + return createGVDecl( + prepgv(new llvm::GlobalVariable(m, ty, /*isConstant=*/false, + llvm::GlobalValue::ExternalLinkage, + /*initializer=*/nullptr, name), + sizeof(void *)), + m, name); }); - g.handle = (*g.protoTypes.get())(m); - globals[name] = g; } -void Globals::add(const std::string& name, llvm::Module& m, llvm::FunctionType* ty, - llvm::Function* existingF) { - Global g; - g.protoTypes = FunFnTy([ty, name](llvm::Module& m) { - return llvm::Function::Create(ty, llvm::Function::ExternalLinkage, name, m); +void Globals::add(const std::string &name, llvm::FunctionType *ty) { + globals[name] = FnDeclFnTy([ty, name](llvm::Module &m) { + return createFnDecl( + llvm::Function::Create(ty, llvm::Function::ExternalLinkage, name, m), m, + name); }); - if (existingF != nullptr) { - g.handle = existingF; - } else { - g.handle = (*g.protoTypes.get())(m); - } - globals[name] = g; } #endif @@ -288,7 +341,7 @@ bool isFileType(const MonoTypePtr&); #if (LLVM_VERSION_MINOR >= 6 || LLVM_VERSION_MAJOR == 4 || LLVM_VERSION_MAJOR == 6 || LLVM_VERSION_MAJOR >= 8) && LLVM_VERSION_MAJOR < 11 class jitmm : public llvm::SectionMemoryManager { public: - explicit jitmm(jitcc* jit) : jit(jit) { } + explicit jitmm(jitcc * jit) : jit(jit) {} // link symbols across modules :T uint64_t getSymbolAddress(const std::string& n) override { @@ -305,6 +358,7 @@ public: throw std::runtime_error("Internal error, can't resolve symbol: " + n); } } + private: jitcc* jit; }; @@ -319,7 +373,7 @@ jitcc::jitcc(const TEnvPtr& tenv) llvm::InitializeNativeTargetAsmParser(); llvm::InitializeNativeTargetAsmPrinter(); - this->orcjit = llvm::cantFail(ORCJIT::create(), "orcjit init failed"); + this->orcjit = std::make_unique(); // allocate an IR builder with an initial dummy basic-block to write into this->irbuilder = withContext([](llvm::LLVMContext& c) { @@ -421,8 +475,7 @@ llvm::IRBuilder<>* jitcc::builder() const { llvm::Module* jitcc::module() { if (this->currentModule == nullptr) { this->currentModule = withContext([](llvm::LLVMContext& c) { - auto m = std::make_unique(createUniqueName("jitModule"), c); - return m; + return std::make_unique(createUniqueName("jitModule"), c); }); } return this->currentModule.get(); @@ -611,7 +664,7 @@ class LenWatch : public llvm::JITEventListener { public: std::string fname; size_t sz; - explicit LenWatch(const std::string& fname) : fname(fname), sz(0) { } + explicit LenWatch(const std::string &fname) : fname(fname), sz(0) {} size_t size() const { return this->sz; } void NotifyObjectEmitted(const llvm::object::ObjectFile& o, const llvm::RuntimeDyld::LoadedObjectInfo&) { for (auto s : o.symbols()) { @@ -734,27 +787,27 @@ op* jitcc::lookupOp(const std::string& vn) const { } #if LLVM_VERSION_MAJOR >= 11 -void jitcc::bindGlobal(const std::string& vn, const MonoTypePtr& ty, void* x) { - assert(not this->globals->contains(vn)); - - void* value = x; +void jitcc::bindGlobal(const std::string &vn, const MonoTypePtr &ty, void *x) { + void *value = x; if (is(ty) != nullptr) { - withContext([&](auto&) { - this->globals->add(vn, *this->module(), - llvm::cast(toLLVM(ty, /*asArg=*/false)), - /*existingF=*/nullptr); + withContext([&](auto &) { + this->globals->add( + vn, llvm::cast(toLLVM(ty, /*asArg=*/false))); }); + llvm::cantFail(orcjit->addExternalCallableSymbol(vn, value)); } else { if (hasPointerRep(ty) || isFileType(ty)) { - void** p = reinterpret_cast(this->globalData.malloc(sizeof(void*))); + void **p = + reinterpret_cast(this->globalData.malloc(sizeof(void *))); *p = x; value = p; } - withContext( - [&](auto&) { return this->globals->add(vn, *this->module(), toLLVM(ty, /*asArg=*/true)); }); + withContext([&](auto &) { + return this->globals->add(vn, toLLVM(ty, /*asArg=*/true)); + }); + llvm::cantFail(orcjit->addExternalNonCallableSymbol(vn, value)); } - llvm::cantFail(orcjit->addExternalSymbol(vn, value)); } #else void jitcc::bindGlobal(const std::string& vn, const MonoTypePtr& ty, void* x) { @@ -811,7 +864,8 @@ llvm::Value* jitcc::maybeRefGlobalV(llvm::Value* v) { } else if (auto gv = llvm::dyn_cast(v)) { if (gv->getParent() == thisMod) { return v; - } else if (llvm::GlobalVariable* rgv = thisMod->getGlobalVariable(gv->getName())) { + } else if (llvm::GlobalVariable *rgv = + thisMod->getGlobalVariable(gv->getName())) { return rgv; } else { return new llvm::GlobalVariable(*thisMod, gv->getType()->getElementType(), gv->isConstant(), llvm::GlobalVariable::ExternalLinkage, 0, gv->getName()); @@ -844,7 +898,7 @@ llvm::GlobalVariable* jitcc::refGlobal(const std::string& vn, llvm::GlobalVariab return 0; } else if (gv->getParent() == mod) { return gv; - } else if (llvm::GlobalVariable* rgv = mod->getGlobalVariable(vn)) { + } else if (llvm::GlobalVariable *rgv = mod->getGlobalVariable(vn)) { return rgv; } else { return prepgv(new llvm::GlobalVariable( @@ -920,11 +974,17 @@ void jitcc::defineGlobal(const std::string& vn, const ExprPtr& ue) { f(); releaseMachineCode(reinterpret_cast(f)); resetMemoryPool(); - } else if (llvm::Constant* c = toLLVMConstant(this, vname, ue)) { + } else if (llvm::Constant *c = toLLVMConstant(this, vname, ue)) { // make a global constant ... #if LLVM_VERSION_MAJOR >= 11 - withContext( - [&](auto&) { return this->constants->createDefinition(vname, *module(), c, uety); }); + if (is(uety) != nullptr) { + withContext( + [&](auto &) { return this->constants->storeFnAddr(vname, c); }); + } else { + withContext([&](auto &) { + return this->constants->createGVDef(vname, *module(), c, uety); + }); + } #else Constant& cv = this->constants[vname]; cv.value = c; @@ -1289,12 +1349,12 @@ llvm::Function* jitcc::allocFunction(const std::string& fname, const MonoTypes& llvm::Function* ret = withContext([&](auto&) { return f(*this->module()); }); if (fname.find(".rfn.t") != std::string::npos) { - this->vtenv->add(fname, f, ret); + this->vtenv->add(fname, f); } else if (!this->globals->contains(fname)) { - withContext([&](auto&) { + withContext([&](auto &) { return this->globals->add( - fname, *this->module(), - llvm::FunctionType::get(toLLVM(rty, true), toLLVM(argl, true), false), ret); + fname, llvm::FunctionType::get(toLLVM(rty, true), toLLVM(argl, true), + false)); }); } return ret; @@ -1362,4 +1422,4 @@ ExprPtr jitcc::inlineGlobals(const ExprPtr& e) { op::~op() { } -} +} // namespace hobbes diff --git a/lib/hobbes/eval/orcjitcc.C b/lib/hobbes/eval/orcjitcc.C index b21082863..332f0f0e0 100644 --- a/lib/hobbes/eval/orcjitcc.C +++ b/lib/hobbes/eval/orcjitcc.C @@ -6,74 +6,20 @@ #include #include +#include #include - -namespace hobbes { - -ORCJIT::ORCJIT(std::unique_ptr tm, - const llvm::DataLayout &dl) - : targetMachine(std::move(tm)), dataLayout(dl), - mangle(execSession, dataLayout), - objectLayer( - execSession, - []() { return std::make_unique(); }), - compileLayer(execSession, objectLayer, - std::make_unique(*targetMachine)), - optLayer(execSession, compileLayer, optimizeModule), - mainJD(execSession.createBareJITDylib(createUniqueName("main"))) { - mainJD.addGenerator( - cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( - dataLayout.getGlobalPrefix()))); -} - -#if LLVM_VERSION_MAJOR >= 12 -ORCJIT::~ORCJIT() { - // https://repo.hca.bsc.es/gitlab/rferrer/llvm-epi/-/commit/0aec49c8531bc5282b095730d34681455826bc2c - // newly added in llvm12, has to be called to destroy objectLayer associated memory manager - llvm::cantFail(execSession.endSession()); -} -#else -ORCJIT::~ORCJIT() = default; -#endif - -llvm::Expected> ORCJIT::create() { - auto jtmb = llvm::orc::JITTargetMachineBuilder::detectHost(); - if (!jtmb) { - return jtmb.takeError(); - } - - auto tm = jtmb->createTargetMachine(); - if (!tm) { - return tm.takeError(); - } - - auto dl = jtmb->getDefaultDataLayoutForTarget(); - if (!dl) { - return dl.takeError(); - } - - return std::make_unique(std::move(*tm), *dl); -} - -llvm::Error ORCJIT::addModule(std::unique_ptr m) { - return withContext([&](auto&) { - m->setDataLayout(dataLayout); - return optLayer.add(mainJD, llvm::orc::ThreadSafeModule(std::move(m), threadSafeContext())); - }); -} - -llvm::Expected ORCJIT::lookup(llvm::StringRef name) { - return execSession.lookup({&mainJD}, mangle(name.str())); -} - -llvm::Error ORCJIT::addExternalSymbol(llvm::StringRef name, void *ptr) { - return mainJD.define(llvm::orc::absoluteSymbols( - {{mangle(name), llvm::JITEvaluatedSymbol::fromPointer(ptr)}})); -} - +#include +#include +#include +#include +#include +#include +#include + +namespace { llvm::Expected -ORCJIT::optimizeModule(llvm::orc::ThreadSafeModule tsm, - const llvm::orc::MaterializationResponsibility &) { +optimizeModule(llvm::orc::ThreadSafeModule tsm, + const llvm::orc::MaterializationResponsibility &) { tsm.withModuleDo([](llvm::Module &m) { auto fpm = llvm::legacy::FunctionPassManager(&m); fpm.add(llvm::createReassociatePass()); @@ -92,5 +38,68 @@ ORCJIT::optimizeModule(llvm::orc::ThreadSafeModule tsm, return tsm; } +} // namespace + +namespace hobbes { + +ORCJIT::ORCJIT() { + // this is for testing + // by default, no threading is enabled + const auto tn = [] { + const auto clamp = [](int v, int lo, int hi) -> int { + return v < lo ? lo : (hi < v ? hi : v); + }; + if (const auto n = llvm::sys::Process::GetEnv("HOBBES_COMPILE_THREADS")) { + const int i = std::atoi(n->c_str()); + return static_cast( + clamp(i, 0, static_cast(std::thread::hardware_concurrency()))); + } + return 0U; + }(); + + llvm::orc::LLLazyJITBuilder jitBuilder; + jit = llvm::cantFail( + jitBuilder + .setJITTargetMachineBuilder( + llvm::cantFail(llvm::orc::JITTargetMachineBuilder::detectHost())) + .setNumCompileThreads(tn) + .setLazyCompileFailureAddr(llvm::pointerToJITTargetAddress(+[] { + throw std::runtime_error("exiting on lazy call through failure"); + })) + .create()); + jit->getIRTransformLayer().setTransform(optimizeModule); + jit->getMainJITDylib().addGenerator( + cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( + jit->getDataLayout().getGlobalPrefix()))); + + mangle = std::make_unique( + jit->getExecutionSession(), jit->getDataLayout()); +} + +ORCJIT::~ORCJIT() = default; + +llvm::Error ORCJIT::addModule(std::unique_ptr m) { + return withContext([&, this](auto &) { + return jit->addLazyIRModule( + llvm::orc::ThreadSafeModule(std::move(m), threadSafeContext())); + }); +} + +llvm::Expected ORCJIT::lookup(llvm::StringRef name) { + return jit->lookup(name); +} + +llvm::Error ORCJIT::addExternalCallableSymbol(llvm::StringRef name, void *ptr) { + return jit->getMainJITDylib().define(llvm::orc::absoluteSymbols( + {{(*mangle)(name), llvm::JITEvaluatedSymbol::fromPointer( + ptr, llvm::JITSymbolFlags::Exported | + llvm::JITSymbolFlags::Callable)}})); +} + +llvm::Error ORCJIT::addExternalNonCallableSymbol(llvm::StringRef name, + void *ptr) { + return jit->getMainJITDylib().define(llvm::orc::absoluteSymbols( + {{(*mangle)(name), llvm::JITEvaluatedSymbol::fromPointer(ptr)}})); +} } // namespace hobbes #endif From 0b8a1ca81310b8a33634690888917743783f472a Mon Sep 17 00:00:00 2001 From: Mo Xiaoming <2188767+mo-xiaoming@users.noreply.github.com> Date: Wed, 11 Aug 2021 02:23:50 +0000 Subject: [PATCH 12/40] bump up pattern matching parameters to 20 (#418) * bump up pattern matching parameters to 20 * use newer bison and fix some indentation warning --- include/hobbes/read/pgen/hexpr.parse.H | 6 +- lib/hobbes/read/pgen/hexpr.lex.C | 90 +- lib/hobbes/read/pgen/hexpr.parse.C | 3821 ++++++++++++------------ lib/hobbes/read/pgen/hexpr.y | 9 + 4 files changed, 2013 insertions(+), 1913 deletions(-) diff --git a/include/hobbes/read/pgen/hexpr.parse.H b/include/hobbes/read/pgen/hexpr.parse.H index f5e8e6e79..facf0b124 100644 --- a/include/hobbes/read/pgen/hexpr.parse.H +++ b/include/hobbes/read/pgen/hexpr.parse.H @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 3.7.4. */ +/* A Bison parser, made by GNU Bison 3.7.6. */ /* Bison interface for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation, + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see . */ + along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work diff --git a/lib/hobbes/read/pgen/hexpr.lex.C b/lib/hobbes/read/pgen/hexpr.lex.C index d681ef9f4..019a10e9c 100644 --- a/lib/hobbes/read/pgen/hexpr.lex.C +++ b/lib/hobbes/read/pgen/hexpr.lex.C @@ -1,6 +1,6 @@ -#line 1 "hexpr.lex.C" +#line 2 "hexpr.lex.C" -#line 3 "hexpr.lex.C" +#line 4 "hexpr.lex.C" #define YY_INT_ALIGNED short int @@ -789,9 +789,9 @@ std::string* identifier(const char* b, const char* e) { return hobbes::autorelease(new std::string(b, e)); } } -#line 792 "hexpr.lex.C" +#line 793 "hexpr.lex.C" -#line 794 "hexpr.lex.C" +#line 795 "hexpr.lex.C" #define INITIAL 0 #define BLOCK_COMMENT 1 @@ -978,43 +978,43 @@ extern int yylex (void); */ YY_DECL { - yy_state_type yy_current_state; - char *yy_cp, *yy_bp; - int yy_act; + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; - if ( !(yy_init) ) - { - (yy_init) = 1; + if ( !(yy_init) ) + { + (yy_init) = 1; #ifdef YY_USER_INIT - YY_USER_INIT; + YY_USER_INIT; #endif - /* Create the reject buffer large enough to save one state per allowed character. */ - if ( ! (yy_state_buf) ) - (yy_state_buf) = (yy_state_type *)yyalloc(YY_STATE_BUF_SIZE ); - if ( ! (yy_state_buf) ) - YY_FATAL_ERROR( "out of dynamic memory in yylex()" ); + /* Create the reject buffer large enough to save one state per allowed character. */ + if ( ! (yy_state_buf) ) + (yy_state_buf) = (yy_state_type *)yyalloc(YY_STATE_BUF_SIZE ); + if ( ! (yy_state_buf) ) + YY_FATAL_ERROR( "out of dynamic memory in yylex()" ); - if ( ! (yy_start) ) - (yy_start) = 1; /* first start state */ + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ - if ( ! yyin ) - yyin = stdin; + if ( ! yyin ) + yyin = stdin; - if ( ! yyout ) - yyout = stdout; + if ( ! yyout ) + yyout = stdout; - if ( ! YY_CURRENT_BUFFER ) { - yyensure_buffer_stack (); - YY_CURRENT_BUFFER_LVALUE = - yy_create_buffer( yyin, YY_BUF_SIZE ); - } + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } - yy_load_buffer_state( ); - } + yy_load_buffer_state( ); + } - { + { #line 71 "hexpr.l" @@ -1028,7 +1028,7 @@ YY_DECL } -#line 1031 "hexpr.lex.C" +#line 1032 "hexpr.lex.C" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { @@ -1730,7 +1730,7 @@ YY_RULE_SETUP #line 214 "hexpr.l" ECHO; YY_BREAK -#line 1733 "hexpr.lex.C" +#line 1734 "hexpr.lex.C" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(BLOCK_COMMENT): yyterminate(); @@ -2013,21 +2013,21 @@ static int yy_get_next_buffer (void) */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { - int yy_is_jam; + int yy_is_jam; - YY_CHAR yy_c = 1; - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 281 ) - yy_c = yy_meta[yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; - yy_is_jam = (yy_current_state == 280); - if ( ! yy_is_jam ) - *(yy_state_ptr)++ = yy_current_state; + YY_CHAR yy_c = 1; + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 281 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 280); + if ( ! yy_is_jam ) + *(yy_state_ptr)++ = yy_current_state; - return yy_is_jam ? 0 : yy_current_state; + return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT diff --git a/lib/hobbes/read/pgen/hexpr.parse.C b/lib/hobbes/read/pgen/hexpr.parse.C index 3711da4f6..d1c6f5a18 100644 --- a/lib/hobbes/read/pgen/hexpr.parse.C +++ b/lib/hobbes/read/pgen/hexpr.parse.C @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 3.7.4. */ +/* A Bison parser, made by GNU Bison 3.7.6. */ /* Bison implementation for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation, + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see . */ + along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -46,10 +46,10 @@ USER NAME SPACE" below. */ /* Identify Bison output, and Bison version. */ -#define YYBISON 30704 +#define YYBISON 30706 /* Bison version string. */ -#define YYBISON_VERSION "3.7.4" +#define YYBISON_VERSION "3.7.6" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -574,6 +574,18 @@ typedef int_least16_t yytype_int16; typedef short yytype_int16; #endif +/* Work around bug in HP-UX 11.23, which defines these macros + incorrectly for preprocessor constants. This workaround can likely + be removed in 2023, as HPE has promised support for HP-UX 11.23 + (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of + . */ +#ifdef __hpux +# undef UINT_LEAST8_MAX +# undef UINT_LEAST16_MAX +# define UINT_LEAST8_MAX 255 +# define UINT_LEAST16_MAX 65535 +#endif + #if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ typedef __UINT_LEAST8_TYPE__ yytype_uint8; #elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ @@ -671,9 +683,9 @@ typedef int yy_state_fast_t; /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ -# define YYUSE(E) ((void) (E)) +# define YY_USE(E) ((void) (E)) #else -# define YYUSE(E) /* empty */ +# define YY_USE(E) /* empty */ #endif #if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ @@ -843,16 +855,16 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 74 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 2999 +#define YYLAST 3078 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 98 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 82 /* YYNRULES -- Number of rules. */ -#define YYNRULES 357 +#define YYNRULES 366 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 782 +#define YYNSTATES 809 /* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK 352 @@ -914,39 +926,40 @@ static const yytype_int16 yyrline[] = 0, 488, 488, 489, 490, 491, 494, 495, 496, 498, 499, 500, 502, 503, 504, 505, 506, 507, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 523, 526, 529, 530, 531, 534, 535, 538, 540, 543, - 544, 545, 546, 547, 548, 549, 550, 552, 553, 555, - 557, 558, 560, 563, 564, 565, 566, 568, 569, 571, - 574, 576, 578, 579, 581, 583, 585, 586, 587, 588, - 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, - 599, 600, 601, 602, 603, 605, 606, 608, 609, 612, - 613, 614, 615, 617, 618, 619, 620, 621, 622, 624, - 625, 627, 628, 629, 630, 631, 632, 633, 634, 635, - 637, 638, 639, 640, 641, 643, 644, 645, 646, 648, - 651, 652, 655, 658, 661, 673, 674, 677, 679, 680, - 682, 684, 685, 687, 688, 690, 691, 693, 694, 696, - 697, 700, 701, 704, 705, 706, 707, 708, 709, 710, - 711, 712, 715, 716, 717, 718, 719, 722, 723, 724, - 727, 730, 733, 734, 737, 738, 739, 740, 741, 742, - 743, 744, 745, 746, 747, 748, 749, 750, 753, 756, - 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, - 767, 768, 769, 770, 771, 772, 773, 776, 778, 779, - 781, 783, 784, 786, 788, 789, 791, 792, 794, 795, - 796, 798, 799, 801, 802, 804, 805, 807, 808, 811, - 812, 814, 815, 816, 817, 818, 819, 820, 821, 822, + 521, 522, 523, 524, 525, 526, 527, 528, 529, 532, + 535, 538, 539, 540, 543, 544, 547, 549, 552, 553, + 554, 555, 556, 557, 558, 559, 561, 562, 564, 566, + 567, 569, 572, 573, 574, 575, 577, 578, 580, 583, + 585, 587, 588, 590, 592, 594, 595, 596, 597, 598, + 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, + 609, 610, 611, 612, 614, 615, 617, 618, 621, 622, + 623, 624, 626, 627, 628, 629, 630, 631, 633, 634, + 636, 637, 638, 639, 640, 641, 642, 643, 644, 646, + 647, 648, 649, 650, 652, 653, 654, 655, 657, 660, + 661, 664, 667, 670, 682, 683, 686, 688, 689, 691, + 693, 694, 696, 697, 699, 700, 702, 703, 705, 706, + 709, 710, 713, 714, 715, 716, 717, 718, 719, 720, + 721, 724, 725, 726, 727, 728, 731, 732, 733, 736, + 739, 742, 743, 746, 747, 748, 749, 750, 751, 752, + 753, 754, 755, 756, 757, 758, 759, 762, 765, 766, + 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, + 777, 778, 779, 780, 781, 782, 785, 787, 788, 790, + 792, 793, 795, 797, 798, 800, 801, 803, 804, 805, + 807, 808, 810, 811, 813, 814, 816, 817, 820, 821, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, - 833, 834, 835, 836, 837, 839, 840, 841, 842, 843, - 845, 847, 848, 850, 851, 853, 854, 856, 858, 859, - 860, 862, 863, 864, 865, 866, 867, 868, 869, 870, - 871, 872, 873, 874, 875, 876, 882, 883, 884, 885, - 887, 888, 890, 891, 892, 894, 895, 896, 898, 899, - 902, 904, 905, 907, 908, 909, 910, 911, 912, 913, - 914, 915, 916, 918, 919, 920, 921, 923, 924, 925, - 926, 928, 929, 930, 932, 933, 935, 936, 938, 939, - 940, 942, 943, 944, 945, 946, 947, 948, 949, 950, - 951, 952, 953, 954, 955, 956, 957, 958, 959, 961, - 962, 964, 965, 967, 968, 970, 971, 973, 974, 976, - 977, 979, 980, 982, 983, 984, 985, 987 + 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, + 843, 844, 845, 846, 848, 849, 850, 851, 852, 854, + 856, 857, 859, 860, 862, 863, 865, 867, 868, 869, + 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, + 881, 882, 883, 884, 885, 891, 892, 893, 894, 896, + 897, 899, 900, 901, 903, 904, 905, 907, 908, 911, + 913, 914, 916, 917, 918, 919, 920, 921, 922, 923, + 924, 925, 927, 928, 929, 930, 932, 933, 934, 935, + 937, 938, 939, 941, 942, 944, 945, 947, 948, 949, + 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, + 961, 962, 963, 964, 965, 966, 967, 968, 970, 971, + 973, 974, 976, 977, 979, 980, 982, 983, 985, 986, + 988, 989, 991, 992, 993, 994, 996 }; #endif @@ -1020,12 +1033,12 @@ static const yytype_int16 yytoknum[] = }; #endif -#define YYPACT_NINF (-597) +#define YYPACT_NINF (-590) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) -#define YYTABLE_NINF (-357) +#define YYTABLE_NINF (-366) #define yytable_value_is_error(Yyn) \ 0 @@ -1034,85 +1047,87 @@ static const yytype_int16 yytoknum[] = STATE-NUM. */ static const yytype_int16 yypact[] = { - 356, 1283, 2038, 2038, 33, 127, 127, 127, 42, 42, - 105, 105, -597, -597, -597, -597, -597, -597, -597, -597, - -597, -597, -597, -597, -597, -597, -597, -597, -597, 501, - 67, 2038, 2818, 11, 2818, 127, 141, 1487, 2038, 501, - 197, 2038, -42, -597, 1406, -597, -597, -597, -597, -597, - -597, -597, 195, -597, 175, 177, 7, 188, 2584, 2428, - 2038, 1570, 2919, 2919, -597, 111, 200, 317, 422, 432, - -597, 217, -597, -597, -597, 1283, 301, 355, -597, 928, - 155, -597, -597, 156, 1311, 307, 42, 351, 1842, -597, - -597, -597, -597, -597, -597, -597, -597, -597, -597, -597, - -597, -597, -597, -597, -597, 2919, 127, 64, -597, 383, - -597, 372, 194, 2740, 127, 194, 410, 2116, 378, 380, - 2506, 384, 385, 391, 501, 392, 398, 403, 412, 413, - 415, 416, 418, 2272, 419, 420, 421, -597, -597, 423, - -597, -26, 295, 248, 329, 461, 464, 30, 414, 127, - 127, 411, -597, 1920, 1920, 2919, 2038, 1804, 7, -597, - -597, 501, 2038, 25, -597, -597, 448, 378, 380, 2506, - 384, 385, 391, 392, 398, 403, 413, 415, 416, 418, - 419, 420, 421, -597, -597, -597, -597, -597, -597, -597, - -597, -597, -597, -597, -597, -597, 2919, 2919, 127, 225, - 177, 845, -597, -597, -597, 2887, 2350, 2350, 2350, 2350, - 2428, 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584, - 2584, 2584, 2662, 2662, 2662, 2038, -597, 1406, 127, -597, - -597, -597, -597, -597, -597, -597, -597, -597, -597, -597, - -597, -597, -597, -597, -597, -597, 1920, -597, 1920, -597, - -597, -597, 127, 127, 227, 260, 1998, 1998, 127, 2038, - 191, -597, 119, 1998, 127, 26, 42, 928, 127, 227, - 127, 127, 22, -597, 13, 483, 474, 477, -597, -597, - 304, 438, 350, -597, 482, 2038, 54, 2428, 444, 445, - 194, 20, -597, 491, 2818, 1648, 501, 447, 1726, -597, - 492, 494, -597, -597, -597, -597, -597, -597, -597, -597, - -597, -597, -597, -597, -597, -597, -597, -597, -597, -597, - -597, -597, 2038, 2919, 1882, -597, -597, 992, 2038, 2038, - 2038, -597, -597, -597, -597, -597, 676, -597, 503, -597, - -597, -597, 309, 456, 2038, 139, -597, -597, 2038, 186, - 2038, 311, 321, 353, 499, 152, 2038, -597, 2038, 173, - 453, 453, -597, -597, -597, -597, -597, -597, -597, -597, - -597, -597, -597, -597, -597, -597, -597, -597, -597, 1406, - -597, -597, -597, 493, 89, 465, -597, 362, -597, 29, - 1842, -597, 1148, 227, 68, 364, 508, 110, 210, 128, - 497, 452, -597, 1311, 298, 1998, 1998, 501, 1998, 1998, - 1998, 1194, 1998, 457, 42, 532, 127, 127, 1842, 466, - 515, 516, 539, -597, 1998, 1998, 1998, 1998, -597, 479, - 2919, -597, 34, 2919, -597, 2038, -597, -597, 267, 2919, - 445, -597, -597, -597, -597, 187, -597, -597, -597, -597, - -597, -597, -597, -597, -597, -597, -597, -597, -597, 1648, - 2194, 501, 337, 177, -597, 482, -597, 2038, -597, -597, - 2038, -597, -597, 326, 520, -597, 480, -597, 522, -597, - 478, 481, 227, 36, 1842, -597, -597, 486, 1960, -597, - -597, 2038, 206, 496, -597, 490, -597, 498, -597, 46, - 2919, 2919, -597, -597, -597, 1998, -597, -597, -597, -597, - 1998, 488, -597, 1998, -597, 127, 1842, 1998, 1842, -597, - 127, 1842, 1998, -597, -597, 1998, 1998, 1998, 2, 39, - 373, 457, 457, 457, -597, 457, 457, 27, 42, 532, - -597, 23, -597, 240, -597, -597, 123, 1842, 1842, 1842, - 42, 539, -597, 457, 457, 457, 457, -597, -597, -597, - -597, -597, -597, 535, 336, -597, 366, 2852, -597, 502, - -597, 40, 2818, 538, 166, 504, 506, -597, 2919, 2038, - -597, 2038, -597, -597, -597, -597, -597, 507, -597, 2038, - 216, 2038, -597, -597, -597, 510, 511, 457, 189, 371, - 244, 547, -597, 79, 132, 512, 552, 514, 62, 457, - 96, 97, 561, 103, 562, 1998, 1998, 1998, 1998, 1998, - 532, 127, -597, -597, 532, 127, 127, -597, 539, -597, - 318, -597, -597, 569, -597, 127, 550, 267, 127, 2038, - 2038, 2038, -597, -597, -597, 2038, -597, -597, 575, 194, - 2194, 2194, -597, -597, -597, -597, 529, -597, -597, -597, - 2038, 246, -597, -597, -597, 573, -597, 578, -597, 581, - 1842, 1998, 582, 584, 1842, 585, 1998, 1998, 1998, 1998, - 1998, 1998, 457, 457, 457, 457, 457, 532, 24, 532, - -597, 127, 539, -597, 1842, 2038, 583, 2038, -597, 587, - -597, 593, -597, -597, 548, 272, 2350, -597, 2038, 251, - 1998, 551, 1998, -597, 245, 1998, 1998, -597, 1998, 263, - 218, 256, 140, 265, 112, 532, -597, -597, 2038, -597, - 2038, 2038, -597, -597, -597, 173, 549, -597, 2038, 274, - 457, -597, 457, 591, 457, 457, 457, 595, -597, -597, - 1998, -597, 1998, 532, -597, -597, -597, 2350, -597, 2038, - 283, 1998, 1998, 270, 275, 173, -597, 2038, 292, 457, - 457, -597, -597, -597, 2038, 293, -597, 2038, 596, -597, - 2038, -597 + 385, 1512, 2283, 2283, 159, 28, 28, 28, 53, 53, + 131, 131, -590, -590, -590, -590, -590, -590, -590, -590, + -590, -590, -590, -590, -590, -590, -590, -590, -590, 93, + 121, 2283, 2985, -32, 2985, 28, 185, 1732, 2283, 93, + 137, 2283, 376, -590, 959, -590, -590, -590, -590, -590, + -590, -590, 260, -590, 263, 301, 21, 273, 2751, 2595, + 2283, 1815, 1690, 1690, -590, 176, 272, 399, 364, 412, + -590, 321, -590, -590, -590, 1512, 365, 373, -590, 2981, + 179, -590, -590, 218, 868, 409, 53, 445, 1177, -590, + -590, -590, -590, -590, -590, -590, -590, -590, -590, -590, + -590, -590, -590, -590, -590, 1690, 28, -14, -590, 353, + -590, 430, 259, 2907, 28, 259, 480, 2361, 444, 446, + 2673, 448, 449, 450, 93, 451, 452, 454, 455, 456, + 457, 461, 465, 1611, 466, 468, 469, -590, -590, 470, + -590, 203, -29, 117, 343, 490, 500, 99, 458, 28, + 28, 460, -590, 1276, 1276, 1690, 2283, 2049, 21, -590, + -590, 93, 2283, 230, -590, -590, 481, 444, 446, 2673, + 448, 449, 450, 451, 452, 454, 456, 457, 461, 465, + 466, 468, 469, -590, -590, -590, -590, -590, -590, -590, + -590, -590, -590, -590, -590, -590, 1690, 1690, 28, 383, + 301, 1096, -590, -590, -590, 1535, 2517, 2517, 2517, 2517, + 2595, 2751, 2751, 2751, 2751, 2751, 2751, 2751, 2751, 2751, + 2751, 2751, 2829, 2829, 2829, 2283, -590, 959, 28, -590, + -590, -590, -590, -590, -590, -590, -590, -590, -590, -590, + -590, -590, -590, -590, -590, -590, 1276, -590, 1276, -590, + -590, -590, 28, 28, 459, 155, 1399, 1399, 28, 2283, + 345, -590, 138, 1399, 28, 29, 53, 2981, 28, 459, + 28, 28, 34, -590, 41, 516, 514, 517, -590, -590, + 346, 483, 358, -590, 523, 2283, 66, 2595, 485, 486, + 259, 19, -590, 530, 2985, 1893, 93, 487, 1971, -590, + 532, 533, -590, -590, -590, -590, -590, -590, -590, -590, + -590, -590, -590, -590, -590, -590, -590, -590, -590, -590, + -590, -590, 2283, 1690, 2127, -590, -590, 403, 2283, 2283, + 2283, -590, -590, -590, -590, -590, 527, -590, 540, -590, + -590, -590, 350, 499, 2283, 124, -590, -590, 2283, 234, + 2283, 359, 233, 435, 537, 196, 2283, -590, 2283, 1, + 495, 495, -590, -590, -590, -590, -590, -590, -590, -590, + -590, -590, -590, -590, -590, -590, -590, -590, -590, 959, + -590, -590, -590, 535, 354, 507, -590, 548, -590, 0, + 1177, -590, 684, 459, 46, 436, 551, 120, 400, 116, + 544, 494, -590, 868, 184, 1399, 1399, 93, 1399, 1399, + 1399, 800, 1399, 503, 53, 582, 28, 28, 1177, 519, + 563, 570, 592, -590, 1399, 1399, 1399, 1399, -590, 534, + 1690, -590, 45, 1690, -590, 2283, -590, -590, 434, 1690, + 486, -590, -590, -590, -590, 205, -590, -590, -590, -590, + -590, -590, -590, -590, -590, -590, -590, -590, -590, 1893, + 2439, 93, 453, 301, -590, 523, -590, 2283, -590, -590, + 2283, -590, -590, -1, 574, -590, 536, -590, 573, -590, + 538, 541, 459, 178, 1177, -590, -590, 539, 2205, -590, + -590, 2283, 255, 547, -590, 542, -590, 543, -590, 52, + 1690, 1690, -590, -590, -590, 1399, -590, -590, -590, -590, + 1399, 545, -590, 1399, -590, 28, 1177, 1399, 1177, -590, + 28, 1177, 1399, -590, -590, 1399, 1399, 1399, 114, 112, + 304, 503, 503, 503, -590, 503, 503, 37, 53, 582, + -590, 26, -590, 351, -590, -590, 195, 1177, 1177, 1177, + 53, 592, -590, 503, 503, 503, 503, -590, -590, -590, + -590, -590, -590, 578, 410, -590, 433, 828, -590, 549, + -590, 47, 2985, 589, 211, 552, 550, -590, 1690, 2283, + -590, 2283, -590, -590, -590, -590, -590, 553, -590, 2283, + 270, 2283, -590, -590, -590, 554, 556, 503, 225, 463, + 54, 599, -590, 7, 298, 561, 608, 564, 42, 503, + 166, 201, 611, 126, 612, 1399, 1399, 1399, 1399, 1399, + 582, 28, -590, -590, 582, 28, 28, -590, 592, -590, + 391, -590, -590, 609, -590, 28, 593, 434, 28, 2283, + 2283, 2283, -590, -590, -590, 2283, -590, -590, 616, 259, + 2439, 2439, -590, -590, -590, -590, 571, -590, -590, -590, + 2283, 278, -590, -590, -590, 615, -590, 620, -590, 617, + 1177, 1399, 618, 621, 1177, 622, 1399, 1399, 1399, 1399, + 1399, 1399, 503, 503, 503, 503, 503, 582, 30, 582, + -590, 28, 592, -590, 1177, 2283, 619, 2283, -590, 624, + -590, 626, -590, -590, 584, 55, 2517, -590, 2283, 292, + 1399, 587, 1399, -590, 236, 1399, 1399, -590, 1399, 305, + 243, 282, 209, 307, 172, 582, -590, -590, 2283, -590, + 2283, 2283, -590, -590, -590, 1, 585, -590, 2283, 296, + 503, -590, 503, 627, 503, 503, 503, 629, -590, -590, + 1399, -590, 1399, 582, -590, -590, -590, 2517, -590, 2283, + 300, 1399, 1399, 283, 329, 1, -590, 2283, 311, 503, + 503, -590, -590, -590, 2283, 319, -590, 2283, 320, -590, + 2283, 322, -590, 2283, 325, -590, 2283, 326, -590, 2283, + 327, -590, 2283, 330, -590, 2283, 341, -590, 2283, 342, + -590, 2283, 344, -590, 2283, 630, -590, 2283, -590 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -1121,104 +1136,106 @@ static const yytype_int16 yypact[] = static const yytype_int16 yydefact[] = { 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 173, 357, 174, 161, 211, 176, 177, 279, 0, - 0, 0, 0, 0, 0, 0, 0, 285, 285, 258, + 0, 0, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 182, 366, 183, 170, 220, 185, 186, 288, 0, + 0, 0, 0, 0, 0, 0, 0, 294, 294, 267, 0, 0, 0, 2, 8, 10, 12, 17, 13, 14, - 15, 16, 0, 30, 119, 175, 160, 142, 0, 0, - 0, 285, 0, 0, 4, 92, 98, 100, 109, 114, - 118, 142, 5, 142, 1, 9, 0, 31, 341, 0, - 0, 62, 64, 0, 0, 0, 0, 0, 0, 269, - 264, 268, 263, 262, 265, 266, 274, 275, 267, 270, - 271, 272, 273, 278, 261, 252, 0, 0, 129, 0, - 245, 0, 214, 0, 0, 162, 0, 0, 0, 0, - 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 68, 71, 0, - 286, 0, 286, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 11, 0, 0, 0, 285, 0, 159, 212, - 277, 0, 0, 0, 113, 93, 0, 0, 0, 0, + 15, 16, 0, 39, 128, 184, 169, 151, 0, 0, + 0, 294, 0, 0, 4, 101, 107, 109, 118, 123, + 127, 151, 5, 151, 1, 9, 0, 40, 350, 0, + 0, 71, 73, 0, 0, 0, 0, 0, 0, 278, + 273, 277, 272, 271, 274, 275, 283, 284, 276, 279, + 280, 281, 282, 287, 270, 261, 0, 0, 138, 0, + 254, 0, 223, 0, 0, 171, 0, 0, 0, 0, + 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 77, 80, 0, + 295, 0, 295, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 11, 0, 0, 0, 294, 0, 168, 221, + 286, 0, 0, 0, 122, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 221, 222, 223, 229, 224, 225, 226, - 227, 228, 230, 234, 232, 233, 252, 252, 0, 0, - 231, 0, 250, 220, 244, 0, 0, 0, 0, 0, + 0, 0, 0, 230, 231, 232, 238, 233, 234, 235, + 236, 237, 239, 243, 241, 242, 261, 261, 0, 0, + 240, 0, 259, 229, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 6, 9, 0, 79, - 80, 81, 82, 83, 84, 69, 73, 72, 70, 74, - 75, 76, 77, 66, 67, 78, 0, 63, 0, 332, - 331, 337, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 291, 0, 321, 0, 43, 60, 64, 0, 0, - 0, 0, 53, 87, 347, 0, 319, 320, 321, 254, - 0, 251, 0, 256, 0, 0, 0, 0, 0, 0, - 213, 0, 199, 0, 0, 252, 258, 0, 0, 132, - 0, 142, 179, 180, 181, 182, 183, 184, 187, 186, - 185, 188, 189, 192, 190, 191, 196, 193, 194, 195, - 65, 178, 0, 0, 0, 146, 157, 0, 0, 0, - 0, 154, 197, 33, 34, 32, 0, 37, 0, 289, - 127, 123, 0, 176, 0, 0, 276, 18, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 219, 0, 91, - 94, 95, 96, 97, 103, 102, 101, 104, 105, 106, - 107, 108, 112, 110, 111, 115, 116, 117, 3, 7, - 342, 35, 36, 0, 0, 0, 330, 0, 317, 347, - 0, 323, 0, 0, 0, 0, 321, 0, 0, 321, - 0, 0, 290, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 293, 314, 0, 0, 0, 0, 0, 317, - 0, 356, 0, 88, 0, 0, 0, 0, 246, 0, - 0, 248, 0, 0, 120, 0, 128, 130, 0, 0, - 122, 216, 124, 198, 205, 0, 164, 165, 166, 167, - 168, 169, 170, 171, 173, 174, 161, 176, 177, 252, - 252, 258, 0, 175, 142, 0, 134, 0, 125, 131, - 0, 287, 140, 0, 0, 144, 0, 158, 0, 259, - 0, 0, 0, 347, 0, 141, 147, 0, 0, 148, - 19, 0, 0, 0, 240, 0, 235, 0, 242, 0, - 0, 0, 237, 89, 90, 0, 322, 326, 327, 316, - 0, 0, 324, 0, 328, 0, 0, 0, 0, 329, - 0, 0, 0, 338, 292, 0, 0, 0, 0, 0, - 0, 294, 296, 295, 335, 334, 315, 39, 0, 45, - 50, 44, 47, 0, 85, 61, 54, 0, 0, 0, - 0, 55, 57, 349, 318, 348, 350, 247, 253, 249, - 255, 257, 121, 0, 0, 280, 0, 0, 215, 200, - 202, 0, 0, 0, 0, 0, 0, 145, 0, 0, - 143, 0, 153, 152, 288, 151, 150, 0, 20, 0, - 0, 0, 241, 236, 243, 0, 0, 333, 0, 0, - 0, 0, 352, 347, 0, 0, 354, 355, 347, 336, - 0, 0, 321, 0, 321, 0, 0, 0, 0, 0, - 0, 0, 52, 51, 0, 0, 0, 86, 0, 345, - 0, 355, 59, 0, 58, 0, 155, 0, 0, 0, - 0, 0, 205, 210, 209, 0, 204, 207, 208, 163, - 0, 0, 154, 126, 133, 139, 138, 260, 149, 21, - 0, 0, 99, 239, 238, 0, 340, 0, 339, 0, + 0, 0, 0, 0, 0, 0, 6, 9, 0, 88, + 89, 90, 91, 92, 93, 78, 82, 81, 79, 83, + 84, 85, 86, 75, 76, 87, 0, 72, 0, 341, + 340, 346, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 300, 0, 330, 0, 52, 69, 73, 0, 0, + 0, 0, 62, 96, 356, 0, 328, 329, 330, 263, + 0, 260, 0, 265, 0, 0, 0, 0, 0, 0, + 222, 0, 208, 0, 0, 261, 267, 0, 0, 141, + 0, 151, 188, 189, 190, 191, 192, 193, 196, 195, + 194, 197, 198, 201, 199, 200, 205, 202, 203, 204, + 74, 187, 0, 0, 0, 155, 166, 0, 0, 0, + 0, 163, 206, 42, 43, 41, 0, 46, 0, 298, + 136, 132, 0, 185, 0, 0, 285, 18, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 228, 0, 100, + 103, 104, 105, 106, 112, 111, 110, 113, 114, 115, + 116, 117, 121, 119, 120, 124, 125, 126, 3, 7, + 351, 44, 45, 0, 0, 0, 339, 0, 326, 356, + 0, 332, 0, 0, 0, 0, 330, 0, 0, 330, + 0, 0, 299, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 302, 323, 0, 0, 0, 0, 0, 326, + 0, 365, 0, 97, 0, 0, 0, 0, 255, 0, + 0, 257, 0, 0, 129, 0, 137, 139, 0, 0, + 131, 225, 133, 207, 214, 0, 173, 174, 175, 176, + 177, 178, 179, 180, 182, 183, 170, 185, 186, 261, + 261, 267, 0, 184, 151, 0, 143, 0, 134, 140, + 0, 296, 149, 0, 0, 153, 0, 167, 0, 268, + 0, 0, 0, 356, 0, 150, 156, 0, 0, 157, + 19, 0, 0, 0, 249, 0, 244, 0, 251, 0, + 0, 0, 246, 98, 99, 0, 331, 335, 336, 325, + 0, 0, 333, 0, 337, 0, 0, 0, 0, 338, + 0, 0, 0, 347, 301, 0, 0, 0, 0, 0, + 0, 303, 305, 304, 344, 343, 324, 48, 0, 54, + 59, 53, 56, 0, 94, 70, 63, 0, 0, 0, + 0, 64, 66, 358, 327, 357, 359, 256, 262, 258, + 264, 266, 130, 0, 0, 289, 0, 0, 224, 209, + 211, 0, 0, 0, 0, 0, 0, 154, 0, 0, + 152, 0, 162, 161, 297, 160, 159, 0, 20, 0, + 0, 0, 250, 245, 252, 0, 0, 342, 0, 0, + 0, 0, 361, 356, 0, 0, 363, 364, 356, 345, + 0, 0, 330, 0, 330, 0, 0, 0, 0, 0, + 0, 0, 61, 60, 0, 0, 0, 95, 0, 354, + 0, 364, 68, 0, 67, 0, 164, 0, 0, 0, + 0, 0, 214, 219, 218, 0, 213, 216, 217, 172, + 0, 0, 163, 135, 142, 148, 147, 269, 158, 21, + 0, 0, 108, 248, 247, 0, 349, 0, 348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 313, 306, 305, 304, 303, 41, 40, 46, - 48, 49, 56, 344, 0, 0, 0, 0, 281, 0, - 282, 0, 217, 201, 0, 0, 0, 22, 0, 0, - 0, 0, 0, 351, 0, 0, 0, 353, 0, 349, - 0, 0, 0, 0, 0, 0, 346, 38, 0, 156, - 0, 0, 203, 206, 208, 136, 137, 23, 0, 0, - 302, 325, 300, 0, 308, 312, 311, 0, 299, 297, - 0, 307, 0, 42, 284, 283, 218, 0, 24, 0, - 0, 0, 0, 0, 0, 135, 25, 0, 0, 301, - 310, 298, 309, 26, 0, 0, 27, 0, 0, 28, - 0, 29 + 0, 0, 322, 315, 314, 313, 312, 50, 49, 55, + 57, 58, 65, 353, 0, 0, 0, 0, 290, 0, + 291, 0, 226, 210, 0, 0, 0, 22, 0, 0, + 0, 0, 0, 360, 0, 0, 0, 362, 0, 358, + 0, 0, 0, 0, 0, 0, 355, 47, 0, 165, + 0, 0, 212, 215, 217, 145, 146, 23, 0, 0, + 311, 334, 309, 0, 317, 321, 320, 0, 308, 306, + 0, 316, 0, 51, 293, 292, 227, 0, 24, 0, + 0, 0, 0, 0, 0, 144, 25, 0, 0, 310, + 319, 307, 318, 26, 0, 0, 27, 0, 0, 28, + 0, 0, 29, 0, 0, 30, 0, 0, 31, 0, + 0, 32, 0, 0, 33, 0, 0, 34, 0, 0, + 35, 0, 0, 36, 0, 0, 37, 0, 38 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -597, -597, 560, 409, -29, -597, -597, -597, -597, 102, - -597, -597, 21, 28, -596, -517, -597, 18, -528, -389, - 365, 1, 374, 31, 229, -2, -202, -39, 388, -32, - 261, 16, -597, 368, -597, 352, -597, 73, -597, -20, - -597, 361, -597, 14, -597, -597, -46, 823, -597, -597, - 215, -50, -597, -96, -19, -178, -597, -182, -391, -597, - -27, -51, -597, 41, -30, -127, 440, -597, 257, -597, - 406, -77, 733, -597, 424, -597, -597, -597, -597, -597, - -597, 417 + -590, -590, 596, 462, -26, -590, -590, -590, -590, 134, + -590, -590, 59, 56, -589, -515, -590, 57, -519, -387, + 498, 4, 415, 58, 265, -2, -198, -39, 284, -28, + 281, 18, -590, 401, -590, 388, -590, 110, -590, -17, + -590, 405, -590, 48, -590, -590, -13, -58, -590, -590, + 251, -47, -590, -91, -56, -174, -590, -173, -376, -590, + -8, -51, -590, 63, -24, -126, 502, -590, 291, -590, + 447, -86, 984, -590, 464, -590, -590, -590, -590, -590, + -590, 668 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 4, 43, 44, 45, 46, 47, 151, 48, 49, + 0, 4, 43, 44, 45, 46, 47, 151, 48, 49, 632, 50, 541, 542, 539, 540, 51, 551, 552, 265, 266, 52, 139, 543, 272, 140, 65, 66, 67, 68, 69, 70, 107, 108, 298, 299, 736, 472, 473, 54, @@ -1234,610 +1251,626 @@ static const yytype_int16 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { - 64, 72, 103, 158, 359, 360, 361, 362, 143, 81, - 81, 273, 112, 205, 115, 152, 353, 53, 351, 352, - 165, 300, 623, 634, 687, 537, 164, 340, 689, 111, - 422, 624, 725, 74, 415, 620, 142, 249, 160, 148, - 615, 560, 250, 203, 203, 22, -343, 22, 251, 321, - 22, 149, 150, 161, 424, 322, 643, 252, 166, 22, - 53, 158, -343, 348, 158, 22, 644, 22, 330, -343, - 424, 22, 510, 253, 404, 616, 405, 424, 617, 22, - 406, 247, 407, 408, 247, 409, 410, 81, 164, 114, - 411, 53, 22, 290, 165, -343, 269, 103, 255, 442, - 270, 411, 271, 676, 625, 625, 416, 621, 560, 258, - 331, 513, -343, 559, 259, 297, 79, 411, 645, 381, - 424, 382, 671, 435, 411, 594, 342, 411, 105, 753, - 22, 628, 106, 285, 346, 228, 341, 164, 249, 677, - 678, 105, 506, 250, 680, 106, 286, 206, 22, 251, - 411, 517, 22, 752, 518, 345, 411, 404, 252, 405, - 347, 633, 521, 406, 634, 407, 408, 411, 409, 410, - 623, 363, 623, 488, 253, 207, 208, 388, 388, 84, - 22, 22, 357, 750, 411, 411, 357, 372, 373, 374, - 501, 411, 419, 246, 248, 423, 209, 269, 411, 255, - 411, 270, 300, 271, 651, 159, 28, 411, -356, -356, - 258, 22, 672, 22, 154, 259, 489, 146, 28, 117, - 411, 29, 22, 378, 491, 28, 162, -64, 411, 79, - 79, 22, 502, 29, 153, 155, 623, 207, 208, 158, - 29, 22, 249, 53, 589, 354, 652, 250, 437, 156, - 22, 157, 22, 251, 660, 225, 572, 401, 209, 419, - 385, 156, 252, 157, 665, 22, 402, 247, 156, 210, - 157, 22, 403, 626, 445, 249, 22, 411, 253, 353, - 250, 351, 352, 434, 708, 22, 251, 563, 643, 738, - 519, 520, 22, 748, 390, 252, 297, 22, 644, 22, - 478, 269, 386, 255, 474, 270, 411, 271, 22, 227, - 509, 253, 759, 511, 258, 509, 388, 22, 22, 259, - 471, 767, 476, 669, 743, 325, 479, 480, 481, 322, - 774, 777, 411, 411, 269, 749, 255, 391, 270, 264, - 271, 273, 487, 747, 411, 751, 490, 258, 493, 771, - 152, 411, 259, 411, 503, 772, 504, 573, 411, 1, - 2, 3, 22, 411, 211, 212, 213, 214, 215, 216, - 217, 218, 525, 80, 83, 323, 526, 249, 527, 428, - 530, 324, 250, 268, 485, 429, 494, 22, 251, 567, - 322, 666, 495, 693, 158, 53, 22, 252, 496, 694, - 638, 228, 497, 577, 639, 419, 578, 584, 326, 618, - 327, 558, 619, 253, 561, 81, 636, 637, 57, 71, - 203, 287, 75, 76, 78, 82, 82, 86, 88, 431, - 143, 432, 498, 562, 499, 288, 269, 508, 255, 602, - 270, 605, 271, 514, 607, 515, 104, 110, 294, 258, - 85, 87, 116, 302, 259, 303, 104, 147, 142, 305, - 306, 57, 219, 220, 221, 575, 307, 308, 576, 423, - 629, 602, 631, 309, 163, 222, 223, 224, 310, 204, - 204, 595, 596, 375, 376, 377, 587, 311, 312, 588, - 313, 314, 57, 315, 317, 318, 319, 82, 320, 328, - 82, 263, 329, 267, 735, 278, 332, 335, 89, 90, - 91, 92, 93, 94, 95, 350, 425, 426, 427, 430, - 433, 96, 204, 284, 438, 439, 22, 97, 444, 466, - 470, 293, -245, 486, 301, 484, 98, 500, 209, 505, - 507, 104, 516, 522, 523, 411, 538, 547, 357, 548, - 549, 81, 649, 550, 557, 765, 579, 580, 582, 474, - 581, 583, 99, 585, 591, 592, 333, 334, 599, 635, - 278, 278, 204, 100, 101, 593, 650, 656, 104, 657, - 349, 670, 642, 653, 658, 102, 674, 659, 654, 662, - 663, 664, 673, 713, 675, 679, 681, 717, 158, 364, - 365, 366, 367, 368, 369, 370, 371, 695, 697, 705, - 706, 710, 711, 204, 204, 284, 355, 726, 204, 712, - 715, 728, 204, 716, 718, 730, 731, 732, 741, 761, - 757, 595, 596, 762, 780, 226, 379, 700, 701, 702, - 622, 417, 688, 704, 57, 380, 692, 546, 480, 481, - 469, 655, 443, 690, 436, 568, 703, 691, 707, 733, - 524, 392, 0, 278, 0, 278, 0, 0, 0, 383, - 78, 278, 278, 396, 399, 400, 0, 384, 698, 0, - 278, 414, 0, 82, 0, 418, 278, 420, 421, 278, - 0, 249, 0, 727, 0, 729, 250, 0, 0, 0, - 0, 22, 251, 110, 0, 0, 737, 0, 293, 385, - 0, 252, 464, 465, 0, 301, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 754, 253, 755, 756, - 0, 0, 0, 0, 0, 0, 758, 0, 0, 0, - 204, 0, 0, 0, 104, 0, 0, 0, 0, 0, - 482, 386, 255, 263, 256, 0, 257, 766, 0, 0, - 0, 0, 0, 258, 0, 773, 492, 0, 259, 0, - 0, 0, 776, 0, 0, 779, 0, 0, 781, 0, + 64, 72, 273, 158, 200, 200, 203, 203, 359, 360, + 361, 362, 81, 81, 143, 112, 205, 115, 152, 53, + 165, 103, 351, 352, 623, 353, 300, 537, 340, 111, + 164, 687, 634, -352, 624, 689, 142, 415, 725, 148, + -352, 424, 422, 510, 22, 620, 114, 200, 424, 249, + 671, 323, 160, 22, 250, 285, 560, 324, 166, 22, + 251, 158, 53, 643, 158, 207, 208, 161, 286, 252, + 22, 643, 22, 644, -352, -352, 577, 22, 22, 578, + 22, 644, 424, 676, 247, 253, 209, 247, 411, 513, + 81, 22, 164, 53, 165, 411, 290, 200, 442, 341, + 89, 90, 91, 92, 93, 94, 95, 625, 269, 416, + 255, 625, 270, 96, 271, 297, 103, 621, 22, 97, + 381, 258, 382, 560, 559, 645, 259, 79, 98, 411, + 411, 594, 342, 669, 411, 435, 753, 330, 200, 200, + 105, 164, 411, 200, 106, 357, 22, 200, 616, 357, + 521, 617, 615, 346, 99, 345, 22, 146, 488, 74, + 347, 517, 22, 633, 518, 100, 101, 680, 388, 388, + 249, 363, 623, 634, 623, 250, 404, 102, 405, 331, + 22, 251, 406, 419, 407, 408, 423, 409, 410, 390, + 252, 372, 373, 374, 325, 105, -365, -365, 322, 106, + 411, 489, 411, 628, 22, 84, 253, 300, 411, 677, + 249, -352, 206, 752, 411, 250, 404, 246, 405, 424, + 22, 251, 406, 378, 407, 408, 411, 409, 410, 269, + 252, 255, 391, 270, 501, 271, 28, 463, 623, 158, + 207, 208, 258, 22, 678, 53, 253, 259, 437, 651, + 419, 29, 750, 79, 411, 22, 248, 401, 525, 22, + 411, 209, 526, 117, 527, 200, 411, 474, 348, 269, + 247, 255, 491, 270, 572, 271, 502, 445, 321, 156, + 22, 157, 258, 434, 322, 351, 352, 259, 353, 411, + 28, 652, 79, 589, 28, 22, 297, 411, 22, 153, + 665, 509, 154, 22, 511, 29, 509, 388, 660, 29, + 496, 162, -73, 411, 497, 743, 708, 22, 748, 478, + 471, 22, 476, 155, 411, 22, 479, 480, 481, 159, + 738, 411, 273, 156, 759, 157, 22, 156, 767, 157, + 618, 210, 487, 619, 22, 22, 490, 22, 493, 774, + 22, 22, 22, 152, 503, 22, 504, 777, 780, 225, + 783, 749, 771, 786, 789, 792, 22, 22, 795, 22, + 411, 411, 200, 227, 558, 200, 22, 561, 672, 798, + 801, 200, 804, 203, 626, 747, 411, 751, 1, 2, + 3, 287, 567, 411, 158, 411, 419, 53, 584, 530, + 228, 463, 463, 354, 219, 220, 221, 506, 22, 772, + 89, 90, 91, 92, 93, 94, 95, 411, 81, 228, + 402, 428, 326, 96, 327, 485, 403, 429, 22, 97, + 602, 322, 605, 562, 494, 607, 143, 431, 98, 432, + 495, 264, 200, 200, 595, 596, 211, 212, 213, 214, + 215, 216, 217, 218, 563, 222, 223, 224, 142, 22, + 423, 629, 602, 631, 99, 575, 693, 638, 576, 149, + 150, 639, 694, 573, 249, 100, 101, 268, 22, 250, + 519, 520, 477, 666, 22, 251, 587, 102, 22, 588, + 636, 637, 385, 288, 252, 364, 365, 366, 367, 368, + 369, 370, 371, 375, 376, 377, 80, 83, 735, 200, + 253, 357, 85, 87, 498, 514, 499, 515, 294, 302, + 200, 303, 474, 305, 306, 307, 308, 309, 328, 310, + 311, 312, 313, 269, 386, 255, 314, 270, 329, 271, + 315, 317, 249, 318, 319, 320, 258, 250, 350, 425, + 332, 259, 22, 251, 81, 649, 335, 426, 427, 765, + 385, 433, 252, 249, 430, 438, 439, 444, 250, 466, + 470, -254, 484, 22, 251, 500, 486, 656, 253, 657, + 209, 505, 507, 252, 713, 516, 523, 659, 717, 662, + 522, 411, 463, 463, 595, 596, 538, 548, 158, 253, + 547, 482, 386, 255, 549, 256, 550, 257, 726, 557, + 579, 581, 635, 580, 258, 591, 585, 592, 582, 259, + 593, 583, 269, 508, 255, 599, 270, 650, 271, 642, + 658, 653, 654, 670, 663, 258, 664, 700, 701, 702, + 259, 673, 674, 704, 675, 679, 681, 695, 480, 481, + 705, 697, 706, 710, 711, 712, 715, 728, 707, 731, + 716, 718, 730, 732, 741, 761, 757, 762, 807, 57, + 71, 226, 622, 75, 76, 78, 82, 82, 86, 88, + 688, 690, 417, 546, 691, 692, 469, 436, 655, 379, + 703, 568, 733, 727, 524, 729, 443, 104, 110, 249, + 698, 0, 392, 116, 250, 0, 737, 104, 147, 22, + 251, 0, 57, 0, 0, 0, 0, 384, 0, 252, + 0, 0, 0, 0, 0, 163, 754, 0, 755, 756, + 204, 204, 0, 0, 0, 253, 758, 0, 0, 0, + 0, 0, 0, 57, 0, 0, 0, 0, 82, 0, + 0, 82, 263, 0, 267, 0, 278, 766, 269, 0, + 255, 512, 270, 0, 271, 773, 0, 0, 0, 0, + 0, 258, 776, 204, 284, 779, 259, 0, 782, 0, + 0, 785, 293, 0, 788, 301, 0, 791, 0, 0, + 794, 0, 104, 797, 0, 0, 800, 0, 0, 803, + 0, 0, 806, 0, 0, 808, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 249, 0, 333, 334, 0, + 250, 278, 278, 204, 0, 22, 251, 0, 0, 104, + 0, 349, 0, 0, 0, 252, 640, 0, 0, 0, + 0, 0, 0, 183, 184, 185, 186, 187, 188, 189, + 190, 253, 191, 22, 192, 193, 25, 194, 195, 0, + 0, 641, 0, 0, 204, 204, 284, 355, 0, 204, + 0, 0, 0, 204, 393, 0, 255, 0, 270, 0, + 271, 0, 0, 249, 0, 0, 0, 258, 250, 0, + 534, 0, 259, 22, 251, 57, 380, 0, 0, 0, + 0, 0, 196, 252, 197, 0, 198, 0, 199, 0, + 0, 0, 0, 0, 278, 0, 278, 0, 0, 253, + 383, 78, 278, 278, 396, 399, 400, 0, 0, 0, + 0, 278, 414, 0, 82, 0, 418, 278, 420, 421, + 278, 0, 254, 0, 255, 0, 256, 0, 257, 0, + 0, 0, 0, 0, 110, 258, 0, 0, 0, 293, + 259, 0, 0, 464, 465, 0, 301, 0, 7, 8, + 9, 10, 11, 0, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 204, 0, 0, 0, 104, 0, 0, 0, 0, + 0, 0, 0, 0, 263, 29, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 30, 31, 492, 32, 0, + 33, 0, 0, 0, 0, 0, 0, 0, 0, 34, + 35, 36, 0, 37, 0, 38, 0, 39, 0, 40, + 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, + 0, 41, 0, 0, 42, 278, 0, 0, 278, 0, + 278, 278, 0, 0, 0, 0, 0, 0, 262, 0, + 0, 263, 0, 278, 278, 104, 278, 278, 278, 278, + 278, 0, 267, 0, 544, 545, 278, 0, 0, 0, + 0, 0, 278, 278, 278, 278, 0, 0, 204, 0, + 284, 204, 0, 0, 0, 0, 566, 204, 0, 0, + 0, 183, 184, 185, 186, 187, 188, 189, 190, 0, + 191, 22, 192, 193, 25, 194, 195, 464, 464, 465, + 574, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 356, 0, 0, 0, 0, 0, 0, 0, + 278, 0, 278, 0, 0, 0, 0, 0, 0, 0, + 590, 0, 0, 0, 0, 0, 0, 284, 204, 204, + 196, 0, 197, 278, 198, 0, 199, 0, 278, 0, + 0, 278, 0, 601, 278, 278, 278, 0, 606, 278, + 278, 0, 249, 278, 612, 614, 0, 250, 0, 0, + 0, 0, 22, 251, 0, 0, 82, 0, 0, 0, + 0, 627, 252, 0, 278, 278, 278, 278, 267, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 253, 0, + 0, 0, 0, 0, 0, 204, 0, 0, 389, 648, + 394, 397, 0, 0, 0, 0, 204, 413, 0, 0, + 0, 269, 0, 255, 0, 270, 0, 271, 661, 0, + 0, 0, 0, 0, 258, 0, 0, 668, 0, 259, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, - 0, 0, 0, 0, 278, 0, 0, 278, 0, 278, - 278, 0, 0, 0, 0, 0, 0, 262, 0, 0, - 263, 0, 278, 278, 104, 278, 278, 278, 278, 278, - 0, 267, 0, 544, 545, 278, 0, 0, 0, 0, - 0, 278, 278, 278, 278, 0, 0, 204, 0, 284, - 204, 0, 0, 0, 0, 566, 204, 0, 0, 0, - 183, 184, 185, 186, 187, 188, 189, 190, 0, 191, - 22, 192, 193, 25, 194, 195, 464, 464, 465, 574, - 0, 0, 0, 0, 0, 200, 200, 0, 0, 0, - 0, 356, 0, 0, 0, 0, 0, 0, 0, 278, - 0, 278, 0, 0, 0, 0, 0, 0, 0, 590, - 0, 0, 0, 0, 0, 0, 284, 204, 204, 196, - 0, 197, 278, 198, 0, 199, 0, 278, 200, 0, - 278, 0, 601, 278, 278, 278, 0, 606, 278, 278, - 0, 0, 278, 612, 614, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 82, 0, 0, 0, 0, - 627, 0, 0, 278, 278, 278, 278, 267, 229, 230, - 231, 232, 233, 234, 235, 236, 237, 238, 200, 239, - 240, 241, 242, 0, 204, 0, 0, 389, 648, 394, - 397, 0, 243, 244, 0, 204, 413, 245, 0, 89, - 90, 91, 92, 93, 94, 95, 0, 661, 0, 0, - 0, 0, 96, 137, 0, 0, 668, 22, 97, 200, - 200, 0, 0, 0, 200, 138, 0, 98, 200, 0, - 0, 0, 278, 278, 278, 278, 278, 0, 544, 0, - 0, 0, 544, 544, 0, 0, 0, 0, 0, 0, - 0, 0, 696, 99, 566, 699, 0, 0, 0, 0, - 0, 0, 0, 0, 100, 101, 0, 464, 464, 483, - 0, 477, 0, 0, 0, 0, 102, 0, 709, 0, - 0, 0, 0, 0, 0, 0, 0, 278, 278, 0, - 0, 278, 0, 278, 278, 278, 278, 278, 278, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 627, 0, - 0, 278, 0, 0, 0, 0, 0, 0, 463, 0, - 0, 0, 734, 0, 0, 0, 739, 278, 0, 278, - 0, 0, 278, 278, 0, 278, 262, 0, 528, 529, - 0, 531, 532, 533, 535, 536, 200, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 760, 553, 554, 555, - 556, 0, 0, 249, 0, 0, 0, 278, 250, 278, - 0, 0, 0, 22, 251, 0, 0, 768, 278, 278, - 0, 0, 0, 252, 0, 775, 0, 0, 0, 0, - 0, 0, 778, 0, 0, 0, 0, 0, 0, 253, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 249, - 0, 0, 0, 0, 250, 389, 0, 0, 0, 22, - 251, 0, 269, 0, 255, 512, 270, 0, 271, 252, - 0, 0, 0, 0, 0, 258, 0, 0, 597, 0, - 259, 0, 0, 598, 0, 253, 600, 0, 0, 603, - 604, 0, 0, 200, 608, 609, 200, 0, 610, 611, - 613, 0, 200, 0, 0, 0, 0, 0, 393, 0, - 255, 0, 270, 0, 271, 0, 0, 0, 0, 0, - 0, 258, 463, 463, 534, 0, 259, 0, 0, 5, - 6, 0, 7, 8, 9, 10, 11, 0, 12, 13, + 0, 0, 0, 278, 278, 278, 278, 278, 0, 544, + 0, 249, 0, 544, 544, 0, 250, 0, 0, 0, + 0, 22, 251, 696, 0, 566, 699, 0, 0, 0, + 0, 252, 0, 0, 0, 0, 0, 0, 464, 464, + 483, 0, 0, 0, 0, 0, 0, 253, 0, 709, + 0, 0, 0, 0, 0, 0, 0, 0, 278, 278, + 0, 0, 278, 0, 278, 278, 278, 278, 278, 278, + 336, 0, 255, 0, 270, 0, 271, 0, 0, 627, + 0, 0, 278, 258, 0, 0, 0, 0, 259, 0, + 0, 0, 0, 734, 0, 0, 0, 739, 278, 0, + 278, 0, 0, 278, 278, 0, 278, 262, 0, 528, + 529, 0, 531, 532, 533, 535, 536, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 760, 553, 554, + 555, 556, 0, 0, 249, 0, 0, 0, 278, 250, + 278, 0, 0, 0, 22, 251, 0, 0, 768, 278, + 278, 0, 0, 0, 252, 0, 775, 0, 0, 0, + 0, 0, 0, 778, 0, 0, 781, 0, 0, 784, + 253, 0, 787, 0, 0, 790, 0, 0, 793, 0, + 0, 796, 0, 0, 799, 0, 389, 802, 0, 0, + 805, 0, 0, 393, 0, 255, 0, 270, 0, 271, + 0, 0, 0, 0, 0, 0, 258, 0, 0, 597, + 0, 259, 0, 0, 598, 0, 0, 600, 0, 0, + 603, 604, 0, 0, 0, 608, 609, 0, 0, 610, + 611, 613, 0, 0, 0, 0, 0, 0, 5, 6, + 0, 7, 8, 9, 10, 11, 0, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 0, 0, 0, 0, 0, 0, + 183, 184, 185, 186, 187, 188, 189, 190, 29, 191, + 22, 192, 193, 25, 194, 195, 0, 0, 30, 31, + 0, 32, 0, 33, 0, 0, 0, 0, 0, 0, + 0, 358, 34, 35, 36, 0, 37, 0, 38, 0, + 39, 0, 40, 0, 0, 0, 0, 0, 0, 682, + 683, 684, 685, 686, 41, 0, 0, 42, 0, 196, + 0, 197, 0, 198, 0, 199, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 58, 0, 714, 0, 29, 0, 0, + 719, 720, 721, 722, 723, 724, 0, 30, 31, 0, + 32, 0, 33, 0, 0, 0, 0, 60, 0, 0, + 0, 34, 35, 36, 0, 61, 316, 38, 0, 39, + 0, 40, 0, 0, 740, 0, 742, 0, 0, 744, + 745, 0, 746, 41, 0, 183, 184, 185, 186, 187, + 188, 189, 190, 0, 191, 22, 192, 193, 25, 194, + 195, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 763, 0, 764, 0, 0, 0, + 0, 0, 0, 0, 0, 769, 770, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 196, 0, 197, 0, 198, 0, + 199, 0, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, 131, 132, 133, 30, 31, + 0, 32, 0, 33, 0, 0, 134, 135, 60, 0, + 0, 136, 34, 35, 36, 0, 61, 0, 38, 0, + 39, 0, 40, 0, 0, 62, 63, 137, 0, 0, + 0, 0, 0, 0, 41, 0, 0, 0, 0, 138, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 167, 168, 169, 170, 171, + 172, 29, 173, 174, 175, 128, 176, 177, 178, 179, + 133, 30, 31, 0, 32, 0, 33, 0, 0, 180, + 181, 60, 0, 0, 182, 34, 35, 36, 0, 61, + 0, 38, 0, 39, 0, 40, 0, 0, 62, 63, + 0, 0, 0, 0, 0, 0, 0, 41, 446, 447, + 448, 449, 450, 451, 452, 453, 20, 454, 22, 455, + 456, 25, 457, 458, 28, 0, 0, 0, 0, 0, + 0, 0, 0, 167, 168, 169, 170, 171, 172, 29, + 173, 174, 175, 128, 176, 177, 178, 179, 133, 30, + 31, 0, 32, 0, 33, 0, 0, 180, 181, 60, + 0, 0, 182, 34, 35, 36, 0, 459, 0, 460, + 0, 461, 0, 462, 0, 0, 62, 63, 0, 0, + 0, 0, 0, 0, 0, 41, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 58, 0, 0, 0, 29, 0, 0, + 0, 0, 0, 0, 0, 0, 59, 30, 31, 0, + 32, 0, 33, 0, 0, 0, 0, 60, 0, 0, + 0, 34, 35, 36, 467, 295, 0, 38, 0, 296, + 468, 40, 0, 0, 62, 63, 0, 0, 0, 0, + 0, 0, 0, 41, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 343, 27, + 28, 0, 0, 344, 0, 0, 0, 0, 0, 0, + 0, 58, 0, 0, 0, 29, 0, 0, 0, 0, + 0, 0, 0, 0, 59, 30, 31, 0, 32, 0, + 33, 0, 0, 0, 0, 60, 0, 0, 0, 34, + 35, 36, 0, 61, 0, 38, 0, 39, 0, 40, + 0, 0, 62, 63, 0, 0, 0, 0, 0, 0, + 0, 41, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, + 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, + 0, 0, 59, 30, 31, 0, 32, 0, 33, 0, + 0, 0, 0, 60, 0, 0, 0, 34, 35, 36, + 0, 61, 0, 38, 475, 39, 0, 40, 0, 0, + 62, 63, 0, 0, 0, 0, 0, 0, 0, 41, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, + 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, + 59, 30, 31, 0, 32, 0, 33, 0, 0, 0, + 0, 60, 0, 0, 0, 34, 35, 36, 0, 61, + 0, 38, 586, 39, 0, 40, 0, 0, 62, 63, + 0, 0, 0, 0, 0, 0, 0, 41, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 0, 0, 0, 0, 0, - 0, 0, 0, 200, 200, 0, 249, 0, 0, 29, - 0, 250, 0, 0, 0, 0, 22, 251, 0, 30, - 31, 0, 32, 0, 33, 0, 252, 0, 682, 683, - 684, 685, 686, 34, 35, 36, 0, 37, 0, 38, - 0, 39, 253, 40, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 41, 0, 0, 42, 0, - 0, 0, 0, 0, 0, 254, 0, 255, 0, 256, - 200, 257, 0, 0, 0, 0, 0, 0, 258, 0, - 0, 200, 0, 259, 714, 0, 0, 0, 0, 719, - 720, 721, 722, 723, 724, 7, 8, 9, 10, 11, - 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 0, 0, - 0, 0, 0, 740, 0, 742, 0, 0, 744, 745, - 0, 746, 29, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 30, 31, 0, 32, 0, 33, 0, 0, - 0, 0, 0, 463, 463, 0, 34, 35, 36, 0, - 37, 0, 38, 763, 39, 764, 40, 0, 0, 0, - 0, 0, 0, 0, 769, 770, 0, 0, 41, 0, - 0, 42, 12, 13, 14, 15, 16, 17, 18, 19, + 0, 0, 0, 0, 0, 58, 0, 0, 0, 29, + 0, 0, 0, 0, 0, 0, 0, 0, 59, 30, + 31, 0, 32, 0, 33, 0, 0, 0, 0, 60, + 0, 0, 0, 34, 35, 36, 0, 61, 0, 38, + 0, 39, 0, 40, 0, 0, 62, 63, 0, 0, + 0, 0, 0, 0, 0, 41, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 58, 0, 0, 0, 29, 0, 0, + 0, 0, 0, 0, 0, 0, 59, 30, 31, 0, + 32, 0, 33, 0, 0, 0, 0, 60, 0, 0, + 0, 34, 35, 36, 0, 295, 0, 38, 0, 296, + 0, 40, 0, 0, 62, 63, 0, 0, 0, 0, + 0, 0, 0, 41, 446, 447, 448, 449, 450, 451, + 452, 453, 20, 454, 22, 455, 456, 25, 457, 458, + 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 58, 0, 0, 0, 29, 0, 0, 0, 0, + 0, 0, 0, 0, 59, 30, 31, 0, 32, 0, + 33, 0, 0, 0, 0, 60, 0, 0, 0, 34, + 35, 36, 0, 459, 0, 460, 0, 461, 0, 462, + 0, 0, 62, 63, 0, 0, 0, 0, 0, 0, + 0, 41, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 0, - 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, - 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, - 131, 132, 133, 30, 31, 0, 32, 0, 33, 0, - 0, 134, 135, 60, 0, 0, 136, 34, 35, 36, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, + 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, + 0, 0, 59, 30, 31, 0, 32, 0, 33, 0, + 0, 0, 0, 60, 0, 0, 0, 34, 35, 36, 0, 61, 0, 38, 0, 39, 0, 40, 0, 0, - 62, 63, 137, 0, 0, 0, 0, 0, 0, 41, - 0, 0, 0, 0, 138, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, - 167, 168, 169, 170, 171, 172, 29, 173, 174, 175, - 128, 176, 177, 178, 179, 133, 30, 31, 0, 32, - 0, 33, 0, 0, 180, 181, 60, 0, 0, 182, - 34, 35, 36, 0, 61, 0, 38, 0, 39, 0, - 40, 0, 0, 62, 63, 0, 0, 0, 0, 0, - 0, 0, 41, 446, 447, 448, 449, 450, 451, 452, - 453, 20, 454, 22, 455, 456, 25, 457, 458, 28, - 0, 0, 0, 0, 0, 0, 0, 0, 167, 168, - 169, 170, 171, 172, 29, 173, 174, 175, 128, 176, - 177, 178, 179, 133, 30, 31, 0, 32, 0, 33, - 0, 0, 180, 181, 60, 0, 0, 182, 34, 35, - 36, 0, 459, 0, 460, 0, 461, 0, 462, 0, - 0, 62, 63, 0, 0, 0, 0, 0, 0, 0, - 41, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 58, 0, - 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, - 0, 59, 30, 31, 0, 32, 0, 33, 0, 0, - 0, 0, 60, 0, 0, 0, 34, 35, 36, 467, - 295, 0, 38, 0, 296, 468, 40, 0, 0, 62, - 63, 0, 0, 0, 0, 0, 0, 0, 41, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 343, 27, 28, 0, 0, 344, 0, - 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, - 29, 0, 0, 0, 0, 0, 0, 249, 0, 59, - 30, 31, 250, 32, 0, 33, 0, 22, 251, 0, - 60, 0, 0, 0, 34, 35, 36, 252, 61, 0, - 38, 0, 39, 0, 40, 0, 0, 62, 63, 0, - 0, 0, 0, 253, 0, 0, 41, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 0, 0, 269, 0, 255, 0, - 270, 0, 271, 0, 58, 0, 0, 0, 29, 258, - 0, 0, 0, 0, 259, 249, 0, 59, 30, 31, - 250, 32, 0, 33, 0, 22, 251, 0, 60, 0, - 0, 0, 34, 35, 36, 252, 61, 0, 38, 475, - 39, 0, 40, 0, 0, 62, 63, 0, 0, 0, - 0, 253, 0, 0, 41, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 0, 0, 336, 0, 255, 0, 270, 0, - 271, 0, 58, 0, 0, 0, 29, 258, 0, 0, - 0, 0, 259, 249, 0, 59, 30, 31, 250, 32, - 0, 33, 0, 22, 251, 0, 60, 0, 0, 0, - 34, 35, 36, 252, 61, 0, 38, 586, 39, 0, - 40, 0, 0, 62, 63, 0, 0, 0, 0, 253, - 0, 0, 41, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 0, 0, 393, 0, 255, 0, 270, 0, 271, 0, - 58, 0, 0, 0, 29, 258, 0, 0, 0, 0, - 259, 0, 0, 59, 30, 31, 0, 32, 0, 33, - 0, 0, 0, 0, 60, 0, 0, 0, 34, 35, - 36, 0, 61, 0, 38, 0, 39, 0, 40, 0, - 0, 62, 63, 0, 0, 0, 0, 0, 0, 0, - 41, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 58, 0, - 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, - 0, 59, 30, 31, 0, 32, 0, 33, 0, 0, - 0, 0, 60, 0, 0, 0, 34, 35, 36, 0, - 295, 0, 38, 0, 296, 0, 40, 0, 0, 62, - 63, 0, 0, 0, 0, 0, 0, 0, 41, 446, - 447, 448, 449, 450, 451, 452, 453, 20, 454, 22, - 455, 456, 25, 457, 458, 28, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, - 29, 0, 0, 0, 0, 0, 0, 0, 0, 59, - 30, 31, 0, 32, 0, 33, 0, 0, 0, 0, - 60, 0, 0, 0, 34, 35, 36, 0, 459, 0, - 460, 0, 461, 0, 462, 0, 0, 62, 63, 0, - 0, 0, 0, 0, 0, 0, 41, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 58, 0, 0, 0, 29, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 30, 31, - 0, 32, 0, 33, 0, 0, 0, 0, 60, 0, - 0, 0, 34, 35, 36, 0, 61, 316, 38, 0, - 39, 0, 40, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 41, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 58, 0, 0, 0, 29, 0, 0, 0, - 0, 0, 0, 0, 0, 59, 30, 31, 0, 32, - 0, 33, 0, 0, 0, 0, 60, 0, 0, 0, - 34, 35, 36, 0, 61, 0, 38, 0, 39, 0, - 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 41, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 58, 0, 0, 0, 29, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 30, 31, 0, 32, 0, 33, - 0, 0, 0, 0, 60, 0, 0, 0, 34, 35, - 36, 0, 61, 0, 38, 0, 39, 0, 40, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 41, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 58, 0, - 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 30, 31, 0, 32, 0, 33, 0, 0, - 0, 0, 0, 0, 0, 0, 34, 35, 36, 0, - 61, 304, 38, 0, 39, 0, 40, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 41, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, - 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 30, 31, 0, 32, 0, 33, 0, 0, 0, 0, - 0, 0, 0, 0, 34, 35, 36, 0, 61, 0, - 38, 0, 39, 0, 40, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 41, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 30, 31, - 0, 32, 0, 33, 0, 0, 0, 0, 0, 0, - 0, 0, 34, 35, 36, 0, 61, 0, 38, 0, - 39, 0, 40, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 41, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, - 0, 0, 289, 0, 0, 0, 0, 0, 0, 0, - 34, 35, 0, 0, 61, 0, 38, 0, 39, 0, - 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 41, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 640, 0, 0, 0, 29, 0, 0, 183, 184, 185, - 186, 187, 188, 189, 190, 31, 191, 22, 192, 193, - 25, 194, 195, 0, 0, 641, 0, 0, 34, 35, - 0, 0, 61, 0, 38, 0, 39, 0, 40, 0, - 0, 0, 183, 184, 185, 186, 187, 188, 189, 190, - 41, 191, 22, 192, 193, 25, 194, 195, 0, 0, - 0, 0, 0, 0, 0, 0, 196, 0, 197, 0, - 198, 0, 199, 358, 183, 184, 185, 186, 187, 188, - 189, 190, 0, 191, 22, 192, 193, 25, 194, 195, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 196, 0, 197, 0, 198, 0, 199, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, + 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 30, 31, 0, 32, 0, 33, 0, 0, 0, + 0, 60, 0, 0, 0, 34, 35, 36, 0, 61, + 0, 38, 0, 39, 0, 40, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 41, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 58, 0, 0, 0, 29, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, + 31, 0, 32, 0, 33, 0, 0, 0, 0, 0, + 0, 0, 0, 34, 35, 36, 0, 61, 304, 38, + 0, 39, 0, 40, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 41, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 58, 0, 0, 0, 29, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 30, 31, 0, + 32, 0, 33, 0, 0, 0, 0, 0, 0, 0, + 0, 34, 35, 36, 0, 61, 0, 38, 0, 39, + 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 41, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 30, 31, 0, 32, 0, + 33, 0, 0, 0, 0, 0, 0, 0, 0, 34, + 35, 36, 0, 61, 0, 38, 0, 39, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 41, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 196, 0, 197, 0, 198, 0, 199 + 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 31, 0, 0, 0, 0, 289, + 0, 0, 0, 0, 0, 0, 0, 34, 35, 0, + 0, 61, 0, 38, 0, 39, 0, 40, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 0, 0, 0, + 0, 229, 230, 231, 232, 233, 234, 235, 236, 237, + 238, 29, 239, 240, 241, 242, 0, 0, 0, 0, + 0, 0, 31, 0, 0, 243, 244, 0, 0, 0, + 245, 0, 0, 0, 0, 34, 35, 0, 0, 61, + 0, 38, 0, 39, 0, 40, 137, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 41, 138 }; static const yytype_int16 yycheck[] = { - 2, 3, 29, 54, 206, 207, 208, 209, 38, 8, - 9, 88, 32, 63, 34, 44, 198, 1, 196, 197, - 59, 117, 539, 551, 620, 414, 58, 154, 624, 31, - 8, 8, 8, 0, 8, 8, 38, 15, 31, 41, - 38, 432, 20, 62, 63, 25, 33, 25, 26, 75, - 25, 93, 94, 46, 41, 81, 16, 35, 60, 25, - 44, 112, 33, 38, 115, 25, 26, 25, 38, 33, - 41, 25, 43, 51, 38, 36, 40, 41, 39, 25, - 44, 80, 46, 47, 83, 49, 50, 86, 120, 78, - 88, 75, 25, 113, 133, 33, 74, 124, 76, 79, - 78, 88, 80, 41, 81, 81, 80, 80, 499, 87, - 80, 43, 33, 79, 92, 117, 74, 88, 78, 246, - 41, 248, 43, 69, 88, 79, 156, 88, 74, 725, - 25, 8, 78, 69, 161, 46, 155, 169, 15, 43, - 43, 74, 53, 20, 41, 78, 82, 36, 25, 26, - 88, 41, 25, 41, 44, 157, 88, 38, 35, 40, - 162, 550, 34, 44, 692, 46, 47, 88, 49, 50, - 687, 210, 689, 34, 51, 64, 65, 254, 255, 74, - 25, 25, 201, 43, 88, 88, 205, 219, 220, 221, - 38, 88, 269, 38, 38, 272, 85, 74, 88, 76, - 88, 78, 298, 80, 38, 28, 31, 88, 80, 81, - 87, 25, 80, 25, 39, 92, 77, 20, 31, 78, - 88, 46, 25, 225, 38, 31, 38, 39, 88, 74, - 74, 25, 80, 46, 39, 60, 753, 64, 65, 290, - 46, 25, 15, 227, 38, 20, 80, 20, 287, 74, - 25, 76, 25, 26, 38, 38, 69, 259, 85, 336, - 33, 74, 35, 76, 75, 25, 75, 266, 74, 69, - 76, 25, 81, 33, 294, 15, 25, 88, 51, 461, - 20, 459, 460, 285, 38, 25, 26, 20, 16, 38, - 80, 81, 25, 75, 34, 35, 298, 25, 26, 25, - 327, 74, 75, 76, 323, 78, 88, 80, 25, 8, - 387, 51, 38, 390, 87, 392, 393, 25, 25, 92, - 322, 38, 324, 79, 79, 77, 328, 329, 330, 81, - 38, 38, 88, 88, 74, 79, 76, 77, 78, 32, - 80, 418, 344, 80, 88, 80, 348, 87, 350, 79, - 379, 88, 92, 88, 356, 80, 358, 20, 88, 3, - 4, 5, 25, 88, 47, 48, 49, 50, 51, 52, - 53, 54, 74, 8, 9, 80, 78, 15, 80, 75, - 407, 86, 20, 32, 75, 81, 75, 25, 26, 439, - 81, 20, 81, 75, 445, 379, 25, 35, 77, 81, - 34, 46, 81, 77, 38, 482, 80, 484, 79, 36, - 81, 430, 39, 51, 433, 414, 80, 81, 1, 2, - 439, 38, 5, 6, 7, 8, 9, 10, 11, 79, - 460, 81, 79, 435, 81, 63, 74, 75, 76, 516, - 78, 518, 80, 79, 521, 81, 29, 30, 38, 87, - 10, 11, 35, 75, 92, 75, 39, 40, 460, 75, - 75, 44, 40, 41, 42, 467, 75, 75, 470, 546, - 547, 548, 549, 75, 57, 43, 44, 45, 75, 62, - 63, 500, 501, 222, 223, 224, 488, 75, 75, 491, - 75, 75, 75, 75, 75, 75, 75, 80, 75, 38, - 83, 84, 38, 86, 706, 88, 92, 96, 7, 8, - 9, 10, 11, 12, 13, 67, 33, 43, 41, 81, - 38, 20, 105, 106, 80, 80, 25, 26, 37, 82, - 38, 114, 38, 77, 117, 32, 35, 38, 85, 46, - 75, 124, 34, 46, 92, 88, 14, 81, 567, 34, - 34, 550, 572, 14, 75, 757, 36, 77, 80, 578, - 38, 80, 61, 77, 68, 75, 149, 150, 80, 34, - 153, 154, 155, 72, 73, 77, 38, 579, 161, 581, - 163, 34, 80, 79, 77, 84, 34, 589, 82, 591, - 80, 80, 80, 670, 80, 34, 34, 674, 649, 211, - 212, 213, 214, 215, 216, 217, 218, 38, 58, 34, - 81, 38, 34, 196, 197, 198, 199, 694, 201, 38, - 38, 38, 205, 39, 39, 38, 33, 79, 77, 38, - 81, 650, 651, 38, 38, 75, 227, 639, 640, 641, - 538, 267, 621, 645, 227, 228, 628, 418, 650, 651, - 298, 578, 291, 625, 286, 440, 642, 626, 660, 705, - 403, 255, -1, 246, -1, 248, -1, -1, -1, 252, - 253, 254, 255, 256, 257, 258, -1, 253, 637, -1, - 263, 264, -1, 266, -1, 268, 269, 270, 271, 272, - -1, 15, -1, 695, -1, 697, 20, -1, -1, -1, - -1, 25, 26, 286, -1, -1, 708, -1, 291, 33, - -1, 35, 295, 296, -1, 298, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 728, 51, 730, 731, - -1, -1, -1, -1, -1, -1, 738, -1, -1, -1, - 323, -1, -1, -1, 327, -1, -1, -1, -1, -1, - 74, 75, 76, 336, 78, -1, 80, 759, -1, -1, - -1, -1, -1, 87, -1, 767, 349, -1, 92, -1, - -1, -1, 774, -1, -1, 777, -1, -1, 780, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 379, -1, -1, -1, - -1, -1, -1, -1, 387, -1, -1, 390, -1, 392, - 393, -1, -1, -1, -1, -1, -1, 84, -1, -1, - 403, -1, 405, 406, 407, 408, 409, 410, 411, 412, - -1, 414, -1, 416, 417, 418, -1, -1, -1, -1, - -1, 424, 425, 426, 427, -1, -1, 430, -1, 432, - 433, -1, -1, -1, -1, 438, 439, -1, -1, -1, - 15, 16, 17, 18, 19, 20, 21, 22, -1, 24, - 25, 26, 27, 28, 29, 30, 459, 460, 461, 462, - -1, -1, -1, -1, -1, 62, 63, -1, -1, -1, - -1, 46, -1, -1, -1, -1, -1, -1, -1, 482, - -1, 484, -1, -1, -1, -1, -1, -1, -1, 492, - -1, -1, -1, -1, -1, -1, 499, 500, 501, 74, - -1, 76, 505, 78, -1, 80, -1, 510, 105, -1, - 513, -1, 515, 516, 517, 518, -1, 520, 521, 522, - -1, -1, 525, 526, 527, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 538, -1, -1, -1, -1, - 543, -1, -1, 546, 547, 548, 549, 550, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 155, 51, - 52, 53, 54, -1, 567, -1, -1, 254, 571, 256, - 257, -1, 64, 65, -1, 578, 263, 69, -1, 7, - 8, 9, 10, 11, 12, 13, -1, 590, -1, -1, - -1, -1, 20, 85, -1, -1, 599, 25, 26, 196, - 197, -1, -1, -1, 201, 97, -1, 35, 205, -1, - -1, -1, 615, 616, 617, 618, 619, -1, 621, -1, - -1, -1, 625, 626, -1, -1, -1, -1, -1, -1, - -1, -1, 635, 61, 637, 638, -1, -1, -1, -1, - -1, -1, -1, -1, 72, 73, -1, 650, 651, 336, - -1, 79, -1, -1, -1, -1, 84, -1, 661, -1, - -1, -1, -1, -1, -1, -1, -1, 670, 671, -1, - -1, 674, -1, 676, 677, 678, 679, 680, 681, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 691, -1, - -1, 694, -1, -1, -1, -1, -1, -1, 295, -1, - -1, -1, 705, -1, -1, -1, 709, 710, -1, 712, - -1, -1, 715, 716, -1, 718, 403, -1, 405, 406, - -1, 408, 409, 410, 411, 412, 323, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 739, 424, 425, 426, - 427, -1, -1, 15, -1, -1, -1, 750, 20, 752, - -1, -1, -1, 25, 26, -1, -1, 760, 761, 762, - -1, -1, -1, 35, -1, 768, -1, -1, -1, -1, - -1, -1, 775, -1, -1, -1, -1, -1, -1, 51, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, - -1, -1, -1, -1, 20, 482, -1, -1, -1, 25, - 26, -1, 74, -1, 76, 77, 78, -1, 80, 35, - -1, -1, -1, -1, -1, 87, -1, -1, 505, -1, - 92, -1, -1, 510, -1, 51, 513, -1, -1, 516, - 517, -1, -1, 430, 521, 522, 433, -1, 525, 526, - 527, -1, 439, -1, -1, -1, -1, -1, 74, -1, - 76, -1, 78, -1, 80, -1, -1, -1, -1, -1, - -1, 87, 459, 460, 90, -1, 92, -1, -1, 6, - 7, -1, 9, 10, 11, 12, 13, -1, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, - -1, -1, -1, 500, 501, -1, 15, -1, -1, 46, - -1, 20, -1, -1, -1, -1, 25, 26, -1, 56, - 57, -1, 59, -1, 61, -1, 35, -1, 615, 616, - 617, 618, 619, 70, 71, 72, -1, 74, -1, 76, - -1, 78, 51, 80, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 92, -1, -1, 95, -1, - -1, -1, -1, -1, -1, 74, -1, 76, -1, 78, - 567, 80, -1, -1, -1, -1, -1, -1, 87, -1, - -1, 578, -1, 92, 671, -1, -1, -1, -1, 676, - 677, 678, 679, 680, 681, 9, 10, 11, 12, 13, - -1, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, -1, -1, - -1, -1, -1, 710, -1, 712, -1, -1, 715, 716, - -1, 718, 46, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 56, 57, -1, 59, -1, 61, -1, -1, - -1, -1, -1, 650, 651, -1, 70, 71, 72, -1, - 74, -1, 76, 750, 78, 752, 80, -1, -1, -1, - -1, -1, -1, -1, 761, 762, -1, -1, 92, -1, - -1, 95, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, -1, - -1, -1, -1, -1, -1, -1, -1, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, -1, 59, -1, 61, -1, - -1, 64, 65, 66, -1, -1, 69, 70, 71, 72, - -1, 74, -1, 76, -1, 78, -1, 80, -1, -1, - 83, 84, 85, -1, -1, -1, -1, -1, -1, 92, - -1, -1, -1, -1, 97, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, - -1, 61, -1, -1, 64, 65, 66, -1, -1, 69, - 70, 71, 72, -1, 74, -1, 76, -1, 78, -1, - 80, -1, -1, 83, 84, -1, -1, -1, -1, -1, - -1, -1, 92, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - -1, -1, -1, -1, -1, -1, -1, -1, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, -1, 59, -1, 61, - -1, -1, 64, 65, 66, -1, -1, 69, 70, 71, - 72, -1, 74, -1, 76, -1, 78, -1, 80, -1, - -1, 83, 84, -1, -1, -1, -1, -1, -1, -1, - 92, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, + 2, 3, 88, 54, 62, 63, 62, 63, 206, 207, + 208, 209, 8, 9, 38, 32, 63, 34, 44, 1, + 59, 29, 196, 197, 539, 198, 117, 414, 154, 31, + 58, 620, 551, 33, 8, 624, 38, 8, 8, 41, + 33, 41, 8, 43, 25, 8, 78, 105, 41, 15, + 43, 80, 31, 25, 20, 69, 432, 86, 60, 25, + 26, 112, 44, 16, 115, 64, 65, 46, 82, 35, + 25, 16, 25, 26, 33, 33, 77, 25, 25, 80, + 25, 26, 41, 41, 80, 51, 85, 83, 88, 43, + 86, 25, 120, 75, 133, 88, 113, 155, 79, 155, + 7, 8, 9, 10, 11, 12, 13, 81, 74, 80, + 76, 81, 78, 20, 80, 117, 124, 80, 25, 26, + 246, 87, 248, 499, 79, 78, 92, 74, 35, 88, + 88, 79, 156, 79, 88, 69, 725, 38, 196, 197, + 74, 169, 88, 201, 78, 201, 25, 205, 36, 205, + 34, 39, 38, 161, 61, 157, 25, 20, 34, 0, + 162, 41, 25, 550, 44, 72, 73, 41, 254, 255, + 15, 210, 687, 692, 689, 20, 38, 84, 40, 80, + 25, 26, 44, 269, 46, 47, 272, 49, 50, 34, + 35, 219, 220, 221, 77, 74, 80, 81, 81, 78, + 88, 77, 88, 8, 25, 74, 51, 298, 88, 43, + 15, 33, 36, 41, 88, 20, 38, 38, 40, 41, + 25, 26, 44, 225, 46, 47, 88, 49, 50, 74, + 35, 76, 77, 78, 38, 80, 31, 295, 753, 290, + 64, 65, 87, 25, 43, 227, 51, 92, 287, 38, + 336, 46, 43, 74, 88, 25, 38, 259, 74, 25, + 88, 85, 78, 78, 80, 323, 88, 323, 38, 74, + 266, 76, 38, 78, 69, 80, 80, 294, 75, 74, + 25, 76, 87, 285, 81, 459, 460, 92, 461, 88, + 31, 80, 74, 38, 31, 25, 298, 88, 25, 39, + 75, 387, 39, 25, 390, 46, 392, 393, 38, 46, + 77, 38, 39, 88, 81, 79, 38, 25, 75, 327, + 322, 25, 324, 60, 88, 25, 328, 329, 330, 28, + 38, 88, 418, 74, 38, 76, 25, 74, 38, 76, + 36, 69, 344, 39, 25, 25, 348, 25, 350, 38, + 25, 25, 25, 379, 356, 25, 358, 38, 38, 38, + 38, 79, 79, 38, 38, 38, 25, 25, 38, 25, + 88, 88, 430, 8, 430, 433, 25, 433, 80, 38, + 38, 439, 38, 439, 33, 80, 88, 80, 3, 4, + 5, 38, 439, 88, 445, 88, 482, 379, 484, 407, + 46, 459, 460, 20, 40, 41, 42, 53, 25, 80, + 7, 8, 9, 10, 11, 12, 13, 88, 414, 46, + 75, 75, 79, 20, 81, 75, 81, 81, 25, 26, + 516, 81, 518, 435, 75, 521, 460, 79, 35, 81, + 81, 32, 500, 501, 500, 501, 47, 48, 49, 50, + 51, 52, 53, 54, 20, 43, 44, 45, 460, 25, + 546, 547, 548, 549, 61, 467, 75, 34, 470, 93, + 94, 38, 81, 20, 15, 72, 73, 32, 25, 20, + 80, 81, 79, 20, 25, 26, 488, 84, 25, 491, + 80, 81, 33, 63, 35, 211, 212, 213, 214, 215, + 216, 217, 218, 222, 223, 224, 8, 9, 706, 567, + 51, 567, 10, 11, 79, 79, 81, 81, 38, 75, + 578, 75, 578, 75, 75, 75, 75, 75, 38, 75, + 75, 75, 75, 74, 75, 76, 75, 78, 38, 80, + 75, 75, 15, 75, 75, 75, 87, 20, 67, 33, + 92, 92, 25, 26, 550, 572, 96, 43, 41, 757, + 33, 38, 35, 15, 81, 80, 80, 37, 20, 82, + 38, 38, 32, 25, 26, 38, 77, 579, 51, 581, + 85, 46, 75, 35, 670, 34, 92, 589, 674, 591, + 46, 88, 650, 651, 650, 651, 14, 34, 649, 51, + 81, 74, 75, 76, 34, 78, 14, 80, 694, 75, + 36, 38, 34, 77, 87, 68, 77, 75, 80, 92, + 77, 80, 74, 75, 76, 80, 78, 38, 80, 80, + 77, 79, 82, 34, 80, 87, 80, 639, 640, 641, + 92, 80, 34, 645, 80, 34, 34, 38, 650, 651, + 34, 58, 81, 38, 34, 38, 38, 38, 660, 33, + 39, 39, 38, 79, 77, 38, 81, 38, 38, 1, + 2, 75, 538, 5, 6, 7, 8, 9, 10, 11, + 621, 625, 267, 418, 626, 628, 298, 286, 578, 227, + 642, 440, 705, 695, 403, 697, 291, 29, 30, 15, + 637, -1, 255, 35, 20, -1, 708, 39, 40, 25, + 26, -1, 44, -1, -1, -1, -1, 253, -1, 35, + -1, -1, -1, -1, -1, 57, 728, -1, 730, 731, + 62, 63, -1, -1, -1, 51, 738, -1, -1, -1, + -1, -1, -1, 75, -1, -1, -1, -1, 80, -1, + -1, 83, 84, -1, 86, -1, 88, 759, 74, -1, + 76, 77, 78, -1, 80, 767, -1, -1, -1, -1, + -1, 87, 774, 105, 106, 777, 92, -1, 780, -1, + -1, 783, 114, -1, 786, 117, -1, 789, -1, -1, + 792, -1, 124, 795, -1, -1, 798, -1, -1, 801, + -1, -1, 804, -1, -1, 807, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 15, -1, 149, 150, -1, + 20, 153, 154, 155, -1, 25, 26, -1, -1, 161, + -1, 163, -1, -1, -1, 35, 8, -1, -1, -1, + -1, -1, -1, 15, 16, 17, 18, 19, 20, 21, + 22, 51, 24, 25, 26, 27, 28, 29, 30, -1, + -1, 33, -1, -1, 196, 197, 198, 199, -1, 201, + -1, -1, -1, 205, 74, -1, 76, -1, 78, -1, + 80, -1, -1, 15, -1, -1, -1, 87, 20, -1, + 90, -1, 92, 25, 26, 227, 228, -1, -1, -1, + -1, -1, 74, 35, 76, -1, 78, -1, 80, -1, + -1, -1, -1, -1, 246, -1, 248, -1, -1, 51, + 252, 253, 254, 255, 256, 257, 258, -1, -1, -1, + -1, 263, 264, -1, 266, -1, 268, 269, 270, 271, + 272, -1, 74, -1, 76, -1, 78, -1, 80, -1, + -1, -1, -1, -1, 286, 87, -1, -1, -1, 291, + 92, -1, -1, 295, 296, -1, 298, -1, 9, 10, + 11, 12, 13, -1, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 323, -1, -1, -1, 327, -1, -1, -1, -1, + -1, -1, -1, -1, 336, 46, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 56, 57, 349, 59, -1, + 61, -1, -1, -1, -1, -1, -1, -1, -1, 70, + 71, 72, -1, 74, -1, 76, -1, 78, -1, 80, + -1, -1, -1, -1, -1, -1, -1, 379, -1, -1, + -1, 92, -1, -1, 95, 387, -1, -1, 390, -1, + 392, 393, -1, -1, -1, -1, -1, -1, 84, -1, + -1, 403, -1, 405, 406, 407, 408, 409, 410, 411, + 412, -1, 414, -1, 416, 417, 418, -1, -1, -1, + -1, -1, 424, 425, 426, 427, -1, -1, 430, -1, + 432, 433, -1, -1, -1, -1, 438, 439, -1, -1, + -1, 15, 16, 17, 18, 19, 20, 21, 22, -1, + 24, 25, 26, 27, 28, 29, 30, 459, 460, 461, + 462, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, -1, -1, -1, -1, -1, -1, -1, - -1, 55, 56, 57, -1, 59, -1, 61, -1, -1, - -1, -1, 66, -1, -1, -1, 70, 71, 72, 73, - 74, -1, 76, -1, 78, 79, 80, -1, -1, 83, - 84, -1, -1, -1, -1, -1, -1, -1, 92, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, -1, -1, 34, -1, - -1, -1, -1, -1, -1, -1, 42, -1, -1, -1, - 46, -1, -1, -1, -1, -1, -1, 15, -1, 55, - 56, 57, 20, 59, -1, 61, -1, 25, 26, -1, - 66, -1, -1, -1, 70, 71, 72, 35, 74, -1, - 76, -1, 78, -1, 80, -1, -1, 83, 84, -1, - -1, -1, -1, 51, -1, -1, 92, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, -1, -1, 74, -1, 76, -1, - 78, -1, 80, -1, 42, -1, -1, -1, 46, 87, - -1, -1, -1, -1, 92, 15, -1, 55, 56, 57, - 20, 59, -1, 61, -1, 25, 26, -1, 66, -1, - -1, -1, 70, 71, 72, 35, 74, -1, 76, 77, - 78, -1, 80, -1, -1, 83, 84, -1, -1, -1, - -1, 51, -1, -1, 92, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, -1, -1, 74, -1, 76, -1, 78, -1, - 80, -1, 42, -1, -1, -1, 46, 87, -1, -1, - -1, -1, 92, 15, -1, 55, 56, 57, 20, 59, - -1, 61, -1, 25, 26, -1, 66, -1, -1, -1, - 70, 71, 72, 35, 74, -1, 76, 77, 78, -1, - 80, -1, -1, 83, 84, -1, -1, -1, -1, 51, - -1, -1, 92, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - -1, -1, 74, -1, 76, -1, 78, -1, 80, -1, - 42, -1, -1, -1, 46, 87, -1, -1, -1, -1, - 92, -1, -1, 55, 56, 57, -1, 59, -1, 61, - -1, -1, -1, -1, 66, -1, -1, -1, 70, 71, - 72, -1, 74, -1, 76, -1, 78, -1, 80, -1, - -1, 83, 84, -1, -1, -1, -1, -1, -1, -1, - 92, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, - -1, -1, 46, -1, -1, -1, -1, -1, -1, -1, - -1, 55, 56, 57, -1, 59, -1, 61, -1, -1, - -1, -1, 66, -1, -1, -1, 70, 71, 72, -1, - 74, -1, 76, -1, 78, -1, 80, -1, -1, 83, - 84, -1, -1, -1, -1, -1, -1, -1, 92, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 42, -1, -1, -1, - 46, -1, -1, -1, -1, -1, -1, -1, -1, 55, - 56, 57, -1, 59, -1, 61, -1, -1, -1, -1, - 66, -1, -1, -1, 70, 71, 72, -1, 74, -1, - 76, -1, 78, -1, 80, -1, -1, 83, 84, -1, - -1, -1, -1, -1, -1, -1, 92, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 42, -1, -1, -1, 46, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 56, 57, - -1, 59, -1, 61, -1, -1, -1, -1, 66, -1, - -1, -1, 70, 71, 72, -1, 74, 75, 76, -1, - 78, -1, 80, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 92, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 42, -1, -1, -1, 46, -1, -1, -1, - -1, -1, -1, -1, -1, 55, 56, 57, -1, 59, - -1, 61, -1, -1, -1, -1, 66, -1, -1, -1, - 70, 71, 72, -1, 74, -1, 76, -1, 78, -1, - 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 92, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 482, -1, 484, -1, -1, -1, -1, -1, -1, -1, + 492, -1, -1, -1, -1, -1, -1, 499, 500, 501, + 74, -1, 76, 505, 78, -1, 80, -1, 510, -1, + -1, 513, -1, 515, 516, 517, 518, -1, 520, 521, + 522, -1, 15, 525, 526, 527, -1, 20, -1, -1, + -1, -1, 25, 26, -1, -1, 538, -1, -1, -1, + -1, 543, 35, -1, 546, 547, 548, 549, 550, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 51, -1, + -1, -1, -1, -1, -1, 567, -1, -1, 254, 571, + 256, 257, -1, -1, -1, -1, 578, 263, -1, -1, + -1, 74, -1, 76, -1, 78, -1, 80, 590, -1, + -1, -1, -1, -1, 87, -1, -1, 599, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 42, -1, -1, -1, 46, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 56, 57, -1, 59, -1, 61, - -1, -1, -1, -1, 66, -1, -1, -1, 70, 71, - 72, -1, 74, -1, 76, -1, 78, -1, 80, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 92, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, - -1, -1, 46, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 56, 57, -1, 59, -1, 61, -1, -1, - -1, -1, -1, -1, -1, -1, 70, 71, 72, -1, - 74, 75, 76, -1, 78, -1, 80, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 92, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 42, -1, -1, -1, - 46, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 56, 57, -1, 59, -1, 61, -1, -1, -1, -1, - -1, -1, -1, -1, 70, 71, 72, -1, 74, -1, - 76, -1, 78, -1, 80, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 92, 15, 16, 17, + -1, -1, -1, 615, 616, 617, 618, 619, -1, 621, + -1, 15, -1, 625, 626, -1, 20, -1, -1, -1, + -1, 25, 26, 635, -1, 637, 638, -1, -1, -1, + -1, 35, -1, -1, -1, -1, -1, -1, 650, 651, + 336, -1, -1, -1, -1, -1, -1, 51, -1, 661, + -1, -1, -1, -1, -1, -1, -1, -1, 670, 671, + -1, -1, 674, -1, 676, 677, 678, 679, 680, 681, + 74, -1, 76, -1, 78, -1, 80, -1, -1, 691, + -1, -1, 694, 87, -1, -1, -1, -1, 92, -1, + -1, -1, -1, 705, -1, -1, -1, 709, 710, -1, + 712, -1, -1, 715, 716, -1, 718, 403, -1, 405, + 406, -1, 408, 409, 410, 411, 412, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 739, 424, 425, + 426, 427, -1, -1, 15, -1, -1, -1, 750, 20, + 752, -1, -1, -1, 25, 26, -1, -1, 760, 761, + 762, -1, -1, -1, 35, -1, 768, -1, -1, -1, + -1, -1, -1, 775, -1, -1, 778, -1, -1, 781, + 51, -1, 784, -1, -1, 787, -1, -1, 790, -1, + -1, 793, -1, -1, 796, -1, 482, 799, -1, -1, + 802, -1, -1, 74, -1, 76, -1, 78, -1, 80, + -1, -1, -1, -1, -1, -1, 87, -1, -1, 505, + -1, 92, -1, -1, 510, -1, -1, 513, -1, -1, + 516, 517, -1, -1, -1, 521, 522, -1, -1, 525, + 526, 527, -1, -1, -1, -1, -1, -1, 6, 7, + -1, 9, 10, 11, 12, 13, -1, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 46, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 56, 57, + 15, 16, 17, 18, 19, 20, 21, 22, 46, 24, + 25, 26, 27, 28, 29, 30, -1, -1, 56, 57, -1, 59, -1, 61, -1, -1, -1, -1, -1, -1, - -1, -1, 70, 71, 72, -1, 74, -1, 76, -1, - 78, -1, 80, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 92, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 46, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 57, -1, -1, - -1, -1, 62, -1, -1, -1, -1, -1, -1, -1, - 70, 71, -1, -1, 74, -1, 76, -1, 78, -1, - 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 92, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 8, -1, -1, -1, 46, -1, -1, 15, 16, 17, - 18, 19, 20, 21, 22, 57, 24, 25, 26, 27, - 28, 29, 30, -1, -1, 33, -1, -1, 70, 71, - -1, -1, 74, -1, 76, -1, 78, -1, 80, -1, - -1, -1, 15, 16, 17, 18, 19, 20, 21, 22, - 92, 24, 25, 26, 27, 28, 29, 30, -1, -1, - -1, -1, -1, -1, -1, -1, 74, -1, 76, -1, - 78, -1, 80, 46, 15, 16, 17, 18, 19, 20, - 21, 22, -1, 24, 25, 26, 27, 28, 29, 30, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 46, 70, 71, 72, -1, 74, -1, 76, -1, + 78, -1, 80, -1, -1, -1, -1, -1, -1, 615, + 616, 617, 618, 619, 92, -1, -1, 95, -1, 74, + -1, 76, -1, 78, -1, 80, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 42, -1, 671, -1, 46, -1, -1, + 676, 677, 678, 679, 680, 681, -1, 56, 57, -1, + 59, -1, 61, -1, -1, -1, -1, 66, -1, -1, + -1, 70, 71, 72, -1, 74, 75, 76, -1, 78, + -1, 80, -1, -1, 710, -1, 712, -1, -1, 715, + 716, -1, 718, 92, -1, 15, 16, 17, 18, 19, + 20, 21, 22, -1, 24, 25, 26, 27, 28, 29, + 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 750, -1, 752, -1, -1, -1, + -1, -1, -1, -1, -1, 761, 762, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 74, -1, 76, -1, 78, -1, + 80, -1, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + -1, 59, -1, 61, -1, -1, 64, 65, 66, -1, + -1, 69, 70, 71, 72, -1, 74, -1, 76, -1, + 78, -1, 80, -1, -1, 83, 84, 85, -1, -1, + -1, -1, -1, -1, 92, -1, -1, -1, -1, 97, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, -1, -1, -1, + -1, -1, -1, -1, -1, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, -1, 59, -1, 61, -1, -1, 64, + 65, 66, -1, -1, 69, 70, 71, 72, -1, 74, + -1, 76, -1, 78, -1, 80, -1, -1, 83, 84, + -1, -1, -1, -1, -1, -1, -1, 92, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, + -1, -1, -1, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, -1, 59, -1, 61, -1, -1, 64, 65, 66, + -1, -1, 69, 70, 71, 72, -1, 74, -1, 76, + -1, 78, -1, 80, -1, -1, 83, 84, -1, -1, + -1, -1, -1, -1, -1, 92, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 42, -1, -1, -1, 46, -1, -1, + -1, -1, -1, -1, -1, -1, 55, 56, 57, -1, + 59, -1, 61, -1, -1, -1, -1, 66, -1, -1, + -1, 70, 71, 72, 73, 74, -1, 76, -1, 78, + 79, 80, -1, -1, 83, 84, -1, -1, -1, -1, + -1, -1, -1, 92, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, -1, -1, 34, -1, -1, -1, -1, -1, -1, + -1, 42, -1, -1, -1, 46, -1, -1, -1, -1, + -1, -1, -1, -1, 55, 56, 57, -1, 59, -1, + 61, -1, -1, -1, -1, 66, -1, -1, -1, 70, + 71, 72, -1, 74, -1, 76, -1, 78, -1, 80, + -1, -1, 83, 84, -1, -1, -1, -1, -1, -1, + -1, 92, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, + -1, -1, -1, 46, -1, -1, -1, -1, -1, -1, + -1, -1, 55, 56, 57, -1, 59, -1, 61, -1, + -1, -1, -1, 66, -1, -1, -1, 70, 71, 72, + -1, 74, -1, 76, 77, 78, -1, 80, -1, -1, + 83, 84, -1, -1, -1, -1, -1, -1, -1, 92, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 42, -1, -1, + -1, 46, -1, -1, -1, -1, -1, -1, -1, -1, + 55, 56, 57, -1, 59, -1, 61, -1, -1, -1, + -1, 66, -1, -1, -1, 70, 71, 72, -1, 74, + -1, 76, 77, 78, -1, 80, -1, -1, 83, 84, + -1, -1, -1, -1, -1, -1, -1, 92, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 42, -1, -1, -1, 46, + -1, -1, -1, -1, -1, -1, -1, -1, 55, 56, + 57, -1, 59, -1, 61, -1, -1, -1, -1, 66, + -1, -1, -1, 70, 71, 72, -1, 74, -1, 76, + -1, 78, -1, 80, -1, -1, 83, 84, -1, -1, + -1, -1, -1, -1, -1, 92, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 42, -1, -1, -1, 46, -1, -1, + -1, -1, -1, -1, -1, -1, 55, 56, 57, -1, + 59, -1, 61, -1, -1, -1, -1, 66, -1, -1, + -1, 70, 71, 72, -1, 74, -1, 76, -1, 78, + -1, 80, -1, -1, 83, 84, -1, -1, -1, -1, + -1, -1, -1, 92, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 42, -1, -1, -1, 46, -1, -1, -1, -1, + -1, -1, -1, -1, 55, 56, 57, -1, 59, -1, + 61, -1, -1, -1, -1, 66, -1, -1, -1, 70, + 71, 72, -1, 74, -1, 76, -1, 78, -1, 80, + -1, -1, 83, 84, -1, -1, -1, -1, -1, -1, + -1, 92, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, + -1, -1, -1, 46, -1, -1, -1, -1, -1, -1, + -1, -1, 55, 56, 57, -1, 59, -1, 61, -1, + -1, -1, -1, 66, -1, -1, -1, 70, 71, 72, -1, 74, -1, 76, -1, 78, -1, 80, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 92, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 42, -1, -1, + -1, 46, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 56, 57, -1, 59, -1, 61, -1, -1, -1, + -1, 66, -1, -1, -1, 70, 71, 72, -1, 74, + -1, 76, -1, 78, -1, 80, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 92, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 42, -1, -1, -1, 46, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 56, + 57, -1, 59, -1, 61, -1, -1, -1, -1, -1, + -1, -1, -1, 70, 71, 72, -1, 74, 75, 76, + -1, 78, -1, 80, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 92, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 42, -1, -1, -1, 46, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 56, 57, -1, + 59, -1, 61, -1, -1, -1, -1, -1, -1, -1, + -1, 70, 71, 72, -1, 74, -1, 76, -1, 78, + -1, 80, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 92, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 46, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 56, 57, -1, 59, -1, + 61, -1, -1, -1, -1, -1, -1, -1, -1, 70, + 71, 72, -1, 74, -1, 76, -1, 78, -1, 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 92, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 74, -1, 76, -1, 78, -1, 80 + -1, -1, -1, 46, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 57, -1, -1, -1, -1, 62, + -1, -1, -1, -1, -1, -1, -1, 70, 71, -1, + -1, 74, -1, 76, -1, 78, -1, 80, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 92, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, -1, -1, -1, + -1, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 46, 51, 52, 53, 54, -1, -1, -1, -1, + -1, -1, 57, -1, -1, 64, 65, -1, -1, -1, + 69, -1, -1, -1, -1, 70, 71, -1, -1, 74, + -1, 76, -1, 78, -1, 80, 85, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 92, 97 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -1922,7 +1955,9 @@ static const yytype_uint8 yystos[] = 43, 80, 41, 112, 123, 123, 123, 81, 123, 38, 179, 38, 38, 170, 170, 124, 123, 38, 179, 170, 170, 79, 80, 123, 38, 179, 123, 38, 179, 123, - 38, 123 + 38, 179, 123, 38, 179, 123, 38, 179, 123, 38, + 179, 123, 38, 179, 123, 38, 179, 123, 38, 179, + 123, 38, 179, 123, 38, 179, 123, 38, 123 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ @@ -1931,39 +1966,40 @@ static const yytype_uint8 yyr1[] = 0, 98, 99, 99, 99, 99, 100, 100, 100, 101, 101, 101, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, - 102, 103, 104, 105, 105, 106, 106, 107, 108, 109, - 109, 109, 109, 109, 109, 109, 109, 110, 110, 111, - 112, 112, 113, 114, 114, 114, 114, 115, 115, 116, - 117, 117, 118, 118, 119, 119, 120, 120, 120, 120, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 103, 104, 105, 105, 106, 106, 107, 108, 109, 109, + 109, 109, 109, 109, 109, 109, 110, 110, 111, 112, + 112, 113, 114, 114, 114, 114, 115, 115, 116, 117, + 117, 118, 118, 119, 119, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 121, 121, 122, 122, 123, - 123, 123, 123, 124, 124, 124, 124, 124, 124, 125, - 125, 126, 126, 126, 126, 126, 126, 126, 126, 126, - 127, 127, 127, 127, 127, 128, 128, 128, 128, 129, - 129, 129, 129, 129, 129, 129, 129, 129, 130, 130, - 131, 132, 132, 133, 133, 134, 134, 135, 135, 136, - 136, 137, 137, 137, 137, 137, 137, 137, 137, 137, + 120, 120, 120, 120, 121, 121, 122, 122, 123, 123, + 123, 123, 124, 124, 124, 124, 124, 124, 125, 125, + 126, 126, 126, 126, 126, 126, 126, 126, 126, 127, + 127, 127, 127, 127, 128, 128, 128, 128, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 130, 130, 131, + 132, 132, 133, 133, 134, 134, 135, 135, 136, 136, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, - 137, 137, 137, 137, 137, 137, 137, 137, 138, 138, - 139, 140, 140, 141, 142, 142, 143, 143, 144, 144, - 144, 145, 145, 146, 146, 147, 147, 148, 148, 149, - 149, 150, 150, 150, 150, 150, 150, 150, 150, 150, + 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 137, 137, 137, 138, 138, 139, + 140, 140, 141, 142, 142, 143, 143, 144, 144, 144, + 145, 145, 146, 146, 147, 147, 148, 148, 149, 149, + 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, - 150, 150, 150, 150, 150, 151, 151, 151, 151, 151, - 152, 153, 153, 154, 154, 155, 155, 156, 157, 157, - 157, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 159, 159, 159, 159, - 160, 160, 161, 161, 161, 162, 162, 162, 163, 163, - 164, 165, 165, 166, 166, 166, 166, 166, 166, 166, + 150, 150, 150, 150, 151, 151, 151, 151, 151, 152, + 153, 153, 154, 154, 155, 155, 156, 157, 157, 157, + 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, + 158, 158, 158, 158, 158, 159, 159, 159, 159, 160, + 160, 161, 161, 161, 162, 162, 162, 163, 163, 164, + 165, 165, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 167, 167, 168, 168, 169, 169, - 169, 170, 170, 170, 170, 170, 170, 170, 170, 170, - 170, 170, 170, 170, 170, 170, 170, 170, 170, 171, - 171, 172, 172, 173, 173, 174, 174, 175, 175, 176, - 176, 177, 177, 178, 178, 178, 178, 179 + 166, 166, 166, 167, 167, 168, 168, 169, 169, 169, + 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, + 170, 170, 170, 170, 170, 170, 170, 170, 171, 171, + 172, 172, 173, 173, 174, 174, 175, 175, 176, 176, + 177, 177, 178, 178, 178, 178, 179 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ @@ -1972,39 +2008,40 @@ static const yytype_int8 yyr2[] = 0, 2, 2, 4, 2, 2, 3, 4, 1, 0, 1, 2, 1, 1, 1, 1, 1, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 1, 2, 3, 2, 2, 4, 4, 3, 3, 5, - 7, 7, 9, 3, 5, 5, 7, 1, 3, 3, - 1, 2, 2, 3, 5, 5, 7, 1, 2, 2, - 1, 3, 1, 2, 1, 3, 1, 1, 1, 1, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 1, + 2, 3, 2, 2, 4, 4, 3, 3, 5, 7, + 7, 9, 3, 5, 5, 7, 1, 3, 3, 1, + 2, 2, 3, 5, 5, 7, 1, 2, 2, 1, + 3, 1, 2, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 2, 1, 2, 4, - 4, 3, 1, 2, 3, 3, 3, 3, 1, 6, - 1, 3, 3, 3, 3, 3, 3, 3, 3, 1, - 3, 3, 3, 2, 1, 3, 3, 3, 1, 1, - 4, 5, 4, 3, 4, 4, 6, 3, 3, 1, - 3, 2, 1, 4, 2, 3, 1, 5, 3, 3, - 1, 4, 1, 5, 4, 5, 3, 4, 4, 6, - 5, 5, 5, 5, 3, 6, 8, 3, 4, 2, - 1, 1, 2, 6, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, + 1, 1, 1, 1, 1, 2, 1, 2, 4, 4, + 3, 1, 2, 3, 3, 3, 3, 1, 6, 1, + 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, + 3, 3, 2, 1, 3, 3, 3, 1, 1, 4, + 5, 4, 3, 4, 4, 6, 3, 3, 1, 3, + 2, 1, 4, 2, 3, 1, 5, 3, 3, 1, + 4, 1, 5, 4, 5, 3, 4, 4, 6, 5, + 5, 5, 5, 3, 6, 8, 3, 4, 2, 1, + 1, 2, 6, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, - 3, 3, 1, 4, 2, 0, 3, 1, 1, 1, - 1, 1, 2, 2, 1, 2, 1, 4, 6, 2, + 3, 3, 3, 3, 3, 3, 3, 2, 1, 3, + 3, 1, 4, 2, 0, 3, 1, 1, 1, 1, + 1, 2, 2, 1, 2, 1, 4, 6, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 3, 4, 3, 5, 5, - 3, 4, 3, 4, 1, 1, 3, 4, 3, 4, - 1, 1, 0, 3, 1, 3, 1, 3, 0, 3, - 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 3, 2, 2, 1, - 1, 3, 3, 5, 5, 0, 1, 3, 3, 1, - 3, 1, 3, 2, 3, 3, 3, 7, 9, 7, - 7, 9, 7, 5, 5, 5, 5, 7, 7, 9, - 9, 7, 7, 5, 1, 2, 2, 1, 3, 1, - 1, 1, 3, 2, 3, 7, 3, 3, 3, 3, - 2, 1, 1, 4, 3, 3, 4, 1, 3, 1, - 1, 1, 3, 1, 5, 1, 3, 1, 3, 3, - 3, 5, 3, 5, 3, 3, 1, 1 + 1, 1, 1, 1, 3, 4, 3, 5, 5, 3, + 4, 3, 4, 1, 1, 3, 4, 3, 4, 1, + 1, 0, 3, 1, 3, 1, 3, 0, 3, 5, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3, 2, 2, 1, 1, + 3, 3, 5, 5, 0, 1, 3, 3, 1, 3, + 1, 3, 2, 3, 3, 3, 7, 9, 7, 7, + 9, 7, 5, 5, 5, 5, 7, 7, 9, 9, + 7, 7, 5, 1, 2, 2, 1, 3, 1, 1, + 1, 3, 2, 3, 7, 3, 3, 3, 3, 2, + 1, 1, 4, 3, 3, 4, 1, 3, 1, 1, + 1, 3, 1, 5, 1, 3, 1, 3, 3, 3, + 5, 3, 5, 3, 3, 1, 1 }; @@ -2148,8 +2185,8 @@ yy_symbol_value_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp) { FILE *yyoutput = yyo; - YYUSE (yyoutput); - YYUSE (yylocationp); + YY_USE (yyoutput); + YY_USE (yylocationp); if (!yyvaluep) return; # ifdef YYPRINT @@ -2157,7 +2194,7 @@ yy_symbol_value_print (FILE *yyo, YYPRINT (yyo, yytoknum[yykind], *yyvaluep); # endif YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - YYUSE (yykind); + YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } @@ -2542,14 +2579,14 @@ static void yydestruct (const char *yymsg, yysymbol_kind_t yykind, YYSTYPE *yyvaluep, YYLTYPE *yylocationp) { - YYUSE (yyvaluep); - YYUSE (yylocationp); + YY_USE (yyvaluep); + YY_USE (yylocationp); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - YYUSE (yykind); + YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } @@ -2840,737 +2877,791 @@ yyreduce: case 2: /* s: "domodule" module */ #line 488 "hexpr.y" { yyParsedModule = (yyvsp[0].module); } -#line 2844 "hexpr.parse.C" +#line 2881 "hexpr.parse.C" break; case 3: /* s: "dodefn" id "=" l0expr */ #line 489 "hexpr.y" { yyParsedVar = *(yyvsp[-2].string); yyParsedExpr = (yyvsp[0].exp); } -#line 2850 "hexpr.parse.C" +#line 2887 "hexpr.parse.C" break; case 4: /* s: "dodefn" l0expr */ #line 490 "hexpr.y" { yyParsedVar = ""; yyParsedExpr = (yyvsp[0].exp); } -#line 2856 "hexpr.parse.C" +#line 2893 "hexpr.parse.C" break; case 5: /* s: "doexpr" l0expr */ #line 491 "hexpr.y" { yyParsedExpr = (yyvsp[0].exp); } -#line 2862 "hexpr.parse.C" +#line 2899 "hexpr.parse.C" break; case 6: /* module: "option" id module */ #line 494 "hexpr.y" { (yyval.module) = (yyvsp[0].module); (yyval.module)->setOption(*(yyvsp[-1].string), m((yylsp[-2]))); } -#line 2868 "hexpr.parse.C" +#line 2905 "hexpr.parse.C" break; case 7: /* module: "module" id "where" defs */ #line 495 "hexpr.y" { (yyval.module) = new Module(*(yyvsp[-2].string), *(yyvsp[0].mdefs)); } -#line 2874 "hexpr.parse.C" +#line 2911 "hexpr.parse.C" break; case 8: /* module: defs */ #line 496 "hexpr.y" { (yyval.module) = new Module(freshName(), *(yyvsp[0].mdefs)); } -#line 2880 "hexpr.parse.C" +#line 2917 "hexpr.parse.C" break; case 9: /* defs: %empty */ #line 498 "hexpr.y" { (yyval.mdefs) = autorelease(new ModuleDefs()); } -#line 2886 "hexpr.parse.C" +#line 2923 "hexpr.parse.C" break; case 10: /* defs: def */ #line 499 "hexpr.y" { (yyval.mdefs) = autorelease(new ModuleDefs()); (yyval.mdefs)->push_back(ModuleDefPtr((yyvsp[0].mdef))); } -#line 2892 "hexpr.parse.C" +#line 2929 "hexpr.parse.C" break; case 11: /* defs: defs def */ #line 500 "hexpr.y" { (yyval.mdefs) = (yyvsp[-1].mdefs); (yyval.mdefs)->push_back(ModuleDefPtr((yyvsp[0].mdef))); } -#line 2898 "hexpr.parse.C" +#line 2935 "hexpr.parse.C" break; case 12: /* def: importdef */ #line 502 "hexpr.y" { (yyval.mdef) = (yyvsp[0].mdef); } -#line 2904 "hexpr.parse.C" +#line 2941 "hexpr.parse.C" break; case 13: /* def: tydef */ #line 503 "hexpr.y" { (yyval.mdef) = (yyvsp[0].mdef); } -#line 2910 "hexpr.parse.C" +#line 2947 "hexpr.parse.C" break; case 14: /* def: vartybind */ #line 504 "hexpr.y" { (yyval.mdef) = (yyvsp[0].mvtydef); } -#line 2916 "hexpr.parse.C" +#line 2953 "hexpr.parse.C" break; case 15: /* def: classdef */ #line 505 "hexpr.y" { (yyval.mdef) = (yyvsp[0].mdef); } -#line 2922 "hexpr.parse.C" +#line 2959 "hexpr.parse.C" break; case 16: /* def: instdef */ #line 506 "hexpr.y" { (yyval.mdef) = (yyvsp[0].mdef); } -#line 2928 "hexpr.parse.C" +#line 2965 "hexpr.parse.C" break; case 17: /* def: pragmadef */ #line 507 "hexpr.y" { (yyval.mdef) = (yyvsp[0].mdef); } -#line 2934 "hexpr.parse.C" +#line 2971 "hexpr.parse.C" break; case 18: /* def: id "=" l0expr */ #line 509 "hexpr.y" { (yyval.mdef) = new MVarDef(list(*(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-2]), (yylsp[0]))); } -#line 2940 "hexpr.parse.C" +#line 2977 "hexpr.parse.C" break; case 19: /* def: id id "=" l0expr */ #line 510 "hexpr.y" { (yyval.mdef) = new MVarDef(list(*(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-3]), (yylsp[0]))); } -#line 2946 "hexpr.parse.C" +#line 2983 "hexpr.parse.C" break; case 20: /* def: id id id "=" l0expr */ #line 511 "hexpr.y" { (yyval.mdef) = new MVarDef(list(*(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-4]), (yylsp[0]))); } -#line 2952 "hexpr.parse.C" +#line 2989 "hexpr.parse.C" break; case 21: /* def: id id id id "=" l0expr */ #line 512 "hexpr.y" { (yyval.mdef) = new MVarDef(list(*(yyvsp[-5].string), *(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-5]), (yylsp[0]))); } -#line 2958 "hexpr.parse.C" +#line 2995 "hexpr.parse.C" break; case 22: /* def: id id id id id "=" l0expr */ #line 513 "hexpr.y" { (yyval.mdef) = new MVarDef(list(*(yyvsp[-6].string), *(yyvsp[-5].string), *(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-6]), (yylsp[0]))); } -#line 2964 "hexpr.parse.C" +#line 3001 "hexpr.parse.C" break; case 23: /* def: id id id id id id "=" l0expr */ #line 514 "hexpr.y" { (yyval.mdef) = new MVarDef(list(*(yyvsp[-7].string), *(yyvsp[-6].string), *(yyvsp[-5].string), *(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-7]), (yylsp[0]))); } -#line 2970 "hexpr.parse.C" +#line 3007 "hexpr.parse.C" break; case 24: /* def: id id id id id id id "=" l0expr */ #line 515 "hexpr.y" { (yyval.mdef) = new MVarDef(list(*(yyvsp[-8].string), *(yyvsp[-7].string), *(yyvsp[-6].string), *(yyvsp[-5].string), *(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-8]), (yylsp[0]))); } -#line 2976 "hexpr.parse.C" +#line 3013 "hexpr.parse.C" break; case 25: /* def: id id id id id id id id "=" l0expr */ #line 516 "hexpr.y" { (yyval.mdef) = new MVarDef(list(*(yyvsp[-9].string), *(yyvsp[-8].string), *(yyvsp[-7].string), *(yyvsp[-6].string), *(yyvsp[-5].string), *(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-9]), (yylsp[0]))); } -#line 2982 "hexpr.parse.C" +#line 3019 "hexpr.parse.C" break; case 26: /* def: id id id id id id id id id "=" l0expr */ #line 517 "hexpr.y" { (yyval.mdef) = new MVarDef(list(*(yyvsp[-10].string), *(yyvsp[-9].string), *(yyvsp[-8].string), *(yyvsp[-7].string), *(yyvsp[-6].string), *(yyvsp[-5].string), *(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-10]), (yylsp[0]))); } -#line 2988 "hexpr.parse.C" +#line 3025 "hexpr.parse.C" break; case 27: /* def: id id id id id id id id id id "=" l0expr */ #line 518 "hexpr.y" { (yyval.mdef) = new MVarDef(list(*(yyvsp[-11].string), *(yyvsp[-10].string), *(yyvsp[-9].string), *(yyvsp[-8].string), *(yyvsp[-7].string), *(yyvsp[-6].string), *(yyvsp[-5].string), *(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-11]), (yylsp[0]))); } -#line 2994 "hexpr.parse.C" +#line 3031 "hexpr.parse.C" break; case 28: /* def: id id id id id id id id id id id "=" l0expr */ #line 519 "hexpr.y" { (yyval.mdef) = new MVarDef(list(*(yyvsp[-12].string), *(yyvsp[-11].string), *(yyvsp[-10].string), *(yyvsp[-9].string), *(yyvsp[-8].string), *(yyvsp[-7].string), *(yyvsp[-6].string), *(yyvsp[-5].string), *(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-12]), (yylsp[0]))); } -#line 3000 "hexpr.parse.C" +#line 3037 "hexpr.parse.C" break; case 29: /* def: id id id id id id id id id id id id "=" l0expr */ #line 520 "hexpr.y" { (yyval.mdef) = new MVarDef(list(*(yyvsp[-13].string), *(yyvsp[-12].string), *(yyvsp[-11].string), *(yyvsp[-10].string), *(yyvsp[-9].string), *(yyvsp[-8].string), *(yyvsp[-7].string), *(yyvsp[-6].string), *(yyvsp[-5].string), *(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-13]), (yylsp[0]))); } -#line 3006 "hexpr.parse.C" +#line 3043 "hexpr.parse.C" + break; + + case 30: /* def: id id id id id id id id id id id id id "=" l0expr */ +#line 521 "hexpr.y" + { (yyval.mdef) = new MVarDef(list(*(yyvsp[-14].string), *(yyvsp[-13].string), *(yyvsp[-12].string), *(yyvsp[-11].string), *(yyvsp[-10].string), *(yyvsp[-9].string), *(yyvsp[-8].string), *(yyvsp[-7].string), *(yyvsp[-6].string), *(yyvsp[-5].string), *(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-14]), (yylsp[0]))); } +#line 3049 "hexpr.parse.C" + break; + + case 31: /* def: id id id id id id id id id id id id id id "=" l0expr */ +#line 522 "hexpr.y" + { (yyval.mdef) = new MVarDef(list(*(yyvsp[-15].string), *(yyvsp[-14].string), *(yyvsp[-13].string), *(yyvsp[-12].string), *(yyvsp[-11].string), *(yyvsp[-10].string), *(yyvsp[-9].string), *(yyvsp[-8].string), *(yyvsp[-7].string), *(yyvsp[-6].string), *(yyvsp[-5].string), *(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-15]), (yylsp[0]))); } +#line 3055 "hexpr.parse.C" break; - case 30: /* def: l5expr */ + case 32: /* def: id id id id id id id id id id id id id id id "=" l0expr */ #line 523 "hexpr.y" - { (yyval.mdef) = new MVarDef(list(freshName()), let(freshName(), ExprPtr((yyvsp[0].exp)), mktunit(m((yylsp[0]))), m((yylsp[0]))), m((yylsp[0]))); } -#line 3012 "hexpr.parse.C" + { (yyval.mdef) = new MVarDef(list(*(yyvsp[-16].string), *(yyvsp[-15].string), *(yyvsp[-14].string), *(yyvsp[-13].string), *(yyvsp[-12].string), *(yyvsp[-11].string), *(yyvsp[-10].string), *(yyvsp[-9].string), *(yyvsp[-8].string), *(yyvsp[-7].string), *(yyvsp[-6].string), *(yyvsp[-5].string), *(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-16]), (yylsp[0]))); } +#line 3061 "hexpr.parse.C" break; - case 31: /* importdef: "import" cppid */ + case 33: /* def: id id id id id id id id id id id id id id id id "=" l0expr */ +#line 524 "hexpr.y" + { (yyval.mdef) = new MVarDef(list(*(yyvsp[-17].string), *(yyvsp[-16].string), *(yyvsp[-15].string), *(yyvsp[-14].string), *(yyvsp[-13].string), *(yyvsp[-12].string), *(yyvsp[-11].string), *(yyvsp[-10].string), *(yyvsp[-9].string), *(yyvsp[-8].string), *(yyvsp[-7].string), *(yyvsp[-6].string), *(yyvsp[-5].string), *(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-17]), (yylsp[0]))); } +#line 3067 "hexpr.parse.C" + break; + + case 34: /* def: id id id id id id id id id id id id id id id id id "=" l0expr */ +#line 525 "hexpr.y" + { (yyval.mdef) = new MVarDef(list(*(yyvsp[-18].string), *(yyvsp[-17].string), *(yyvsp[-16].string), *(yyvsp[-15].string), *(yyvsp[-14].string), *(yyvsp[-13].string), *(yyvsp[-12].string), *(yyvsp[-11].string), *(yyvsp[-10].string), *(yyvsp[-9].string), *(yyvsp[-8].string), *(yyvsp[-7].string), *(yyvsp[-6].string), *(yyvsp[-5].string), *(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-18]), (yylsp[0]))); } +#line 3073 "hexpr.parse.C" + break; + + case 35: /* def: id id id id id id id id id id id id id id id id id id "=" l0expr */ #line 526 "hexpr.y" - { (yyval.mdef) = new MImport(yyModulePath, *(yyvsp[0].string), m((yylsp[-1]), (yylsp[0]))); } -#line 3018 "hexpr.parse.C" + { (yyval.mdef) = new MVarDef(list(*(yyvsp[-19].string), *(yyvsp[-18].string), *(yyvsp[-17].string), *(yyvsp[-16].string), *(yyvsp[-15].string), *(yyvsp[-14].string), *(yyvsp[-13].string), *(yyvsp[-12].string), *(yyvsp[-11].string), *(yyvsp[-10].string), *(yyvsp[-9].string), *(yyvsp[-8].string), *(yyvsp[-7].string), *(yyvsp[-6].string), *(yyvsp[-5].string), *(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-19]), (yylsp[0]))); } +#line 3079 "hexpr.parse.C" + break; + + case 36: /* def: id id id id id id id id id id id id id id id id id id id "=" l0expr */ +#line 527 "hexpr.y" + { (yyval.mdef) = new MVarDef(list(*(yyvsp[-20].string), *(yyvsp[-19].string), *(yyvsp[-18].string), *(yyvsp[-17].string), *(yyvsp[-16].string), *(yyvsp[-15].string), *(yyvsp[-14].string), *(yyvsp[-13].string), *(yyvsp[-12].string), *(yyvsp[-11].string), *(yyvsp[-10].string), *(yyvsp[-9].string), *(yyvsp[-8].string), *(yyvsp[-7].string), *(yyvsp[-6].string), *(yyvsp[-5].string), *(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-20]), (yylsp[0]))); } +#line 3085 "hexpr.parse.C" + break; + + case 37: /* def: id id id id id id id id id id id id id id id id id id id id "=" l0expr */ +#line 528 "hexpr.y" + { (yyval.mdef) = new MVarDef(list(*(yyvsp[-21].string), *(yyvsp[-20].string), *(yyvsp[-19].string), *(yyvsp[-18].string), *(yyvsp[-17].string), *(yyvsp[-16].string), *(yyvsp[-15].string), *(yyvsp[-14].string), *(yyvsp[-13].string), *(yyvsp[-12].string), *(yyvsp[-11].string), *(yyvsp[-10].string), *(yyvsp[-9].string), *(yyvsp[-8].string), *(yyvsp[-7].string), *(yyvsp[-6].string), *(yyvsp[-5].string), *(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-21]), (yylsp[0]))); } +#line 3091 "hexpr.parse.C" break; - case 32: /* pragmadef: "{-#" pragmaty "#-}" */ + case 38: /* def: id id id id id id id id id id id id id id id id id id id id id "=" l0expr */ #line 529 "hexpr.y" + { (yyval.mdef) = new MVarDef(list(*(yyvsp[-22].string), *(yyvsp[-21].string), *(yyvsp[-20].string), *(yyvsp[-19].string), *(yyvsp[-18].string), *(yyvsp[-17].string), *(yyvsp[-16].string), *(yyvsp[-15].string), *(yyvsp[-14].string), *(yyvsp[-13].string), *(yyvsp[-12].string), *(yyvsp[-11].string), *(yyvsp[-10].string), *(yyvsp[-9].string), *(yyvsp[-8].string), *(yyvsp[-7].string), *(yyvsp[-6].string), *(yyvsp[-5].string), *(yyvsp[-4].string), *(yyvsp[-3].string), *(yyvsp[-2].string)), ExprPtr((yyvsp[0].exp)), m((yylsp[-22]), (yylsp[0]))); } +#line 3097 "hexpr.parse.C" + break; + + case 39: /* def: l5expr */ +#line 532 "hexpr.y" + { (yyval.mdef) = new MVarDef(list(freshName()), let(freshName(), ExprPtr((yyvsp[0].exp)), mktunit(m((yylsp[0]))), m((yylsp[0]))), m((yylsp[0]))); } +#line 3103 "hexpr.parse.C" + break; + + case 40: /* importdef: "import" cppid */ +#line 535 "hexpr.y" + { (yyval.mdef) = new MImport(yyModulePath, *(yyvsp[0].string), m((yylsp[-1]), (yylsp[0]))); } +#line 3109 "hexpr.parse.C" + break; + + case 41: /* pragmadef: "{-#" pragmaty "#-}" */ +#line 538 "hexpr.y" { (yyval.mdef) = (yyvsp[-1].mdef); } -#line 3024 "hexpr.parse.C" +#line 3115 "hexpr.parse.C" break; - case 33: /* pragmaty: "UNSAFE" id */ -#line 530 "hexpr.y" + case 42: /* pragmaty: "UNSAFE" id */ +#line 539 "hexpr.y" { (yyval.mdef) = new MUnsafePragmaDef(*(yyvsp[0].string), m((yylsp[-1]), (yylsp[0]))); } -#line 3030 "hexpr.parse.C" +#line 3121 "hexpr.parse.C" break; - case 34: /* pragmaty: "SAFE" id */ -#line 531 "hexpr.y" + case 43: /* pragmaty: "SAFE" id */ +#line 540 "hexpr.y" { (yyval.mdef) = new MSafePragmaDef(*(yyvsp[0].string), m((yylsp[-1]), (yylsp[0]))); } -#line 3036 "hexpr.parse.C" +#line 3127 "hexpr.parse.C" break; - case 35: /* tydef: "type" nameseq "=" qtype */ -#line 534 "hexpr.y" + case 44: /* tydef: "type" nameseq "=" qtype */ +#line 543 "hexpr.y" { (yyval.mdef) = new MTypeDef(MTypeDef::Transparent, hobbes::select(*(yyvsp[-2].strings), 0), hobbes::select(*(yyvsp[-2].strings), 1, (int)(yyvsp[-2].strings)->size()), QualTypePtr((yyvsp[0].qualtype)), m((yylsp[-3]), (yylsp[0]))); } -#line 3042 "hexpr.parse.C" +#line 3133 "hexpr.parse.C" break; - case 36: /* tydef: "data" nameseq "=" qtype */ -#line 535 "hexpr.y" + case 45: /* tydef: "data" nameseq "=" qtype */ +#line 544 "hexpr.y" { (yyval.mdef) = new MTypeDef(MTypeDef::Opaque, hobbes::select(*(yyvsp[-2].strings), 0), hobbes::select(*(yyvsp[-2].strings), 1, (int)(yyvsp[-2].strings)->size()), QualTypePtr((yyvsp[0].qualtype)), m((yylsp[-3]), (yylsp[0]))); } -#line 3048 "hexpr.parse.C" +#line 3139 "hexpr.parse.C" break; - case 37: /* vartybind: name "::" qtype */ -#line 538 "hexpr.y" + case 46: /* vartybind: name "::" qtype */ +#line 547 "hexpr.y" { (yyval.mvtydef) = new MVarTypeDef(*(yyvsp[-2].string), QualTypePtr((yyvsp[0].qualtype)), m((yylsp[-2]), (yylsp[0]))); } -#line 3054 "hexpr.parse.C" +#line 3145 "hexpr.parse.C" break; - case 38: /* vardef: names "=" l0expr */ -#line 540 "hexpr.y" + case 47: /* vardef: names "=" l0expr */ +#line 549 "hexpr.y" { (yyval.mvdef) = new MVarDef(*(yyvsp[-2].strings), ExprPtr((yyvsp[0].exp)), m((yylsp[-2]), (yylsp[0]))); } -#line 3060 "hexpr.parse.C" +#line 3151 "hexpr.parse.C" break; - case 39: /* classdef: "class" cst "=>" id names */ -#line 543 "hexpr.y" + case 48: /* classdef: "class" cst "=>" id names */ +#line 552 "hexpr.y" { (yyval.mdef) = new ClassDef(*(yyvsp[-3].tconstraints), *(yyvsp[-1].string), *(yyvsp[0].strings), CFunDepDefs(), MVarTypeDefs(), m((yylsp[-4]), (yylsp[0]))); wantIndent(false); } -#line 3066 "hexpr.parse.C" +#line 3157 "hexpr.parse.C" break; - case 40: /* classdef: "class" cst "=>" id names "|" fundeps */ -#line 544 "hexpr.y" + case 49: /* classdef: "class" cst "=>" id names "|" fundeps */ +#line 553 "hexpr.y" { (yyval.mdef) = new ClassDef(*(yyvsp[-5].tconstraints), *(yyvsp[-3].string), *(yyvsp[-2].strings), *(yyvsp[0].fundeps), MVarTypeDefs(), m((yylsp[-6]), (yylsp[0]))); wantIndent(false); } -#line 3072 "hexpr.parse.C" +#line 3163 "hexpr.parse.C" break; - case 41: /* classdef: "class" cst "=>" id names "where" cmembers */ -#line 545 "hexpr.y" + case 50: /* classdef: "class" cst "=>" id names "where" cmembers */ +#line 554 "hexpr.y" { (yyval.mdef) = new ClassDef(*(yyvsp[-5].tconstraints), *(yyvsp[-3].string), *(yyvsp[-2].strings), CFunDepDefs(), *(yyvsp[0].mvtydefs), m((yylsp[-6]), (yylsp[0]))); wantIndent(false); } -#line 3078 "hexpr.parse.C" +#line 3169 "hexpr.parse.C" break; - case 42: /* classdef: "class" cst "=>" id names "|" fundeps "where" cmembers */ -#line 546 "hexpr.y" + case 51: /* classdef: "class" cst "=>" id names "|" fundeps "where" cmembers */ +#line 555 "hexpr.y" { (yyval.mdef) = new ClassDef(*(yyvsp[-7].tconstraints), *(yyvsp[-5].string), *(yyvsp[-4].strings), *(yyvsp[-2].fundeps), *(yyvsp[0].mvtydefs), m((yylsp[-8]), (yylsp[0]))); wantIndent(false); } -#line 3084 "hexpr.parse.C" +#line 3175 "hexpr.parse.C" break; - case 43: /* classdef: "class" id names */ -#line 547 "hexpr.y" + case 52: /* classdef: "class" id names */ +#line 556 "hexpr.y" { (yyval.mdef) = new ClassDef(Constraints(), *(yyvsp[-1].string), *(yyvsp[0].strings), CFunDepDefs(), MVarTypeDefs(), m((yylsp[-2]), (yylsp[0]))); wantIndent(false); } -#line 3090 "hexpr.parse.C" +#line 3181 "hexpr.parse.C" break; - case 44: /* classdef: "class" id names "|" fundeps */ -#line 548 "hexpr.y" + case 53: /* classdef: "class" id names "|" fundeps */ +#line 557 "hexpr.y" { (yyval.mdef) = new ClassDef(Constraints(), *(yyvsp[-3].string), *(yyvsp[-2].strings), *(yyvsp[0].fundeps), MVarTypeDefs(), m((yylsp[-4]), (yylsp[0]))); wantIndent(false); } -#line 3096 "hexpr.parse.C" +#line 3187 "hexpr.parse.C" break; - case 45: /* classdef: "class" id names "where" cmembers */ -#line 549 "hexpr.y" + case 54: /* classdef: "class" id names "where" cmembers */ +#line 558 "hexpr.y" { (yyval.mdef) = new ClassDef(Constraints(), *(yyvsp[-3].string), *(yyvsp[-2].strings), CFunDepDefs(), *(yyvsp[0].mvtydefs), m((yylsp[-4]), (yylsp[0]))); wantIndent(false); } -#line 3102 "hexpr.parse.C" +#line 3193 "hexpr.parse.C" break; - case 46: /* classdef: "class" id names "|" fundeps "where" cmembers */ -#line 550 "hexpr.y" + case 55: /* classdef: "class" id names "|" fundeps "where" cmembers */ +#line 559 "hexpr.y" { (yyval.mdef) = new ClassDef(Constraints(), *(yyvsp[-5].string), *(yyvsp[-4].strings), *(yyvsp[-2].fundeps), *(yyvsp[0].mvtydefs), m((yylsp[-6]), (yylsp[0]))); wantIndent(false); } -#line 3108 "hexpr.parse.C" +#line 3199 "hexpr.parse.C" break; - case 47: /* fundeps: fundep */ -#line 552 "hexpr.y" + case 56: /* fundeps: fundep */ +#line 561 "hexpr.y" { (yyval.fundeps) = autorelease(new CFunDepDefs()); (yyval.fundeps)->push_back(*(yyvsp[0].fundep)); } -#line 3114 "hexpr.parse.C" +#line 3205 "hexpr.parse.C" break; - case 48: /* fundeps: fundeps "," fundep */ -#line 553 "hexpr.y" + case 57: /* fundeps: fundeps "," fundep */ +#line 562 "hexpr.y" { (yyval.fundeps) = (yyvsp[-2].fundeps); (yyval.fundeps)->push_back(*(yyvsp[0].fundep)); } -#line 3120 "hexpr.parse.C" +#line 3211 "hexpr.parse.C" break; - case 49: /* fundep: idseq "->" idseq */ -#line 555 "hexpr.y" + case 58: /* fundep: idseq "->" idseq */ +#line 564 "hexpr.y" { (yyval.fundep) = autorelease(new CFunDepDef(*(yyvsp[-2].strings), *(yyvsp[0].strings))); } -#line 3126 "hexpr.parse.C" +#line 3217 "hexpr.parse.C" break; - case 50: /* cmembers: cmember */ -#line 557 "hexpr.y" + case 59: /* cmembers: cmember */ +#line 566 "hexpr.y" { (yyval.mvtydefs) = autorelease(new MVarTypeDefs()); (yyval.mvtydefs)->push_back(MVarTypeDefPtr((yyvsp[0].mvtydef))); } -#line 3132 "hexpr.parse.C" +#line 3223 "hexpr.parse.C" break; - case 51: /* cmembers: cmembers cmember */ -#line 558 "hexpr.y" + case 60: /* cmembers: cmembers cmember */ +#line 567 "hexpr.y" { (yyval.mvtydefs) = (yyvsp[-1].mvtydefs); (yyval.mvtydefs)->push_back(MVarTypeDefPtr((yyvsp[0].mvtydef))); } -#line 3138 "hexpr.parse.C" +#line 3229 "hexpr.parse.C" break; - case 52: /* cmember: "indent" vartybind */ -#line 560 "hexpr.y" + case 61: /* cmember: "indent" vartybind */ +#line 569 "hexpr.y" { (yyval.mvtydef) = (yyvsp[0].mvtydef); } -#line 3144 "hexpr.parse.C" +#line 3235 "hexpr.parse.C" break; - case 53: /* instdef: "instance" id types */ -#line 563 "hexpr.y" + case 62: /* instdef: "instance" id types */ +#line 572 "hexpr.y" { (yyval.mdef) = new InstanceDef(Constraints(), *(yyvsp[-1].string), *(yyvsp[0].mtypes), MVarDefs(), m((yylsp[-2]), (yylsp[0]))); wantIndent(false); } -#line 3150 "hexpr.parse.C" +#line 3241 "hexpr.parse.C" break; - case 54: /* instdef: "instance" cst "=>" id types */ -#line 564 "hexpr.y" + case 63: /* instdef: "instance" cst "=>" id types */ +#line 573 "hexpr.y" { (yyval.mdef) = new InstanceDef(*(yyvsp[-3].tconstraints), *(yyvsp[-1].string), *(yyvsp[0].mtypes), MVarDefs(), m((yylsp[-4]), (yylsp[0]))); wantIndent(false); } -#line 3156 "hexpr.parse.C" +#line 3247 "hexpr.parse.C" break; - case 55: /* instdef: "instance" id types "where" imembers */ -#line 565 "hexpr.y" + case 64: /* instdef: "instance" id types "where" imembers */ +#line 574 "hexpr.y" { (yyval.mdef) = new InstanceDef(Constraints(), *(yyvsp[-3].string), *(yyvsp[-2].mtypes), *(yyvsp[0].mvdefs), m((yylsp[-4]), (yylsp[0]))); wantIndent(false); } -#line 3162 "hexpr.parse.C" +#line 3253 "hexpr.parse.C" break; - case 56: /* instdef: "instance" cst "=>" id types "where" imembers */ -#line 566 "hexpr.y" + case 65: /* instdef: "instance" cst "=>" id types "where" imembers */ +#line 575 "hexpr.y" { (yyval.mdef) = new InstanceDef(*(yyvsp[-5].tconstraints), *(yyvsp[-3].string), *(yyvsp[-2].mtypes), *(yyvsp[0].mvdefs), m((yylsp[-6]), (yylsp[0]))); wantIndent(false); } -#line 3168 "hexpr.parse.C" +#line 3259 "hexpr.parse.C" break; - case 57: /* imembers: imember */ -#line 568 "hexpr.y" + case 66: /* imembers: imember */ +#line 577 "hexpr.y" { (yyval.mvdefs) = autorelease(new MVarDefs()); (yyval.mvdefs)->push_back(MVarDefPtr((yyvsp[0].mvdef))); } -#line 3174 "hexpr.parse.C" +#line 3265 "hexpr.parse.C" break; - case 58: /* imembers: imembers imember */ -#line 569 "hexpr.y" + case 67: /* imembers: imembers imember */ +#line 578 "hexpr.y" { (yyval.mvdefs) = (yyvsp[-1].mvdefs); (yyval.mvdefs)->push_back(MVarDefPtr((yyvsp[0].mvdef))); } -#line 3180 "hexpr.parse.C" +#line 3271 "hexpr.parse.C" break; - case 59: /* imember: "indent" vardef */ -#line 571 "hexpr.y" + case 68: /* imember: "indent" vardef */ +#line 580 "hexpr.y" { (yyval.mvdef) = (yyvsp[0].mvdef); } -#line 3186 "hexpr.parse.C" +#line 3277 "hexpr.parse.C" break; - case 60: /* names: nameseq */ -#line 574 "hexpr.y" + case 69: /* names: nameseq */ +#line 583 "hexpr.y" { (yyval.strings) = (yyvsp[0].strings); } -#line 3192 "hexpr.parse.C" +#line 3283 "hexpr.parse.C" break; - case 61: /* names: id opname id */ -#line 576 "hexpr.y" + case 70: /* names: id opname id */ +#line 585 "hexpr.y" { (yyval.strings) = autorelease(new str::seq()); (yyval.strings)->push_back(*(yyvsp[-1].string)); (yyval.strings)->push_back(*(yyvsp[-2].string)); (yyval.strings)->push_back(*(yyvsp[0].string)); } -#line 3198 "hexpr.parse.C" +#line 3289 "hexpr.parse.C" break; - case 62: /* nameseq: name */ -#line 578 "hexpr.y" + case 71: /* nameseq: name */ +#line 587 "hexpr.y" { (yyval.strings) = autorelease(new str::seq()); (yyval.strings)->push_back(*(yyvsp[0].string)); } -#line 3204 "hexpr.parse.C" +#line 3295 "hexpr.parse.C" break; - case 63: /* nameseq: nameseq name */ -#line 579 "hexpr.y" + case 72: /* nameseq: nameseq name */ +#line 588 "hexpr.y" { (yyval.strings) = (yyvsp[-1].strings); (yyval.strings)->push_back(*(yyvsp[0].string)); } -#line 3210 "hexpr.parse.C" +#line 3301 "hexpr.parse.C" break; - case 64: /* name: id */ -#line 581 "hexpr.y" + case 73: /* name: id */ +#line 590 "hexpr.y" { (yyval.string) = (yyvsp[0].string); } -#line 3216 "hexpr.parse.C" +#line 3307 "hexpr.parse.C" break; - case 65: /* name: "(" opname ")" */ -#line 583 "hexpr.y" + case 74: /* name: "(" opname ")" */ +#line 592 "hexpr.y" { (yyval.string) = (yyvsp[-1].string); } -#line 3222 "hexpr.parse.C" +#line 3313 "hexpr.parse.C" break; - case 66: /* opname: "and" */ -#line 585 "hexpr.y" + case 75: /* opname: "and" */ +#line 594 "hexpr.y" { (yyval.string) = autorelease(new std::string("and")); } -#line 3228 "hexpr.parse.C" +#line 3319 "hexpr.parse.C" break; - case 67: /* opname: "or" */ -#line 586 "hexpr.y" + case 76: /* opname: "or" */ +#line 595 "hexpr.y" { (yyval.string) = autorelease(new std::string("or")); } -#line 3234 "hexpr.parse.C" +#line 3325 "hexpr.parse.C" break; - case 68: /* opname: "o" */ -#line 587 "hexpr.y" + case 77: /* opname: "o" */ +#line 596 "hexpr.y" { (yyval.string) = autorelease(new std::string("compose")); } -#line 3240 "hexpr.parse.C" +#line 3331 "hexpr.parse.C" break; - case 69: /* opname: "." */ -#line 588 "hexpr.y" + case 78: /* opname: "." */ +#line 597 "hexpr.y" { (yyval.string) = autorelease(new std::string("compose")); } -#line 3246 "hexpr.parse.C" +#line 3337 "hexpr.parse.C" break; - case 70: /* opname: "~" */ -#line 589 "hexpr.y" + case 79: /* opname: "~" */ +#line 598 "hexpr.y" { (yyval.string) = autorelease(new std::string("~")); } -#line 3252 "hexpr.parse.C" +#line 3343 "hexpr.parse.C" break; - case 71: /* opname: "=~" */ -#line 590 "hexpr.y" + case 80: /* opname: "=~" */ +#line 599 "hexpr.y" { (yyval.string) = autorelease(new std::string("=~")); } -#line 3258 "hexpr.parse.C" +#line 3349 "hexpr.parse.C" break; - case 72: /* opname: "===" */ -#line 591 "hexpr.y" + case 81: /* opname: "===" */ +#line 600 "hexpr.y" { (yyval.string) = autorelease(new std::string("===")); } -#line 3264 "hexpr.parse.C" +#line 3355 "hexpr.parse.C" break; - case 73: /* opname: "==" */ -#line 592 "hexpr.y" + case 82: /* opname: "==" */ +#line 601 "hexpr.y" { (yyval.string) = autorelease(new std::string("==")); } -#line 3270 "hexpr.parse.C" +#line 3361 "hexpr.parse.C" break; - case 74: /* opname: "<" */ -#line 593 "hexpr.y" + case 83: /* opname: "<" */ +#line 602 "hexpr.y" { (yyval.string) = autorelease(new std::string("<")); } -#line 3276 "hexpr.parse.C" +#line 3367 "hexpr.parse.C" break; - case 75: /* opname: "<=" */ -#line 594 "hexpr.y" + case 84: /* opname: "<=" */ +#line 603 "hexpr.y" { (yyval.string) = autorelease(new std::string("<=")); } -#line 3282 "hexpr.parse.C" +#line 3373 "hexpr.parse.C" break; - case 76: /* opname: ">" */ -#line 595 "hexpr.y" + case 85: /* opname: ">" */ +#line 604 "hexpr.y" { (yyval.string) = autorelease(new std::string(">")); } -#line 3288 "hexpr.parse.C" +#line 3379 "hexpr.parse.C" break; - case 77: /* opname: ">=" */ -#line 596 "hexpr.y" + case 86: /* opname: ">=" */ +#line 605 "hexpr.y" { (yyval.string) = autorelease(new std::string(">=")); } -#line 3294 "hexpr.parse.C" +#line 3385 "hexpr.parse.C" break; - case 78: /* opname: "in" */ -#line 597 "hexpr.y" + case 87: /* opname: "in" */ +#line 606 "hexpr.y" { (yyval.string) = autorelease(new std::string("in")); } -#line 3300 "hexpr.parse.C" +#line 3391 "hexpr.parse.C" break; - case 79: /* opname: "++" */ -#line 598 "hexpr.y" + case 88: /* opname: "++" */ +#line 607 "hexpr.y" { (yyval.string) = autorelease(new std::string("append")); } -#line 3306 "hexpr.parse.C" +#line 3397 "hexpr.parse.C" break; - case 80: /* opname: "+" */ -#line 599 "hexpr.y" + case 89: /* opname: "+" */ +#line 608 "hexpr.y" { (yyval.string) = autorelease(new std::string("+")); } -#line 3312 "hexpr.parse.C" +#line 3403 "hexpr.parse.C" break; - case 81: /* opname: "-" */ -#line 600 "hexpr.y" + case 90: /* opname: "-" */ +#line 609 "hexpr.y" { (yyval.string) = autorelease(new std::string("-")); } -#line 3318 "hexpr.parse.C" +#line 3409 "hexpr.parse.C" break; - case 82: /* opname: "*" */ -#line 601 "hexpr.y" + case 91: /* opname: "*" */ +#line 610 "hexpr.y" { (yyval.string) = autorelease(new std::string("*")); } -#line 3324 "hexpr.parse.C" +#line 3415 "hexpr.parse.C" break; - case 83: /* opname: "/" */ -#line 602 "hexpr.y" + case 92: /* opname: "/" */ +#line 611 "hexpr.y" { (yyval.string) = autorelease(new std::string("/")); } -#line 3330 "hexpr.parse.C" +#line 3421 "hexpr.parse.C" break; - case 84: /* opname: "%" */ -#line 603 "hexpr.y" + case 93: /* opname: "%" */ +#line 612 "hexpr.y" { (yyval.string) = autorelease(new std::string("%")); } -#line 3336 "hexpr.parse.C" +#line 3427 "hexpr.parse.C" break; - case 85: /* idseq: id */ -#line 605 "hexpr.y" + case 94: /* idseq: id */ +#line 614 "hexpr.y" { (yyval.strings) = autorelease(new str::seq()); (yyval.strings)->push_back(*(yyvsp[0].string)); } -#line 3342 "hexpr.parse.C" +#line 3433 "hexpr.parse.C" break; - case 86: /* idseq: idseq id */ -#line 606 "hexpr.y" + case 95: /* idseq: idseq id */ +#line 615 "hexpr.y" { (yyval.strings) = (yyvsp[-1].strings); (yyval.strings)->push_back(*(yyvsp[0].string)); } -#line 3348 "hexpr.parse.C" +#line 3439 "hexpr.parse.C" break; - case 87: /* types: l0mtype */ -#line 608 "hexpr.y" + case 96: /* types: l0mtype */ +#line 617 "hexpr.y" { (yyval.mtypes) = autorelease(new MonoTypes()); (yyval.mtypes)->push_back(*(yyvsp[0].mtype)); } -#line 3354 "hexpr.parse.C" +#line 3445 "hexpr.parse.C" break; - case 88: /* types: types l0mtype */ -#line 609 "hexpr.y" + case 97: /* types: types l0mtype */ +#line 618 "hexpr.y" { (yyval.mtypes) = (yyvsp[-1].mtypes); (yyval.mtypes)->push_back(*(yyvsp[0].mtype)); } -#line 3360 "hexpr.parse.C" +#line 3451 "hexpr.parse.C" break; - case 89: /* l0expr: "\\" patterns "." l0expr */ -#line 612 "hexpr.y" + case 98: /* l0expr: "\\" patterns "." l0expr */ +#line 621 "hexpr.y" { (yyval.exp) = makePatternFn(*(yyvsp[-2].patterns), ExprPtr((yyvsp[0].exp)), m((yylsp[-3]), (yylsp[0]))); } -#line 3366 "hexpr.parse.C" +#line 3457 "hexpr.parse.C" break; - case 90: /* l0expr: "fn" patterns "." l0expr */ -#line 613 "hexpr.y" + case 99: /* l0expr: "fn" patterns "." l0expr */ +#line 622 "hexpr.y" { (yyval.exp) = makePatternFn(*(yyvsp[-2].patterns), ExprPtr((yyvsp[0].exp)), m((yylsp[-3]), (yylsp[0]))); } -#line 3372 "hexpr.parse.C" +#line 3463 "hexpr.parse.C" break; - case 91: /* l0expr: lhexpr "<-" lhexpr */ -#line 614 "hexpr.y" + case 100: /* l0expr: lhexpr "<-" lhexpr */ +#line 623 "hexpr.y" { (yyval.exp) = new Assign(ExprPtr((yyvsp[-2].exp)), ExprPtr((yyvsp[0].exp)), m((yylsp[-2]), (yylsp[0]))); } -#line 3378 "hexpr.parse.C" +#line 3469 "hexpr.parse.C" break; - case 92: /* l0expr: lhexpr */ -#line 615 "hexpr.y" + case 101: /* l0expr: lhexpr */ +#line 624 "hexpr.y" { (yyval.exp) = (yyvsp[0].exp); } -#line 3384 "hexpr.parse.C" +#line 3475 "hexpr.parse.C" break; - case 93: /* lhexpr: "!" l1expr */ -#line 617 "hexpr.y" + case 102: /* lhexpr: "!" l1expr */ +#line 626 "hexpr.y" { (yyval.exp) = TAPP1(var("not",m((yylsp[-1]))), (yyvsp[0].exp), m((yylsp[-1]),(yylsp[0]))); } -#line 3390 "hexpr.parse.C" +#line 3481 "hexpr.parse.C" break; - case 94: /* lhexpr: lhexpr "and" lhexpr */ -#line 618 "hexpr.y" + case 103: /* lhexpr: lhexpr "and" lhexpr */ +#line 627 "hexpr.y" { (yyval.exp) = TAPP2(var("and",m((yylsp[-1]))), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-2]),(yylsp[0]))); } -#line 3396 "hexpr.parse.C" +#line 3487 "hexpr.parse.C" break; - case 95: /* lhexpr: lhexpr "or" lhexpr */ -#line 619 "hexpr.y" + case 104: /* lhexpr: lhexpr "or" lhexpr */ +#line 628 "hexpr.y" { (yyval.exp) = TAPP2(var("or",m((yylsp[-1]))), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-2]),(yylsp[0]))); } -#line 3402 "hexpr.parse.C" +#line 3493 "hexpr.parse.C" break; - case 96: /* lhexpr: lhexpr "o" lhexpr */ -#line 620 "hexpr.y" + case 105: /* lhexpr: lhexpr "o" lhexpr */ +#line 629 "hexpr.y" { (yyval.exp) = TAPP2(var("compose",m((yylsp[-1]))), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-2]),(yylsp[0]))); } -#line 3408 "hexpr.parse.C" +#line 3499 "hexpr.parse.C" break; - case 97: /* lhexpr: l1expr "in" l1expr */ -#line 621 "hexpr.y" + case 106: /* lhexpr: l1expr "in" l1expr */ +#line 630 "hexpr.y" { (yyval.exp) = TAPP2(var("in",m((yylsp[-1]))), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-2]),(yylsp[0]))); } -#line 3414 "hexpr.parse.C" +#line 3505 "hexpr.parse.C" break; - case 98: /* lhexpr: l1expr */ -#line 622 "hexpr.y" + case 107: /* lhexpr: l1expr */ +#line 631 "hexpr.y" { (yyval.exp) = (yyvsp[0].exp); } -#line 3420 "hexpr.parse.C" +#line 3511 "hexpr.parse.C" break; - case 99: /* l1expr: "if" l0expr "then" l0expr "else" l0expr */ -#line 624 "hexpr.y" + case 108: /* l1expr: "if" l0expr "then" l0expr "else" l0expr */ +#line 633 "hexpr.y" { (yyval.exp) = TAPP3(var("if",m((yylsp[-5]))), (yyvsp[-4].exp), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-5]), (yylsp[0]))); } -#line 3426 "hexpr.parse.C" +#line 3517 "hexpr.parse.C" break; - case 100: /* l1expr: l2expr */ -#line 625 "hexpr.y" + case 109: /* l1expr: l2expr */ +#line 634 "hexpr.y" { (yyval.exp) = (yyvsp[0].exp); } -#line 3432 "hexpr.parse.C" +#line 3523 "hexpr.parse.C" break; - case 101: /* l2expr: l2expr "~" l2expr */ -#line 627 "hexpr.y" + case 110: /* l2expr: l2expr "~" l2expr */ +#line 636 "hexpr.y" { (yyval.exp) = TAPP2(var("~",m((yylsp[-1]))), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-2]),(yylsp[0]))); } -#line 3438 "hexpr.parse.C" +#line 3529 "hexpr.parse.C" break; - case 102: /* l2expr: l2expr "===" l2expr */ -#line 628 "hexpr.y" + case 111: /* l2expr: l2expr "===" l2expr */ +#line 637 "hexpr.y" { (yyval.exp) = TAPP2(var("===",m((yylsp[-1]))), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-2]),(yylsp[0]))); } -#line 3444 "hexpr.parse.C" +#line 3535 "hexpr.parse.C" break; - case 103: /* l2expr: l2expr "==" l2expr */ -#line 629 "hexpr.y" + case 112: /* l2expr: l2expr "==" l2expr */ +#line 638 "hexpr.y" { (yyval.exp) = TAPP2(var("==",m((yylsp[-1]))), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-2]),(yylsp[0]))); } -#line 3450 "hexpr.parse.C" +#line 3541 "hexpr.parse.C" break; - case 104: /* l2expr: l2expr "!=" l2expr */ -#line 630 "hexpr.y" + case 113: /* l2expr: l2expr "!=" l2expr */ +#line 639 "hexpr.y" { (yyval.exp) = TAPP1(var("not",m((yylsp[-1]))), TAPP2(var("==",m((yylsp[-1]))), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-2]),(yylsp[0]))), m((yylsp[-2]),(yylsp[0]))); } -#line 3456 "hexpr.parse.C" +#line 3547 "hexpr.parse.C" break; - case 105: /* l2expr: l2expr "<" l2expr */ -#line 631 "hexpr.y" + case 114: /* l2expr: l2expr "<" l2expr */ +#line 640 "hexpr.y" { (yyval.exp) = TAPP2(var("<",m((yylsp[-1]))), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-2]),(yylsp[0]))); } -#line 3462 "hexpr.parse.C" +#line 3553 "hexpr.parse.C" break; - case 106: /* l2expr: l2expr "<=" l2expr */ -#line 632 "hexpr.y" + case 115: /* l2expr: l2expr "<=" l2expr */ +#line 641 "hexpr.y" { (yyval.exp) = TAPP2(var("<=",m((yylsp[-1]))), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-2]),(yylsp[0]))); } -#line 3468 "hexpr.parse.C" +#line 3559 "hexpr.parse.C" break; - case 107: /* l2expr: l2expr ">" l2expr */ -#line 633 "hexpr.y" + case 116: /* l2expr: l2expr ">" l2expr */ +#line 642 "hexpr.y" { (yyval.exp) = TAPP2(var(">",m((yylsp[-1]))), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-2]),(yylsp[0]))); } -#line 3474 "hexpr.parse.C" +#line 3565 "hexpr.parse.C" break; - case 108: /* l2expr: l2expr ">=" l2expr */ -#line 634 "hexpr.y" + case 117: /* l2expr: l2expr ">=" l2expr */ +#line 643 "hexpr.y" { (yyval.exp) = TAPP2(var(">=",m((yylsp[-1]))), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-2]),(yylsp[0]))); } -#line 3480 "hexpr.parse.C" +#line 3571 "hexpr.parse.C" break; - case 109: /* l2expr: l3expr */ -#line 635 "hexpr.y" + case 118: /* l2expr: l3expr */ +#line 644 "hexpr.y" { (yyval.exp) = (yyvsp[0].exp); } -#line 3486 "hexpr.parse.C" +#line 3577 "hexpr.parse.C" break; - case 110: /* l3expr: l3expr "+" l3expr */ -#line 637 "hexpr.y" + case 119: /* l3expr: l3expr "+" l3expr */ +#line 646 "hexpr.y" { (yyval.exp) = TAPP2(var("+",m((yylsp[-1]))), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-2]),(yylsp[0]))); } -#line 3492 "hexpr.parse.C" +#line 3583 "hexpr.parse.C" break; - case 111: /* l3expr: l3expr "-" l3expr */ -#line 638 "hexpr.y" + case 120: /* l3expr: l3expr "-" l3expr */ +#line 647 "hexpr.y" { (yyval.exp) = TAPP2(var("-",m((yylsp[-1]))), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-2]),(yylsp[0]))); } -#line 3498 "hexpr.parse.C" +#line 3589 "hexpr.parse.C" break; - case 112: /* l3expr: l3expr "++" l3expr */ -#line 639 "hexpr.y" + case 121: /* l3expr: l3expr "++" l3expr */ +#line 648 "hexpr.y" { (yyval.exp) = TAPP2(var("append",m((yylsp[-1]))), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-2]),(yylsp[0]))); } -#line 3504 "hexpr.parse.C" +#line 3595 "hexpr.parse.C" break; - case 113: /* l3expr: "-" l3expr */ -#line 640 "hexpr.y" + case 122: /* l3expr: "-" l3expr */ +#line 649 "hexpr.y" { (yyval.exp) = TAPP1(var("neg",m((yylsp[-1]))), ExprPtr((yyvsp[0].exp)), m((yylsp[-1]),(yylsp[0]))); } -#line 3510 "hexpr.parse.C" +#line 3601 "hexpr.parse.C" break; - case 114: /* l3expr: l4expr */ -#line 641 "hexpr.y" + case 123: /* l3expr: l4expr */ +#line 650 "hexpr.y" { (yyval.exp) = (yyvsp[0].exp); } -#line 3516 "hexpr.parse.C" +#line 3607 "hexpr.parse.C" break; - case 115: /* l4expr: l4expr "*" l4expr */ -#line 643 "hexpr.y" + case 124: /* l4expr: l4expr "*" l4expr */ +#line 652 "hexpr.y" { (yyval.exp) = TAPP2(var("*", m((yylsp[-1]))), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-2]), (yylsp[0]))); } -#line 3522 "hexpr.parse.C" +#line 3613 "hexpr.parse.C" break; - case 116: /* l4expr: l4expr "/" l4expr */ -#line 644 "hexpr.y" + case 125: /* l4expr: l4expr "/" l4expr */ +#line 653 "hexpr.y" { (yyval.exp) = TAPP2(var("/", m((yylsp[-1]))), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-2]), (yylsp[0]))); } -#line 3528 "hexpr.parse.C" +#line 3619 "hexpr.parse.C" break; - case 117: /* l4expr: l4expr "%" l4expr */ -#line 645 "hexpr.y" + case 126: /* l4expr: l4expr "%" l4expr */ +#line 654 "hexpr.y" { (yyval.exp) = TAPP2(var("%", m((yylsp[-1]))), (yyvsp[-2].exp), (yyvsp[0].exp), m((yylsp[-2]), (yylsp[0]))); } -#line 3534 "hexpr.parse.C" +#line 3625 "hexpr.parse.C" break; - case 118: /* l4expr: l5expr */ -#line 646 "hexpr.y" + case 127: /* l4expr: l5expr */ +#line 655 "hexpr.y" { (yyval.exp) = (yyvsp[0].exp); } -#line 3540 "hexpr.parse.C" +#line 3631 "hexpr.parse.C" break; - case 119: /* l5expr: l6expr */ -#line 648 "hexpr.y" + case 128: /* l5expr: l6expr */ +#line 657 "hexpr.y" { (yyval.exp) = (yyvsp[0].exp); } -#line 3546 "hexpr.parse.C" +#line 3637 "hexpr.parse.C" break; - case 120: /* l5expr: "let" letbindings "in" l0expr */ -#line 651 "hexpr.y" + case 129: /* l5expr: "let" letbindings "in" l0expr */ +#line 660 "hexpr.y" { (yyval.exp) = compileNestedLetMatch(*(yyvsp[-2].letbindings), ExprPtr((yyvsp[0].exp)), m((yylsp[-3]),(yylsp[0])))->clone(); } -#line 3552 "hexpr.parse.C" +#line 3643 "hexpr.parse.C" break; - case 121: /* l5expr: "let" letbindings ";" "in" l0expr */ -#line 652 "hexpr.y" + case 130: /* l5expr: "let" letbindings ";" "in" l0expr */ +#line 661 "hexpr.y" { (yyval.exp) = compileNestedLetMatch(*(yyvsp[-3].letbindings), ExprPtr((yyvsp[0].exp)), m((yylsp[-4]),(yylsp[0])))->clone(); } -#line 3558 "hexpr.parse.C" +#line 3649 "hexpr.parse.C" break; - case 122: /* l5expr: "match" l6exprs "with" patternexps */ -#line 655 "hexpr.y" + case 131: /* l5expr: "match" l6exprs "with" patternexps */ +#line 664 "hexpr.y" { (yyval.exp) = compileMatch(yyParseCC, *(yyvsp[-2].exps), normPatternRules(*(yyvsp[0].patternexps), m((yylsp[-3]),(yylsp[0]))), m((yylsp[-3]),(yylsp[0])))->clone(); } -#line 3564 "hexpr.parse.C" +#line 3655 "hexpr.parse.C" break; - case 123: /* l5expr: l6expr "matches" pattern */ -#line 658 "hexpr.y" + case 132: /* l5expr: l6expr "matches" pattern */ +#line 667 "hexpr.y" { (yyval.exp) = compileMatchTest(yyParseCC, ExprPtr((yyvsp[-2].exp)), PatternPtr((yyvsp[0].pattern)), m((yylsp[-2]),(yylsp[0])))->clone(); } -#line 3570 "hexpr.parse.C" +#line 3661 "hexpr.parse.C" break; - case 124: /* l5expr: "parse" "{" prules "}" */ -#line 661 "hexpr.y" + case 133: /* l5expr: "parse" "{" prules "}" */ +#line 670 "hexpr.y" { try { (yyval.exp) = makeParser(yyParseCC, *(yyvsp[-1].prules), m((yylsp[-3]),(yylsp[0])))->clone(); @@ -3581,1407 +3672,1407 @@ yyreduce: throw annotated_error(m((yylsp[-3]),(yylsp[0])), ss.str()); } } -#line 3585 "hexpr.parse.C" +#line 3676 "hexpr.parse.C" break; - case 125: /* l5expr: "do" "{" dobindings "}" */ -#line 673 "hexpr.y" + case 134: /* l5expr: "do" "{" dobindings "}" */ +#line 682 "hexpr.y" { (yyval.exp) = compileNestedLetMatch(*(yyvsp[-1].letbindings), ExprPtr(new Unit(m((yylsp[-3]),(yylsp[0])))), m((yylsp[-3]),(yylsp[0]))); } -#line 3591 "hexpr.parse.C" +#line 3682 "hexpr.parse.C" break; - case 126: /* l5expr: "do" "{" dobindings "return" l0expr "}" */ -#line 674 "hexpr.y" + case 135: /* l5expr: "do" "{" dobindings "return" l0expr "}" */ +#line 683 "hexpr.y" { (yyval.exp) = compileNestedLetMatch(*(yyvsp[-3].letbindings), ExprPtr((yyvsp[-1].exp)), m((yylsp[-5]),(yylsp[0]))); } -#line 3597 "hexpr.parse.C" +#line 3688 "hexpr.parse.C" break; - case 127: /* l5expr: l6expr "::" qtype */ -#line 677 "hexpr.y" + case 136: /* l5expr: l6expr "::" qtype */ +#line 686 "hexpr.y" { (yyval.exp) = new Assump(ExprPtr((yyvsp[-2].exp)), QualTypePtr((yyvsp[0].qualtype)), m((yylsp[-2]),(yylsp[0]))); } -#line 3603 "hexpr.parse.C" +#line 3694 "hexpr.parse.C" break; - case 128: /* letbindings: letbindings ";" letbinding */ -#line 679 "hexpr.y" + case 137: /* letbindings: letbindings ";" letbinding */ +#line 688 "hexpr.y" { (yyvsp[-2].letbindings)->push_back(*(yyvsp[0].letbinding)); (yyval.letbindings) = (yyvsp[-2].letbindings); } -#line 3609 "hexpr.parse.C" +#line 3700 "hexpr.parse.C" break; - case 129: /* letbindings: letbinding */ -#line 680 "hexpr.y" + case 138: /* letbindings: letbinding */ +#line 689 "hexpr.y" { (yyval.letbindings) = autorelease(new LetBindings()); (yyval.letbindings)->push_back(*(yyvsp[0].letbinding)); } -#line 3615 "hexpr.parse.C" +#line 3706 "hexpr.parse.C" break; - case 130: /* letbinding: irrefutablep "=" l1expr */ -#line 682 "hexpr.y" + case 139: /* letbinding: irrefutablep "=" l1expr */ +#line 691 "hexpr.y" { (yyval.letbinding) = autorelease(new LetBinding(PatternPtr((yyvsp[-2].pattern)), ExprPtr((yyvsp[0].exp)))); } -#line 3621 "hexpr.parse.C" +#line 3712 "hexpr.parse.C" break; - case 131: /* dobindings: dobindings dobinding */ -#line 684 "hexpr.y" + case 140: /* dobindings: dobindings dobinding */ +#line 693 "hexpr.y" { (yyval.letbindings) = (yyvsp[-1].letbindings); (yyval.letbindings)->push_back(*(yyvsp[0].letbinding)); } -#line 3627 "hexpr.parse.C" +#line 3718 "hexpr.parse.C" break; - case 132: /* dobindings: dobinding */ -#line 685 "hexpr.y" + case 141: /* dobindings: dobinding */ +#line 694 "hexpr.y" { (yyval.letbindings) = autorelease(new LetBindings()); (yyval.letbindings)->push_back(*(yyvsp[0].letbinding)); } -#line 3633 "hexpr.parse.C" +#line 3724 "hexpr.parse.C" break; - case 133: /* dobinding: irrefutablep "=" l0expr ";" */ -#line 687 "hexpr.y" + case 142: /* dobinding: irrefutablep "=" l0expr ";" */ +#line 696 "hexpr.y" { (yyval.letbinding) = autorelease(new LetBinding(PatternPtr((yyvsp[-3].pattern)), ExprPtr((yyvsp[-1].exp)))); } -#line 3639 "hexpr.parse.C" +#line 3730 "hexpr.parse.C" break; - case 134: /* dobinding: l0expr ";" */ -#line 688 "hexpr.y" + case 143: /* dobinding: l0expr ";" */ +#line 697 "hexpr.y" { (yyval.letbinding) = autorelease(new LetBinding(PatternPtr(new MatchAny("_",m((yylsp[-1])))), ExprPtr((yyvsp[-1].exp)))); } -#line 3645 "hexpr.parse.C" +#line 3736 "hexpr.parse.C" break; - case 135: /* cselconds: cselconds "," lhexpr */ -#line 690 "hexpr.y" + case 144: /* cselconds: cselconds "," lhexpr */ +#line 699 "hexpr.y" { (yyval.exps) = (yyvsp[-2].exps); (yyval.exps)->push_back(ExprPtr((yyvsp[0].exp))); } -#line 3651 "hexpr.parse.C" +#line 3742 "hexpr.parse.C" break; - case 136: /* cselconds: lhexpr */ -#line 691 "hexpr.y" + case 145: /* cselconds: lhexpr */ +#line 700 "hexpr.y" { (yyval.exps) = autorelease(new Exprs()); (yyval.exps)->push_back(ExprPtr((yyvsp[0].exp))); } -#line 3657 "hexpr.parse.C" +#line 3748 "hexpr.parse.C" break; - case 137: /* cselection: pattern "<-" l0expr "," cselconds */ -#line 693 "hexpr.y" + case 146: /* cselection: pattern "<-" l0expr "," cselconds */ +#line 702 "hexpr.y" { (yyval.cselection) = new CSelection(); (yyval.cselection)->pat = PatternPtr((yyvsp[-4].pattern)); (yyval.cselection)->seq = ExprPtr((yyvsp[-2].exp)); (yyval.cselection)->conds = *(yyvsp[0].exps); } -#line 3663 "hexpr.parse.C" +#line 3754 "hexpr.parse.C" break; - case 138: /* cselection: pattern "<-" l0expr */ -#line 694 "hexpr.y" + case 147: /* cselection: pattern "<-" l0expr */ +#line 703 "hexpr.y" { (yyval.cselection) = new CSelection(); (yyval.cselection)->pat = PatternPtr((yyvsp[-2].pattern)); (yyval.cselection)->seq = ExprPtr((yyvsp[0].exp)); } -#line 3669 "hexpr.parse.C" +#line 3760 "hexpr.parse.C" break; - case 139: /* cselections: cselections "|" cselection */ -#line 696 "hexpr.y" + case 148: /* cselections: cselections "|" cselection */ +#line 705 "hexpr.y" { (yyval.cselections) = (yyvsp[-2].cselections); (yyval.cselections)->push_back(CSelectionPtr((yyvsp[0].cselection))); } -#line 3675 "hexpr.parse.C" +#line 3766 "hexpr.parse.C" break; - case 140: /* cselections: cselection */ -#line 697 "hexpr.y" + case 149: /* cselections: cselection */ +#line 706 "hexpr.y" { (yyval.cselections) = autorelease(new CSelections()); (yyval.cselections)->push_back(CSelectionPtr((yyvsp[0].cselection))); } -#line 3681 "hexpr.parse.C" +#line 3772 "hexpr.parse.C" break; - case 141: /* l6expr: l6expr "(" cargs ")" */ -#line 700 "hexpr.y" + case 150: /* l6expr: l6expr "(" cargs ")" */ +#line 709 "hexpr.y" { (yyval.exp) = new App(ExprPtr((yyvsp[-3].exp)), *(yyvsp[-1].exps), m((yylsp[-3]), (yylsp[0]))); } -#line 3687 "hexpr.parse.C" +#line 3778 "hexpr.parse.C" break; - case 142: /* l6expr: id */ -#line 701 "hexpr.y" + case 151: /* l6expr: id */ +#line 710 "hexpr.y" { (yyval.exp) = varCtorFn(*(yyvsp[0].string), m((yylsp[0]))); } -#line 3693 "hexpr.parse.C" +#line 3784 "hexpr.parse.C" break; - case 143: /* l6expr: "[" l0expr ".." l0expr "]" */ -#line 704 "hexpr.y" + case 152: /* l6expr: "[" l0expr ".." l0expr "]" */ +#line 713 "hexpr.y" { (yyval.exp) = new App(var("range", m((yylsp[-2]))), list(ExprPtr((yyvsp[-3].exp)), ExprPtr((yyvsp[-1].exp))), m((yylsp[-4]), (yylsp[0]))); } -#line 3699 "hexpr.parse.C" +#line 3790 "hexpr.parse.C" break; - case 144: /* l6expr: "[" l0expr ".." "]" */ -#line 705 "hexpr.y" + case 153: /* l6expr: "[" l0expr ".." "]" */ +#line 714 "hexpr.y" { (yyval.exp) = new App(var("iterateS", m((yylsp[-1]))), list(ExprPtr((yyvsp[-2].exp)), fn(str::strings(".x"), fncall(var("+", m((yylsp[-1]))), list(var(".x", m((yylsp[-1]))), ExprPtr(new Int(1, m((yylsp[-1]))))), m((yylsp[-1]))), m((yylsp[-1])))), m((yylsp[-3]), (yylsp[0]))); } -#line 3705 "hexpr.parse.C" +#line 3796 "hexpr.parse.C" break; - case 145: /* l6expr: "[" l0expr "|" cselections "]" */ -#line 706 "hexpr.y" + case 154: /* l6expr: "[" l0expr "|" cselections "]" */ +#line 715 "hexpr.y" { (yyval.exp) = desugarComprehension(yyParseCC, ExprPtr((yyvsp[-3].exp)), *(yyvsp[-1].cselections), m((yylsp[-4]), (yylsp[0]))); } -#line 3711 "hexpr.parse.C" +#line 3802 "hexpr.parse.C" break; - case 146: /* l6expr: "[" cargs "]" */ -#line 707 "hexpr.y" + case 155: /* l6expr: "[" cargs "]" */ +#line 716 "hexpr.y" { (yyval.exp) = new MkArray(*(yyvsp[-1].exps), m((yylsp[-2]), (yylsp[0]))); } -#line 3717 "hexpr.parse.C" +#line 3808 "hexpr.parse.C" break; - case 147: /* l6expr: l6expr "[" "timeV" "]" */ -#line 708 "hexpr.y" + case 156: /* l6expr: l6expr "[" "timeV" "]" */ +#line 717 "hexpr.y" { (yyval.exp) = maybeArraySliceWithTime(ExprPtr((yyvsp[-3].exp)), *(yyvsp[-1].string), m((yylsp[-3]), (yylsp[0]))); } -#line 3723 "hexpr.parse.C" +#line 3814 "hexpr.parse.C" break; - case 148: /* l6expr: l6expr "[" l0expr "]" */ -#line 709 "hexpr.y" + case 157: /* l6expr: l6expr "[" l0expr "]" */ +#line 718 "hexpr.y" { (yyval.exp) = mkAIndex(ExprPtr((yyvsp[-3].exp)), ExprPtr((yyvsp[-1].exp)), m((yylsp[-3]), (yylsp[0]))); } -#line 3729 "hexpr.parse.C" +#line 3820 "hexpr.parse.C" break; - case 149: /* l6expr: l6expr "[" l0expr ":" l0expr "]" */ -#line 710 "hexpr.y" + case 158: /* l6expr: l6expr "[" l0expr ":" l0expr "]" */ +#line 719 "hexpr.y" { (yyval.exp) = new App(var("slice", m((yylsp[-2]))), list(ExprPtr((yyvsp[-5].exp)), ExprPtr((yyvsp[-3].exp)), ExprPtr((yyvsp[-1].exp))), m((yylsp[-5]), (yylsp[0]))); } -#line 3735 "hexpr.parse.C" +#line 3826 "hexpr.parse.C" break; - case 150: /* l6expr: l6expr "[" l0expr ":" "]" */ -#line 711 "hexpr.y" + case 159: /* l6expr: l6expr "[" l0expr ":" "]" */ +#line 720 "hexpr.y" { std::string vn = freshName(); (yyval.exp) = new Let(vn, ExprPtr((yyvsp[-4].exp)), fncall(var("slice",m((yylsp[-1]))), list(var(vn,m((yylsp[-4]))), ExprPtr((yyvsp[-2].exp)), fncall(var("size",m((yylsp[-1]))), list(var(vn,m((yylsp[-4])))),m((yylsp[-4])))),m((yylsp[-4]),(yylsp[0]))), m((yylsp[-4]), (yylsp[0]))); } -#line 3741 "hexpr.parse.C" +#line 3832 "hexpr.parse.C" break; - case 151: /* l6expr: l6expr "[" ":" l0expr "]" */ -#line 712 "hexpr.y" + case 160: /* l6expr: l6expr "[" ":" l0expr "]" */ +#line 721 "hexpr.y" { std::string vn = freshName(); (yyval.exp) = new Let(vn, ExprPtr((yyvsp[-4].exp)), fncall(var("slice",m((yylsp[-2]))), list(var(vn,m((yylsp[-4]))), fncall(var("size",m((yylsp[-2]))), list(var(vn,m((yylsp[-2])))),m((yylsp[-4]))), ExprPtr((yyvsp[-1].exp))), m((yylsp[-4]),(yylsp[0]))), m((yylsp[-4]), (yylsp[0]))); } -#line 3747 "hexpr.parse.C" +#line 3838 "hexpr.parse.C" break; - case 152: /* l6expr: "|" id "=" l0expr "|" */ -#line 715 "hexpr.y" + case 161: /* l6expr: "|" id "=" l0expr "|" */ +#line 724 "hexpr.y" { (yyval.exp) = new MkVariant(*(yyvsp[-3].string), ExprPtr((yyvsp[-1].exp)), m((yylsp[-4]), (yylsp[0]))); } -#line 3753 "hexpr.parse.C" +#line 3844 "hexpr.parse.C" break; - case 153: /* l6expr: "|" "intV" "=" l0expr "|" */ -#line 716 "hexpr.y" + case 162: /* l6expr: "|" "intV" "=" l0expr "|" */ +#line 725 "hexpr.y" { (yyval.exp) = new MkVariant(".f" + str::from((yyvsp[-3].intv)), ExprPtr((yyvsp[-1].exp)), m((yylsp[-4]), (yylsp[0]))); } -#line 3759 "hexpr.parse.C" +#line 3850 "hexpr.parse.C" break; - case 154: /* l6expr: "|" id "|" */ -#line 717 "hexpr.y" + case 163: /* l6expr: "|" id "|" */ +#line 726 "hexpr.y" { (yyval.exp) = new MkVariant(*(yyvsp[-1].string), ExprPtr(new Unit(m((yylsp[-1])))), m((yylsp[-2]), (yylsp[0]))); } -#line 3765 "hexpr.parse.C" +#line 3856 "hexpr.parse.C" break; - case 155: /* l6expr: "case" l0expr "of" "|" varfields "|" */ -#line 718 "hexpr.y" + case 164: /* l6expr: "case" l0expr "of" "|" varfields "|" */ +#line 727 "hexpr.y" { (yyval.exp) = new Case(ExprPtr((yyvsp[-4].exp)), *(yyvsp[-1].vfields), m((yylsp[-5]), (yylsp[0]))); } -#line 3771 "hexpr.parse.C" +#line 3862 "hexpr.parse.C" break; - case 156: /* l6expr: "case" l0expr "of" "|" varfields "|" "default" l0expr */ -#line 719 "hexpr.y" + case 165: /* l6expr: "case" l0expr "of" "|" varfields "|" "default" l0expr */ +#line 728 "hexpr.y" { (yyval.exp) = new Case(ExprPtr((yyvsp[-6].exp)), *(yyvsp[-3].vfields), ExprPtr((yyvsp[0].exp)), m((yylsp[-7]), (yylsp[0]))); } -#line 3777 "hexpr.parse.C" +#line 3868 "hexpr.parse.C" break; - case 157: /* l6expr: "{" recfields "}" */ -#line 722 "hexpr.y" + case 166: /* l6expr: "{" recfields "}" */ +#line 731 "hexpr.y" { if ((yyvsp[-1].rfields)->size() > 0) { (yyval.exp) = new MkRecord(*(yyvsp[-1].rfields), m((yylsp[-2]), (yylsp[0]))); } else { (yyval.exp) = new Unit(m((yylsp[-2]), (yylsp[0]))); } } -#line 3783 "hexpr.parse.C" +#line 3874 "hexpr.parse.C" break; - case 158: /* l6expr: "{" recfields "," "}" */ -#line 723 "hexpr.y" + case 167: /* l6expr: "{" recfields "," "}" */ +#line 732 "hexpr.y" { if ((yyvsp[-2].rfields)->size() > 0) { (yyval.exp) = new MkRecord(*(yyvsp[-2].rfields), m((yylsp[-3]), (yylsp[0]))); } else { (yyval.exp) = new Unit(m((yylsp[-3]), (yylsp[0]))); } } -#line 3789 "hexpr.parse.C" +#line 3880 "hexpr.parse.C" break; - case 159: /* l6expr: l6expr recfieldpath */ -#line 724 "hexpr.y" + case 168: /* l6expr: l6expr recfieldpath */ +#line 733 "hexpr.y" { (yyval.exp) = makeProjSeq((yyvsp[-1].exp), *(yyvsp[0].strings), m((yylsp[-1]), (yylsp[0]))); } -#line 3795 "hexpr.parse.C" +#line 3886 "hexpr.parse.C" break; - case 160: /* l6expr: recfieldpath */ -#line 727 "hexpr.y" + case 169: /* l6expr: recfieldpath */ +#line 736 "hexpr.y" { (yyval.exp) = new Fn(str::strings("x"), proj(var("x", m((yylsp[0]))), *(yyvsp[0].strings), m((yylsp[0]))), m((yylsp[0]))); } -#line 3801 "hexpr.parse.C" +#line 3892 "hexpr.parse.C" break; - case 161: /* l6expr: "regexV" */ -#line 730 "hexpr.y" + case 170: /* l6expr: "regexV" */ +#line 739 "hexpr.y" { (yyval.exp) = compileRegexFn(yyParseCC, std::string((yyvsp[0].string)->begin() + 1, (yyvsp[0].string)->end() - 1), m((yylsp[0])))->clone(); } -#line 3807 "hexpr.parse.C" +#line 3898 "hexpr.parse.C" break; - case 162: /* l6expr: "pack" l6expr */ -#line 733 "hexpr.y" + case 171: /* l6expr: "pack" l6expr */ +#line 742 "hexpr.y" { (yyval.exp) = new Pack(ExprPtr((yyvsp[0].exp)), m((yylsp[-1]), (yylsp[0]))); } -#line 3813 "hexpr.parse.C" +#line 3904 "hexpr.parse.C" break; - case 163: /* l6expr: "unpack" id "=" l6expr "in" l6expr */ -#line 734 "hexpr.y" + case 172: /* l6expr: "unpack" id "=" l6expr "in" l6expr */ +#line 743 "hexpr.y" { (yyval.exp) = new Unpack(*(yyvsp[-4].string), ExprPtr((yyvsp[-2].exp)), ExprPtr((yyvsp[0].exp)), m((yylsp[-5]), (yylsp[0]))); } -#line 3819 "hexpr.parse.C" +#line 3910 "hexpr.parse.C" break; - case 164: /* l6expr: "boolV" */ -#line 737 "hexpr.y" + case 173: /* l6expr: "boolV" */ +#line 746 "hexpr.y" { (yyval.exp) = new Bool((yyvsp[0].boolv), m((yylsp[0]))); } -#line 3825 "hexpr.parse.C" +#line 3916 "hexpr.parse.C" break; - case 165: /* l6expr: "charV" */ -#line 738 "hexpr.y" + case 174: /* l6expr: "charV" */ +#line 747 "hexpr.y" { (yyval.exp) = new Char(str::readCharDef(*(yyvsp[0].string)), m((yylsp[0]))); } -#line 3831 "hexpr.parse.C" +#line 3922 "hexpr.parse.C" break; - case 166: /* l6expr: "byteV" */ -#line 739 "hexpr.y" + case 175: /* l6expr: "byteV" */ +#line 748 "hexpr.y" { (yyval.exp) = new Byte(str::dehex(*(yyvsp[0].string)), m((yylsp[0]))); } -#line 3837 "hexpr.parse.C" +#line 3928 "hexpr.parse.C" break; - case 167: /* l6expr: "bytesV" */ -#line 740 "hexpr.y" + case 176: /* l6expr: "bytesV" */ +#line 749 "hexpr.y" { (yyval.exp) = mkarray(str::dehexs(*(yyvsp[0].string)), m((yylsp[0]))); } -#line 3843 "hexpr.parse.C" +#line 3934 "hexpr.parse.C" break; - case 168: /* l6expr: "shortV" */ -#line 741 "hexpr.y" + case 177: /* l6expr: "shortV" */ +#line 750 "hexpr.y" { (yyval.exp) = new Short((yyvsp[0].shortv), m((yylsp[0]))); } -#line 3849 "hexpr.parse.C" +#line 3940 "hexpr.parse.C" break; - case 169: /* l6expr: "intV" */ -#line 742 "hexpr.y" + case 178: /* l6expr: "intV" */ +#line 751 "hexpr.y" { (yyval.exp) = new Int((yyvsp[0].intv), m((yylsp[0]))); } -#line 3855 "hexpr.parse.C" +#line 3946 "hexpr.parse.C" break; - case 170: /* l6expr: "longV" */ -#line 743 "hexpr.y" + case 179: /* l6expr: "longV" */ +#line 752 "hexpr.y" { (yyval.exp) = new Long((yyvsp[0].longv), m((yylsp[0]))); } -#line 3861 "hexpr.parse.C" +#line 3952 "hexpr.parse.C" break; - case 171: /* l6expr: "int128V" */ -#line 744 "hexpr.y" + case 180: /* l6expr: "int128V" */ +#line 753 "hexpr.y" { (yyval.exp) = new Int128((yyvsp[0].int128v), m((yylsp[0]))); } -#line 3867 "hexpr.parse.C" +#line 3958 "hexpr.parse.C" break; - case 172: /* l6expr: "floatV" */ -#line 745 "hexpr.y" + case 181: /* l6expr: "floatV" */ +#line 754 "hexpr.y" { (yyval.exp) = new Float((yyvsp[0].floatv), m((yylsp[0]))); } -#line 3873 "hexpr.parse.C" +#line 3964 "hexpr.parse.C" break; - case 173: /* l6expr: "doubleV" */ -#line 746 "hexpr.y" + case 182: /* l6expr: "doubleV" */ +#line 755 "hexpr.y" { (yyval.exp) = new Double((yyvsp[0].doublev), m((yylsp[0]))); } -#line 3879 "hexpr.parse.C" +#line 3970 "hexpr.parse.C" break; - case 174: /* l6expr: "stringV" */ -#line 747 "hexpr.y" + case 183: /* l6expr: "stringV" */ +#line 756 "hexpr.y" { (yyval.exp) = mkarray(str::unescape(str::trimq(*(yyvsp[0].string))), m((yylsp[0]))); } -#line 3885 "hexpr.parse.C" +#line 3976 "hexpr.parse.C" break; - case 175: /* l6expr: tsseq */ -#line 748 "hexpr.y" + case 184: /* l6expr: tsseq */ +#line 757 "hexpr.y" { (yyval.exp) = mkTimespanExpr(*(yyvsp[0].strings), m((yylsp[0])))->clone(); } -#line 3891 "hexpr.parse.C" +#line 3982 "hexpr.parse.C" break; - case 176: /* l6expr: "timeV" */ -#line 749 "hexpr.y" + case 185: /* l6expr: "timeV" */ +#line 758 "hexpr.y" { (yyval.exp) = mkTimeExpr(*(yyvsp[0].string), m((yylsp[0])))->clone(); } -#line 3897 "hexpr.parse.C" +#line 3988 "hexpr.parse.C" break; - case 177: /* l6expr: "dateTimeV" */ -#line 750 "hexpr.y" + case 186: /* l6expr: "dateTimeV" */ +#line 759 "hexpr.y" { (yyval.exp) = mkDateTimeExpr(*(yyvsp[0].string), m((yylsp[0])))->clone(); } -#line 3903 "hexpr.parse.C" +#line 3994 "hexpr.parse.C" break; - case 178: /* l6expr: "(" cargs ")" */ -#line 753 "hexpr.y" + case 187: /* l6expr: "(" cargs ")" */ +#line 762 "hexpr.y" { (yyval.exp) = pickNestedExp((yyvsp[-1].exps), m((yylsp[-2]),(yylsp[0]))); } -#line 3909 "hexpr.parse.C" +#line 4000 "hexpr.parse.C" break; - case 179: /* l6expr: "(" "++" ")" */ -#line 756 "hexpr.y" + case 188: /* l6expr: "(" "++" ")" */ +#line 765 "hexpr.y" { (yyval.exp) = new Var("append", m((yylsp[-1]))); } -#line 3915 "hexpr.parse.C" +#line 4006 "hexpr.parse.C" break; - case 180: /* l6expr: "(" "+" ")" */ -#line 757 "hexpr.y" + case 189: /* l6expr: "(" "+" ")" */ +#line 766 "hexpr.y" { (yyval.exp) = new Var("+", m((yylsp[-1]))); } -#line 3921 "hexpr.parse.C" +#line 4012 "hexpr.parse.C" break; - case 181: /* l6expr: "(" "-" ")" */ -#line 758 "hexpr.y" + case 190: /* l6expr: "(" "-" ")" */ +#line 767 "hexpr.y" { (yyval.exp) = new Var("-", m((yylsp[-1]))); } -#line 3927 "hexpr.parse.C" +#line 4018 "hexpr.parse.C" break; - case 182: /* l6expr: "(" "*" ")" */ -#line 759 "hexpr.y" + case 191: /* l6expr: "(" "*" ")" */ +#line 768 "hexpr.y" { (yyval.exp) = new Var("*", m((yylsp[-1]))); } -#line 3933 "hexpr.parse.C" +#line 4024 "hexpr.parse.C" break; - case 183: /* l6expr: "(" "/" ")" */ -#line 760 "hexpr.y" + case 192: /* l6expr: "(" "/" ")" */ +#line 769 "hexpr.y" { (yyval.exp) = new Var("/", m((yylsp[-1]))); } -#line 3939 "hexpr.parse.C" +#line 4030 "hexpr.parse.C" break; - case 184: /* l6expr: "(" "%" ")" */ -#line 761 "hexpr.y" + case 193: /* l6expr: "(" "%" ")" */ +#line 770 "hexpr.y" { (yyval.exp) = new Var("%", m((yylsp[-1]))); } -#line 3945 "hexpr.parse.C" +#line 4036 "hexpr.parse.C" break; - case 185: /* l6expr: "(" "~" ")" */ -#line 762 "hexpr.y" + case 194: /* l6expr: "(" "~" ")" */ +#line 771 "hexpr.y" { (yyval.exp) = new Var("~", m((yylsp[-1]))); } -#line 3951 "hexpr.parse.C" +#line 4042 "hexpr.parse.C" break; - case 186: /* l6expr: "(" "===" ")" */ -#line 763 "hexpr.y" + case 195: /* l6expr: "(" "===" ")" */ +#line 772 "hexpr.y" { (yyval.exp) = new Var("===", m((yylsp[-1]))); } -#line 3957 "hexpr.parse.C" +#line 4048 "hexpr.parse.C" break; - case 187: /* l6expr: "(" "==" ")" */ -#line 764 "hexpr.y" + case 196: /* l6expr: "(" "==" ")" */ +#line 773 "hexpr.y" { (yyval.exp) = new Var("==", m((yylsp[-1]))); } -#line 3963 "hexpr.parse.C" +#line 4054 "hexpr.parse.C" break; - case 188: /* l6expr: "(" "!=" ")" */ -#line 765 "hexpr.y" + case 197: /* l6expr: "(" "!=" ")" */ +#line 774 "hexpr.y" { (yyval.exp) = new Var("!=", m((yylsp[-1]))); } -#line 3969 "hexpr.parse.C" +#line 4060 "hexpr.parse.C" break; - case 189: /* l6expr: "(" "<" ")" */ -#line 766 "hexpr.y" + case 198: /* l6expr: "(" "<" ")" */ +#line 775 "hexpr.y" { (yyval.exp) = new Var("<", m((yylsp[-1]))); } -#line 3975 "hexpr.parse.C" +#line 4066 "hexpr.parse.C" break; - case 190: /* l6expr: "(" ">" ")" */ -#line 767 "hexpr.y" + case 199: /* l6expr: "(" ">" ")" */ +#line 776 "hexpr.y" { (yyval.exp) = new Var(">", m((yylsp[-1]))); } -#line 3981 "hexpr.parse.C" +#line 4072 "hexpr.parse.C" break; - case 191: /* l6expr: "(" ">=" ")" */ -#line 768 "hexpr.y" + case 200: /* l6expr: "(" ">=" ")" */ +#line 777 "hexpr.y" { (yyval.exp) = new Var(">=", m((yylsp[-1]))); } -#line 3987 "hexpr.parse.C" +#line 4078 "hexpr.parse.C" break; - case 192: /* l6expr: "(" "<=" ")" */ -#line 769 "hexpr.y" + case 201: /* l6expr: "(" "<=" ")" */ +#line 778 "hexpr.y" { (yyval.exp) = new Var("<=", m((yylsp[-1]))); } -#line 3993 "hexpr.parse.C" +#line 4084 "hexpr.parse.C" break; - case 193: /* l6expr: "(" "and" ")" */ -#line 770 "hexpr.y" + case 202: /* l6expr: "(" "and" ")" */ +#line 779 "hexpr.y" { (yyval.exp) = new Var("and", m((yylsp[-1]))); } -#line 3999 "hexpr.parse.C" +#line 4090 "hexpr.parse.C" break; - case 194: /* l6expr: "(" "or" ")" */ -#line 771 "hexpr.y" + case 203: /* l6expr: "(" "or" ")" */ +#line 780 "hexpr.y" { (yyval.exp) = new Var("or", m((yylsp[-1]))); } -#line 4005 "hexpr.parse.C" +#line 4096 "hexpr.parse.C" break; - case 195: /* l6expr: "(" "in" ")" */ -#line 772 "hexpr.y" + case 204: /* l6expr: "(" "in" ")" */ +#line 781 "hexpr.y" { (yyval.exp) = new Var("in", m((yylsp[-1]))); } -#line 4011 "hexpr.parse.C" +#line 4102 "hexpr.parse.C" break; - case 196: /* l6expr: "(" "!" ")" */ -#line 773 "hexpr.y" + case 205: /* l6expr: "(" "!" ")" */ +#line 782 "hexpr.y" { (yyval.exp) = new Var("not", m((yylsp[-1]))); } -#line 4017 "hexpr.parse.C" +#line 4108 "hexpr.parse.C" break; - case 197: /* l6expr: "`" l0expr "`" */ -#line 776 "hexpr.y" + case 206: /* l6expr: "`" l0expr "`" */ +#line 785 "hexpr.y" { (yyval.exp) = new Assump(fncall(var("unsafeCast", m((yylsp[-1]))), list(mktunit(m((yylsp[-1])))), m((yylsp[-1]))), qualtype(tapp(primty("quote"), list(texpr(ExprPtr((yyvsp[-1].exp)))))), m((yylsp[-1]))); } -#line 4023 "hexpr.parse.C" +#line 4114 "hexpr.parse.C" break; - case 198: /* prules: prules prule */ -#line 778 "hexpr.y" + case 207: /* prules: prules prule */ +#line 787 "hexpr.y" { (yyval.prules) = (yyvsp[-1].prules); (yyval.prules)->push_back(*(yyvsp[0].prule)); } -#line 4029 "hexpr.parse.C" +#line 4120 "hexpr.parse.C" break; - case 199: /* prules: prule */ -#line 779 "hexpr.y" + case 208: /* prules: prule */ +#line 788 "hexpr.y" { (yyval.prules) = autorelease(new Grammar()); (yyval.prules)->push_back(*(yyvsp[0].prule)); } -#line 4035 "hexpr.parse.C" +#line 4126 "hexpr.parse.C" break; - case 200: /* prule: id ":=" prdefs */ -#line 781 "hexpr.y" + case 209: /* prule: id ":=" prdefs */ +#line 790 "hexpr.y" { (yyval.prule) = autorelease(new Grammar::value_type(*(yyvsp[-2].string), *(yyvsp[0].prdefs))); } -#line 4041 "hexpr.parse.C" +#line 4132 "hexpr.parse.C" break; - case 201: /* prdefs: prdefs "|" prdef */ -#line 783 "hexpr.y" + case 210: /* prdefs: prdefs "|" prdef */ +#line 792 "hexpr.y" { (yyval.prdefs) = (yyvsp[-2].prdefs); (yyval.prdefs)->push_back(*(yyvsp[0].prdef)); } -#line 4047 "hexpr.parse.C" +#line 4138 "hexpr.parse.C" break; - case 202: /* prdefs: prdef */ -#line 784 "hexpr.y" + case 211: /* prdefs: prdef */ +#line 793 "hexpr.y" { (yyval.prdefs) = autorelease(new GrammarRules()); (yyval.prdefs)->push_back(*(yyvsp[0].prdef)); } -#line 4053 "hexpr.parse.C" +#line 4144 "hexpr.parse.C" break; - case 203: /* prdef: pbelems "{" l0expr "}" */ -#line 786 "hexpr.y" + case 212: /* prdef: pbelems "{" l0expr "}" */ +#line 795 "hexpr.y" { (yyval.prdef) = autorelease(new GrammarRule(*(yyvsp[-3].pbelems), ExprPtr((yyvsp[-1].exp)))); } -#line 4059 "hexpr.parse.C" +#line 4150 "hexpr.parse.C" break; - case 204: /* pbelems: pbelems pbelem */ -#line 788 "hexpr.y" + case 213: /* pbelems: pbelems pbelem */ +#line 797 "hexpr.y" { (yyval.pbelems) = (yyvsp[-1].pbelems); (yyval.pbelems)->push_back(*(yyvsp[0].pbelem)); } -#line 4065 "hexpr.parse.C" +#line 4156 "hexpr.parse.C" break; - case 205: /* pbelems: %empty */ -#line 789 "hexpr.y" + case 214: /* pbelems: %empty */ +#line 798 "hexpr.y" { (yyval.pbelems) = autorelease(new BoundGrammarValues()); } -#line 4071 "hexpr.parse.C" +#line 4162 "hexpr.parse.C" break; - case 206: /* pbelem: id ":" pvalue */ -#line 791 "hexpr.y" + case 215: /* pbelem: id ":" pvalue */ +#line 800 "hexpr.y" { (yyval.pbelem) = autorelease(new BoundGrammarValue(*(yyvsp[-2].string), GrammarValuePtr((yyvsp[0].pvalue)))); } -#line 4077 "hexpr.parse.C" +#line 4168 "hexpr.parse.C" break; - case 207: /* pbelem: pvalue */ -#line 792 "hexpr.y" + case 216: /* pbelem: pvalue */ +#line 801 "hexpr.y" { (yyval.pbelem) = autorelease(new BoundGrammarValue("_", GrammarValuePtr((yyvsp[0].pvalue)))); } -#line 4083 "hexpr.parse.C" +#line 4174 "hexpr.parse.C" break; - case 208: /* pvalue: id */ -#line 794 "hexpr.y" + case 217: /* pvalue: id */ +#line 803 "hexpr.y" { (yyval.pvalue) = new GSymRef(*(yyvsp[0].string), m((yylsp[0]))); } -#line 4089 "hexpr.parse.C" +#line 4180 "hexpr.parse.C" break; - case 209: /* pvalue: "stringV" */ -#line 795 "hexpr.y" + case 218: /* pvalue: "stringV" */ +#line 804 "hexpr.y" { (yyval.pvalue) = new GStr(str::unescape(str::trimq(*(yyvsp[0].string))), m((yylsp[0]))); } -#line 4095 "hexpr.parse.C" +#line 4186 "hexpr.parse.C" break; - case 210: /* pvalue: "charV" */ -#line 796 "hexpr.y" + case 219: /* pvalue: "charV" */ +#line 805 "hexpr.y" { (yyval.pvalue) = new GStr(std::string(1, str::readCharDef(*(yyvsp[0].string))), m((yylsp[0]))); } -#line 4101 "hexpr.parse.C" +#line 4192 "hexpr.parse.C" break; - case 211: /* tsseq: "timespanV" */ -#line 798 "hexpr.y" + case 220: /* tsseq: "timespanV" */ +#line 807 "hexpr.y" { (yyval.strings) = autorelease(new str::seq()); (yyval.strings)->push_back(*(yyvsp[0].string)); } -#line 4107 "hexpr.parse.C" +#line 4198 "hexpr.parse.C" break; - case 212: /* tsseq: tsseq "timespanV" */ -#line 799 "hexpr.y" + case 221: /* tsseq: tsseq "timespanV" */ +#line 808 "hexpr.y" { (yyval.strings) = (yyvsp[-1].strings); (yyval.strings)->push_back(*(yyvsp[0].string)); } -#line 4113 "hexpr.parse.C" +#line 4204 "hexpr.parse.C" break; - case 213: /* l6exprs: l6exprs l6expr */ -#line 801 "hexpr.y" + case 222: /* l6exprs: l6exprs l6expr */ +#line 810 "hexpr.y" { (yyval.exps) = (yyvsp[-1].exps); (yyval.exps)->push_back(ExprPtr((yyvsp[0].exp))); } -#line 4119 "hexpr.parse.C" +#line 4210 "hexpr.parse.C" break; - case 214: /* l6exprs: l6expr */ -#line 802 "hexpr.y" + case 223: /* l6exprs: l6expr */ +#line 811 "hexpr.y" { (yyval.exps) = autorelease(new Exprs()); (yyval.exps)->push_back(ExprPtr((yyvsp[0].exp))); } -#line 4125 "hexpr.parse.C" +#line 4216 "hexpr.parse.C" break; - case 215: /* patternexps: patternexps patternexp */ -#line 804 "hexpr.y" + case 224: /* patternexps: patternexps patternexp */ +#line 813 "hexpr.y" { (yyval.patternexps) = (yyvsp[-1].patternexps); (yyval.patternexps)->push_back(*(yyvsp[0].patternexp)); } -#line 4131 "hexpr.parse.C" +#line 4222 "hexpr.parse.C" break; - case 216: /* patternexps: patternexp */ -#line 805 "hexpr.y" + case 225: /* patternexps: patternexp */ +#line 814 "hexpr.y" { (yyval.patternexps) = autorelease(new PatternRows()); (yyval.patternexps)->push_back(*(yyvsp[0].patternexp)); } -#line 4137 "hexpr.parse.C" +#line 4228 "hexpr.parse.C" break; - case 217: /* patternexp: "|" patterns "->" l0expr */ -#line 807 "hexpr.y" + case 226: /* patternexp: "|" patterns "->" l0expr */ +#line 816 "hexpr.y" { (yyval.patternexp) = autorelease(new PatternRow(*(yyvsp[-2].patterns), ExprPtr((yyvsp[0].exp)))); } -#line 4143 "hexpr.parse.C" +#line 4234 "hexpr.parse.C" break; - case 218: /* patternexp: "|" patterns "where" l0expr "->" l0expr */ -#line 808 "hexpr.y" + case 227: /* patternexp: "|" patterns "where" l0expr "->" l0expr */ +#line 817 "hexpr.y" { (yyval.patternexp) = autorelease(new PatternRow(*(yyvsp[-4].patterns), ExprPtr((yyvsp[-2].exp)), ExprPtr((yyvsp[0].exp)))); } -#line 4149 "hexpr.parse.C" +#line 4240 "hexpr.parse.C" break; - case 219: /* patterns: patterns pattern */ -#line 811 "hexpr.y" + case 228: /* patterns: patterns pattern */ +#line 820 "hexpr.y" { (yyval.patterns) = (yyvsp[-1].patterns); (yyval.patterns)->push_back(PatternPtr((yyvsp[0].pattern))); } -#line 4155 "hexpr.parse.C" +#line 4246 "hexpr.parse.C" break; - case 220: /* patterns: pattern */ -#line 812 "hexpr.y" + case 229: /* patterns: pattern */ +#line 821 "hexpr.y" { (yyval.patterns) = autorelease(new Patterns()); (yyval.patterns)->push_back(PatternPtr((yyvsp[0].pattern))); } -#line 4161 "hexpr.parse.C" +#line 4252 "hexpr.parse.C" break; - case 221: /* refutablep: "boolV" */ -#line 814 "hexpr.y" + case 230: /* refutablep: "boolV" */ +#line 823 "hexpr.y" { (yyval.pattern) = new MatchLiteral(PrimitivePtr(new Bool((yyvsp[0].boolv), m((yylsp[0])))), m((yylsp[0]))); } -#line 4167 "hexpr.parse.C" +#line 4258 "hexpr.parse.C" break; - case 222: /* refutablep: "charV" */ -#line 815 "hexpr.y" + case 231: /* refutablep: "charV" */ +#line 824 "hexpr.y" { (yyval.pattern) = new MatchLiteral(PrimitivePtr(new Char(str::readCharDef(*(yyvsp[0].string)), m((yylsp[0])))), m((yylsp[0]))); } -#line 4173 "hexpr.parse.C" +#line 4264 "hexpr.parse.C" break; - case 223: /* refutablep: "byteV" */ -#line 816 "hexpr.y" + case 232: /* refutablep: "byteV" */ +#line 825 "hexpr.y" { (yyval.pattern) = new MatchLiteral(PrimitivePtr(new Byte(str::dehex(*(yyvsp[0].string)), m((yylsp[0])))), m((yylsp[0]))); } -#line 4179 "hexpr.parse.C" +#line 4270 "hexpr.parse.C" break; - case 224: /* refutablep: "shortV" */ -#line 817 "hexpr.y" + case 233: /* refutablep: "shortV" */ +#line 826 "hexpr.y" { (yyval.pattern) = new MatchLiteral(PrimitivePtr(new Short((yyvsp[0].shortv), m((yylsp[0])))), m((yylsp[0]))); } -#line 4185 "hexpr.parse.C" +#line 4276 "hexpr.parse.C" break; - case 225: /* refutablep: "intV" */ -#line 818 "hexpr.y" + case 234: /* refutablep: "intV" */ +#line 827 "hexpr.y" { (yyval.pattern) = new MatchLiteral(PrimitivePtr(new Int((yyvsp[0].intv), m((yylsp[0])))), m((yylsp[0]))); } -#line 4191 "hexpr.parse.C" +#line 4282 "hexpr.parse.C" break; - case 226: /* refutablep: "longV" */ -#line 819 "hexpr.y" + case 235: /* refutablep: "longV" */ +#line 828 "hexpr.y" { (yyval.pattern) = new MatchLiteral(PrimitivePtr(new Long((yyvsp[0].longv), m((yylsp[0])))), m((yylsp[0]))); } -#line 4197 "hexpr.parse.C" +#line 4288 "hexpr.parse.C" break; - case 227: /* refutablep: "int128V" */ -#line 820 "hexpr.y" + case 236: /* refutablep: "int128V" */ +#line 829 "hexpr.y" { (yyval.pattern) = new MatchLiteral(PrimitivePtr(new Int128((yyvsp[0].int128v), m((yylsp[0])))), m((yylsp[0]))); } -#line 4203 "hexpr.parse.C" +#line 4294 "hexpr.parse.C" break; - case 228: /* refutablep: "doubleV" */ -#line 821 "hexpr.y" + case 237: /* refutablep: "doubleV" */ +#line 830 "hexpr.y" { (yyval.pattern) = new MatchLiteral(PrimitivePtr(new Double((yyvsp[0].doublev), m((yylsp[0])))), m((yylsp[0]))); } -#line 4209 "hexpr.parse.C" +#line 4300 "hexpr.parse.C" break; - case 229: /* refutablep: "bytesV" */ -#line 822 "hexpr.y" + case 238: /* refutablep: "bytesV" */ +#line 831 "hexpr.y" { (yyval.pattern) = mkpatarray(str::dehexs(*(yyvsp[0].string)), m((yylsp[0]))); } -#line 4215 "hexpr.parse.C" +#line 4306 "hexpr.parse.C" break; - case 230: /* refutablep: "stringV" */ -#line 823 "hexpr.y" + case 239: /* refutablep: "stringV" */ +#line 832 "hexpr.y" { (yyval.pattern) = mkpatarray(str::unescape(str::trimq(*(yyvsp[0].string))), m((yylsp[0]))); } -#line 4221 "hexpr.parse.C" +#line 4312 "hexpr.parse.C" break; - case 231: /* refutablep: tsseq */ -#line 824 "hexpr.y" + case 240: /* refutablep: tsseq */ +#line 833 "hexpr.y" { (yyval.pattern) = new MatchLiteral(mkTimespanPrim(*(yyvsp[0].strings), m((yylsp[0]))), mkTimespanExpr(*(yyvsp[0].strings), m((yylsp[0]))), m((yylsp[0]))); } -#line 4227 "hexpr.parse.C" +#line 4318 "hexpr.parse.C" break; - case 232: /* refutablep: "timeV" */ -#line 825 "hexpr.y" + case 241: /* refutablep: "timeV" */ +#line 834 "hexpr.y" { (yyval.pattern) = new MatchLiteral(mkTimePrim(*(yyvsp[0].string), m((yylsp[0]))), mkTimeExpr(*(yyvsp[0].string), m((yylsp[0]))), m((yylsp[0]))); } -#line 4233 "hexpr.parse.C" +#line 4324 "hexpr.parse.C" break; - case 233: /* refutablep: "dateTimeV" */ -#line 826 "hexpr.y" + case 242: /* refutablep: "dateTimeV" */ +#line 835 "hexpr.y" { (yyval.pattern) = new MatchLiteral(mkDateTimePrim(*(yyvsp[0].string), m((yylsp[0]))), mkDateTimeExpr(*(yyvsp[0].string), m((yylsp[0]))), m((yylsp[0]))); } -#line 4239 "hexpr.parse.C" +#line 4330 "hexpr.parse.C" break; - case 234: /* refutablep: "regexV" */ -#line 827 "hexpr.y" + case 243: /* refutablep: "regexV" */ +#line 836 "hexpr.y" { (yyval.pattern) = new MatchRegex(std::string((yyvsp[0].string)->begin() + 1, (yyvsp[0].string)->end() - 1), m((yylsp[0]))); } -#line 4245 "hexpr.parse.C" +#line 4336 "hexpr.parse.C" break; - case 235: /* refutablep: "[" patternseq "]" */ -#line 828 "hexpr.y" + case 244: /* refutablep: "[" patternseq "]" */ +#line 837 "hexpr.y" { (yyval.pattern) = new MatchArray(*(yyvsp[-1].patterns), m((yylsp[-2]),(yylsp[0]))); } -#line 4251 "hexpr.parse.C" +#line 4342 "hexpr.parse.C" break; - case 236: /* refutablep: "[" patternseq "," "]" */ -#line 829 "hexpr.y" + case 245: /* refutablep: "[" patternseq "," "]" */ +#line 838 "hexpr.y" { (yyval.pattern) = new MatchArray(*(yyvsp[-2].patterns), m((yylsp[-3]),(yylsp[0]))); } -#line 4257 "hexpr.parse.C" +#line 4348 "hexpr.parse.C" break; - case 237: /* refutablep: "|" id "|" */ -#line 830 "hexpr.y" + case 246: /* refutablep: "|" id "|" */ +#line 839 "hexpr.y" { (yyval.pattern) = new MatchVariant(*(yyvsp[-1].string), PatternPtr(new MatchLiteral(PrimitivePtr(new Unit(m((yylsp[-1])))), m((yylsp[-1])))), m((yylsp[-2]),(yylsp[0]))); } -#line 4263 "hexpr.parse.C" +#line 4354 "hexpr.parse.C" break; - case 238: /* refutablep: "|" id "=" pattern "|" */ -#line 831 "hexpr.y" + case 247: /* refutablep: "|" id "=" pattern "|" */ +#line 840 "hexpr.y" { (yyval.pattern) = new MatchVariant(*(yyvsp[-3].string), PatternPtr((yyvsp[-1].pattern)), m((yylsp[-4]),(yylsp[0]))); } -#line 4269 "hexpr.parse.C" +#line 4360 "hexpr.parse.C" break; - case 239: /* refutablep: "|" "intV" "=" pattern "|" */ -#line 832 "hexpr.y" + case 248: /* refutablep: "|" "intV" "=" pattern "|" */ +#line 841 "hexpr.y" { (yyval.pattern) = new MatchVariant(".f" + str::from((yyvsp[-3].intv)), PatternPtr((yyvsp[-1].pattern)), m((yylsp[-4]),(yylsp[0]))); } -#line 4275 "hexpr.parse.C" +#line 4366 "hexpr.parse.C" break; - case 240: /* refutablep: "(" patternseq ")" */ -#line 833 "hexpr.y" + case 249: /* refutablep: "(" patternseq ")" */ +#line 842 "hexpr.y" { (yyval.pattern) = pickNestedPat((yyvsp[-1].patterns), m((yylsp[-2]),(yylsp[0]))); } -#line 4281 "hexpr.parse.C" +#line 4372 "hexpr.parse.C" break; - case 241: /* refutablep: "(" patternseq "," ")" */ -#line 834 "hexpr.y" + case 250: /* refutablep: "(" patternseq "," ")" */ +#line 843 "hexpr.y" { (yyval.pattern) = pickNestedPat((yyvsp[-2].patterns), m((yylsp[-3]),(yylsp[0]))); } -#line 4287 "hexpr.parse.C" +#line 4378 "hexpr.parse.C" break; - case 242: /* refutablep: "{" recpatfields "}" */ -#line 835 "hexpr.y" + case 251: /* refutablep: "{" recpatfields "}" */ +#line 844 "hexpr.y" { (yyval.pattern) = new MatchRecord(*(yyvsp[-1].recpatfields), m((yylsp[-2]),(yylsp[0]))); } -#line 4293 "hexpr.parse.C" +#line 4384 "hexpr.parse.C" break; - case 243: /* refutablep: "{" recpatfields "," "}" */ -#line 836 "hexpr.y" + case 252: /* refutablep: "{" recpatfields "," "}" */ +#line 845 "hexpr.y" { (yyval.pattern) = new MatchRecord(*(yyvsp[-2].recpatfields), m((yylsp[-3]),(yylsp[0]))); } -#line 4299 "hexpr.parse.C" +#line 4390 "hexpr.parse.C" break; - case 244: /* refutablep: id */ -#line 837 "hexpr.y" + case 253: /* refutablep: id */ +#line 846 "hexpr.y" { (yyval.pattern) = patVarCtorFn(*(yyvsp[0].string), m((yylsp[0]))); } -#line 4305 "hexpr.parse.C" +#line 4396 "hexpr.parse.C" break; - case 245: /* irrefutablep: id */ -#line 839 "hexpr.y" + case 254: /* irrefutablep: id */ +#line 848 "hexpr.y" { (yyval.pattern) = new MatchAny(*(yyvsp[0].string), m((yylsp[0]))); } -#line 4311 "hexpr.parse.C" +#line 4402 "hexpr.parse.C" break; - case 246: /* irrefutablep: "(" patternseq ")" */ -#line 840 "hexpr.y" + case 255: /* irrefutablep: "(" patternseq ")" */ +#line 849 "hexpr.y" { (yyval.pattern) = pickNestedPat((yyvsp[-1].patterns), m((yylsp[-2]),(yylsp[0]))); } -#line 4317 "hexpr.parse.C" +#line 4408 "hexpr.parse.C" break; - case 247: /* irrefutablep: "(" patternseq "," ")" */ -#line 841 "hexpr.y" + case 256: /* irrefutablep: "(" patternseq "," ")" */ +#line 850 "hexpr.y" { (yyval.pattern) = pickNestedPat((yyvsp[-2].patterns), m((yylsp[-3]),(yylsp[0]))); } -#line 4323 "hexpr.parse.C" +#line 4414 "hexpr.parse.C" break; - case 248: /* irrefutablep: "{" recpatfields "}" */ -#line 842 "hexpr.y" + case 257: /* irrefutablep: "{" recpatfields "}" */ +#line 851 "hexpr.y" { (yyval.pattern) = new MatchRecord(*(yyvsp[-1].recpatfields), m((yylsp[-2]),(yylsp[0]))); } -#line 4329 "hexpr.parse.C" +#line 4420 "hexpr.parse.C" break; - case 249: /* irrefutablep: "{" recpatfields "," "}" */ -#line 843 "hexpr.y" + case 258: /* irrefutablep: "{" recpatfields "," "}" */ +#line 852 "hexpr.y" { (yyval.pattern) = new MatchRecord(*(yyvsp[-2].recpatfields), m((yylsp[-3]),(yylsp[0]))); } -#line 4335 "hexpr.parse.C" +#line 4426 "hexpr.parse.C" break; - case 250: /* pattern: refutablep */ -#line 845 "hexpr.y" + case 259: /* pattern: refutablep */ +#line 854 "hexpr.y" { (yyval.pattern) = (yyvsp[0].pattern); } -#line 4341 "hexpr.parse.C" +#line 4432 "hexpr.parse.C" break; - case 251: /* patternseq: patternseqn */ -#line 847 "hexpr.y" + case 260: /* patternseq: patternseqn */ +#line 856 "hexpr.y" { (yyval.patterns) = (yyvsp[0].patterns); } -#line 4347 "hexpr.parse.C" +#line 4438 "hexpr.parse.C" break; - case 252: /* patternseq: %empty */ -#line 848 "hexpr.y" + case 261: /* patternseq: %empty */ +#line 857 "hexpr.y" { (yyval.patterns) = new Patterns(); } -#line 4353 "hexpr.parse.C" +#line 4444 "hexpr.parse.C" break; - case 253: /* patternseqn: patternseqn "," pattern */ -#line 850 "hexpr.y" + case 262: /* patternseqn: patternseqn "," pattern */ +#line 859 "hexpr.y" { (yyval.patterns) = (yyvsp[-2].patterns); (yyval.patterns)->push_back(PatternPtr((yyvsp[0].pattern))); } -#line 4359 "hexpr.parse.C" +#line 4450 "hexpr.parse.C" break; - case 254: /* patternseqn: pattern */ -#line 851 "hexpr.y" + case 263: /* patternseqn: pattern */ +#line 860 "hexpr.y" { (yyval.patterns) = new Patterns(); (yyval.patterns)->push_back(PatternPtr((yyvsp[0].pattern))); } -#line 4365 "hexpr.parse.C" +#line 4456 "hexpr.parse.C" break; - case 255: /* recpatfields: recpatfields "," recpatfield */ -#line 853 "hexpr.y" + case 264: /* recpatfields: recpatfields "," recpatfield */ +#line 862 "hexpr.y" { (yyval.recpatfields) = (yyvsp[-2].recpatfields); (yyval.recpatfields)->push_back(*(yyvsp[0].recpatfield)); } -#line 4371 "hexpr.parse.C" +#line 4462 "hexpr.parse.C" break; - case 256: /* recpatfields: recpatfield */ -#line 854 "hexpr.y" + case 265: /* recpatfields: recpatfield */ +#line 863 "hexpr.y" { (yyval.recpatfields) = new MatchRecord::Fields(); (yyval.recpatfields)->push_back(*(yyvsp[0].recpatfield)); } -#line 4377 "hexpr.parse.C" +#line 4468 "hexpr.parse.C" break; - case 257: /* recpatfield: id "=" pattern */ -#line 856 "hexpr.y" + case 266: /* recpatfield: id "=" pattern */ +#line 865 "hexpr.y" { (yyval.recpatfield) = new MatchRecord::Field(*(yyvsp[-2].string), PatternPtr((yyvsp[0].pattern))); } -#line 4383 "hexpr.parse.C" +#line 4474 "hexpr.parse.C" break; - case 258: /* recfields: %empty */ -#line 858 "hexpr.y" + case 267: /* recfields: %empty */ +#line 867 "hexpr.y" { (yyval.rfields) = autorelease(new MkRecord::FieldDefs()); } -#line 4389 "hexpr.parse.C" +#line 4480 "hexpr.parse.C" break; - case 259: /* recfields: recfieldname "=" l0expr */ -#line 859 "hexpr.y" + case 268: /* recfields: recfieldname "=" l0expr */ +#line 868 "hexpr.y" { (yyval.rfields) = autorelease(new MkRecord::FieldDefs()); (yyval.rfields)->push_back(MkRecord::FieldDef(*(yyvsp[-2].string), ExprPtr((yyvsp[0].exp)))); } -#line 4395 "hexpr.parse.C" +#line 4486 "hexpr.parse.C" break; - case 260: /* recfields: recfields "," recfieldname "=" l0expr */ -#line 860 "hexpr.y" + case 269: /* recfields: recfields "," recfieldname "=" l0expr */ +#line 869 "hexpr.y" { (yyval.rfields) = (yyvsp[-4].rfields); (yyval.rfields)->push_back(MkRecord::FieldDef(*(yyvsp[-2].string), ExprPtr((yyvsp[0].exp)))); } -#line 4401 "hexpr.parse.C" +#line 4492 "hexpr.parse.C" break; - case 261: /* recfieldname: id */ -#line 862 "hexpr.y" + case 270: /* recfieldname: id */ +#line 871 "hexpr.y" { (yyval.string) = (yyvsp[0].string); } -#line 4407 "hexpr.parse.C" +#line 4498 "hexpr.parse.C" break; - case 262: /* recfieldname: "data" */ -#line 863 "hexpr.y" + case 271: /* recfieldname: "data" */ +#line 872 "hexpr.y" { (yyval.string) = autorelease(new std::string("data")); } -#line 4413 "hexpr.parse.C" +#line 4504 "hexpr.parse.C" break; - case 263: /* recfieldname: "type" */ -#line 864 "hexpr.y" + case 272: /* recfieldname: "type" */ +#line 873 "hexpr.y" { (yyval.string) = autorelease(new std::string("type")); } -#line 4419 "hexpr.parse.C" +#line 4510 "hexpr.parse.C" break; - case 264: /* recfieldname: "where" */ -#line 865 "hexpr.y" + case 273: /* recfieldname: "where" */ +#line 874 "hexpr.y" { (yyval.string) = autorelease(new std::string("where")); } -#line 4425 "hexpr.parse.C" +#line 4516 "hexpr.parse.C" break; - case 265: /* recfieldname: "class" */ -#line 866 "hexpr.y" + case 274: /* recfieldname: "class" */ +#line 875 "hexpr.y" { (yyval.string) = autorelease(new std::string("class")); wantIndent(false); } -#line 4431 "hexpr.parse.C" +#line 4522 "hexpr.parse.C" break; - case 266: /* recfieldname: "instance" */ -#line 867 "hexpr.y" + case 275: /* recfieldname: "instance" */ +#line 876 "hexpr.y" { (yyval.string) = autorelease(new std::string("instance")); wantIndent(false); } -#line 4437 "hexpr.parse.C" +#line 4528 "hexpr.parse.C" break; - case 267: /* recfieldname: "exists" */ -#line 868 "hexpr.y" + case 276: /* recfieldname: "exists" */ +#line 877 "hexpr.y" { (yyval.string) = autorelease(new std::string("exists")); } -#line 4443 "hexpr.parse.C" +#line 4534 "hexpr.parse.C" break; - case 268: /* recfieldname: "import" */ -#line 869 "hexpr.y" + case 277: /* recfieldname: "import" */ +#line 878 "hexpr.y" { (yyval.string) = autorelease(new std::string("import")); } -#line 4449 "hexpr.parse.C" +#line 4540 "hexpr.parse.C" break; - case 269: /* recfieldname: "module" */ -#line 870 "hexpr.y" + case 278: /* recfieldname: "module" */ +#line 879 "hexpr.y" { (yyval.string) = autorelease(new std::string("module")); } -#line 4455 "hexpr.parse.C" +#line 4546 "hexpr.parse.C" break; - case 270: /* recfieldname: "parse" */ -#line 871 "hexpr.y" + case 279: /* recfieldname: "parse" */ +#line 880 "hexpr.y" { (yyval.string) = autorelease(new std::string("parse")); } -#line 4461 "hexpr.parse.C" +#line 4552 "hexpr.parse.C" break; - case 271: /* recfieldname: "do" */ -#line 872 "hexpr.y" + case 280: /* recfieldname: "do" */ +#line 881 "hexpr.y" { (yyval.string) = autorelease(new std::string("do")); } -#line 4467 "hexpr.parse.C" +#line 4558 "hexpr.parse.C" break; - case 272: /* recfieldname: "return" */ -#line 873 "hexpr.y" + case 281: /* recfieldname: "return" */ +#line 882 "hexpr.y" { (yyval.string) = autorelease(new std::string("return")); } -#line 4473 "hexpr.parse.C" +#line 4564 "hexpr.parse.C" break; - case 273: /* recfieldname: "fn" */ -#line 874 "hexpr.y" + case 282: /* recfieldname: "fn" */ +#line 883 "hexpr.y" { (yyval.string) = autorelease(new std::string("fn")); } -#line 4479 "hexpr.parse.C" +#line 4570 "hexpr.parse.C" break; - case 274: /* recfieldname: "intV" */ -#line 875 "hexpr.y" + case 283: /* recfieldname: "intV" */ +#line 884 "hexpr.y" { (yyval.string) = autorelease(new std::string(".f" + str::from((yyvsp[0].intv)))); } -#line 4485 "hexpr.parse.C" +#line 4576 "hexpr.parse.C" break; - case 275: /* recfieldname: "stringV" */ -#line 876 "hexpr.y" + case 284: /* recfieldname: "stringV" */ +#line 885 "hexpr.y" { std::string stringField = str::unescape(str::trimq(*(yyvsp[0].string))); if (stringField.size() > 0 && stringField[0] == '.' ) { throw annotated_error(m((yylsp[0])), "Cannot define record string label with leading '.'"); } (yyval.string) = autorelease(new std::string(str::unescape(str::trimq(*(yyvsp[0].string))))); } -#line 4495 "hexpr.parse.C" +#line 4586 "hexpr.parse.C" break; - case 276: /* recfieldpath: recfieldpath "." recfieldname */ -#line 882 "hexpr.y" + case 285: /* recfieldpath: recfieldpath "." recfieldname */ +#line 891 "hexpr.y" { (yyval.strings) = (yyvsp[-2].strings); (yyval.strings)->push_back(*(yyvsp[0].string)); } -#line 4501 "hexpr.parse.C" +#line 4592 "hexpr.parse.C" break; - case 277: /* recfieldpath: recfieldpath "tupSection" */ -#line 883 "hexpr.y" + case 286: /* recfieldpath: recfieldpath "tupSection" */ +#line 892 "hexpr.y" { (yyval.strings) = (yyvsp[-1].strings); str::seq x = tupSectionFields(*(yyvsp[0].string)); (yyval.strings)->insert((yyval.strings)->end(), x.begin(), x.end()); } -#line 4507 "hexpr.parse.C" +#line 4598 "hexpr.parse.C" break; - case 278: /* recfieldpath: "." recfieldname */ -#line 884 "hexpr.y" + case 287: /* recfieldpath: "." recfieldname */ +#line 893 "hexpr.y" { (yyval.strings) = autorelease(new str::seq()); (yyval.strings)->push_back(*(yyvsp[0].string)); } -#line 4513 "hexpr.parse.C" +#line 4604 "hexpr.parse.C" break; - case 279: /* recfieldpath: "tupSection" */ -#line 885 "hexpr.y" + case 288: /* recfieldpath: "tupSection" */ +#line 894 "hexpr.y" { (yyval.strings) = autorelease(new str::seq()); *(yyval.strings) = tupSectionFields(*(yyvsp[0].string)); } -#line 4519 "hexpr.parse.C" +#line 4610 "hexpr.parse.C" break; - case 280: /* varfields: varbind */ -#line 887 "hexpr.y" + case 289: /* varfields: varbind */ +#line 896 "hexpr.y" { (yyval.vfields) = autorelease(new Case::Bindings()); (yyval.vfields)->push_back(*(yyvsp[0].vbind)); } -#line 4525 "hexpr.parse.C" +#line 4616 "hexpr.parse.C" break; - case 281: /* varfields: varfields "," varbind */ -#line 888 "hexpr.y" + case 290: /* varfields: varfields "," varbind */ +#line 897 "hexpr.y" { (yyval.vfields) = (yyvsp[-2].vfields); (yyval.vfields)->push_back(*(yyvsp[0].vbind)); } -#line 4531 "hexpr.parse.C" +#line 4622 "hexpr.parse.C" break; - case 282: /* varbind: id "=" l0expr */ -#line 890 "hexpr.y" + case 291: /* varbind: id "=" l0expr */ +#line 899 "hexpr.y" { (yyval.vbind) = autorelease(new Case::Binding(*(yyvsp[-2].string), *(yyvsp[-2].string), ExprPtr((yyvsp[0].exp)))); } -#line 4537 "hexpr.parse.C" +#line 4628 "hexpr.parse.C" break; - case 283: /* varbind: id ":" id "=" l0expr */ -#line 891 "hexpr.y" + case 292: /* varbind: id ":" id "=" l0expr */ +#line 900 "hexpr.y" { (yyval.vbind) = autorelease(new Case::Binding(*(yyvsp[-4].string), *(yyvsp[-2].string), ExprPtr((yyvsp[0].exp)))); } -#line 4543 "hexpr.parse.C" +#line 4634 "hexpr.parse.C" break; - case 284: /* varbind: "intV" ":" id "=" l0expr */ -#line 892 "hexpr.y" + case 293: /* varbind: "intV" ":" id "=" l0expr */ +#line 901 "hexpr.y" { (yyval.vbind) = autorelease(new Case::Binding(".f" + str::from((yyvsp[-4].intv)), *(yyvsp[-2].string), ExprPtr((yyvsp[0].exp)))); } -#line 4549 "hexpr.parse.C" +#line 4640 "hexpr.parse.C" break; - case 285: /* cargs: %empty */ -#line 894 "hexpr.y" + case 294: /* cargs: %empty */ +#line 903 "hexpr.y" { (yyval.exps) = autorelease(new Exprs()); } -#line 4555 "hexpr.parse.C" +#line 4646 "hexpr.parse.C" break; - case 286: /* cargs: l0expr */ -#line 895 "hexpr.y" + case 295: /* cargs: l0expr */ +#line 904 "hexpr.y" { (yyval.exps) = autorelease(new Exprs()); (yyval.exps)->push_back(ExprPtr((yyvsp[0].exp))); } -#line 4561 "hexpr.parse.C" +#line 4652 "hexpr.parse.C" break; - case 287: /* cargs: cargs "," l0expr */ -#line 896 "hexpr.y" + case 296: /* cargs: cargs "," l0expr */ +#line 905 "hexpr.y" { (yyvsp[-2].exps)->push_back(ExprPtr((yyvsp[0].exp))); (yyval.exps) = (yyvsp[-2].exps); } -#line 4567 "hexpr.parse.C" +#line 4658 "hexpr.parse.C" break; - case 288: /* qtype: cst "=>" l0mtype */ -#line 898 "hexpr.y" + case 297: /* qtype: cst "=>" l0mtype */ +#line 907 "hexpr.y" { (yyval.qualtype) = new QualType(*(yyvsp[-2].tconstraints), *(yyvsp[0].mtype)); } -#line 4573 "hexpr.parse.C" +#line 4664 "hexpr.parse.C" break; - case 289: /* qtype: l0mtype */ -#line 899 "hexpr.y" + case 298: /* qtype: l0mtype */ +#line 908 "hexpr.y" { (yyval.qualtype) = new QualType(Constraints(), *(yyvsp[0].mtype)); } -#line 4579 "hexpr.parse.C" +#line 4670 "hexpr.parse.C" break; - case 290: /* cst: "(" tpreds ")" */ -#line 902 "hexpr.y" + case 299: /* cst: "(" tpreds ")" */ +#line 911 "hexpr.y" { (yyval.tconstraints) = (yyvsp[-1].tconstraints); } -#line 4585 "hexpr.parse.C" +#line 4676 "hexpr.parse.C" break; - case 291: /* tpreds: tpred */ -#line 904 "hexpr.y" + case 300: /* tpreds: tpred */ +#line 913 "hexpr.y" { (yyval.tconstraints) = autorelease(new Constraints()); (yyval.tconstraints)->push_back(ConstraintPtr((yyvsp[0].tconstraint))); } -#line 4591 "hexpr.parse.C" +#line 4682 "hexpr.parse.C" break; - case 292: /* tpreds: tpreds "," tpred */ -#line 905 "hexpr.y" + case 301: /* tpreds: tpreds "," tpred */ +#line 914 "hexpr.y" { (yyvsp[-2].tconstraints)->push_back(ConstraintPtr((yyvsp[0].tconstraint))); (yyval.tconstraints) = (yyvsp[-2].tconstraints); } -#line 4597 "hexpr.parse.C" +#line 4688 "hexpr.parse.C" break; - case 293: /* tpred: id l1mtargl */ -#line 907 "hexpr.y" + case 302: /* tpred: id l1mtargl */ +#line 916 "hexpr.y" { (yyval.tconstraint) = new Constraint(*(yyvsp[-1].string), *(yyvsp[0].mtypes)); } -#line 4603 "hexpr.parse.C" +#line 4694 "hexpr.parse.C" break; - case 294: /* tpred: l1mtype "==" l1mtype */ -#line 908 "hexpr.y" + case 303: /* tpred: l1mtype "==" l1mtype */ +#line 917 "hexpr.y" { (yyval.tconstraint) = new Constraint(EqualTypes::constraintName(), list(*(yyvsp[-2].mtype), *(yyvsp[0].mtype))); } -#line 4609 "hexpr.parse.C" +#line 4700 "hexpr.parse.C" break; - case 295: /* tpred: l1mtype "!=" l1mtype */ -#line 909 "hexpr.y" + case 304: /* tpred: l1mtype "!=" l1mtype */ +#line 918 "hexpr.y" { (yyval.tconstraint) = new Constraint(NotEqualTypes::constraintName(), list(*(yyvsp[-2].mtype), *(yyvsp[0].mtype))); } -#line 4615 "hexpr.parse.C" +#line 4706 "hexpr.parse.C" break; - case 296: /* tpred: l1mtype "~" l1mtype */ -#line 910 "hexpr.y" + case 305: /* tpred: l1mtype "~" l1mtype */ +#line 919 "hexpr.y" { (yyval.tconstraint) = new Constraint(FixIsoRecur::constraintName(), list(*(yyvsp[-2].mtype), *(yyvsp[0].mtype))); } -#line 4621 "hexpr.parse.C" +#line 4712 "hexpr.parse.C" break; - case 297: /* tpred: l1mtype "=" "{" l1mtype "*" l1mtype "}" */ -#line 911 "hexpr.y" + case 306: /* tpred: l1mtype "=" "{" l1mtype "*" l1mtype "}" */ +#line 920 "hexpr.y" { (yyval.tconstraint) = new Constraint(RecordDeconstructor::constraintName(), list(tlong(1), tlong(0), *(yyvsp[-6].mtype), freshTypeVar(), *(yyvsp[-3].mtype), *(yyvsp[-1].mtype))); } -#line 4627 "hexpr.parse.C" +#line 4718 "hexpr.parse.C" break; - case 298: /* tpred: l1mtype "=" "{" id ":" l1mtype "*" l1mtype "}" */ -#line 912 "hexpr.y" + case 307: /* tpred: l1mtype "=" "{" id ":" l1mtype "*" l1mtype "}" */ +#line 921 "hexpr.y" { (yyval.tconstraint) = new Constraint(RecordDeconstructor::constraintName(), list(tlong(1), tlong(0), *(yyvsp[-8].mtype), TVar::make(*(yyvsp[-5].string)), *(yyvsp[-3].mtype), *(yyvsp[-1].mtype))); } -#line 4633 "hexpr.parse.C" +#line 4724 "hexpr.parse.C" break; - case 299: /* tpred: l1mtype "=" "(" l1mtype "*" l1mtype ")" */ -#line 913 "hexpr.y" + case 308: /* tpred: l1mtype "=" "(" l1mtype "*" l1mtype ")" */ +#line 922 "hexpr.y" { (yyval.tconstraint) = new Constraint(RecordDeconstructor::constraintName(), list(tlong(1), tlong(1), *(yyvsp[-6].mtype), freshTypeVar(), *(yyvsp[-3].mtype), *(yyvsp[-1].mtype))); } -#line 4639 "hexpr.parse.C" +#line 4730 "hexpr.parse.C" break; - case 300: /* tpred: "{" l1mtype "*" l1mtype "}" "=" l1mtype */ -#line 914 "hexpr.y" + case 309: /* tpred: "{" l1mtype "*" l1mtype "}" "=" l1mtype */ +#line 923 "hexpr.y" { (yyval.tconstraint) = new Constraint(RecordDeconstructor::constraintName(), list(tlong(0), tlong(0), *(yyvsp[0].mtype), freshTypeVar(), *(yyvsp[-5].mtype), *(yyvsp[-3].mtype))); } -#line 4645 "hexpr.parse.C" +#line 4736 "hexpr.parse.C" break; - case 301: /* tpred: "{" id ":" l1mtype "*" l1mtype "}" "=" l1mtype */ -#line 915 "hexpr.y" + case 310: /* tpred: "{" id ":" l1mtype "*" l1mtype "}" "=" l1mtype */ +#line 924 "hexpr.y" { (yyval.tconstraint) = new Constraint(RecordDeconstructor::constraintName(), list(tlong(0), tlong(0), *(yyvsp[0].mtype), TVar::make(*(yyvsp[-7].string)), *(yyvsp[-5].mtype), *(yyvsp[-3].mtype))); } -#line 4651 "hexpr.parse.C" +#line 4742 "hexpr.parse.C" break; - case 302: /* tpred: "(" l1mtype "*" l1mtype ")" "=" l1mtype */ -#line 916 "hexpr.y" + case 311: /* tpred: "(" l1mtype "*" l1mtype ")" "=" l1mtype */ +#line 925 "hexpr.y" { (yyval.tconstraint) = new Constraint(RecordDeconstructor::constraintName(), list(tlong(0), tlong(1), *(yyvsp[0].mtype), freshTypeVar(), *(yyvsp[-5].mtype), *(yyvsp[-3].mtype))); } -#line 4657 "hexpr.parse.C" +#line 4748 "hexpr.parse.C" break; - case 303: /* tpred: l1mtype "." recfieldname "::" l1mtype */ -#line 918 "hexpr.y" + case 312: /* tpred: l1mtype "." recfieldname "::" l1mtype */ +#line 927 "hexpr.y" { (yyval.tconstraint) = HasField::newConstraint(HasField::Read, *(yyvsp[-4].mtype), TString::make(*(yyvsp[-2].string)), *(yyvsp[0].mtype)); } -#line 4663 "hexpr.parse.C" +#line 4754 "hexpr.parse.C" break; - case 304: /* tpred: l1mtype "." recfieldname "<-" l1mtype */ -#line 919 "hexpr.y" + case 313: /* tpred: l1mtype "." recfieldname "<-" l1mtype */ +#line 928 "hexpr.y" { (yyval.tconstraint) = HasField::newConstraint(HasField::Write, *(yyvsp[-4].mtype), TString::make(*(yyvsp[-2].string)), *(yyvsp[0].mtype)); } -#line 4669 "hexpr.parse.C" +#line 4760 "hexpr.parse.C" break; - case 305: /* tpred: l1mtype "/" l1mtype "::" l1mtype */ -#line 920 "hexpr.y" + case 314: /* tpred: l1mtype "/" l1mtype "::" l1mtype */ +#line 929 "hexpr.y" { (yyval.tconstraint) = HasField::newConstraint(HasField::Read, *(yyvsp[-4].mtype), *(yyvsp[-2].mtype), *(yyvsp[0].mtype)); } -#line 4675 "hexpr.parse.C" +#line 4766 "hexpr.parse.C" break; - case 306: /* tpred: l1mtype "/" l1mtype "<-" l1mtype */ -#line 921 "hexpr.y" + case 315: /* tpred: l1mtype "/" l1mtype "<-" l1mtype */ +#line 930 "hexpr.y" { (yyval.tconstraint) = HasField::newConstraint(HasField::Write, *(yyvsp[-4].mtype), *(yyvsp[-2].mtype), *(yyvsp[0].mtype)); } -#line 4681 "hexpr.parse.C" +#line 4772 "hexpr.parse.C" break; - case 307: /* tpred: l1mtype "=" "|" l1mtype "+" l1mtype "|" */ -#line 923 "hexpr.y" + case 316: /* tpred: l1mtype "=" "|" l1mtype "+" l1mtype "|" */ +#line 932 "hexpr.y" { (yyval.tconstraint) = new Constraint(VariantDeconstructor::constraintName(), list(tlong(1), *(yyvsp[-6].mtype), freshTypeVar(), *(yyvsp[-3].mtype), *(yyvsp[-1].mtype))); } -#line 4687 "hexpr.parse.C" +#line 4778 "hexpr.parse.C" break; - case 308: /* tpred: "|" l1mtype "+" l1mtype "|" "=" l1mtype */ -#line 924 "hexpr.y" + case 317: /* tpred: "|" l1mtype "+" l1mtype "|" "=" l1mtype */ +#line 933 "hexpr.y" { (yyval.tconstraint) = new Constraint(VariantDeconstructor::constraintName(), list(tlong(0), *(yyvsp[0].mtype), freshTypeVar(), *(yyvsp[-5].mtype), *(yyvsp[-3].mtype))); } -#line 4693 "hexpr.parse.C" +#line 4784 "hexpr.parse.C" break; - case 309: /* tpred: l1mtype "=" "|" id ":" l1mtype "+" l1mtype "|" */ -#line 925 "hexpr.y" + case 318: /* tpred: l1mtype "=" "|" id ":" l1mtype "+" l1mtype "|" */ +#line 934 "hexpr.y" { (yyval.tconstraint) = new Constraint(VariantDeconstructor::constraintName(), list(tlong(1), *(yyvsp[-8].mtype), TVar::make(*(yyvsp[-5].string)), *(yyvsp[-3].mtype), *(yyvsp[-1].mtype))); } -#line 4699 "hexpr.parse.C" +#line 4790 "hexpr.parse.C" break; - case 310: /* tpred: "|" id ":" l1mtype "+" l1mtype "|" "=" l1mtype */ -#line 926 "hexpr.y" + case 319: /* tpred: "|" id ":" l1mtype "+" l1mtype "|" "=" l1mtype */ +#line 935 "hexpr.y" { (yyval.tconstraint) = new Constraint(VariantDeconstructor::constraintName(), list(tlong(0), *(yyvsp[0].mtype), TVar::make(*(yyvsp[-7].string)), *(yyvsp[-5].mtype), *(yyvsp[-3].mtype))); } -#line 4705 "hexpr.parse.C" +#line 4796 "hexpr.parse.C" break; - case 311: /* tpred: "|" id ":" l0mtype "|" "::" l1mtype */ -#line 928 "hexpr.y" + case 320: /* tpred: "|" id ":" l0mtype "|" "::" l1mtype */ +#line 937 "hexpr.y" { (yyval.tconstraint) = new Constraint(CtorVerifier::constraintName(), list(*(yyvsp[0].mtype), TString::make(*(yyvsp[-5].string)), *(yyvsp[-3].mtype))); } -#line 4711 "hexpr.parse.C" +#line 4802 "hexpr.parse.C" break; - case 312: /* tpred: "|" l1mtype "/" l0mtype "|" "::" l1mtype */ -#line 929 "hexpr.y" + case 321: /* tpred: "|" l1mtype "/" l0mtype "|" "::" l1mtype */ +#line 938 "hexpr.y" { (yyval.tconstraint) = new Constraint(CtorVerifier::constraintName(), list(*(yyvsp[0].mtype), *(yyvsp[-5].mtype), *(yyvsp[-3].mtype))); } -#line 4717 "hexpr.parse.C" +#line 4808 "hexpr.parse.C" break; - case 313: /* tpred: l1mtype "++" l1mtype "=" l1mtype */ -#line 930 "hexpr.y" + case 322: /* tpred: l1mtype "++" l1mtype "=" l1mtype */ +#line 939 "hexpr.y" { (yyval.tconstraint) = new Constraint(AppendsToUnqualifier::constraintName(), list(*(yyvsp[-4].mtype), *(yyvsp[-2].mtype), *(yyvsp[0].mtype))); } -#line 4723 "hexpr.parse.C" +#line 4814 "hexpr.parse.C" break; - case 314: /* l1mtargl: l1mtype */ -#line 932 "hexpr.y" + case 323: /* l1mtargl: l1mtype */ +#line 941 "hexpr.y" { (yyval.mtypes) = autorelease(new MonoTypes()); (yyval.mtypes)->push_back(*(yyvsp[0].mtype)); } -#line 4729 "hexpr.parse.C" +#line 4820 "hexpr.parse.C" break; - case 315: /* l1mtargl: l1mtargl l1mtype */ -#line 933 "hexpr.y" + case 324: /* l1mtargl: l1mtargl l1mtype */ +#line 942 "hexpr.y" { (yyvsp[-1].mtypes)->push_back(*(yyvsp[0].mtype)); (yyval.mtypes) = (yyvsp[-1].mtypes); } -#line 4735 "hexpr.parse.C" +#line 4826 "hexpr.parse.C" break; - case 316: /* ltmtype: ltmtype l0mtype */ -#line 935 "hexpr.y" + case 325: /* ltmtype: ltmtype l0mtype */ +#line 944 "hexpr.y" { (yyval.mtypes) = (yyvsp[-1].mtypes); (yyval.mtypes)->push_back(*(yyvsp[0].mtype)); } -#line 4741 "hexpr.parse.C" +#line 4832 "hexpr.parse.C" break; - case 317: /* ltmtype: l0mtype */ -#line 936 "hexpr.y" + case 326: /* ltmtype: l0mtype */ +#line 945 "hexpr.y" { (yyval.mtypes) = autorelease(new MonoTypes()); (yyval.mtypes)->push_back(*(yyvsp[0].mtype)); } -#line 4747 "hexpr.parse.C" +#line 4838 "hexpr.parse.C" break; - case 318: /* l0mtype: l0mtargl "->" l1mtype */ -#line 938 "hexpr.y" + case 327: /* l0mtype: l0mtargl "->" l1mtype */ +#line 947 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(Func::make(tuplety(*(yyvsp[-2].mtypes)), *(yyvsp[0].mtype)))); } -#line 4753 "hexpr.parse.C" +#line 4844 "hexpr.parse.C" break; - case 319: /* l0mtype: mtuplist */ -#line 939 "hexpr.y" + case 328: /* l0mtype: mtuplist */ +#line 948 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(makeTupleType(*(yyvsp[0].mtypes)))); } -#line 4759 "hexpr.parse.C" +#line 4850 "hexpr.parse.C" break; - case 320: /* l0mtype: msumlist */ -#line 940 "hexpr.y" + case 329: /* l0mtype: msumlist */ +#line 949 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(makeSumType(*(yyvsp[0].mtypes)))); } -#line 4765 "hexpr.parse.C" +#line 4856 "hexpr.parse.C" break; - case 321: /* l1mtype: id */ -#line 942 "hexpr.y" + case 330: /* l1mtype: id */ +#line 951 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(monoTypeByName(*(yyvsp[0].string)))); } -#line 4771 "hexpr.parse.C" +#line 4862 "hexpr.parse.C" break; - case 322: /* l1mtype: "<" cppid ">" */ -#line 943 "hexpr.y" + case 331: /* l1mtype: "<" cppid ">" */ +#line 952 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(OpaquePtr::make(str::replace(*(yyvsp[-1].string), ".", "::"), 0, false))); } -#line 4777 "hexpr.parse.C" +#line 4868 "hexpr.parse.C" break; - case 323: /* l1mtype: "[" "]" */ -#line 944 "hexpr.y" + case 332: /* l1mtype: "[" "]" */ +#line 953 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(Prim::make("[]"))); } -#line 4783 "hexpr.parse.C" +#line 4874 "hexpr.parse.C" break; - case 324: /* l1mtype: "[" ltmtype "]" */ -#line 945 "hexpr.y" + case 333: /* l1mtype: "[" ltmtype "]" */ +#line 954 "hexpr.y" { try { (yyval.mtype) = autorelease(new MonoTypePtr(Array::make(yyParseCC->replaceTypeAliases(accumTApp(*(yyvsp[-1].mtypes)))))); } catch (std::exception& ex) { throw annotated_error(m((yylsp[-1])), ex.what()); } } -#line 4789 "hexpr.parse.C" +#line 4880 "hexpr.parse.C" break; - case 325: /* l1mtype: "[" ":" l0mtype "|" tyind ":" "]" */ -#line 946 "hexpr.y" + case 334: /* l1mtype: "[" ":" l0mtype "|" tyind ":" "]" */ +#line 955 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(FixedArray::make(*(yyvsp[-4].mtype), *(yyvsp[-2].mtype)))); } -#line 4795 "hexpr.parse.C" +#line 4886 "hexpr.parse.C" break; - case 326: /* l1mtype: "(" "->" ")" */ -#line 947 "hexpr.y" + case 335: /* l1mtype: "(" "->" ")" */ +#line 956 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(Prim::make("->"))); } -#line 4801 "hexpr.parse.C" +#line 4892 "hexpr.parse.C" break; - case 327: /* l1mtype: "(" ltmtype ")" */ -#line 948 "hexpr.y" + case 336: /* l1mtype: "(" ltmtype ")" */ +#line 957 "hexpr.y" { try { (yyval.mtype) = autorelease(new MonoTypePtr(clone(yyParseCC->replaceTypeAliases(accumTApp(*(yyvsp[-1].mtypes)))))); } catch (std::exception& ex) { throw annotated_error(m((yylsp[-1])), ex.what()); } } -#line 4807 "hexpr.parse.C" +#line 4898 "hexpr.parse.C" break; - case 328: /* l1mtype: "{" mreclist "}" */ -#line 949 "hexpr.y" + case 337: /* l1mtype: "{" mreclist "}" */ +#line 958 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(makeRecType(*(yyvsp[-1].mreclist)))); } -#line 4813 "hexpr.parse.C" +#line 4904 "hexpr.parse.C" break; - case 329: /* l1mtype: "|" mvarlist "|" */ -#line 950 "hexpr.y" + case 338: /* l1mtype: "|" mvarlist "|" */ +#line 959 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(makeVarType(*(yyvsp[-1].mvarlist)))); } -#line 4819 "hexpr.parse.C" +#line 4910 "hexpr.parse.C" break; - case 330: /* l1mtype: "(" ")" */ -#line 951 "hexpr.y" + case 339: /* l1mtype: "(" ")" */ +#line 960 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(Prim::make("unit"))); } -#line 4825 "hexpr.parse.C" +#line 4916 "hexpr.parse.C" break; - case 331: /* l1mtype: "intV" */ -#line 952 "hexpr.y" + case 340: /* l1mtype: "intV" */ +#line 961 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(((yyvsp[0].intv) == 0) ? Prim::make("void") : TLong::make((yyvsp[0].intv)))); } -#line 4831 "hexpr.parse.C" +#line 4922 "hexpr.parse.C" break; - case 332: /* l1mtype: "boolV" */ -#line 953 "hexpr.y" + case 341: /* l1mtype: "boolV" */ +#line 962 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr((yyvsp[0].boolv) ? TLong::make(1) : TLong::make(0))); } -#line 4837 "hexpr.parse.C" +#line 4928 "hexpr.parse.C" break; - case 333: /* l1mtype: "exists" id "." l1mtype */ -#line 954 "hexpr.y" + case 342: /* l1mtype: "exists" id "." l1mtype */ +#line 963 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(Exists::make(*(yyvsp[-2].string), *(yyvsp[0].mtype)))); } -#line 4843 "hexpr.parse.C" +#line 4934 "hexpr.parse.C" break; - case 334: /* l1mtype: l1mtype "@" l1mtype */ -#line 955 "hexpr.y" + case 343: /* l1mtype: l1mtype "@" l1mtype */ +#line 964 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(fileRefTy(*(yyvsp[-2].mtype), *(yyvsp[0].mtype)))); } -#line 4849 "hexpr.parse.C" +#line 4940 "hexpr.parse.C" break; - case 335: /* l1mtype: l1mtype "@" "?" */ -#line 956 "hexpr.y" + case 344: /* l1mtype: l1mtype "@" "?" */ +#line 965 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(fileRefTy(*(yyvsp[-2].mtype)))); } -#line 4855 "hexpr.parse.C" +#line 4946 "hexpr.parse.C" break; - case 336: /* l1mtype: "^" id "." l1mtype */ -#line 957 "hexpr.y" + case 345: /* l1mtype: "^" id "." l1mtype */ +#line 966 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(Recursive::make(*(yyvsp[-2].string), *(yyvsp[0].mtype)))); } -#line 4861 "hexpr.parse.C" +#line 4952 "hexpr.parse.C" break; - case 337: /* l1mtype: "stringV" */ -#line 958 "hexpr.y" + case 346: /* l1mtype: "stringV" */ +#line 967 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(TString::make(str::unescape(str::trimq(*(yyvsp[0].string)))))); } -#line 4867 "hexpr.parse.C" +#line 4958 "hexpr.parse.C" break; - case 338: /* l1mtype: "`" l0expr "`" */ -#line 959 "hexpr.y" + case 347: /* l1mtype: "`" l0expr "`" */ +#line 968 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(TApp::make(primty("quote"), list(texpr(ExprPtr((yyvsp[-1].exp))))))); } -#line 4873 "hexpr.parse.C" +#line 4964 "hexpr.parse.C" break; - case 339: /* tyind: id */ -#line 961 "hexpr.y" + case 348: /* tyind: id */ +#line 970 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(TVar::make(*(yyvsp[0].string)))); } -#line 4879 "hexpr.parse.C" +#line 4970 "hexpr.parse.C" break; - case 340: /* tyind: "intV" */ -#line 962 "hexpr.y" + case 349: /* tyind: "intV" */ +#line 971 "hexpr.y" { (yyval.mtype) = autorelease(new MonoTypePtr(TLong::make((yyvsp[0].intv)))); } -#line 4885 "hexpr.parse.C" +#line 4976 "hexpr.parse.C" break; - case 341: /* cppid: id */ -#line 964 "hexpr.y" + case 350: /* cppid: id */ +#line 973 "hexpr.y" { (yyval.string) = (yyvsp[0].string); } -#line 4891 "hexpr.parse.C" +#line 4982 "hexpr.parse.C" break; - case 342: /* cppid: cppid "." id */ -#line 965 "hexpr.y" + case 351: /* cppid: cppid "." id */ +#line 974 "hexpr.y" { (yyval.string) = (yyvsp[-2].string); *(yyval.string) += "."; *(yyval.string) += *(yyvsp[0].string); } -#line 4897 "hexpr.parse.C" +#line 4988 "hexpr.parse.C" break; - case 343: /* l0mtargl: l1mtype */ -#line 967 "hexpr.y" + case 352: /* l0mtargl: l1mtype */ +#line 976 "hexpr.y" { (yyval.mtypes) = autorelease(new MonoTypes()); (yyval.mtypes)->push_back(*(yyvsp[0].mtype)); } -#line 4903 "hexpr.parse.C" +#line 4994 "hexpr.parse.C" break; - case 344: /* l0mtargl: "(" l0mtype "," l0mtarglt ")" */ -#line 968 "hexpr.y" + case 353: /* l0mtargl: "(" l0mtype "," l0mtarglt ")" */ +#line 977 "hexpr.y" { (yyvsp[-1].mtypes)->insert((yyvsp[-1].mtypes)->begin(), *(yyvsp[-3].mtype)); (yyval.mtypes) = (yyvsp[-1].mtypes); } -#line 4909 "hexpr.parse.C" +#line 5000 "hexpr.parse.C" break; - case 345: /* l0mtarglt: l0mtype */ -#line 970 "hexpr.y" + case 354: /* l0mtarglt: l0mtype */ +#line 979 "hexpr.y" { (yyval.mtypes) = autorelease(new MonoTypes()); (yyval.mtypes)->push_back(*(yyvsp[0].mtype)); } -#line 4915 "hexpr.parse.C" +#line 5006 "hexpr.parse.C" break; - case 346: /* l0mtarglt: l0mtarglt "," l0mtype */ -#line 971 "hexpr.y" + case 355: /* l0mtarglt: l0mtarglt "," l0mtype */ +#line 980 "hexpr.y" { (yyvsp[-2].mtypes)->push_back(*(yyvsp[0].mtype)); (yyval.mtypes) = (yyvsp[-2].mtypes); } -#line 4921 "hexpr.parse.C" +#line 5012 "hexpr.parse.C" break; - case 347: /* mtuplist: l1mtype */ -#line 973 "hexpr.y" + case 356: /* mtuplist: l1mtype */ +#line 982 "hexpr.y" { (yyval.mtypes) = autorelease(new MonoTypes()); (yyval.mtypes)->push_back(*(yyvsp[0].mtype)); } -#line 4927 "hexpr.parse.C" +#line 5018 "hexpr.parse.C" break; - case 348: /* mtuplist: mtuplist "*" l1mtype */ -#line 974 "hexpr.y" + case 357: /* mtuplist: mtuplist "*" l1mtype */ +#line 983 "hexpr.y" { (yyval.mtypes) = (yyvsp[-2].mtypes); (yyval.mtypes)->push_back(*(yyvsp[0].mtype)); } -#line 4933 "hexpr.parse.C" +#line 5024 "hexpr.parse.C" break; - case 349: /* msumlist: l1mtype "+" l1mtype */ -#line 976 "hexpr.y" + case 358: /* msumlist: l1mtype "+" l1mtype */ +#line 985 "hexpr.y" { (yyval.mtypes) = autorelease(new MonoTypes()); (yyval.mtypes)->push_back(*(yyvsp[-2].mtype)); (yyval.mtypes)->push_back(*(yyvsp[0].mtype)); } -#line 4939 "hexpr.parse.C" +#line 5030 "hexpr.parse.C" break; - case 350: /* msumlist: msumlist "+" l1mtype */ -#line 977 "hexpr.y" + case 359: /* msumlist: msumlist "+" l1mtype */ +#line 986 "hexpr.y" { (yyval.mtypes) = (yyvsp[-2].mtypes); (yyval.mtypes)->push_back(*(yyvsp[0].mtype)); } -#line 4945 "hexpr.parse.C" +#line 5036 "hexpr.parse.C" break; - case 351: /* mreclist: mreclist "," id ":" l0mtype */ -#line 979 "hexpr.y" + case 360: /* mreclist: mreclist "," id ":" l0mtype */ +#line 988 "hexpr.y" { (yyval.mreclist) = (yyvsp[-4].mreclist); (yyval.mreclist)->push_back(Record::Member(*(yyvsp[-2].string), *(yyvsp[0].mtype))); } -#line 4951 "hexpr.parse.C" +#line 5042 "hexpr.parse.C" break; - case 352: /* mreclist: id ":" l0mtype */ -#line 980 "hexpr.y" + case 361: /* mreclist: id ":" l0mtype */ +#line 989 "hexpr.y" { (yyval.mreclist) = autorelease(new Record::Members()); (yyval.mreclist)->push_back(Record::Member(*(yyvsp[-2].string), *(yyvsp[0].mtype))); } -#line 4957 "hexpr.parse.C" +#line 5048 "hexpr.parse.C" break; - case 353: /* mvarlist: mvarlist "," id ":" l0mtype */ -#line 982 "hexpr.y" + case 362: /* mvarlist: mvarlist "," id ":" l0mtype */ +#line 991 "hexpr.y" { (yyval.mvarlist) = (yyvsp[-4].mvarlist); (yyval.mvarlist)->push_back(Variant::Member(*(yyvsp[-2].string), *(yyvsp[0].mtype), 0)); } -#line 4963 "hexpr.parse.C" +#line 5054 "hexpr.parse.C" break; - case 354: /* mvarlist: mvarlist "," id */ -#line 983 "hexpr.y" + case 363: /* mvarlist: mvarlist "," id */ +#line 992 "hexpr.y" { (yyval.mvarlist) = (yyvsp[-2].mvarlist); (yyval.mvarlist)->push_back(Variant::Member(*(yyvsp[0].string), Prim::make("unit"), 0)); } -#line 4969 "hexpr.parse.C" +#line 5060 "hexpr.parse.C" break; - case 355: /* mvarlist: id ":" l0mtype */ -#line 984 "hexpr.y" + case 364: /* mvarlist: id ":" l0mtype */ +#line 993 "hexpr.y" { (yyval.mvarlist) = autorelease(new Variant::Members()); (yyval.mvarlist)->push_back(Variant::Member(*(yyvsp[-2].string), *(yyvsp[0].mtype), 0)); } -#line 4975 "hexpr.parse.C" +#line 5066 "hexpr.parse.C" break; - case 356: /* mvarlist: id */ -#line 985 "hexpr.y" + case 365: /* mvarlist: id */ +#line 994 "hexpr.y" { (yyval.mvarlist) = autorelease(new Variant::Members()); (yyval.mvarlist)->push_back(Variant::Member(*(yyvsp[0].string), Prim::make("unit"), 0)); } -#line 4981 "hexpr.parse.C" +#line 5072 "hexpr.parse.C" break; -#line 4985 "hexpr.parse.C" +#line 5076 "hexpr.parse.C" default: break; } @@ -5211,7 +5302,7 @@ yyreturn: return yyresult; } -#line 989 "hexpr.y" +#line 998 "hexpr.y" #pragma GCC diagnostic pop diff --git a/lib/hobbes/read/pgen/hexpr.y b/lib/hobbes/read/pgen/hexpr.y index 4cbfe7bce..6284c0a4d 100644 --- a/lib/hobbes/read/pgen/hexpr.y +++ b/lib/hobbes/read/pgen/hexpr.y @@ -518,6 +518,15 @@ def: importdef { $$ = $1; } | id id id id id id id id id id "=" l0expr { $$ = new MVarDef(list(*$1, *$2, *$3, *$4, *$5, *$6, *$7, *$8, *$9, *$10), ExprPtr($12), m(@1, @12)); } | id id id id id id id id id id id "=" l0expr { $$ = new MVarDef(list(*$1, *$2, *$3, *$4, *$5, *$6, *$7, *$8, *$9, *$10, *$11), ExprPtr($13), m(@1, @13)); } | id id id id id id id id id id id id "=" l0expr { $$ = new MVarDef(list(*$1, *$2, *$3, *$4, *$5, *$6, *$7, *$8, *$9, *$10, *$11, *$12), ExprPtr($14), m(@1, @14)); } + | id id id id id id id id id id id id id "=" l0expr { $$ = new MVarDef(list(*$1, *$2, *$3, *$4, *$5, *$6, *$7, *$8, *$9, *$10, *$11, *$12, *$13), ExprPtr($15), m(@1, @15)); } + | id id id id id id id id id id id id id id "=" l0expr { $$ = new MVarDef(list(*$1, *$2, *$3, *$4, *$5, *$6, *$7, *$8, *$9, *$10, *$11, *$12, *$13, *$14), ExprPtr($16), m(@1, @16)); } + | id id id id id id id id id id id id id id id "=" l0expr { $$ = new MVarDef(list(*$1, *$2, *$3, *$4, *$5, *$6, *$7, *$8, *$9, *$10, *$11, *$12, *$13, *$14, *$15), ExprPtr($17), m(@1, @17)); } + | id id id id id id id id id id id id id id id id "=" l0expr { $$ = new MVarDef(list(*$1, *$2, *$3, *$4, *$5, *$6, *$7, *$8, *$9, *$10, *$11, *$12, *$13, *$14, *$15, *$16), ExprPtr($18), m(@1, @18)); } + | id id id id id id id id id id id id id id id id id "=" l0expr { $$ = new MVarDef(list(*$1, *$2, *$3, *$4, *$5, *$6, *$7, *$8, *$9, *$10, *$11, *$12, *$13, *$14, *$15, *$16, *$17), ExprPtr($19), m(@1, @19)); } + | id id id id id id id id id id id id id id id id id id "=" l0expr { $$ = new MVarDef(list(*$1, *$2, *$3, *$4, *$5, *$6, *$7, *$8, *$9, *$10, *$11, *$12, *$13, *$14, *$15, *$16, *$17, *$18), ExprPtr($20), m(@1, @20)); } + | id id id id id id id id id id id id id id id id id id id "=" l0expr { $$ = new MVarDef(list(*$1, *$2, *$3, *$4, *$5, *$6, *$7, *$8, *$9, *$10, *$11, *$12, *$13, *$14, *$15, *$16, *$17, *$18, *$19), ExprPtr($21), m(@1, @21)); } + | id id id id id id id id id id id id id id id id id id id id "=" l0expr { $$ = new MVarDef(list(*$1, *$2, *$3, *$4, *$5, *$6, *$7, *$8, *$9, *$10, *$11, *$12, *$13, *$14, *$15, *$16, *$17, *$18, *$19, *$20), ExprPtr($22), m(@1, @22)); } + | id id id id id id id id id id id id id id id id id id id id id "=" l0expr { $$ = new MVarDef(list(*$1, *$2, *$3, *$4, *$5, *$6, *$7, *$8, *$9, *$10, *$11, *$12, *$13, *$14, *$15, *$16, *$17, *$18, *$19, *$20, *$21), ExprPtr($23), m(@1, @23)); } // evaluate an expression just for side-effects, then discard it | l5expr { $$ = new MVarDef(list(freshName()), let(freshName(), ExprPtr($1), mktunit(m(@1)), m(@1)), m(@1)); } From d3e2a51e12fbed2c37da4f063ed2603806ab279e Mon Sep 17 00:00:00 2001 From: Mo Xiaoming <2188767+mo-xiaoming@users.noreply.github.com> Date: Wed, 11 Aug 2021 19:38:36 +0000 Subject: [PATCH 13/40] add address and undefined sanitizers to github action (#417) * add address and undefined sanitizers to github action * fix Python.C failed under sanitizers check * get sanitizers check clang build only * minor fixes in build files * suppress reflect.H ubsan error * disable implicit-signed-integer-truncation check, integaral promotion causes too many failures in current code base * get address of a null pointer is not allowed, using offsetof instead * replace hobbes::variant in jitcc.C --- .github/workflows/build.yml | 29 ++++++ CMakeLists.txt | 15 ++- flake.nix | 4 +- include/hobbes/fregion.H | 3 + lib/hobbes/eval/jitcc.C | 188 +++++++++++++++++++++++++++++++++++- nix/overlays.nix | 36 ++++++- nix/ubsan_supp.patch | 24 +++++ test/Structs.C | 9 +- 8 files changed, 299 insertions(+), 9 deletions(-) create mode 100644 nix/ubsan_supp.patch diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2cea80578..c9dfc1de8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,35 @@ name: "Build" on: [push, pull_request] jobs: + linux-clang-ASanAndUBSan-build: + runs-on: ${{matrix.os}} + strategy: + matrix: + os: [ubuntu-20.04] + clang: [8] + steps: + - uses: actions/checkout@v2 + with: + # Nix Flakes doesn't work on shallow clones + fetch-depth: 0 + - uses: cachix/install-nix-action@v12 + with: + install_url: https://github.com/numtide/nix-flakes-installer/releases/download/nix-2.4pre20201221_9fab14a/install + extra_nix_config: | + experimental-features = nix-command flakes ca-references + - name: nix build hobbesPackages/clang-${{ matrix.clang }}-ASanAndUBSan/hobbes + run: | + nix build .#hobbesPackages/clang-${{ matrix.clang }}-ASanAndUBSan/hobbes + - name: nix log hobbesPackages/clang-${{ matrix.clang }}-ASanAndUBSan/hobbes + if: ${{ always() }} + run: | + nix log .#hobbesPackages/clang-${{ matrix.clang }}-ASanAndUBSan/hobbes &> ${{ matrix.os }}-clang-${{ matrix.clang }}-ASanAndUBSan-hobbes.log + - name: upload log ${{ matrix.os }}-clang-${{ matrix.clang }}-ASanAndUBSan-hobbes.log + if: ${{ always() }} + uses: actions/upload-artifact@v1 + with: + name: output-log-file + path: ${{ matrix.os }}-clang-${{ matrix.clang }}-ASanAndUBSan-hobbes.log linux-clang-build: runs-on: ${{matrix.os}} strategy: diff --git a/CMakeLists.txt b/CMakeLists.txt index dc8b250d6..10b30a169 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,6 +81,19 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${cxx_flags}") set(CMAKE_CXX_FLAGS_DEBUG "-g") set(CMAKE_CXX_FLAGS_RELEASE "-O2") +option(USE_ASAN_UBSAN "Use address,undefined sanitizers" OFF) +if(USE_ASAN_AND_UBSAN) + # _FORTIFY_SOURCE doesn't play well with asan + # https://github.com/google/sanitizers/issues/247 + add_definitions(-U_FORTIFY_SOURCE) + add_compile_options("-fno-omit-frame-pointer;-fsanitize=address,undefined;-fno-optimize-sibling-calls;-fno-sanitize-recover=all") + add_link_options("-fsanitize=address,undefined;-fno-optimize-sibling-calls;-fno-sanitize-recover=all") + add_compile_options("$<$,$>:-fsanitize=local-bounds,float-divide-by-zero,nullability,signed-integer-overflow,shift,integer-divide-by-zero>") + add_link_options("$<$,$>:-fsanitize=local-bounds,float-divide-by-zero,nullability,signed-integer-overflow,shift,integer-divide-by-zero>") + add_compile_options("$<$:--param=max-vartrack-size=60000000>") + message(STATUS "address and undefined sanitizers enabled") +endif() + add_library(hobbes STATIC ${lib_files}) target_link_libraries(hobbes PUBLIC ${llvm_ldflags} ${llvm_libs} ${ZLIB_LIBRARIES} ${CURSES_LIBRARIES} ${sys_libs}) add_library(hobbes-pic STATIC ${lib_files}) @@ -96,7 +109,7 @@ enable_testing() add_executable(hobbes-test ${test_files}) target_link_libraries(hobbes-test PRIVATE hobbes) add_test(hobbes-test hobbes-test) -include(FindPythonInterp) +find_package(PythonInterp 2.7 REQUIRED) set_property(TARGET hobbes-test PROPERTY COMPILE_FLAGS "-DPYTHON_EXECUTABLE=\"${PYTHON_EXECUTABLE}\" -DSCRIPT_DIR=\"${CMAKE_SOURCE_DIR}/scripts/\"") install(TARGETS hobbes hobbes-pic DESTINATION "lib") diff --git a/flake.nix b/flake.nix index ffc7d13b6..8b9ab9903 100644 --- a/flake.nix +++ b/flake.nix @@ -1,6 +1,6 @@ { description = "A language and an embedded JIT compiler"; - + inputs.flake-utils.url = "github:numtide/flake-utils"; outputs = { self, nixpkgs, flake-utils }: @@ -20,7 +20,7 @@ ]; }) ]; - + pkgs = import nixpkgs { inherit system overlays; }; diff --git a/include/hobbes/fregion.H b/include/hobbes/fregion.H index 24a4b8988..b507fd0c8 100644 --- a/include/hobbes/fregion.H +++ b/include/hobbes/fregion.H @@ -262,6 +262,9 @@ template } template inline void writes(imagefile* f, TIter begin, TIter end) { + if (begin == end) { + return; + } fdwrite(f, reinterpret_cast(&(*begin)), (end - begin) * sizeof(*begin)); } inline void write(imagefile* f, const std::string& x) { diff --git a/lib/hobbes/eval/jitcc.C b/lib/hobbes/eval/jitcc.C index 6bc76d480..e8caf497a 100644 --- a/lib/hobbes/eval/jitcc.C +++ b/lib/hobbes/eval/jitcc.C @@ -26,6 +26,13 @@ #if LLVM_VERSION_MAJOR >= 11 #include + +#include +#include +#include +#include +#include +#include #else #if LLVM_VERSION_MINOR == 3 or LLVM_VERSION_MINOR == 5 #include @@ -49,6 +56,181 @@ #if LLVM_VERSION_MAJOR >= 11 namespace { +template struct hasType { + static constexpr bool value = false; +}; + +template struct hasType { + static constexpr bool value = + std::is_same::value || hasType::value; +}; + +template struct hasDuplication { + static constexpr bool value = false; +}; + +template struct hasDuplication { + static constexpr bool value = + hasType::value || hasDuplication::value; +}; + +template struct IndexByType; + +template struct IndexByType { + static constexpr int value = 0; +}; + +template +struct IndexByType { + static constexpr int value = 1 + IndexByType::value; +}; + +template struct VariantLiteTypeMatch { + static bool act(std::size_t, std::size_t) { return false; } +}; + +template +struct VariantLiteTypeMatch { + static bool act(std::size_t N, std::size_t tag) { + if (tag == (N - sizeof...(Ts) - 1U)) { + return std::is_same::value; + } else { + return VariantLiteTypeMatch::act(N, tag); + } + } +}; + +template struct VariantLiteDeletor { + static void act(std::size_t, std::size_t, void *) {} +}; + +template struct VariantLiteDeletor { + static void act(std::size_t N, std::size_t tag, void *storage) { + if (tag == (N - sizeof...(Ts) - 1)) { + reinterpret_cast(storage)->~T(); + } else { + VariantLiteDeletor::act(N, tag, storage); + } + } +}; + +template struct VariantLiteCopyCreator { + static void act(std::size_t, std::size_t, void *, const void *) {} +}; + +template struct VariantLiteCopyCreator { + static void act(std::size_t N, std::size_t other_tag, void *this_storage, + const void *other_storage) { + if (other_tag == (N - sizeof...(Ts) - 1)) { + new (this_storage) T(*reinterpret_cast(other_storage)); + } else { + VariantLiteCopyCreator::act(N, other_tag, this_storage, + other_storage); + } + } +}; + +template struct VariantLiteMoveCreator { + static void act(std::size_t, std::size_t, void *, const void *) {} +}; + +template struct VariantLiteMoveCreator { + static void act(std::size_t N, std::size_t other_tag, void *this_storage, + const void *other_storage) { + if (other_tag == (N - sizeof...(Ts) - 1)) { + new (this_storage) + T(std::move(*reinterpret_cast(other_storage))); + } else { + VariantLiteMoveCreator::act(N, other_tag, this_storage, + other_storage); + } + } +}; + +template struct VariantLite { + static constexpr std::size_t N = sizeof...(Ts); + + static_assert(N > 0, ""); + static_assert(not hasDuplication::value, ""); + + VariantLite() = default; + + template VariantLite(T t) { + static_assert(hasType::value, ""); + new (&storage) T(std::move(t)); + tag = IndexByType::value; + } + + VariantLite(const VariantLite &rhs) { + tag = rhs.tag; + if (isValid()) { + VariantLiteCopyCreator::act(N, rhs.tag, &storage, &rhs.storage); + } + } + + VariantLite &operator=(const VariantLite &rhs) & { + if (isValid()) { + VariantLiteDeletor::act(N, tag, &storage); + } + tag = rhs.tag; + if (isValid()) { + VariantLiteCopyCreator::act(N, rhs.tag, &storage, &rhs.storage); + } + return *this; + } + + VariantLite(VariantLite &&rhs) { + tag = rhs.tag; + if (isValid()) { + VariantLiteMoveCreator::act(N, rhs.tag, &storage, &rhs.storage); + } + } + + VariantLite &operator=(VariantLite &&rhs) & { + if (isValid()) { + VariantLiteDeletor::act(N, tag, &storage); + } + tag = rhs.tag; + if (isValid()) { + VariantLiteMoveCreator::act(N, rhs.tag, &storage, &rhs.storage); + } + return *this; + } + + template VariantLite &operator=(T t) { + static_assert(hasType::value, ""); + if (isValid()) { + VariantLiteDeletor::act(N, tag, &storage); + } + new (&storage) T(std::move(t)); + tag = IndexByType::value; + return *this; + } + + ~VariantLite() { + if (isValid()) { + VariantLiteDeletor::act(N, tag, &storage); + } + } + + bool isValid() const { return tag != InvalidTag; } + + template T *get() { + static_assert(hasType::value, ""); + if (isValid() && VariantLiteTypeMatch::act(N, tag)) { + return reinterpret_cast(&storage); + } + return nullptr; + } + +private: + static constexpr std::size_t InvalidTag = + std::numeric_limits::max(); + + std::aligned_union_t<0, Ts...> storage; + std::size_t tag = InvalidTag; +}; + LLVM_NODISCARD llvm::Function *createFnDecl(llvm::Function *f, llvm::Module &m, llvm::StringRef name) { if (f->getReturnType() == hobbes::boolType()) { @@ -86,7 +268,7 @@ class ConstantList { struct Constant { // function is a constant // globalvariable returned by a function - variant value; + VariantLite value; Ty ty = Ty::Other; }; llvm::StringMap constants; @@ -181,7 +363,7 @@ public: using FnDeclFnTy = std::function; private: - using ValOrFnTy = variant; + using ValOrFnTy = VariantLite; using VarBindingStack = llvm::SmallVector, 8>; VarBindingStack vtenv; @@ -255,7 +437,7 @@ class Globals { private: using FnDeclFnTy = std::function; using VarDeclFnTy = std::function; - llvm::StringMap> globals; + llvm::StringMap> globals; LLVM_NODISCARD bool isFunc(decltype(globals)::iterator it) const { return it->second.get() != nullptr; diff --git a/nix/overlays.nix b/nix/overlays.nix index 813e97a95..0061ae020 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -16,7 +16,7 @@ let separateDebugInfo = debug; - meta = with stdenv.lib; { + meta = with lib; { description = "A language and an embedded JIT compiler"; longDescription = '' Hobbes is a language, embedded compiler, and runtime for efficient @@ -69,6 +69,34 @@ let ''; }); + withCLANGAsanAndUBSan = let + llvmPkgs = { llvmVersion }: + builtins.getAttr ("llvmPackages_" + (toString llvmVersion)) final; + in makeOverridable + ({ llvmVersion, stdenv ? (llvmPkgs { inherit llvmVersion; }).stdenv }: + stdenv.mkDerivation { + pname = "hobbes-clang-" + (toString llvmVersion) + "-ASanAndUBSan"; + inherit version src meta doCheck doTarget; + + patches = [ ./ubsan_supp.patch ]; + + dontStrip = true; + cmakeBuildType="Debug"; + cmakeFlags = [ + "-DUSE_ASAN_AND_UBSAN:BOOL=ON" + ]; + ninjaFlags = [ "-v" ]; + UBSAN_OPTIONS="print_stacktrace=1"; + ASAN_OPTIONS="detect_leaks=0:strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:use_odr_indicator=1"; + + nativeBuildInputs = nativeBuildInputs; + buildInputs = buildInputs ++ [ (llvmPkgs { inherit llvmVersion; }).llvm ]; + postPatch = '' + substituteInPlace CMakeLists.txt \ + --replace "\''${CMAKE_SOURCE_DIR}" "${src}" + ''; + }); + in { hobbesPackages = when stdenv.isLinux (recurseIntoAttrs (builtins.listToAttrs (builtins.map (gccConstraint: { @@ -89,5 +117,11 @@ in { value = recurseIntoAttrs ({ hobbes = dbg (callPackage withCLANG { inherit llvmVersion; }); }); + }) llvmVersions)) // recurseIntoAttrs (builtins.listToAttrs (builtins.map + (llvmVersion: { + name = "clang-" + toString llvmVersion + "-ASanAndUBSan"; + value = recurseIntoAttrs ({ + hobbes = (callPackage withCLANGAsanAndUBSan { inherit llvmVersion; }); + }); }) llvmVersions)); } diff --git a/nix/ubsan_supp.patch b/nix/ubsan_supp.patch new file mode 100644 index 000000000..dd5ca200b --- /dev/null +++ b/nix/ubsan_supp.patch @@ -0,0 +1,24 @@ +diff --git a/include/hobbes/reflect.H b/include/hobbes/reflect.H +index b575156..1b1132d 100644 +--- a/include/hobbes/reflect.H ++++ b/include/hobbes/reflect.H +@@ -526,6 +526,9 @@ template