예제 #1
0
파일: builtin.c 프로젝트: geraldstanje/luci
/**
 * 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;
}
예제 #2
0
파일: builtin.c 프로젝트: geraldstanje/luci
/**
 * 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;
}
예제 #3
0
파일: builtin.c 프로젝트: geraldstanje/luci
/**
 * 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;
}
예제 #4
0
파일: builtin.c 프로젝트: geraldstanje/luci
/**
 * 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;
}
예제 #5
0
파일: builtin.c 프로젝트: geraldstanje/luci
/**
 * 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;
}
예제 #6
0
/**
 * 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;
}
예제 #7
0
파일: builtin.c 프로젝트: geraldstanje/luci
/**
 * 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;
}
예제 #8
0
파일: builtin.c 프로젝트: geraldstanje/luci
/**
 * 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;
}
예제 #9
0
파일: builtin.c 프로젝트: geraldstanje/luci
/**
 * 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;
}
예제 #10
0
파일: builtin.c 프로젝트: geraldstanje/luci
/**
 * 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;
}
예제 #11
0
/**
 * 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;
}
예제 #12
0
파일: builtin.c 프로젝트: geraldstanje/luci
/**
 * 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);
}
예제 #13
0
파일: udp_socket.c 프로젝트: berkus/nemesis
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;
}
예제 #14
0
파일: builtin.c 프로젝트: geraldstanje/luci
/**
 * 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;
}
예제 #15
0
파일: builtin.c 프로젝트: geraldstanje/luci
/**
 * 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;
}
예제 #16
0
파일: builtin.c 프로젝트: geraldstanje/luci
/** 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;
}
예제 #17
0
파일: traits.c 프로젝트: apriori/dsss
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);
}
예제 #18
0
파일: traits.c 프로젝트: FrankLIKE/ldc
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())
    }
예제 #19
0
파일: builtin.c 프로젝트: geraldstanje/luci
/**
 * 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;
}
예제 #20
0
파일: traits.c 프로젝트: OlioEngr/dmd
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())
    }
예제 #21
0
/**
 * 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;
}