/***** * runtime.in * Tom Prince 2005/4/15 * * Generate the runtime functions used by the vm::stack machine. * *****/ /* Autogenerated routines are specified like this (separated by a formfeed): type asyname:cname(cparams) { C code } */ // Use Void f() instead of void f() to force an explicit Stack argument. pen => primPen() pair => primPair() triple => primTriple() path => primPath() path3 => primPath3() guide* => primGuide() cycleToken => primCycleToken() tensionSpecifier => primTensionSpecifier() curlSpecifier => primCurlSpecifier() file* => primFile() picture* => primPicture() transform => primTransform() callable* => voidFunction() runnable* => primCode() boolarray* => booleanArray() Intarray* => IntArray() Intarray2* => IntArray2() realarray* => realArray() realarray2* => realArray2() pairarray* => pairArray() pairarray2* => pairArray2() triplearray* => tripleArray() triplearray2* => tripleArray2() patharray* => pathArray() patharray2* => pathArray2() guidearray* => guideArray() transformarray* => transformArray() penarray* => penArray() penarray2* => penArray2() stringarray* => stringArray() stringarray2* => stringArray2() #include #include #include #include #include #include #if !defined(_WIN32) #include #endif #include #include "angle.h" #include "pair.h" #include "triple.h" #include "transform.h" #include "path.h" #include "path3.h" #include "pen.h" #include "drawpath.h" #include "guide.h" #include "picture.h" #include "fileio.h" #include "genv.h" #include "builtin.h" #include "texfile.h" #include "pipestream.h" #include "asyparser.h" #include "stack.h" #include "util.h" #include "locate.h" #include "mathop.h" #include "callable.h" #include "stm.h" #include "lexical.h" #include "asyprocess.h" #include "arrayop.h" #include "seconds.h" #if defined(USEGC) && defined(GC_DEBUG) && defined(GC_BACKTRACE) extern "C" { void *GC_generate_random_valid_address(void); void GC_debug_print_heap_obj_proc(void *); } #endif using namespace vm; using namespace camp; using namespace settings; using namespace utils; #undef OUT #undef IN namespace run { using camp::pair; using vm::array; using vm::vmFrame; using vm::stack; using camp::transform; using absyntax::runnable; typedef array boolarray; typedef array Intarray; typedef array Intarray2; typedef array realarray; typedef array realarray2; typedef array pairarray; typedef array pairarray2; typedef array triplearray; typedef array triplearray2; typedef array patharray; typedef array patharray2; typedef array guidearray; typedef array transformarray; typedef array penarray; typedef array penarray2; typedef array stringarray; typedef array stringarray2; } using vm::array; using types::function; #define PRIMITIVE(name,Name,asyName) using types::prim##Name; #include #undef PRIMITIVE using types::booleanArray; using types::IntArray; using types::IntArray2; using types::realArray; using types::realArray2; using types::pairArray; using types::pairArray2; using types::tripleArray; using types::tripleArray2; using types::pathArray; using types::pathArray2; using types::guideArray; using types::transformArray; using types::penArray; using types::penArray2; using types::stringArray; using types::stringArray2; using types::formal; function *realRealFunction() { return new function(primReal(),primReal()); } function *realTripleFunction() { return new function(primReal(),primTriple()); } const size_t camp::ColorComponents[]={0,0,1,3,4,0}; namespace vm { #if COMPACT const Int DefaultValue=0x7fffffffffffffffLL; const Int Undefined=0x7ffffffffffffffeLL; const Int BoolTruthValue=0xABABABABABABABACLL; const Int BoolFalseValue=0xABABABABABABABABLL; const item Default=DefaultValue; #else const item Default=item(default_t()); #endif } namespace run { stopWatch wallClock; cpuTimer cpuTime; const char *arrayempty="cannot take min or max of empty array"; const char *noruntime="no runtime environment for embedded eval"; void writestring(stack *s) { callable *suffix=pop(s,NULL); string S=pop(s); vm::item it=pop(s); bool defaultfile=isdefault(it); camp::file *f=defaultfile ? &camp::Stdout : vm::get(it); if(!f->isOpen() || !f->enabled()) return; if(S != "") f->write(S); if(f->text()) { if(suffix) { s->push(f); suffix->call(s); } else if(defaultfile) f->writeline(); } } string toplocation() { ostringstream buf; position& topPos=processData().topPos; buf << topPos.Line() << "." << topPos.Column(); return buf.str(); } string emptystring; pair zero; } static string defaulttransparency=string("Compatible"); void unused(void *) { } // Autogenerated routines: // Initializers Int :IntZero() { return 0; } real :realZero() { return 0.0; } bool :boolFalse() { return false; } bool isnan(real x) { return std::isnan(x); } array* :pushNullArray() { return 0; } vmFrame* :pushNullRecord() { return 0; } item :pushNullFunction() { return nullfunc::instance(); } // Default operations // Put the default value token on the stack (in place of an argument when // making a function call). item :pushDefault() { return Default; } // Test if the value on the stack is the default value token. bool :isDefault(item i) { return isdefault(i); } // Casts guide* :pairToGuide(pair z) { return new pairguide(z); } guide* :pathToGuide(path p) { return new pathguide(p); } path :guideToPath(guide *g) { return g->solve(); } // Pen operations pen :newPen() { return pen(); } bool ==(pen a, pen b) { return a == b; } bool !=(pen a, pen b) { return a != b; } pen +(pen a, pen b) { return a+b; } pen Operator *(real a, pen b) { return a*b; } pen Operator *(pen a, real b) { return b*a; } pair max(pen p) { return p.bounds().Max(); } pair min(pen p) { return p.bounds().Min(); } // Reset the meaning of pen default attributes. void resetdefaultpen() { processData().defaultpen=camp::pen::initialpen(); } void defaultpen(pen p) { processData().defaultpen=pen(resolvepen,p); } pen defaultpen() { return processData().defaultpen; } bool invisible(pen p) { return p.invisible(); } pen invisible() { return pen(invisiblepen); } pen gray(pen p) { p.togrey(); return p; } pen rgb(pen p) { p.torgb(); return p; } pen cmyk(pen p) { p.tocmyk(); return p; } pen interp(pen a, pen b, real t) { return interpolate(a,b,t); } pen rgb(real r, real g, real b) { return pen(r,g,b); } pen cmyk(real c, real m, real y, real k) { return pen(c,m,y,k); } pen gray(real gray) { return pen(gray); } realarray *colors(pen p) { size_t n=ColorComponents[p.colorspace()]; array *a=new array(n); switch(n) { case 0: break; case 1: (*a)[0]=p.gray(); break; case 3: (*a)[0]=p.red(); (*a)[1]=p.green(); (*a)[2]=p.blue(); break; case 4: (*a)[0]=p.cyan(); (*a)[1]=p.magenta(); (*a)[2]=p.yellow(); (*a)[3]=p.black(); break; default: break; } return a; } string hex(pen p) { return p.hex(); } Int byte(real x) { return camp::byte(x); } real byteinv(Int x) { return x >= 0 ? camp::byteinv(x) : 0.0; } string colorspace(pen p) { string s=ColorDeviceSuffix[p.colorspace()]; std::transform(s.begin(),s.end(),s.begin(),tolower); return s; } pen pattern(string *s) { return pen(setpattern,*s); } string pattern(pen p) { return p.fillpattern(); } pen fillrule(Int n) { return pen(n >= 0 && n < nFill ? (FillRule) n : DEFFILL); } Int fillrule(pen p) { return p.Fillrule(); } pen opacity(real opacity=1.0, string blend=defaulttransparency) { for(Int i=0; i < nBlendMode; ++i) if(blend == BlendMode[i]) return pen(Transparency(blend,opacity)); ostringstream buf; buf << "Unknown blend mode: " << "'" << blend << "'"; error(buf); } real opacity(pen p) { return p.opacity(); } string blend(pen p) { return p.blend(); } pen linetype(realarray *pattern, real offset=0, bool scale=true, bool adjust=true) { size_t size=checkArray(pattern); array *a=new array(size); for(size_t i=0; i < size; ++i) (*a)[i]=::max(vm::read(pattern,i),0.0); return pen(LineType(*a,offset,scale,adjust)); } realarray *linetype(pen p=CURRENTPEN) { array a=p.linetype()->pattern; return copyArray(&a); } real offset(pen p) { return p.linetype()->offset; } bool scale(pen p) { return p.linetype()->scale; } bool adjust(pen p) { return p.linetype()->adjust; } pen adjust(pen p, real arclength, bool cyclic) { return adjustdash(p,arclength,cyclic); } pen linecap(Int n) { return pen(setlinecap,n >= 0 && n < nCap ? n : DEFCAP); } Int linecap(pen p=CURRENTPEN) { return p.cap(); } pen linejoin(Int n) { return pen(setlinejoin,n >= 0 && n < nJoin ? n : DEFJOIN); } Int linejoin(pen p=CURRENTPEN) { return p.join(); } pen miterlimit(real x) { return pen(setmiterlimit,x >= 1.0 ? x : DEFJOIN); } real miterlimit(pen p=CURRENTPEN) { return p.miter(); } pen linewidth(real x) { return pen(setlinewidth,x >= 0.0 ? x : DEFWIDTH); } real linewidth(pen p=CURRENTPEN) { return p.width(); } pen fontcommand(string *s) { return pen(setfont,*s); } string font(pen p=CURRENTPEN) { return p.Font(); } pen fontsize(real size, real lineskip) { return pen(setfontsize,size > 0.0 ? size : 0.0, lineskip > 0.0 ? lineskip : 0.0); } real fontsize(pen p=CURRENTPEN) { return p.size(); } real lineskip(pen p=CURRENTPEN) { return p.Lineskip(); } pen overwrite(Int n) { return pen(setoverwrite,n >= 0 && n < nOverwrite ? (overwrite_t) n : DEFWRITE); } Int overwrite(pen p=CURRENTPEN) { return p.Overwrite(); } pen basealign(Int n) { return pen(n >= 0 && n < nBaseLine ? (BaseLine) n : DEFBASE); } Int basealign(pen p=CURRENTPEN) { return p.Baseline(); } transform transform(pen p) { return p.getTransform(); } path nib(pen p) { return p.Path(); } pen makepen(path p) { return pen(p); } pen colorless(pen p) { p.colorless(); return p; } // Interactive mode bool interactive() { return interact::interactive; } bool uptodate() { return interact::uptodate; } // System commands Int system(stringarray *s) { if(safe) error("system() call disabled; override with option -nosafe"); size_t size=checkArray(s); if(size == 0) return 0; mem::vector cmd; for(size_t i=0; i < size; ++i) cmd.push_back(read(s,i)); return System(cmd); } bool view() { return view(); } string asydir() { return systemDir; } string locale(string s=emptystring) { char *L=setlocale(LC_ALL,s.empty() ? NULL : s.c_str()); return L != NULL ? string(L) : ""; } void abort(string s=emptystring) { if(s.empty()) throw handled_error(); error(s.c_str()); } void exit() { throw quit(); } void assert(bool b, string s=emptystring) { flush(cout); if(!b) { ostringstream buf; buf << "assert FAILED"; if(s != "") buf << ": " << s; error(buf); } } void sleep(Int seconds) { if(seconds <= 0) return; std::this_thread::sleep_for(std::chrono::seconds(seconds)); } void usleep(Int microseconds) { if(microseconds <= 0) return; std::this_thread::sleep_for(std::chrono::microseconds(microseconds)); } void _eval(string *s, bool embedded, bool interactiveWrite=false) { if(embedded) { trans::coenv *e=Stack->getEnvironment(); vm::interactiveStack *is=dynamic_cast(Stack); if(e && is) runStringEmbedded(*s, *e, *is); else error(noruntime); } else runString(*s,interactiveWrite); } void _eval(runnable *s, bool embedded) { absyntax::block *ast=new absyntax::block(s->getPos(), false); ast->add(s); if(embedded) { trans::coenv *e=Stack->getEnvironment(); vm::interactiveStack *is=dynamic_cast(Stack); if(e && is) runCodeEmbedded(ast, *e, *is); else error(noruntime); } else runCode(ast); } string xasyKEY() { processDataStruct& P=processData(); xkey_t& xkey=P.xkey; xkey_t::iterator p=xkey.find(P.topPos.LineColumn()); return p != xkey.end() ? p->second+" 1" : toplocation()+" 0"; } void xasyKEY(string *s) { processData().KEY=*s; } string location() { ostringstream buf; buf << getPos(); return buf.str(); } // Wrapper for the stack::load() method. void :loadModule(string *index) { Stack->load(*index); } string cd(string s=emptystring) { if(!globalread()) readDisabled(); if(!s.empty() && !globalwrite()) { string outname=settings::outname(); string dir=stripFile(outname); if(dir.empty()) Setting("outname")=getPath()+dirsep+outname; } return setPath(s.c_str()); } void list(string *s, bool imports=false) { if(*s == "-") return; trans::genv ge; symbol name=symbol::trans(*s); record *r=ge.getModule(name,*s); r->e.list(imports ? 0 : r); } // Guide operations guide* :nullGuide() { return new pathguide(path()); } guide* :dotsGuide(guidearray *a) { guidevector v; size_t size=checkArray(a); for (size_t i=0; i < size; ++i) v.push_back(a->read(i)); return new multiguide(v); } guide* :dashesGuide(guidearray *a) { static camp::curlSpec curly; static camp::specguide curlout(&curly, camp::OUT); static camp::specguide curlin(&curly, camp::IN); size_t n=checkArray(a); // a--b is equivalent to a{curl 1}..{curl 1}b guidevector v; if (n > 0) v.push_back(a->read(0)); if (n==1) { v.push_back(&curlout); v.push_back(&curlin); } else for (size_t i=1; iread(i)); } return new multiguide(v); } cycleToken :newCycleToken() { return cycleToken(); } guide *operator cast(cycleToken tok) { // Avoid unused variable warning messages. unused(&tok); return new cycletokguide(); } guide* operator spec(pair z, Int p) { camp::side d=(camp::side) p; camp::dirSpec *sp=new camp::dirSpec(z); return new specguide(sp,d); } curlSpecifier operator curl(real gamma, Int p) { camp::side s=(camp::side) p; return curlSpecifier(gamma,s); } real :curlSpecifierValuePart(curlSpecifier spec) { return spec.getValue(); } Int :curlSpecifierSidePart(curlSpecifier spec) { return spec.getSide(); } guide *operator cast(curlSpecifier spec) { return new specguide(spec); } tensionSpecifier operator tension(real tout, real tin, bool atleast) { return tensionSpecifier(tout, tin, atleast); } real :tensionSpecifierOutPart(tensionSpecifier t) { return t.getOut(); } real :tensionSpecifierInPart(tensionSpecifier t) { return t.getIn(); } bool :tensionSpecifierAtleastPart(tensionSpecifier t) { return t.getAtleast(); } guide *operator cast(tensionSpecifier t) { return new tensionguide(t); } guide* operator controls(pair zout, pair zin) { return new controlguide(zout, zin); } Int size(guide *g) { flatguide f; g->flatten(f,false); return f.size(); } Int length(guide *g) { flatguide f; g->flatten(f,false); return g->cyclic() ? f.size() : f.size()-1; } bool cyclic(guide *g) { flatguide f; g->flatten(f,false); return g->cyclic(); } pair point(guide *g, Int t) { flatguide f; g->flatten(f,false); return f.Nodes(adjustedIndex(t,f.size(),g->cyclic())).z; } pairarray *dirSpecifier(guide *g, Int t) { flatguide f; g->flatten(f,false); Int n=f.size(); if(!g->cyclic() && (t < 0 || t >= n-1)) return new array(0); array *c=new array(2); (*c)[0]=f.Nodes(t).out->dir(); (*c)[1]=f.Nodes(t+1).in->dir(); return c; } pairarray *controlSpecifier(guide *g, Int t) { flatguide f; g->flatten(f,false); Int n=f.size(); if(!g->cyclic() && (t < 0 || t >= n-1)) return new array(0); knot curr=f.Nodes(t); knot next=f.Nodes(t+1); if(curr.out->controlled()) { assert(next.in->controlled()); array *c=new array(2); (*c)[0]=curr.out->control(); (*c)[1]=next.in->control(); return c; } else return new array(0); } tensionSpecifier tensionSpecifier(guide *g, Int t) { flatguide f; g->flatten(f,false); Int n=f.size(); if(!g->cyclic() && (t < 0 || t >= n-1)) return tensionSpecifier(1.0,1.0,false); knot curr=f.Nodes(t); return tensionSpecifier(curr.tout.val,f.Nodes(t+1).tin.val,curr.tout.atleast); } realarray *curlSpecifier(guide *g, Int t) { flatguide f; g->flatten(f,false); Int n=f.size(); if(!g->cyclic() && (t < 0 || t >= n-1)) return new array(0); array *c=new array(2); real c0=f.Nodes(t).out->curl(); real c1=f.Nodes(t+1).in->curl(); (*c)[0]=c0 >= 0.0 ? c0 : 1.0; (*c)[1]=c1 >= 0.0 ? c1 : 1.0; return c; } guide *reverse(guide *g) { flatguide f; g->flatten(f,false); if(f.precyclic()) return new pathguide(g->solve().reverse()); size_t n=f.size(); bool cyclic=g->cyclic(); guidevector v; size_t start=cyclic ? n : n-1; knot curr=f.Nodes(start); knot next=curr; for(size_t i=start; i > 0; --i) { next=f.Nodes(i-1); v.push_back(new pairguide(curr.z)); if(next.out->controlled()) { assert(curr.in->controlled()); v.push_back(new controlguide(curr.in->control(),next.out->control())); } else { pair d=curr.in->dir(); if(d != zero) v.push_back(new specguide(new dirSpec(-d),camp::OUT)); else { real C=curr.in->curl(); if(C >= 0.0) v.push_back(new specguide(new curlSpec(C),camp::OUT)); } real tout=curr.tin.val; real tin=next.tout.val; bool atleast=next.tout.atleast; if(tout != 1.0 || tin != 1.0 || next.tout.atleast) v.push_back(new tensionguide(tensionSpecifier(tout,tin,atleast))); d=next.out->dir(); if(d != zero) v.push_back(new specguide(new dirSpec(-d),camp::IN)); else { real C=next.out->curl(); if(C >= 0.0) v.push_back(new specguide(new curlSpec(C),camp::IN)); } } curr=next; } if(cyclic) v.push_back(new cycletokguide()); else v.push_back(new pairguide(next.z)); return new multiguide(v); } realarray *_cputime() { #if !defined(_WIN32) static const real ticktime=1.0/sysconf(_SC_CLK_TCK); struct tms buf; ::times(&buf); real realCutime=((real)buf.tms_cutime)*ticktime; real realCstime=((real)buf.tms_cstime)*ticktime; #else // FIXME: See if there's a way to get cutime/cstime on windows, // if it's possible. real realCutime=0.0; real realCstime=0.0; #endif array *t=new array(5); (*t)[0]=cpuTime.seconds(); // Includes system time (*t)[1]=0.0; (*t)[2]=realCutime; (*t)[3]=realCstime; (*t)[4]=wallClock.seconds(); return t; } // Transforms bool ==(transform a, transform b) { return a == b; } bool !=(transform a, transform b) { return a != b; } transform +(transform a, transform b) { return a+b; } transform Operator *(transform a, transform b) { return a*b; } pair Operator *(transform t, pair z) { return t*z; } path Operator *(transform t, path g) { return transformed(t,g); } pen Operator *(transform t, pen p) { return transformed(t,p); } picture * Operator *(transform t, picture *f) { return transformed(t,f); } picture * Operator *(realarray2 *t, picture *f) { return transformed(*t,f); } transform ^(transform t, Int n) { transform T; if(n < 0) { n=-n; t=inverse(t); } for(Int i=0; i < n; i++) T=T*t; return T; } real :transformXPart(transform t) { return t.getx(); } real :transformYPart(transform t) { return t.gety(); } real :transformXXPart(transform t) { return t.getxx(); } real :transformXYPart(transform t) { return t.getxy(); } real :transformYXPart(transform t) { return t.getyx(); } real :transformYYPart(transform t) { return t.getyy(); } transform :real6ToTransform(real x, real y, real xx, real xy, real yx, real yy) { return transform(x,y,xx,xy,yx,yy); } transform shift(transform t) { return transform(t.getx(),t.gety(),0,0,0,0); } transform shiftless(transform t) { return transform(0,0,t.getxx(),t.getxy(),t.getyx(),t.getyy()); } transform identity:transformIdentity() { return identity; } transform inverse(transform t) { return inverse(t); } transform shift(pair z) { return shift(z); } transform shift(real x, real y) { return shift(pair(x,y)); } transform xscale(real x) { return xscale(x); } transform yscale(real y) { return yscale(y); } transform scale(real x) { return scale(x); } transform scale(real x, real y) { return scale(x,y); } transform slant(real s) { return slant(s); } transform rotate(real angle, pair z=0) { return rotatearound(z,radians(angle)); } transform reflect(pair a, pair b) { return reflectabout(a,b); } bool isometry(transform t) { return t.isIsometry(); } real bezier(real a, real b, real c, real d, real t) { real onemt=1-t; real onemt2=onemt*onemt; return onemt2*onemt*a+t*(3.0*(onemt2*b+t*onemt*c)+t*t*d); }