/*****
* 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 <cfloat>
#include <iostream>
#include <fstream>
#include <time.h>
#include <chrono>
#include <thread>
#if !defined(_WIN32)
#include <sys/times.h>
#endif
#include <locale.h>
#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 <primitives.h>
#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<callable *>(s,NULL);
string S=pop<string>(s);
vm::item it=pop(s);
bool defaultfile=isdefault(it);
camp::file *f=defaultfile ? &camp::Stdout : vm::get<camp::file*>(it);
if(!f->isOpen() || !f->enabled()) return;
if(S != "" || f->isBinary() || f->isXDR()) 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<double>(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<string> cmd;
for(size_t i=0; i < size; ++i)
cmd.push_back(read<string>(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<vm::interactiveStack *>(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<vm::interactiveStack *>(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());
if(settings::keys)
return p != xkey.end() ? p->second : toplocation();
else
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::loadModule() method.
void :loadModule(string *index, Int numPushedParents)
{
Stack->loadModule(*index, numPushedParents);
}
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<guide*>(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<guide*>(0));
if (n==1) {
v.push_back(&curlout);
v.push_back(&curlin);
}
else
for (size_t i=1; i<n; ++i) {
v.push_back(&curlout);
v.push_back(&curlin);
v.push_back(a->read<guide*>(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);
}