// Array access - generic int api_val_array_size(value arg1) { if (val_is_array(arg1)) return val_array_size(arg1); value l = val_field(arg1,length_id); return val_int(l); }
static void report( neko_vm *vm, value exc, int isexc ) { int i; buffer b = alloc_buffer(NULL); value st = neko_exc_stack(vm); for(i=0;i<val_array_size(st);i++) { value s = val_array_ptr(st)[i]; buffer_append(b,"Called from "); if( val_is_null(s) ) buffer_append(b,"a C function"); else if( val_is_string(s) ) { buffer_append(b,val_string(s)); buffer_append(b," (no debug available)"); } else if( val_is_array(s) && val_array_size(s) == 2 && val_is_string(val_array_ptr(s)[0]) && val_is_int(val_array_ptr(s)[1]) ) { val_buffer(b,val_array_ptr(s)[0]); buffer_append(b," line "); val_buffer(b,val_array_ptr(s)[1]); } else val_buffer(b,s); buffer_append_char(b,'\n'); } if( isexc ) buffer_append(b,"Uncaught exception - "); val_buffer(b,exc); # ifdef NEKO_STANDALONE neko_standalone_error(val_string(buffer_to_string(b))); # else fprintf(stderr,"%s\n",val_string(buffer_to_string(b))); # endif }
EXTERN value neko_select_file( value path, const char *file, const char *ext ) { struct stat s; value ff; buffer b = alloc_buffer(file); buffer_append(b,ext); ff = buffer_to_string(b); if( stat(val_string(ff),&s) == 0 ) { char *p = strchr(file,'/'); if( p == NULL ) p = strchr(file,'\\'); if( p != NULL ) return ff; b = alloc_buffer("./"); buffer_append(b,file); buffer_append(b,ext); return buffer_to_string(b); } while( val_is_array(path) && val_array_size(path) == 2 ) { value p = val_array_ptr(path)[0]; buffer b = alloc_buffer(NULL); path = val_array_ptr(path)[1]; val_buffer(b,p); val_buffer(b,ff); p = buffer_to_string(b); if( stat(val_string(p),&s) == 0 ) return p; } return ff; }
static void report( neko_vm *vm, value exc ) { #if OSX CFStringRef title = CFSTR("Uncaught exception"); CFStringRef message; #endif int i = 0; buffer b = alloc_buffer(NULL); value st = neko_exc_stack(vm); if( val_array_size(st) > 20 ) { i = val_array_size(st) - 20; buffer_append(b,"...\n"); } for(i;i<val_array_size(st);i++) { value s = val_array_ptr(st)[i]; if( val_is_null(s) ) buffer_append(b,"Called from a C function\n"); else if( val_is_string(s) ) { buffer_append(b,"Called from "); buffer_append(b,val_string(s)); buffer_append(b," (no debug available)\n"); } else if( val_is_array(s) && val_array_size(s) == 2 && val_is_string(val_array_ptr(s)[0]) && val_is_int(val_array_ptr(s)[1]) ) { buffer_append(b,"Called from "); buffer_append(b,val_string(val_array_ptr(s)[0])); buffer_append(b," line "); val_buffer(b,val_array_ptr(s)[1]); buffer_append(b,"\n"); } else { buffer_append(b,"Called from "); val_buffer(b,s); buffer_append(b,"\n"); } } val_buffer(b,exc); #if _WIN32 MessageBox(NULL,val_string(buffer_to_string(b)),"Uncaught exception",MB_OK | MB_ICONERROR); #elif OSX message = CFStringCreateWithCString(NULL,val_string(buffer_to_string(b)), kCFStringEncodingUTF8); CFUserNotificationDisplayNotice(0,0,NULL,NULL,NULL,title,message,NULL); #elif LINUX fprintf(stderr,"Uncaught Exception: %s\n",val_string(buffer_to_string(b))); #endif }
static fd_set *make_socket_array( value a, fd_set *tmp, SOCKET *n ) { int i, len; SOCKET sock; FD_ZERO(tmp); if( val_is_null(a) ) return tmp; if( !val_is_array(a) ) return &INVALID; len = val_array_size(a); if( len > FD_SETSIZE ) val_throw(alloc_string("Too many sockets in select")); for(i=0;i<len;i++) { value s = val_array_i(a,i); // make sure it is a socket... sock = val_sock(s); if( sock > *n ) *n = sock; FD_SET(sock,tmp); } return tmp; }
static fd_set *make_socket_array( value a, int len, fd_set *tmp, SOCKET *n ) { int i; SOCKET sock; if( val_is_null(a) ) return NULL; if( !val_is_array(a) ) return &INVALID; if( len > FD_SETSIZE ) val_throw(alloc_string("Too many sockets in select")); FD_ZERO(tmp); for(i=0;i<len;i++) { value s = val_array_ptr(a)[i]; if( !val_is_kind(s,k_socket) ) return &INVALID; sock = val_sock(s); if( sock > *n ) *n = sock; FD_SET(sock,tmp); } return tmp; }
// Determine value type int api_val_type(value arg1) { int t=val_type(arg1); if (t==VAL_OBJECT) { value __a = val_field(arg1,__a_id); if (val_is_array(__a)) return valtArray; value __s = val_field(arg1,__s_id); if (val_is_string(__s)) return valtString; } if (t<7) return (ValueType)t; if (t==VAL_ABSTRACT) return valtAbstractBase; if (t==VAL_PRIMITIVE || t==VAL_JITFUN) return valtFunction; if (t==VAL_32_BITS || t==VAL_INT) return valtInt; return valtNull; }
void NekoCodeChunk::neko_dump(std::string const & indent) const { for (const_iterator it = begin(); it != end(); ++it) { std::cout << indent << it->first << ": "; print_neko_instruction((OPCODE) it->second.first, it->second.second, parameter_table[it->second.first]); std::cout << "; // "; { int ppc = (int)((int_val *)it->first - m->code); int idx = m->dbgidxs[ppc>>5].base + bitcount(m->dbgidxs[ppc>>5].bits >> (31 - (ppc & 31))); value s = val_array_ptr(m->dbgtbl)[idx]; if( val_is_string(s) ) printf("%s",val_string(s)); else if( val_is_array(s) && val_array_size(s) == 2 && val_is_string(val_array_ptr(s)[0]) && val_is_int(val_array_ptr(s)[1]) ) printf("file %s line %d",val_string(val_array_ptr(s)[0]),val_int(val_array_ptr(s)[1])); else printf("???"); } std::cout << std::endl; } }
static value unserialize_rec( sbuffer *b, value loader ) { switch( read_char(b) ) { case 'N': return val_null; case 'T': return val_true; case 'F': return val_false; case 'i': return alloc_int(read_int(b)); case 'I': return alloc_int32(read_int(b)); case 'f': { tfloat d; read_str(b,sizeof(tfloat),&d); return alloc_float(d); } case 's': { int l = read_int(b); value v; if( l < 0 || l > max_string_size ) ERROR(); v = alloc_empty_string(l); add_ref(b,v); read_str(b,l,(char*)val_string(v)); return v; } case 'o': { int f; value o = alloc_object(NULL); add_ref(b,o); while( (f = read_int(b)) != 0 ) { value fval = unserialize_rec(b,loader); alloc_field(o,(field)f,fval); } switch( read_char(b) ) { case 'p': { value v = unserialize_rec(b,loader); if( !val_is_object(v) ) ERROR(); ((vobject*)o)->proto = (vobject*)v; } break; case 'z': break; default: ERROR(); } return o; } case 'r': { int n = read_int(b); if( n < 0 || n >= b->nrefs ) ERROR(); return b->trefs[b->nrefs - n - 1]; } case 'a': { int i; int n = read_int(b); value o; value *t; if( n < 0 || n > max_array_size ) ERROR(); o = alloc_array(n); t = val_array_ptr(o); add_ref(b,o); for(i=0;i<n;i++) t[i] = unserialize_rec(b,loader); return o; } case 'p': { int nargs = read_int(b); vfunction *f = (vfunction*)alloc_function((void*)1,nargs,NULL); vfunction *f2; value name; add_ref(b,(value)f); name = unserialize_rec(b,loader); f2 = (vfunction*)val_ocall2(loader,id_loadprim,name,alloc_int(nargs)); if( !val_is_function(f2) || val_fun_nargs(f2) != nargs ) failure("Loader returned not-a-function"); f->t = f2->t; f->addr = f2->addr; f->module = f2->module; return (value)f; } case 'L': { vfunction *f = (vfunction*)alloc_function((void*)1,0,NULL); value mname; int pos; int nargs; value env; add_ref(b,(value)f); mname = unserialize_rec(b,loader); pos = read_int(b); nargs = read_int(b); env = unserialize_rec(b,loader); if( !val_is_array(env) ) ERROR(); { value exp = val_ocall2(loader,id_loadmodule,mname,loader); value mval; unsigned int i; int_val *mpos; neko_module *m; if( !val_is_object(exp) ) { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," is not an object"); bfailure(b); } mval = val_field(exp,id_module); if( !val_is_kind(mval,neko_kind_module) ) { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," has invalid type"); bfailure(b); } m = (neko_module*)val_data(mval); mpos = m->code + pos; for(i=0;i<m->nglobals;i++) { vfunction *g = (vfunction*)m->globals[i]; if( val_is_function(g) && g->addr == mpos && g->module == m && g->nargs == nargs ) { f->t = VAL_FUNCTION; f->env = env; f->addr = mpos; f->nargs = nargs; f->module = m; return (value)f; } } { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," has been modified"); bfailure(b); } } return val_null; } case 'x': { value mname = unserialize_rec(b,loader); value data = unserialize_rec(b,loader); value exports = val_ocall2(loader,id_loadmodule,mname,loader); value s; if( !val_is_object(exports) ) { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," is not an object"); bfailure(b); } s = val_field(exports,id_unserialize); if( !val_is_function(s) || (val_fun_nargs(s) != 1 && val_fun_nargs(s) != VAR_ARGS) ) { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," has invalid __unserialize function"); } s = val_call1(s,data); add_ref(b,s); return s; } case 'h': { int i; vhash *h = (vhash*)alloc(sizeof(vhash)); h->ncells = read_int(b); h->nitems = read_int(b); h->cells = (hcell**)alloc(sizeof(hcell*)*h->ncells); for(i=0;i<h->ncells;i++) h->cells[i] = NULL; for(i=0;i<h->nitems;i++) { hcell **p; hcell *c = (hcell*)alloc(sizeof(hcell)); c->hkey = read_int(b); c->key = unserialize_rec(b,loader); c->val = unserialize_rec(b,loader); c->next = NULL; p = &h->cells[c->hkey % h->ncells]; while( *p != NULL ) p = &(*p)->next; *p = c; } return alloc_abstract(k_hash,h); } default: ERROR(); return val_null; } }
/** sprintf : fmt:string -> params:(any | array) -> string <doc> Format a string. If only one parameter is needed then it can be directly passed, either the parameters need to be stored in an array. The following formats are accepted (with corresponding types) : <ul> <li>[%s] : string</li> <li>[%d] [%x] [%X] : int</li> <li>[%c] : int in the 0..255 range</li> <li>[%b] : bool</li> <li>[%f] : float</li> </ul> </doc> **/ static value neko_sprintf( value fmt, value params ) { const char *last, *cur, *end; int count = 0; buffer b; val_check(fmt,string); b = alloc_buffer(0); last = val_string(fmt); cur = last; end = cur + val_strlen(fmt); while( cur != end ) { if( *cur == '%' ) { int width = 0, prec = 0, flags = 0; buffer_append_sub(b,last,cur - last); cur++; while( *cur >= '0' && *cur <= '9' ) { width = width * 10 + (*cur - '0'); cur++; } if( *cur == '.' ) { cur++; while( *cur >= '0' && *cur <= '9' ) { prec = prec * 10 + (*cur - '0'); cur++; } } if( *cur == '%' ) { buffer_append_sub(b,"%",1); cur++; } else { value param; if( count == 0 && !val_is_array(params) ) { // first ? param = params; count++; } else if( !val_is_array(params) || val_array_size(params) <= count ) return alloc_null(); else param = val_array_i(params,count++); switch( *cur ) { case 'c': { int c; char cc; val_check(param,int); c = val_int(param); if( c < 0 || c > 255 ) return alloc_null(); cc = (char)c; buffer_append_sub(b,&cc,1); } break; case 'x': flags |= HEX_SMALL; case 'X': flags |= HEX; case 'd': { char tmp[10]; int sign = 0; int size = 0; int tsize; int n; val_check(param,int); n = val_int(param); if( !(flags & HEX) && n < 0 ) { sign++; prec--; n = -n; } else if( n == 0 ) tmp[9-size++] = '0'; if( flags & HEX ) { unsigned int nn = (unsigned int)n; while( nn > 0 ) { int k = nn&15; if( k < 10 ) tmp[9-size++] = k + '0'; else tmp[9-size++] = (k - 10) + ((flags & HEX_SMALL)?'a':'A'); nn = nn >> 4; } } else { while( n > 0 ) { tmp[9-size++] = (n % 10) + '0'; n = n / 10; } } tsize = (size > prec)?size:prec + sign; while( width > tsize ) { width--; buffer_append_sub(b," ",1); } if( sign ) buffer_append_sub(b,"-",1); while( prec > size ) { prec--; buffer_append_sub(b,"0",1); } buffer_append_sub(b,tmp+10-size,size); } break; case 'f': { val_check(param,float); val_buffer(b,param); } break; case 's': { int size; int tsize; val_check(param,string); size = val_strlen(param); tsize = (size > prec)?size:prec; while( width > tsize ) { width--; buffer_append_sub(b," ",1); } while( prec > size ) { prec--; buffer_append_sub(b," ",1); } buffer_append_sub(b,val_string(param),size); } break; case 'b': { val_check(param,bool); buffer_append_sub(b,val_bool(param)?"true":"false",val_bool(param)?4:5); } break; default: return alloc_null(); break; } }
static int neko_handler_rec( request_rec *r ) { mcontext ctx; neko_vm *vm; const char *ctype; value exc = NULL; /* Seems to crash on Windows. And on Linux, we rarely have libGC 7.x installed anyway # if defined(APACHE_2_X) || defined(NEKO_WINDOWS) // we are using threads, so let's make sure that the current thread is registered neko_thread_register(true); # endif */ config.hits++; ctx.r = r; ctx.main = cache_find(r); ctx.post_data = val_null; ctx.headers_sent = false; ctx.content_type = alloc_string("text/html"); r->content_type = val_string(ctx.content_type); if( ap_setup_client_block(r,REQUEST_CHUNKED_ERROR) != 0 ) { send_headers(&ctx); apache_error(APLOG_WARNING,r,"ap_setup_client_block failed"); return OK; } ctype = ap_table_get(r->headers_in,"Content-Type"); if( (!ctype || strstr(ctype,"multipart/form-data") == NULL) && ap_should_client_block(r) ) { # define MAXLEN 1024 char buf[MAXLEN]; int len; int tlen = 0; buffer b = alloc_buffer(NULL); while( (len = ap_get_client_block(r,buf,MAXLEN)) > 0 ) { if( tlen < config.max_post_size ) buffer_append_sub(b,buf,len); tlen += len; } if( tlen >= config.max_post_size ) { send_headers(&ctx); apache_error(APLOG_WARNING,r,"Maximum POST data exceeded. Try using multipart encoding"); return OK; } ctx.post_data = buffer_to_string(b); } vm = neko_vm_alloc(NULL); if( config.use_stats ) neko_vm_set_stats(vm,neko_stats_measure,config.use_prim_stats?neko_stats_measure:NULL); neko_vm_set_custom(vm,k_mod_neko,&ctx); if( config.use_jit && !neko_vm_jit(vm,1) ) { send_headers(&ctx); apache_error(APLOG_WARNING,r,"JIT required by env. var but not enabled in NekoVM"); return OK; } neko_vm_redirect(vm,request_print,&ctx); neko_vm_select(vm); if( ctx.main != NULL ) { value old = ctx.main; if( config.use_stats ) neko_stats_measure(vm,r->filename,1); val_callEx(val_null,old,NULL,0,&exc); if( config.use_stats ) neko_stats_measure(vm,r->filename,0); if( old != ctx.main ) cache_module(r->filename,FTIME(r),ctx.main); } else { char *base_uri = request_base_uri(r); value mload = neko_default_loader(&base_uri,1); value args[] = { alloc_string(r->filename), mload }; char *p = strrchr(val_string(args[0]),'.'); if( p != NULL ) *p = 0; val_callEx(mload,val_field(mload,val_id("loadmodule")),args,2,&exc); if( ctx.main != NULL && config.use_cache ) cache_module(r->filename,FTIME(r),ctx.main); } if( exc != NULL ) { buffer b = alloc_buffer(NULL); value v; int i; const char *p, *start; value st = neko_exc_stack(vm); val_buffer(b,exc); config.exceptions++; ap_soft_timeout("Client Timeout",r); send_headers(&ctx); v = buffer_to_string(b); p = val_string(v); start = p; ap_rprintf(r,"Uncaught exception - "); while( *p ) { if( *p == '<' || *p == '>' ) { ap_rwrite(start,(int)(p - start),r); ap_rwrite((*p == '<')?"<":">",4, r); start = p + 1; } p++; } ap_rwrite(start,(int)(p - start),r); ap_rprintf(r,"<br/><br/>"); for(i=0;i<val_array_size(st);i++) { value s = val_array_ptr(st)[i]; if( val_is_null(s) ) ap_rprintf(r,"Called from a C function<br/>"); else if( val_is_string(s) ) { ap_rprintf(r,"Called from %s (no debug available)<br/>",val_string(s)); } else if( val_is_array(s) && val_array_size(s) == 2 && val_is_string(val_array_ptr(s)[0]) && val_is_int(val_array_ptr(s)[1]) ) ap_rprintf(r,"Called from %s line %d<br/>",val_string(val_array_ptr(s)[0]),val_int(val_array_ptr(s)[1])); else { b = alloc_buffer(NULL); val_buffer(b,s); ap_rprintf(r,"Called from %s<br/>",val_string(buffer_to_string(b))); } } ap_kill_timeout(r); return OK; } send_headers(&ctx); return OK; }
value * api_val_array_value(value arg1) { if (val_is_array(arg1)) return val_array_ptr(arg1); return val_array_ptr(val_field(arg1,__a_id)); }
void api_val_array_set_i(value arg1,int arg2,value inVal) { if (!val_is_array(arg1)) arg1 = val_field(arg1,__a_id); val_array_ptr(arg1)[arg2] = inVal; }
value api_val_array_i(value arg1,int arg2) { if (val_is_array(arg1)) return val_array_ptr(arg1)[arg2]; return val_array_ptr(val_field(arg1,__a_id))[arg2]; }