/** * Writes a given LuciStringObj to a LuciFileObj. * * @param args list of args * @param c number of args * @returns LuciNilObj */ LuciObject *luci_fwrite(LuciObject **args, unsigned int c) { if (c < 2) { LUCI_DIE("%s", "Missing parameter to write()\n"); } /* grab the FILE parameter */ LuciObject *fobj = args[0]; if (!fobj || (!ISTYPE(fobj, obj_file_t))) { LUCI_DIE("%s", "Not a file object\n"); } /* grab string parameter */ LuciObject *text_obj = args[1]; if (!text_obj || (!ISTYPE(text_obj, obj_string_t)) ) { LUCI_DIE("%s", "Not a string\n"); } char *text = AS_STRING(text_obj)->s; if (AS_FILE(fobj)->mode == f_read_m) { LUCI_DIE("%s", "Can't write to It is opened for reading.\n"); } fwrite(text, sizeof(char), strlen(text), AS_FILE(fobj)->ptr); return LuciNilObj; }
/** * Casts a LuciObject to a LuciFloatObj if possible, then returns * the new object. * * @param args list of args * @param c number of args * @returns LuciFloatObj cast of the first arg */ LuciObject *luci_cast_float(LuciObject **args, unsigned int c) { LuciObject *ret = LuciNilObj; if (c < 1) { LUCI_DIE("%s", "Missing parameter to int()\n"); } LuciObject *item = args[0]; if (!item) { LUCI_DIE("%s", "Can't cast NULL to int\n"); } if (ISTYPE(item, obj_int_t)) { ret = LuciFloat_new((double)AS_INT(item)->i); } else if (ISTYPE(item, obj_float_t)) { ret = LuciFloat_new(AS_FLOAT(item)->f); } else if (ISTYPE(item, obj_string_t)) { double f; int scanned = sscanf(AS_STRING(item)->s, "%f", (float *)&f); if (scanned <= 0 || scanned == EOF) { LUCI_DIE("%s", "Could not cast to float\n"); } ret = LuciFloat_new(f); } else { LUCI_DIE("Cannot cast type %s to type float\n", item->type->type_name); } return ret; }
/** * Opens a file in read, write, or append mode. * * @param args list of args * @param c number of args * @returns LuciFileObj opened from the filename in the first arg */ LuciObject *luci_fopen(LuciObject **args, unsigned int c) { char *filename; char *req_mode; int mode; FILE *file = NULL; if (c < 2) { LUCI_DIE("%s", "Missing parameter to open()\n"); } LuciObject *fname_obj = args[0]; if (!ISTYPE(fname_obj, obj_string_t)) { LUCI_DIE("%s", "Parameter 1 to open must be a string\n"); } LuciObject *mode_obj = args[1]; if (!ISTYPE(mode_obj, obj_string_t)) { LUCI_DIE("%s", "Parameter 2 to open must be a string\n"); } filename = AS_STRING(fname_obj)->s; req_mode = AS_STRING(mode_obj)->s; mode = get_file_mode(req_mode); if (mode < 0) { LUCI_DIE("%s\n", "Invalid mode to open()"); } /* Open in read-binary mode and fseek to SEEK_END to calculate the file's size in bytes. Then close it and reopen it the way the user requests */ long file_length; /* store the FILE's byte length */ if (!(file = fopen(filename, "rb"))) { file_length = 0; } else { fseek(file, 0, SEEK_END); file_length = ftell(file); fseek(file, 0, SEEK_SET); close_file(file); } if (!(file = fopen(filename, req_mode))) { LUCI_DIE("Could not open file %s\n", filename); } LuciObject *ret = LuciFile_new(file, file_length, mode); LUCI_DEBUG("Opened file %s of size %ld bytes with mode %s.\n", filename, file_length, req_mode); return ret; }
/** * Finds the minimum value in a list. * * @param args list of args * @param c number of args * @returns min number in list */ LuciObject *luci_min(LuciObject **args, unsigned int c) { if (c < 1) { LUCI_DIE("%s", "Missing parameter to min()\n"); } LuciObject *list = args[0]; if (!list || (!ISTYPE(list, obj_list_t))) { LUCI_DIE("%s", "Must specify a list to calculate min\n"); } LuciObject *item; double min = 0; unsigned int i, found_float = 0; for (i = 0; i < AS_LIST(list)->count; i ++) { item = AS_LIST(list)->items[i]; if (!item) { LUCI_DIE("%s", "Can't calulate max of list containing NULL value\n"); } if (ISTYPE(item, obj_int_t)) { if (i == 0) { min = (double)AS_INT(item)->i; } else if ( (double)AS_INT(item)->i < min) { min = (double)AS_INT(item)->i; } } else if (ISTYPE(item, obj_float_t)) { found_float = 1; if (i == 0) { min = AS_FLOAT(item)->f; } else if (AS_FLOAT(item)->f < min) { min = AS_FLOAT(item)->f; } } else { LUCI_DIE("Can't find min of list containing an object of type %s\n", item->type->type_name); } } LuciObject *ret; if (!found_float) { ret = LuciInt_new((long)min); } else { ret = LuciFloat_new(min); } return ret; }
/** * Reads the contents of a file into a LuciStringObj. * * @param args list of args * @param c number of args * @returns contents of the file from the first arg. */ LuciObject *luci_fread(LuciObject **args, unsigned int c) { if (c < 1) { LUCI_DIE("%s", "Missing parameter to read()\n"); } LuciObject *fobj = args[0]; if (!ISTYPE(fobj, obj_file_t)) { LUCI_DIE("%s", "Not a file object\n"); } if (AS_FILE(fobj)->mode != f_read_m) { LUCI_DIE("%s", "Can't open It is opened for writing.\n"); } /* seek to file start, we're gonna read the whole thing */ /* fseek(fobj->ptr, 0, SEEK_SET); */ long len = AS_FILE(fobj)->size; char *read = alloc(len + 1); fread(read, sizeof(char), len, AS_FILE(fobj)->ptr); read[len] = '\0'; /* fseek(fobj->ptr, 0, SEEK_SET); */ LuciObject *ret = LuciString_new(read); return ret; }
/** * Returns a boolean representation of a LuciIteratorObj * * @param o LuciIteratorObj * @returns true if the iterator can continue to iterate */ LuciObject* LuciIterator_asbool(LuciObject *o) { LuciObject *res = LuciNilObj; LuciObject *container = AS_ITERATOR(o)->container; unsigned int len = 0; if (ISTYPE(container, obj_list_t)) { len = AS_LIST(container)->count; } else if (ISTYPE(container, obj_map_t)) { len = AS_LIST(container)->size; } if (AS_INT(AS_ITERATOR(o)->idx)->i < len) { res = LuciInt_new(true); } else { res = LuciInt_new(false); } return res; }
/** * Computes the sum of a range of numbers. * * @param args list of args * @param c number of args * @returns sum of numbers */ LuciObject * luci_sum(LuciObject **args, unsigned int c) { if (c < 1) { LUCI_DIE("%s", "Missing parameter to sum()\n"); } LuciObject *list = args[0]; if (!list || (!ISTYPE(list, obj_list_t))) { LUCI_DIE("%s", "Must specify a list to calculate sum\n"); } LuciObject *item; double sum = 0; unsigned int i, found_float = 0; for (i = 0; i < AS_LIST(list)->count; i++) { item = AS_LIST(list)->items[i]; if (!item) { LUCI_DIE("%s", "Can't calulate sum of list containing NULL value\n"); } if (ISTYPE(item, obj_int_t)) { sum += (double)AS_INT(item)->i; } else if (ISTYPE(item, obj_float_t)) { found_float = 1; sum += AS_FLOAT(item)->f; } else { LUCI_DIE("%s", "Can't calculate sum of list containing non-numeric value\n"); } } LuciObject *ret; if (!found_float) { ret = LuciInt_new((long)sum); } else { ret = LuciFloat_new(sum); } return ret; }
/** * Asserts that a given LuciObject is equivalent to a boolean True * * Currently uses C @code assert @endcode , which will exit a program * mid-execution if the assertion fails. * * @param args list of args * @param c number of args * @returns LuciNilObj */ LuciObject *luci_assert(LuciObject **args, unsigned int c) { if (c < 1) { LUCI_DIE("%s", "Missing condition parameter to assert()\n"); } LuciObject *item = args[0]; if (ISTYPE(item, obj_int_t) && !AS_INT(item)->i) { LUCI_DIE("%s\n", "Assertion failed"); } else if (ISTYPE(item, obj_float_t) && !((long)AS_FLOAT(item)->f)) { LUCI_DIE("%s\n", "Float assertion failed"); } else if (ISTYPE(item, obj_string_t)) { if (strcmp("", AS_STRING(item)->s) == 0) { LUCI_DIE("%s\n", "String assertion failed"); } } else if (ISTYPE(item, obj_list_t) && (AS_LIST(item)->count == 0)) { LUCI_DIE("%s\n", "List assertion failed"); } else if (ISTYPE(item, obj_map_t) && (AS_MAP(item)->count == 0)) { LUCI_DIE("%s\n", "Map assertion failed"); } else if (ISTYPE(item, obj_file_t) && (AS_FILE(item)->ptr)) { LUCI_DIE("%s\n", "File assertion failed"); } return LuciNilObj; }
/** * Reads a line of input from stdin * * @param args first arg is either NULL or a LuciFileObj * @param c if 0, read from stdin. if > 0, read from file. * @returns LuciStringObj containing what was read */ LuciObject *luci_readline(LuciObject **args, unsigned int c) { size_t lenmax = 64, len = 0; int ch; FILE *read_from = NULL; char *input; if (c < 1) { LUCI_DEBUG("%s\n", "readline from stdin"); read_from = stdin; } else { LuciObject *item = args[0]; if (item && (ISTYPE(item, obj_file_t))) { LUCI_DEBUG("%s\n", "readline from file"); read_from = AS_FILE(item)->ptr; } else { LUCI_DIE("args[0]: %p, type: %s\n", args[0], item->type->type_name); LUCI_DIE("%s", "Can't readline from non-file object\n"); } } input = alloc(lenmax * sizeof(char)); if (input == NULL) { LUCI_DIE("%s", "Failed to allocate buffer for reading stdin\n"); } do { ch = fgetc(read_from); if (len >= lenmax) { lenmax *= 2; if ((input = realloc(input, lenmax * sizeof(char))) == NULL) { LUCI_DIE("%s", "Failed to allocate buffer for reading\n"); } } input[len++] = (char)ch; } while (ch != EOF && ch != '\n'); if (ch == EOF) { LUCI_DEBUG("%s\n", "readline at EOF, returning nil"); return LuciNilObj; } /* overwrite the newline or EOF char with a NUL terminator */ input[--len] = '\0'; LuciObject *ret = LuciString_new(input); LUCI_DEBUG("Read line %s\n", AS_STRING(ret)->s); return ret; }
/** * Reads all the lines from the given input to create a * list of lines. * * @param args list of args * @param c number of args * @returns list of lines from file or stdin */ LuciObject *luci_flines(LuciObject **args, unsigned int c) { LuciObject *list = LuciList_new(); LuciObject *line = luci_readline(args, c); /* read lines until either NULL or LuciNilObj returned */ while (line && !ISTYPE(line, obj_nil_t)) { LuciList_append(list, line); line = luci_readline(args, c); } return list; }
/** * Returns the next LuciObject in a container. * * @param iterator from which to compute next object * @returns next object in iterator's sequence or NULL if finished iterating */ LuciObject *iterator_next_object(LuciObject *iterator) { if (!iterator || (!ISTYPE(iterator, obj_iterator_t))) { LUCI_DIE("%s", "Can't get next from non-iterator object\n"); } LuciIteratorObj *iter = (LuciIteratorObj *)iterator; LuciObject *container = iter->container; LuciObject *next = container->type->next(container, iter->idx); AS_INT(iter->idx)->i += iter->step; return next; }
/** * Returns a hex string representation of an integer * * @param args list of args * @param c number of args * @returns LuciStringObj representation of an integer */ LuciObject *luci_hex(LuciObject **args, unsigned int c) { if (c < 1) { LUCI_DIE("%s\n", "Missing param to hex()"); } LuciObject *hexint = args[0]; if (!ISTYPE(hexint, obj_int_t)) { LUCI_DIE("Cannot get hex representation of an object of type %s\n", hexint->type->type_name); } char *s = alloc(MAX_INT_DIGITS + 2); snprintf(s, MAX_INT_DIGITS, "0x%lX", AS_INT(hexint)->i); return LuciString_new(s); }
static IO_clp bindIO(IOOffer_cl *io_offer, HeapMod_cl *hmod, Heap_clp *heap) { IO_clp res; IOData_Shm *shm; if(io_offer != NULL) { if(*heap) { /* We have some memory => bind using it */ Type_Any any; IDCClientBinding_clp cb; shm = SEQ_NEW(IOData_Shm, 1, Pvs(heap)); SEQ_ELEM(shm, 0).buf.base = HeapMod$Where(hmod, *heap, &(SEQ_ELEM(shm, 0).buf.len)); SEQ_ELEM(shm, 0).param.attrs = 0; SEQ_ELEM(shm, 0).param.awidth = PAGE_WIDTH; SEQ_ELEM(shm, 0).param.pwidth = PAGE_WIDTH; cb = IOOffer$ExtBind(io_offer, shm, Pvs(gkpr), &any); if(!ISTYPE(&any, IO_clp)) { eprintf("udp_socket.c [bindIO]: IOOffer$ExtBind failed.\n"); if(cb) IDCClientBinding$Destroy(cb); RAISE_TypeSystem$Incompatible(); } res = NARROW (&any, IO_clp); } else { /* Just bind to offer and create a heap afterwards. */ res = IO_BIND(io_offer); shm = IO$QueryShm(res); if(SEQ_LEN(shm) != 1) eprintf("udp_socket.c [bindIO]: " "got > 1 data areas in channel!\n"); /* Ignore extra areas for now */ *heap = HeapMod$NewRaw(hmod, SEQ_ELEM(shm, 0).buf.base, SEQ_ELEM(shm, 0).buf.len); } return res; } return (IO_cl *)NULL; }
/** * Casts a LuciObject to a LuciStringObj if possible, then returns * the new object. * * @param args list of args * @param c number of args * @returns LuciStringObj cast of the first arg */ LuciObject *luci_cast_str(LuciObject **args, unsigned int c) { LuciObject *ret = LuciNilObj; if (c < 1) { LUCI_DIE("%s", "Missing parameter to str()\n"); } /* grab the first parameter from the param list */ LuciObject *item = args[0]; ret = item->type->repr(item); if (ISTYPE(ret, obj_nil_t)) { LUCI_DIE("Cannot cast object of type %s to type string", item->type->type_name); } LUCI_DEBUG("str() returning %s\n", AS_STRING(ret)->s); return ret; }
/** * Closes an open LuciFileObj. * * @param args list of args * @param c number of args * @returns LuciNilObj */ LuciObject *luci_fclose(LuciObject **args, unsigned int c) { if (c < 1) { LUCI_DIE("%s", "Missing parameter to close()\n"); } LuciObject *fobj = args[0]; if (!ISTYPE(fobj, obj_file_t)) { LUCI_DIE("%s", "Not a file object\n"); } if (AS_FILE(fobj)->ptr) { close_file(AS_FILE(fobj)->ptr); } /* else, probably already closed (it's NULL) */ LUCI_DEBUG("%s\n", "Closed file object."); return LuciNilObj; }
/** Prints a help message, which is essentially just a list of * builtin library functions for now * * @param args unused * @param c unused * @returns NULL */ LuciObject *luci_help(LuciObject **args, unsigned int c) { int width = 32; if (c == 0) { printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n"); printf(" HELP \n"); printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n"); printf(" BUILTIN FUNCTIONS \n"); printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n"); int i, len, f, l, j; for (i = 0; builtins_registry[i].name != 0; i++) { len = strlen(builtins_registry[i].name); f = (width - len) / 2; l = width - f; for (j = 0; j < f; j++) printf(" "); printf("%s", builtins_registry[i].name); for (j = 0; j < l; j++) printf(" "); printf("\n"); } printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n"); } else { unsigned int i; for (i = 0; i < c; i++) { LuciObject *o = args[i]; if (!ISTYPE(o, obj_libfunc_t)) { printf("No help available for object of type %s\n", o->type->type_name); } else { printf("%s\n", AS_LIBFUNC(o)->help); } } } return LuciNilObj; }
Expression *TraitsExp::semantic(Scope *sc) { #if LOGSEMANTIC printf("TraitsExp::semantic() %s\n", toChars()); #endif if (ident != Id::compiles && ident != Id::isSame) TemplateInstance::semanticTiargs(loc, sc, args, 1); size_t dim = args ? args->dim : 0; Object *o; FuncDeclaration *f; #define ISTYPE(cond) \ for (size_t i = 0; i < dim; i++) \ { Type *t = getType((Object *)args->data[i]); \ if (!t) \ goto Lfalse; \ if (!(cond)) \ goto Lfalse; \ } \ if (!dim) \ goto Lfalse; \ goto Ltrue; #define ISDSYMBOL(cond) \ for (size_t i = 0; i < dim; i++) \ { Dsymbol *s = getDsymbol((Object *)args->data[i]); \ if (!s) \ goto Lfalse; \ if (!(cond)) \ goto Lfalse; \ } \ if (!dim) \ goto Lfalse; \ goto Ltrue; if (ident == Id::isArithmetic) { ISTYPE(t->isintegral() || t->isfloating()) } else if (ident == Id::isFloating) { ISTYPE(t->isfloating()) } else if (ident == Id::isIntegral) { ISTYPE(t->isintegral()) } else if (ident == Id::isScalar) { ISTYPE(t->isscalar()) } else if (ident == Id::isUnsigned) { ISTYPE(t->isunsigned()) } else if (ident == Id::isAssociativeArray) { ISTYPE(t->toBasetype()->ty == Taarray) } else if (ident == Id::isStaticArray) { ISTYPE(t->toBasetype()->ty == Tsarray) } else if (ident == Id::isAbstractClass) { ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract()) } else if (ident == Id::isFinalClass) { ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal) } else if (ident == Id::isAbstractFunction) { ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isAbstract()) } else if (ident == Id::isVirtualFunction) { ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isVirtual()) } else if (ident == Id::isFinalFunction) { ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isFinal()) } else if (ident == Id::hasMember || ident == Id::getMember || ident == Id::getVirtualFunctions) { if (dim != 2) goto Ldimerror; Object *o = (Object *)args->data[0]; Expression *e = isExpression((Object *)args->data[1]); if (!e) { // error("expression expected as second argument of __traits %s", ident->toChars()); goto Lfalse; } e = e->optimize(WANTvalue | WANTinterpret); if (e->op != TOKstring) { // error("string expected as second argument of __traits %s instead of %s", ident->toChars(), e->toChars()); goto Lfalse; } StringExp *se = (StringExp *)e; se = se->toUTF8(sc); if (se->sz != 1) { // error("string must be chars"); goto Lfalse; } Identifier *id = Lexer::idPool((char *)se->string); Type *t = isType(o); e = isExpression(o); Dsymbol *s = isDsymbol(o); if (t) e = new TypeDotIdExp(loc, t, id); else if (e) e = new DotIdExp(loc, e, id); else if (s) { e = new DsymbolExp(loc, s); e = new DotIdExp(loc, e, id); } else { // error("invalid first argument"); goto Lfalse; } if (ident == Id::hasMember) { /* Take any errors as meaning it wasn't found */ unsigned errors = global.errors; global.gag++; e = e->semantic(sc); global.gag--; if (errors != global.errors) { if (global.gag == 0) global.errors = errors; goto Lfalse; } else goto Ltrue; } else if (ident == Id::getMember) { e = e->semantic(sc); return e; } else if (ident == Id::getVirtualFunctions) { unsigned errors = global.errors; Expression *ex = e; e = e->semantic(sc); /* if (errors < global.errors) error("%s cannot be resolved", ex->toChars()); */ /* Create tuple of virtual function overloads of e */ //e->dump(0); Expressions *exps = new Expressions(); FuncDeclaration *f; if (e->op == TOKvar) { VarExp *ve = (VarExp *)e; f = ve->var->isFuncDeclaration(); } else if (e->op == TOKdotvar) { DotVarExp *dve = (DotVarExp *)e; f = dve->var->isFuncDeclaration(); } else f = NULL; Pvirtuals p; p.exps = exps; p.e1 = e; overloadApply(f, fpvirtuals, &p); TupleExp *tup = new TupleExp(loc, exps); return tup->semantic(sc); } else assert(0); } else if (ident == Id::classInstanceSize) { if (dim != 1) goto Ldimerror; Object *o = (Object *)args->data[0]; Dsymbol *s = getDsymbol(o); ClassDeclaration *cd; if (!s || (cd = s->isClassDeclaration()) == NULL) { // error("first argument is not a class"); goto Lfalse; } return new IntegerExp(loc, cd->structsize, Type::tsize_t); } else if (ident == Id::allMembers || ident == Id::derivedMembers) { if (dim != 1) goto Ldimerror; Object *o = (Object *)args->data[0]; Dsymbol *s = getDsymbol(o); ScopeDsymbol *sd; if (!s) { // error("argument has no members"); goto Lfalse; } if ((sd = s->isScopeDsymbol()) == NULL) { // error("%s %s has no members", s->kind(), s->toChars()); goto Lfalse; } Expressions *exps = new Expressions; while (1) { size_t dim = ScopeDsymbol::dim(sd->members); for (size_t i = 0; i < dim; i++) { Dsymbol *sm = ScopeDsymbol::getNth(sd->members, i); //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars()); if (sm->ident) { //printf("\t%s\n", sm->ident->toChars()); char *str = sm->ident->toChars(); /* Skip if already present in exps[] */ for (size_t j = 0; j < exps->dim; j++) { StringExp *se2 = (StringExp *)exps->data[j]; if (strcmp(str, (char *)se2->string) == 0) goto Lnext; } StringExp *se = new StringExp(loc, str); exps->push(se); } Lnext: ; } ClassDeclaration *cd = sd->isClassDeclaration(); if (cd && cd->baseClass && ident == Id::allMembers) sd = cd->baseClass; // do again with base class else break; } Expression *e = new ArrayLiteralExp(loc, exps); e = e->semantic(sc); return e; } else if (ident == Id::compiles) { /* Determine if all the objects - types, expressions, or symbols - * compile without error */ if (!dim) goto Lfalse; for (size_t i = 0; i < dim; i++) { Object *o = (Object *)args->data[i]; Type *t; Expression *e; Dsymbol *s; unsigned errors = global.errors; global.gag++; t = isType(o); if (t) { t->resolve(loc, sc, &e, &t, &s); if (t) t->semantic(loc, sc); else if (e) e->semantic(sc); } else { e = isExpression(o); if (e) e->semantic(sc); } global.gag--; if (errors != global.errors) { if (global.gag == 0) global.errors = errors; goto Lfalse; } } goto Ltrue; } else if (ident == Id::isSame) { /* Determine if two symbols are the same */ if (dim != 2) goto Ldimerror; TemplateInstance::semanticTiargs(loc, sc, args, 0); Object *o1 = (Object *)args->data[0]; Object *o2 = (Object *)args->data[1]; Dsymbol *s1 = getDsymbol(o1); Dsymbol *s2 = getDsymbol(o2); #if 0 printf("o1: %p\n", o1); printf("o2: %p\n", o2); if (!s1) { Expression *ea = isExpression(o1); if (ea) printf("%s\n", ea->toChars()); Type *ta = isType(o1); if (ta) printf("%s\n", ta->toChars()); goto Lfalse; } else printf("%s %s\n", s1->kind(), s1->toChars()); #endif if (!s1 && !s2) { Expression *ea1 = isExpression(o1); Expression *ea2 = isExpression(o2); if (ea1 && ea2 && ea1->equals(ea2)) goto Ltrue; } if (!s1 || !s2) goto Lfalse; s1 = s1->toAlias(); s2 = s2->toAlias(); if (s1 == s2) goto Ltrue; else goto Lfalse; } else { // error("unrecognized trait %s", ident->toChars()); goto Lfalse; } return NULL; Lnottype: // error("%s is not a type", o->toChars()); goto Lfalse; Ldimerror: // error("wrong number of arguments %d", dim); goto Lfalse; Lfalse: return new IntegerExp(loc, 0, Type::tbool); Ltrue: return new IntegerExp(loc, 1, Type::tbool); }
Expression *TraitsExp::semantic(Scope *sc) { #if LOGSEMANTIC printf("TraitsExp::semantic() %s\n", toChars()); #endif if (ident != Id::compiles && ident != Id::isSame && ident != Id::identifier) { TemplateInstance::semanticTiargs(loc, sc, args, 1); } size_t dim = args ? args->dim : 0; Declaration *d; #define ISTYPE(cond) \ for (size_t i = 0; i < dim; i++) \ { Type *t = getType((*args)[i]); \ if (!t) \ goto Lfalse; \ if (!(cond)) \ goto Lfalse; \ } \ if (!dim) \ goto Lfalse; \ goto Ltrue; #define ISDSYMBOL(cond) \ for (size_t i = 0; i < dim; i++) \ { Dsymbol *s = getDsymbol((*args)[i]); \ if (!s) \ goto Lfalse; \ if (!(cond)) \ goto Lfalse; \ } \ if (!dim) \ goto Lfalse; \ goto Ltrue; if (ident == Id::isArithmetic) { ISTYPE(t->isintegral() || t->isfloating()) } else if (ident == Id::isFloating) { ISTYPE(t->isfloating()) } else if (ident == Id::isIntegral) { ISTYPE(t->isintegral()) } else if (ident == Id::isScalar) { ISTYPE(t->isscalar()) } else if (ident == Id::isUnsigned) { ISTYPE(t->isunsigned()) } else if (ident == Id::isAssociativeArray) { ISTYPE(t->toBasetype()->ty == Taarray) } else if (ident == Id::isStaticArray) { ISTYPE(t->toBasetype()->ty == Tsarray) } else if (ident == Id::isAbstractClass) { ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract()) } else if (ident == Id::isFinalClass) { ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal) } else if (ident == Id::isPOD) { if (dim != 1) goto Ldimerror; Object *o = (*args)[0]; Type *t = isType(o); StructDeclaration *sd; if (!t) { error("type expected as second argument of __traits %s instead of %s", ident->toChars(), o->toChars()); goto Lfalse; } if (t->toBasetype()->ty == Tstruct && ((sd = (StructDeclaration *)(((TypeStruct *)t->toBasetype())->sym)) != NULL)) { if (sd->isPOD()) goto Ltrue; else goto Lfalse; } goto Ltrue; } else if (ident == Id::isNested) { if (dim != 1) goto Ldimerror; Object *o = (*args)[0]; Dsymbol *s = getDsymbol(o); AggregateDeclaration *a; FuncDeclaration *f; if (!s) { } else if ((a = s->isAggregateDeclaration()) != NULL) { if (a->isNested()) goto Ltrue; else goto Lfalse; } else if ((f = s->isFuncDeclaration()) != NULL) { if (f->isNested()) goto Ltrue; else goto Lfalse; } error("aggregate or function expected instead of '%s'", o->toChars()); goto Lfalse; } else if (ident == Id::isAbstractFunction) { FuncDeclaration *f; ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isAbstract()) }
/** * Creates a LuciListObj containing a range of numbers. * * @param args list of args * @param c number of args * @returns list of numbers */ LuciObject * luci_range(LuciObject **args, unsigned int c) { long start, end, incr; LuciObject *first, *second, *third; if (c < 1) { LUCI_DIE("%s", "Missing parameter to range()\n"); } first = args[0]; if (!ISTYPE(first, obj_int_t)) { LUCI_DIE("%s", "First parameter to range must be integer\n"); } if (c > 1) { second = args[1]; if (!ISTYPE(second, obj_int_t)) { LUCI_DIE("%s", "Second parameter to range must be integer\n"); } start = AS_INT(first)->i; end = AS_INT(second)->i; if (c > 2) { /* Ternary range(X, Y, Z) call */ third = args[2]; if (!ISTYPE(third, obj_int_t)) { LUCI_DIE("%s", "Third parameter to range must be integer\n"); } incr = AS_INT(third)->i; } else { incr = 1; } } else { /* Basic range(X) call, increment by 1 starting from 0 */ start = 0; end = AS_INT(first)->i; incr = 1; } /* Build a list of integers from start to end, incrementing by incr */ LuciObject *item, *list = LuciList_new(); long i; if (incr < 0) { if (start <= end) { /* return empty list if idiotically requested */ return list; } for (i = start; i > end; i += incr) { item = LuciInt_new(i); LuciList_append(list, item); } } else { if (start >= end) { /* return empty list if idiotically requested */ return list; } for (i = start; i < end; i += incr) { item = LuciInt_new(i); LuciList_append(list, item); } } return list; }
Expression *TraitsExp::semantic(Scope *sc) { #if LOGSEMANTIC printf("TraitsExp::semantic() %s\n", toChars()); #endif if (ident != Id::compiles && ident != Id::isSame && ident != Id::identifier) { TemplateInstance::semanticTiargs(loc, sc, args, 1); } size_t dim = args ? args->dim : 0; Declaration *d; #define ISTYPE(cond) \ for (size_t i = 0; i < dim; i++) \ { Type *t = getType((*args)[i]); \ if (!t) \ goto Lfalse; \ if (!(cond)) \ goto Lfalse; \ } \ if (!dim) \ goto Lfalse; \ goto Ltrue; #define ISDSYMBOL(cond) \ for (size_t i = 0; i < dim; i++) \ { Dsymbol *s = getDsymbol((*args)[i]); \ if (!s) \ goto Lfalse; \ if (!(cond)) \ goto Lfalse; \ } \ if (!dim) \ goto Lfalse; \ goto Ltrue; if (ident == Id::isArithmetic) { ISTYPE(t->isintegral() || t->isfloating()) } else if (ident == Id::isFloating) { ISTYPE(t->isfloating()) } else if (ident == Id::isIntegral) { ISTYPE(t->isintegral()) } else if (ident == Id::isScalar) { ISTYPE(t->isscalar()) } else if (ident == Id::isUnsigned) { ISTYPE(t->isunsigned()) } else if (ident == Id::isAssociativeArray) { ISTYPE(t->toBasetype()->ty == Taarray) } else if (ident == Id::isStaticArray) { ISTYPE(t->toBasetype()->ty == Tsarray) } else if (ident == Id::isAbstractClass) { ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract()) } else if (ident == Id::isFinalClass) { ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal) } else if (ident == Id::isAbstractFunction) { FuncDeclaration *f; ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isAbstract()) }
/** * Main interpreter loop * *------- Computed Goto Definitions (Labels as Values) ------- * Popular interpreters such as Python and Ruby utilize this * GCC extension for up to 20% performance improvement. * The advantage of using of an explicit jump table and explicit * indirect jump instruction after each opcode's execution is * described in the Python 3.3 source (ceval.c). * Eli Bendersky also has a good explanation and demo available * at http://eli.thegreenplace.net/2012/07/12/computed-goto-for-efficient-dispatch-tables * NOTE (directly from Python 3.3): * "care must be taken that the compiler doesn't try to 'optimize' the * indirect jumps by sharing them between all opcodes. Such optimizations * can be disabled on gcc by using the -fno-gcse flag (or possibly * -fno-crossjumping)." * * @param frame top-level function to being interpreting */ void eval(LuciObject *frame) { /* If GNU extensions are available... defined by GCC/Clang */ #ifdef __GNUC__ #include "dispatch.h" /* include static jump table */ /** initial dispatch */ #define INTERP_INIT() DISPATCH /** no op */ #define SWITCH /** no op */ #define DEFAULT /** label (as value) */ #define HANDLE(op) do_##op: { GC_COLLECT(); a = GETARG; } /** computed goto */ #define DISPATCH goto *dispatch_table[GETOPCODE] #else /* __GNUC__ */ /** no op */ #define INTERP_INIT() /** switch statement */ #define SWITCH switch(GETOPCODE) /** default case */ #define DEFAULT default: goto done_eval; /** case statement for opcode */ #define HANDLE(op) case (op): { GC_COLLECT(); a = GETARG; } /** break statement */ #define DISPATCH break #endif /* __GNUC__ */ /**************************************************************/ /** increment instruction pointer */ #define FETCH(c) (ip += (c)) /** dereference instruction pointer */ #define READ (*ip) /** get opcode from instruction */ #define GETOPCODE OPCODE(READ) /** get argument from instruction */ #define GETARG OPARG(READ) LuciObject *stack = LuciList_new(); gc_track_root(&stack); gc_track_root(&frame); LuciObject* lfargs[MAX_LIBFUNC_ARGS]; register LuciObject *x = LuciNilObj; register LuciObject *y = LuciNilObj; register LuciObject *z = LuciNilObj; int a; int i = 0; Instruction *ip = AS_FUNCTION(frame)->instructions; for (i = 0; i < MAX_LIBFUNC_ARGS; i++) { lfargs[i] = LuciNilObj; } i = 0; INTERP_INIT(); /* Begin interpreting instructions */ #define EVER ;; /* saw this on stackoverflow. so dumb */ for(EVER) { SWITCH { HANDLE(NOP) { LUCI_DEBUG("%s\n", "NOP"); } FETCH(1); DISPATCH; HANDLE(ADD) { LUCI_DEBUG("%s\n", "ADD"); y = LuciList_pop(stack); x = LuciList_pop(stack); z = x->type->add(x, y); LuciList_push(stack, z); } FETCH(1); DISPATCH; HANDLE(SUB) { LUCI_DEBUG("%s\n", "SUB"); y = LuciList_pop(stack); x = LuciList_pop(stack); z = x->type->sub(x, y); LuciList_push(stack, z); } FETCH(1); DISPATCH; HANDLE(MUL) { LUCI_DEBUG("%s\n", "MUL"); y = LuciList_pop(stack); x = LuciList_pop(stack); z = x->type->mul(x, y); LuciList_push(stack, z); } FETCH(1); DISPATCH; HANDLE(DIV) { LUCI_DEBUG("%s\n", "DIV"); y = LuciList_pop(stack); x = LuciList_pop(stack); z = x->type->div(x, y); LuciList_push(stack, z); } FETCH(1); DISPATCH; HANDLE(MOD) { LUCI_DEBUG("%s\n", "MOD"); y = LuciList_pop(stack); x = LuciList_pop(stack); z = x->type->mod(x, y); LuciList_push(stack, z); } FETCH(1); DISPATCH; HANDLE(POW) { LUCI_DEBUG("%s\n", "POW"); y = LuciList_pop(stack); x = LuciList_pop(stack); z = x->type->pow(x, y); LuciList_push(stack, z); } FETCH(1); DISPATCH; HANDLE(EQ) { LUCI_DEBUG("%s\n", "EQ"); y = LuciList_pop(stack); x = LuciList_pop(stack); z = x->type->eq(x, y); LuciList_push(stack, z); } FETCH(1); DISPATCH; HANDLE(NEQ) { LUCI_DEBUG("%s\n", "NEQ"); y = LuciList_pop(stack); x = LuciList_pop(stack); z = x->type->neq(x, y); LuciList_push(stack, z); } FETCH(1); DISPATCH; HANDLE(LT) { LUCI_DEBUG("%s\n", "LT"); y = LuciList_pop(stack); x = LuciList_pop(stack); z = x->type->lt(x, y); LuciList_push(stack, z); } FETCH(1); DISPATCH; HANDLE(GT) { LUCI_DEBUG("%s\n", "GT"); y = LuciList_pop(stack); x = LuciList_pop(stack); z = x->type->gt(x, y); LuciList_push(stack, z); } FETCH(1); DISPATCH; HANDLE(LTE) { LUCI_DEBUG("%s\n", "LTE"); y = LuciList_pop(stack); x = LuciList_pop(stack); z = x->type->lte(x, y); LuciList_push(stack, z); } FETCH(1); DISPATCH; HANDLE(GTE) { LUCI_DEBUG("%s\n", "GTE"); y = LuciList_pop(stack); x = LuciList_pop(stack); z = x->type->gte(x, y); LuciList_push(stack, z); } FETCH(1); DISPATCH; HANDLE(LGOR) { LUCI_DEBUG("%s\n", "LGOR"); y = LuciList_pop(stack); x = LuciList_pop(stack); z = x->type->lgor(x, y); LuciList_push(stack, z); } FETCH(1); DISPATCH; HANDLE(LGAND) { LUCI_DEBUG("%s\n", "LGAND"); y = LuciList_pop(stack); x = LuciList_pop(stack); z = x->type->lgand(x, y); LuciList_push(stack, z); } FETCH(1); DISPATCH; HANDLE(BWXOR) { LUCI_DEBUG("%s\n", "BWXOR"); y = LuciList_pop(stack); x = LuciList_pop(stack); z = x->type->bwxor(x, y); LuciList_push(stack, z); } FETCH(1); DISPATCH; HANDLE(BWOR) { LUCI_DEBUG("%s\n", "BWOR"); y = LuciList_pop(stack); x = LuciList_pop(stack); z = x->type->bwor(x, y); LuciList_push(stack, z); } FETCH(1); DISPATCH; HANDLE(BWAND) { LUCI_DEBUG("%s\n", "BWAND"); y = LuciList_pop(stack); x = LuciList_pop(stack); z = x->type->bwand(x, y); LuciList_push(stack, z); } FETCH(1); DISPATCH; HANDLE(NEG) { LUCI_DEBUG("%s\n", "NEG"); x = LuciList_pop(stack); y = x->type->neg(x); LuciList_push(stack, y); } FETCH(1); DISPATCH; HANDLE(LGNOT) { LUCI_DEBUG("%s\n", "LGNOT"); x = LuciList_pop(stack); y = x->type->lgnot(x); LuciList_push(stack, y); } FETCH(1); DISPATCH; HANDLE(BWNOT) { LUCI_DEBUG("%s\n", "BWNOT"); x = LuciList_pop(stack); y = x->type->bwnot(x); LuciList_push(stack, y); } FETCH(1); DISPATCH; HANDLE(POP) { LUCI_DEBUG("%s\n", "POP"); x = LuciList_pop(stack); } FETCH(1); DISPATCH; HANDLE(PUSHNIL) LUCI_DEBUG("%s\n", "PUSHNIL"); LuciList_push(stack, LuciNilObj); FETCH(1); DISPATCH; HANDLE(LOADK) LUCI_DEBUG("LOADK %d\n", a); x = AS_FUNCTION(frame)->constants[a]; LuciList_push(stack, x); FETCH(1); DISPATCH; HANDLE(LOADS) LUCI_DEBUG("LOADS %d\n", a); x = AS_FUNCTION(frame)->locals[a]; LuciList_push(stack, x); FETCH(1); DISPATCH; HANDLE(LOADG) LUCI_DEBUG("LOADG %d\n", a); x = AS_FUNCTION(frame)->globals[a]; LuciList_push(stack, x); FETCH(1); DISPATCH; HANDLE(LOADB) LUCI_DEBUG("LOADB %d\n", a); x = builtins[a]; LuciList_push(stack, x); FETCH(1); DISPATCH; HANDLE(DUP) LUCI_DEBUG("%s\n", "DUP"); /* duplicate object on top of stack * and push it back on */ x = LuciList_peek(stack); y = x->type->copy(x); LuciList_push(stack, y); FETCH(1); DISPATCH; HANDLE(STORE) LUCI_DEBUG("STORE %d\n", a); /* pop object off of stack */ x = LuciList_pop(stack); /* store the new object */ y = x->type->copy(x); AS_FUNCTION(frame)->locals[a] = y; FETCH(1); DISPATCH; HANDLE(CALL) { LUCI_DEBUG("CALL %d\n", a); x = LuciList_pop(stack); /* function object */ /* setup user-defined function */ if (ISTYPE(x, obj_func_t)) { /* save instruction pointer */ AS_FUNCTION(frame)->ip = ip; /* save pointer to current frame */ LuciObject *parent_frame = frame; /* activate a copy of the function frame */ frame = x->type->copy(x); /* check that the # of arguments equals the # of parameters */ if (a < AS_FUNCTION(frame)->nparams) { LUCI_DIE("%s", "Missing arguments to function.\n"); } else if (a > AS_FUNCTION(frame)->nparams) { LUCI_DIE("%s", "Too many arguments to function.\n"); } /* pop arguments and push COPIES into locals */ for (i = 0; i < a; i++) { y = LuciList_pop(stack); AS_FUNCTION(frame)->locals[i] = y->type->copy(y); } /* the stack is clean, now push the previous frame */ LuciList_push(stack, parent_frame); /* reset instruction pointer and carry on our merry way */ /* NOTE: while ugly, we decrement ip by one instruction * so that the following FETCH call starts at the 1st * instruction!!! */ ip = AS_FUNCTION(frame)->instructions - 1; } /* call library function */ else if (ISTYPE(x, obj_libfunc_t)) { if (a >= MAX_LIBFUNC_ARGS) { LUCI_DIE("%s\n", "Too many arguments to function"); } else if (a < AS_LIBFUNC(x)->min_args) { LUCI_DIE("%s\n", "Missing arguments to function"); } /* pop args and push into args array */ /* must happen in reverse */ for (i = a - 1; i >= 0; i--) { y = LuciList_pop(stack); lfargs[i] = y->type->copy(y); } /* call func, passing args array and arg count */ z = ((LuciLibFuncObj *)x)->func(lfargs, a); LuciList_push(stack, z); /* always push return val */ } else { LUCI_DIE("%s", "Can't call something that isn't a function\n"); } } FETCH(1); DISPATCH; HANDLE(RETURN) LUCI_DEBUG("%s\n", "RETURN"); /* pop the return value */ LuciObject *return_value = LuciList_pop(stack); /* pop function stack frame and replace active frame */ frame = LuciList_pop(stack); //assert(frame->type == &obj_func_t); /* push the return value back onto the stack */ LuciList_push(stack, return_value); /* restore saved instruction pointer */ ip = AS_FUNCTION(frame)->ip; FETCH(1); DISPATCH; HANDLE(MKMAP) LUCI_DEBUG("MKMAP %d\n", a); x = LuciMap_new(); for (i = 0; i < a; i ++) { /* first item is the value */ y = LuciList_pop(stack); /* then the key */ z = LuciList_pop(stack); /* add the key & value to the map */ x->type->cput(x, z, y); } LuciList_push(stack, x); FETCH(1); DISPATCH; HANDLE(MKLIST) LUCI_DEBUG("MKLIST %d\n", a); x = LuciList_new(); for (i = 0; i < a; i ++) { y = LuciList_pop(stack); LuciList_append(x, y); } LuciList_push(stack, x); FETCH(1); DISPATCH; HANDLE(CGET) { LUCI_DEBUG("%s\n", "CGET"); /* pop container */ x = LuciList_pop(stack); /* pop 'index' */ y = LuciList_pop(stack); /* cget from the container */ z = x->type->cget(x, y); LuciList_push(stack, z); } FETCH(1); DISPATCH; HANDLE(CPUT) { LUCI_DEBUG("%s\n", "CPUT"); /* pop container */ x = LuciList_pop(stack); /* pop index/key/... */ y = LuciList_pop(stack); /* pop right hand value */ z = LuciList_pop(stack); /* put the right hand value into the container */ y = x->type->cput(x, y, z); } FETCH(1); DISPATCH; HANDLE(MKITER) LUCI_DEBUG("%s\n", "MKITER"); /* x should be a container */ x = LuciList_pop(stack); y = LuciIterator_new(x, 1); /* step = 1 */ LuciList_push(stack, y); FETCH(1); DISPATCH; HANDLE(JUMP) LUCI_DEBUG("JUMP %d\n", a); FETCH(a); DISPATCH; HANDLE(POPJUMP) LUCI_DEBUG("POPJUMP %d\n", a); x = LuciList_pop(stack); FETCH(a); DISPATCH; HANDLE(JUMPZ) LUCI_DEBUG("JUMPZ %d\n", a); x = LuciList_pop(stack); if (((LuciIntObj *)x)->i == 0) { FETCH(a); } else { FETCH(1); } DISPATCH; HANDLE(ITERJUMP) LUCI_DEBUG("ITERJUMP %d\n", a); x = LuciList_peek(stack); /* get a COPY of the next object in the iterator's list */ y = iterator_next_object(x); /* if the iterator returned NULL, jump to the * end of the for loop. Otherwise, push iterator->next */ if (y == NULL) { /* pop the iterator object */ x = LuciList_pop(stack); FETCH(a); } else { LuciList_push(stack, y); FETCH(1); } DISPATCH; HANDLE(HALT) LUCI_DEBUG("%s\n", "HALT"); gc_untrack_roots(); goto done_eval; DISPATCH; DEFAULT LUCI_DIE("Invalid opcode: %d\n", GETOPCODE); } } done_eval:; return; }