Пример #1
0
fa_signal_t fa_signal_copy(fa_signal_t signal)
{
    switch (signal->tag) {
    case time_signal:
        return fa_signal_time();

    case random_signal:
        return fa_signal_random();

    case constant_signal:
        return copy_constant(signal);

    case lift_signal:
        return copy_lift(signal);

    case lift2_signal:
        return copy_lift2(signal);

    case loop_signal:
        return copy_loop(signal);

    case delay_signal:
        return copy_delay(signal);

    case insert_signal:
        return copy_insert(signal);

    case custom_signal:
        return copy_custom(signal);

    case input_signal:
        return copy_input(signal);

    case output_signal:
        return copy_output(signal);

    default:
        assert(false);
    }
}
Пример #2
0
void execute_function(VM *vm) {
restart: {
    Frame *frame = vm->current;
    Closure *closure = frame->closure;
    Chunk *chunk = closure->chunk;
    StackObject *registers = frame->registers;

    while (frame->pc < chunk->numinstructions) {
        int instruction = chunk->instructions[frame->pc];

        OpCode o = GET_O(instruction);
        int a = GET_A(instruction);
        int b = GET_B(instruction);
        int c = GET_C(instruction);

        switch (o) {
            case OP_MOVE:
            {
                if (b < 256) {
                    copy_object(&registers[a], &registers[b]);
                } else {
                    copy_constant(vm, &registers[a], chunk->constants[b - 256]);
                }
            } break;

            case OP_GETUPVAR:
            {
                Upval *upval = closure->upvals[b];

                if (!upval->open) {
                    // upval is closed
                    copy_object(&registers[a], upval->data.o);
                } else {
                    // still on stack
                    copy_object(&registers[a], &upval->data.ref.frame->registers[upval->data.ref.slot]);
                }
            } break;

            case OP_SETUPVAR:
            {
                Upval *upval = closure->upvals[b];

                if (!upval->open) {
                    // upval is closed
                    copy_object(upval->data.o, &registers[a]);
                } else {
                    // still on stack
                    copy_object(&upval->data.ref.frame->registers[upval->data.ref.slot], &registers[a]);
                }
            } break;

            case OP_ADD:
            {
                // TODO - make string coercion better
                // TODO - make string type with special operators

                if (IS_STR(b) || IS_STR(c)) {
                    char *arg1 = TO_STR(b);
                    char *arg2 = TO_STR(c);

                    char *arg3 = malloc((strlen(arg1) + strlen(arg2) + 1) + sizeof *arg3);

                    strcpy(arg3, arg1);
                    strcat(arg3, arg2);

                    registers[a].value.o = make_string_ref(vm, arg3);
                    registers[a].type = OBJECT_REFERENCE; // put this after

                    free(arg1);
                    free(arg2);
                } else {
                    if (!(IS_INT(b) || IS_REAL(b)) || !(IS_INT(c) || IS_REAL(c))) {
                        fatal("Cannot add types.");
                    }

                    if (IS_INT(b) && IS_INT(c)) {
                        int arg1 = AS_INT(b);
                        int arg2 = AS_INT(c);

                        registers[a].type = OBJECT_INT;
                        registers[a].value.i = arg1 + arg2;
                    } else {
                        double arg1 = IS_INT(b) ? (double) AS_INT(b) : AS_REAL(b);
                        double arg2 = IS_INT(c) ? (double) AS_INT(c) : AS_REAL(c);

                        registers[a].type = OBJECT_REAL;
                        registers[a].value.d = arg1 + arg2;
                    }
                }
            } break;

            case OP_SUB:
            {
                if (!(IS_INT(b) || IS_REAL(b)) || !(IS_INT(c) || IS_REAL(c))) {
                    fatal("Tried to sub non-numbers.");
                }

                if (IS_INT(b) && IS_INT(c)) {
                    int arg1 = AS_INT(b);
                    int arg2 = AS_INT(c);

                    registers[a].type = OBJECT_INT;
                    registers[a].value.i = arg1 - arg2;
                } else {
                    double arg1 = IS_INT(b) ? (double) AS_INT(b) : AS_REAL(b);
                    double arg2 = IS_INT(c) ? (double) AS_INT(c) : AS_REAL(c);

                    registers[a].type = OBJECT_REAL;
                    registers[a].value.d = arg1 - arg2;
                }
            } break;

            case OP_MUL:
            {
                if (!(IS_INT(b) || IS_REAL(b)) || !(IS_INT(c) || IS_REAL(c))) {
                    fatal("Tried to mul non-numbers.");
                }

                if (IS_INT(b) && IS_INT(c)) {
                    int arg1 = AS_INT(b);
                    int arg2 = AS_INT(c);

                    registers[a].type = OBJECT_INT;
                    registers[a].value.i = arg1 * arg2;
                } else {
                    double arg1 = IS_INT(b) ? (double) AS_INT(b) : AS_REAL(b);
                    double arg2 = IS_INT(c) ? (double) AS_INT(c) : AS_REAL(c);

                    registers[a].type = OBJECT_REAL;
                    registers[a].value.d = arg1 * arg2;
                }
            } break;

            case OP_DIV:
            {
                if (!(IS_INT(b) || IS_REAL(b)) || !(IS_INT(c) || IS_REAL(c))) {
                    fatal("Tried to div non-numbers.");
                }

                if ((IS_INT(c) && AS_INT(c) == 0) || (IS_REAL(c) && AS_REAL(c) == 0)) {
                    fatal("Div by 0.");
                }

                if (IS_INT(b) && IS_INT(c)) {
                    int arg1 = AS_INT(b);
                    int arg2 = AS_INT(c);

                    registers[a].type = OBJECT_INT;
                    registers[a].value.i = arg1 / arg2;
                } else {
                    double arg1 = IS_INT(b) ? (double) AS_INT(b) : AS_REAL(b);
                    double arg2 = IS_INT(c) ? (double) AS_INT(c) : AS_REAL(c);

                    registers[a].type = OBJECT_REAL;
                    registers[a].value.d = arg1 / arg2;
                }
            } break;

            case OP_MOD:
            {
                if (!(IS_INT(b) || IS_REAL(b)) || !(IS_INT(c) || IS_REAL(c))) {
                    fatal("Tried to div non-numbers.");
                }

                if ((IS_INT(c) && AS_INT(c) == 0) || (IS_REAL(c) && AS_REAL(c) == 0)) {
                    fatal("Mod by 0.");
                }

                if (IS_INT(b) && IS_INT(c)) {
                    int arg1 = AS_INT(b);
                    int arg2 = AS_INT(c);

                    registers[a].type = OBJECT_INT;
                    registers[a].value.i = arg1 % arg2;
                } else {
                    double arg1 = IS_INT(b) ? (double) AS_INT(b) : AS_REAL(b);
                    double arg2 = IS_INT(c) ? (double) AS_INT(c) : AS_REAL(c);

                    registers[a].type = OBJECT_REAL;
                    registers[a].value.i = fmod(arg1, arg2);
                }
            } break;

            case OP_POW:
            {
                if (!(IS_INT(b) || IS_REAL(b)) || !(IS_INT(c) || IS_REAL(c))) {
                    fatal("Tried to div non-numbers.");
                }

                if (IS_INT(b) && IS_INT(c)) {
                    int arg1 = AS_INT(b);
                    int arg2 = AS_INT(c);

                    registers[a].type = OBJECT_INT;
                    registers[a].value.i = (int) pow(arg1, arg2);
                } else {
                    double arg1 = IS_INT(b) ? (double) AS_INT(b) : AS_REAL(b);
                    double arg2 = IS_INT(c) ? (double) AS_INT(c) : AS_REAL(c);

                    registers[a].type = OBJECT_REAL;
                    registers[a].value.d = pow(arg1, arg2);
                }
            } break;

            case OP_NEG:
            {
                if (IS_INT(b)) {
                    registers[a].type = OBJECT_INT;
                    registers[a].value.i = -AS_INT(b);
                } else if (IS_REAL(b)) {
                    registers[a].type = OBJECT_INT;
                    registers[a].value.i = -AS_REAL(b);
                } else {
                    fatal("Tried to negate non-numeric type.");
                }
            } break;

            case OP_NOT:
            {
                if (registers[a].type != OBJECT_BOOL) {
                    fatal("Expected boolean type, not %d.", registers[a].type);
                }

                registers[a].value.i = registers[a].value.i == 1 ? 0 : 1;
            } break;

            case OP_EQ:
            {
                if ((IS_INT(b) || IS_REAL(b)) && (IS_INT(c) || IS_REAL(c))) {
                    double arg1 = IS_INT(b) ? (double) AS_INT(b) : AS_REAL(b);
                    double arg2 = IS_INT(c) ? (double) AS_INT(c) : AS_REAL(c);

                    registers[a].type = OBJECT_BOOL;
                    registers[a].value.i = arg1 == arg2;
                } else {
                    fatal("Comparison of reference types not yet supported.");
                }
            } break;

            case OP_LT:
            {
                if (!(IS_INT(b) || IS_REAL(b)) || !(IS_INT(c) || IS_REAL(c))) {
                    fatal("Tried to compare non-numbers.");
                }

                double arg1 = IS_INT(b) ? (double) AS_INT(b) : AS_REAL(b);
                double arg2 = IS_INT(c) ? (double) AS_INT(c) : AS_REAL(c);

                registers[a].type = OBJECT_BOOL;
                registers[a].value.i = arg1 < arg2;
            } break;

            case OP_LE:
            {
                if (!(IS_INT(b) || IS_REAL(b)) || !(IS_INT(c) || IS_REAL(c))) {
                    fatal("Tried to compare non-numbers.");
                }

                double arg1 = IS_INT(b) ? (double) AS_INT(b) : AS_REAL(b);
                double arg2 = IS_INT(c) ? (double) AS_INT(c) : AS_REAL(c);

                registers[a].type = OBJECT_BOOL;
                registers[a].value.i = arg1 <= arg2;
            } break;

            case OP_CLOSURE:
            {
                Closure *child = make_closure(chunk->children[b]);

                int i;
                for (i = 0; i < chunk->children[b]->numupvars; i++) {
                    int inst = chunk->instructions[++frame->pc];

                    OpCode oc = GET_O(inst);
                    int ac = GET_A(inst);
                    int bc = GET_B(inst);
                    int cc = GET_C(inst);

                    if (oc == OP_MOVE) {
                        // first upval for this variable
                        child->upvals[ac] = make_upval(vm, bc);
                    } else {
                        // share upval
                        child->upvals[ac] = closure->upvals[bc];
                        child->upvals[ac]->refcount++;
                    }
                }

                registers[a].value.o = make_closure_ref(vm, child);
                registers[a].type = OBJECT_REFERENCE; // put this after
            } break;

            case OP_CALL:
            {
                if (registers[b].type != OBJECT_REFERENCE || registers[b].value.o->type != OBJECT_CLOSURE) {
                    fatal("Tried to call non-closure.");
                }

                // TODO - safety issue (see compile.c for notes)

                Closure *child = registers[b].value.o->value.c;
                Frame *subframe = make_frame(frame, child);

                int i;
                for (i = 0; i < child->chunk->numparams; i++) {
                    copy_object(&subframe->registers[i + 1], &registers[c + i]);
                }

                vm->current = subframe;
                goto restart;
            } break;

            case OP_RETURN:
            {
                UpvalNode *head;
                for (head = vm->open; head != NULL; ) {
                    Upval *u = head->upval;

                    if (u->data.ref.frame == frame) {
                        StackObject *o = malloc(sizeof *o);

                        if (!o) {
                            fatal("Out of memory.");
                        }

                        u->open = 0;
                        copy_object(o, &registers[u->data.ref.slot]);
                        u->data.o = o;

                        if (vm->open == head) {
                            vm->open = head->next;
                        } else {
                            head->next->prev = head->prev;
                            head->prev->next = head->next;
                        }

                        UpvalNode *temp = head;
                        head = head->next;
                        free(temp);
                    } else {
                        head = head->next;
                    }
                }

                if (vm->current->parent != NULL) {
                    Frame *p = vm->current->parent;
                    StackObject *target = &p->registers[GET_A(p->closure->chunk->instructions[p->pc++])];

                    if (b < 256) {
                        // debug
                        char *d = obj_to_str(&registers[b]);
                        printf("Return value: %s\n", d);
                        free(d);

                        copy_object(target, &registers[b]);
                    } else {
                        copy_constant(vm, target, chunk->constants[b - 256]);
                    }

                    free_frame(frame);

                    vm->current = p;
                    goto restart;
                } else {
                    // debug
                    char *d = obj_to_str(&registers[b]);
                    printf("Return value: %s\n", d);
                    free(d);

                    free_frame(frame);
                    vm->current = NULL;
                    return;
                }
            } break;

            case OP_JUMP:
                frame->pc += c ? -b : b;
                break;

            case OP_JUMP_TRUE:
            {
                if (registers[a].type != OBJECT_BOOL) {
                    fatal("Expected boolean type, not %d.", registers[a].type);
                }

                if (registers[a].value.i == 1) {
                    frame->pc += c ? -b : b;
                }
            } break;

            case OP_JUMP_FALSE:
            {
                if (registers[a].type != OBJECT_BOOL) {
                    fatal("Expected boolean type, not %d.", registers[a].type);
                }

                if (registers[a].value.i == 0) {
                    frame->pc += c ? -b : b;
                }
            } break;

            case OP_ENTER_TRY:
            {
                vm->catchframe = make_catch_frame(frame, vm->catchframe, frame->pc + b);
            } break;

            case OP_LEAVE_TRY:
            {
                CatchFrame *temp = vm->catchframe;
                vm->catchframe = vm->catchframe->parent;
                free_catch_frame(temp);
            } break;

            case OP_THROW:
            {
                // TODO - replace unwinding of stack with an exceptions
                // table per-chunk. It will have an instructions range,
                // the starting instruction of a handler, and the type of
                // exception that it may handle.

                // Exception table:
                // From    To      Target      Type
                // 0       4       5           Class TestExc1
                // 0       12      12          Class TestExc2

                // TODO - implement a way to expect an exception
                // of a given type instead of a generic catch-all.

                char *s = obj_to_str(&registers[a]);
                printf("Exception value: %s!\n", s);
                free(s);

                // TODO - this is probably wrong. Not sure how complicated
                // it will be to handle upvalues and frame destruction here,
                // so we're just doing it a shitty way for now :D [GO LAZE].

                if (!vm->catchframe) {
                    // TODO - print a stack trace [ requires debug symbols :( ]
                    fatal("Exception thrown outside of handler.");
                }

                while (vm->current != vm->catchframe->frame) {
                    // TODO - destruct frame
                    vm->current = vm->current->parent;
                }

                vm->current->pc = vm->catchframe->target;

                CatchFrame *temp = vm->catchframe;
                vm->catchframe = vm->catchframe->parent;
                free_catch_frame(temp);

                goto restart;
            } break;
        }

        frame->pc++;
    }

    fatal("VM left instruction-space.");
}
}