Example #1
0
File: VM.cpp Project: preda/pepper
inline Value doAdd(GC *gc, Value a, Value b) {
    int ta = TAG(a);
    if (IS_NUM_TAG(ta) && IS_NUM(b)) {
        return VAL_NUM(GET_NUM(a) + GET_NUM(b));
    } else if (IS_STRING(a)) {
        return String::concat(gc, a, b);
    } else {
        if (ta != T_OBJ) { return E_WRONG_TYPE; }
        int type = O_TYPE(a);
        if (type == O_ARRAY && (IS_ARRAY(b) || IS_MAP(b) || IS_STRING(b))) {
            Array *array = Array::alloc(gc);
            array->add(a);
            array->add(b);
            return VAL_OBJ(array);
        } else if (type == O_MAP && (IS_ARRAY(b) || IS_MAP(b) || IS_STRING(b))) {
            Map *map = MAP(a)->copy(gc);
            map->add(b);
            return VAL_OBJ(map);
        } else {
            return VERR;
        }
    }
}
Example #2
0
static void como_execute(ComoFrame *frame, ComoFrame *callingframe) {
    size_t i;
    for(i = 0; i < O_AVAL(frame->code)->size; i++) {
        ComoOpCode *opcode = ((ComoOpCode *)(O_PTVAL(O_AVAL(frame->code)->table[i])));
        switch(opcode->op_code) {
            default: {
                como_error_noreturn("Invalid OpCode got %d", opcode->op_code);
            }
            case POSTFIX_INC: {
                Object *value = NULL;
                value = mapSearchEx(frame->cf_symtab, 
                    O_SVAL(opcode->operand)->value);

                if(value == NULL) {
                    como_error_noreturn("undefined variable '%s'", 
                        O_SVAL(opcode->operand)->value);
                } else {
                    if(O_TYPE(value) != IS_LONG) {
                        como_error_noreturn("unsupported value for POSTFIX_INC");
                    } else {
                        long oldvalue = O_LVAL(value);
                        O_LVAL(value) = oldvalue + 1;
                        push(frame, newLong(oldvalue));
                    }   
                }
                break;        
            }
            case POSTFIX_DEC: {
                Object *value = NULL;
                value = mapSearchEx(frame->cf_symtab, 
                    O_SVAL(opcode->operand)->value);

                if(value == NULL) {
                    como_error_noreturn("undefined variable '%s'", 
                        O_SVAL(opcode->operand)->value);
                } else {
                    if(O_TYPE(value) != IS_LONG) {
                        como_error_noreturn("unsupported value for POSTFIX_DEC");
                    } else {
                        long oldvalue = O_LVAL(value);
                        O_LVAL(value) = oldvalue - 1;
                        push(frame, newLong(oldvalue));
                    }   
                }
                break;        
            }
						case IS_LESS_THAN: {
							Object *right = pop(frame);
							Object *left = pop(frame);
							assert(right);
							assert(left);

							if(objectValueIsLessThan(left, right)) {
								push(frame, newLong(1L));
							} else {
								push(frame, newLong(0L));
							}
							break;
						}
						case IADD: {
							Object *right = pop(frame);
							Object *left = pop(frame);
							assert(right);
							assert(left);

							if(O_TYPE(left) == IS_LONG && O_TYPE(right) == IS_LONG) {
								long value = O_LVAL(left) + O_LVAL(right);
								push(frame, newLong(value));
							} else {
								char *left_str = objectToString(left);
								char *right_str = objectToString(right);
								Object *s1 = newString(left_str);
								Object *s2 = newString(right_str);
								Object *value = stringCat(s1, s2);
								push(frame, value);
								objectDestroy(s1);
								objectDestroy(s2);
								free(left_str);
								free(right_str);	
							}
							break;
						}
            case IMINUS: {
                Object *right = pop(frame);
                Object *left = pop(frame);
                assert(right);
                assert(left);
                if(O_TYPE(left) != IS_LONG && O_TYPE(right) != IS_LONG) {
                    como_error_noreturn("unsupported value for IMINUS");
                } else {
                    push(frame, newLong(O_LVAL(left) - O_LVAL(right)));
                }      
                break;
            }
            case IS_LESS_THAN_OR_EQUAL: {
                Object *right = pop(frame);
                Object *left = pop(frame);
                assert(right);
                assert(left);

                if(objectValueCompare(left, right) || objectValueIsLessThan(left, right)) {
                    push(frame, newLong(1L));
                } else {
                    push(frame, newLong(0L));
                }
                break;
            }
            case JZ: {
                Object *cond = pop(frame);
                if(O_TYPE(cond) == IS_LONG && O_LVAL(cond) == 0) {
                    i = (size_t)O_LVAL(opcode->operand);      
                    continue;          
                }
                break;
            }
            case JMP: {
                i = O_LVAL(opcode->operand);
                continue;
            }
            case LABEL: {
                break;
            }
            case HALT: {
                break;
            }
						case IS_NOT_EQUAL: {
							Object *right = pop(frame);
							Object *left = pop(frame);

							if(!objectValueCompare(left, right)) {
								push(frame, newLong(1L));
							} else {
								push(frame, newLong(0L));
							}
							break;
						}
            case LOAD_CONST: {
								como_debug("LOAD_CONST");
                push(frame, opcode->operand);
                break;
            }
            case STORE_NAME: {
                Object *value = pop(frame);
                mapInsertEx(frame->cf_symtab, 
                    O_SVAL(opcode->operand)->value, value);
                break;
            }
						/* This is where recursion was broken, don't do *ex */
            case LOAD_NAME: {
                Object *value = NULL;
                value = mapSearch(frame->cf_symtab, 
                    O_SVAL(opcode->operand)->value);
                if(value) {
                    goto load_name_leave;
                } else {
                    value = mapSearch(global_frame->cf_symtab, 
                        O_SVAL(opcode->operand)->value);
                }

                if(value == NULL) {
                    como_error_noreturn("undefined variable '%s'", 
                        O_SVAL(opcode->operand)->value);
                }
load_name_leave:
                push(frame, value);
                break;
            }
            case CALL_FUNCTION: {
                Object *fn = pop(frame);
                Object *argcount = pop(frame);
                long i = O_LVAL(argcount);
                ComoFrame *fnframe;
                if(O_TYPE(fn) != IS_POINTER) {
                    como_error_noreturn("name '%s' is not callable",
                        O_SVAL(opcode->operand)->value);
                }
                fnframe = (ComoFrame *)O_PTVAL(fn);
                if(O_LVAL(argcount) != (long)(O_AVAL(fnframe->namedparameters)->size)) {
                    como_error_noreturn("callable '%s' expects %ld arguments, but %ld were given",
                        O_SVAL(opcode->operand)->value, 
                        (long)(O_AVAL(fnframe->namedparameters)->size), 
                        O_LVAL(argcount));
                }
								//como_debug("calling '%s'", O_SVAL(opcode->operand)->value);
                // DOING THIS ACTUALLY DEFINES THE NAME AT RUNTIME
								// which could not be equal to that actual function body 
								// declared
								// name = my_function
								// name() 
								// that call will have "name" for value __FUNCTION__
								// even though the real function is my_function
								// must define it at COMPILE time
								// mapInsertEx(fnframe->cf_symtab, "__FUNCTION__", 
                // newString(O_SVAL(opcode->operand)->value));

                while(i--) {
                    como_debug("getting %ldth argument for function call '%s'",
                        i, O_SVAL(opcode->operand)->value);
                    Object *argname = O_AVAL(fnframe->namedparameters)->table[i];

                    Object *argvalue = pop(frame);
                    mapInsert(fnframe->cf_symtab, O_SVAL(argname)->value,
                        argvalue);
                    char *argvaluestr = objectToString(argvalue);
                    
										como_debug("%ldth argument: '%s' has value: %s", i, O_SVAL(argname)->value,
                        argvaluestr);
										free(argvaluestr);
                }
                //ComoFrame *prev = frame;

                //fnframe->next = prev;

                como_execute(fnframe, NULL);
                
								push(frame, pop(fnframe));
								//fnframe->next = NULL;

                break;
            }
						case IS_EQUAL: {
							Object *right = pop(frame);
							Object *left = pop(frame);
							push(frame, newLong((long)objectValueCompare(left, right)));
							break;
						}
            case ITIMES: {
                Object *right = pop(frame);
                Object *left = pop(frame);
                assert(right);
								assert(left);

								if(O_TYPE(right) != IS_LONG && O_TYPE(left) != IS_LONG) {
                    como_error_noreturn("invalid operands for ITIMES");
                }
								como_debug("ITIMES: %d, %d", O_TYPE(left),
											O_TYPE(right));

                long value = O_LVAL(left) * O_LVAL(right);
                push(frame, newLong(value));
                break;
            }
            case IRETURN: {
                /* If there wasn't a return statement found in func body*
								 * The compiler will insert a 1 as the operand if 
								 * the AST had an expression for the return statement,
								 * otherwise, it will be 0
								 * The actual value to be returned is popped from the stack
								 */
								if(! (O_LVAL(opcode->operand))) {
                    push(frame, newLong(0L));
                }
                return;
            }
            case IPRINT: {
                Object *value = pop(frame);
                size_t len = 0;
                char *sval = objectToStringLength(value, &len);
                fprintf(stdout, "%s\n", sval);
                fflush(stdout);
                free(sval);
                break;          
            }
        }
    }
}