Exemple #1
0
/**
Evaluate an expression in a given frame
*/
value_t eval_expr(
    heapptr_t expr, 
    clos_t* clos,
    value_t* locals
)
{
    //printf("eval_expr\n");

    // Get the shape of the AST node
    // Note: AST nodes must match the shapes defined in init_parser,
    // otherwise this interpreter can't handle it
    shapeidx_t shape = get_shape(expr);

    // Variable or constant declaration (let/var)
    if (shape == SHAPE_AST_DECL)
    {
        ast_decl_t* decl = (ast_decl_t*)expr;

        // Let declarations should be initialized
        assert (decl->cst == false);

        return VAL_FALSE;
    }

    // Variable reference (read)
    if (shape == SHAPE_AST_REF)
    {
        ast_ref_t* ref = (ast_ref_t*)expr;
        assert (ref->decl != NULL);

        //printf("evaluating ref to %s\n", string_cstr(ref->name));

        // If this is a variable from an outer function
        if (ref->decl->fun != clos->fun)
        {
            //printf("ref from outer fun\n");

            assert (ref->idx < clos->fun->free_vars->len);
            cell_t* cell = clos->cells[ref->idx];
            assert (cell != NULL);

            value_t value;
            value.word = cell->word;
            value.tag = cell->tag;

            return value;
        }

        // Check that the ref index is valid
        if (ref->idx > clos->fun->local_decls->len)
        {
            printf("invalid variable reference\n");
            printf("ref->name=%s\n", string_cstr(ref->name));
            printf("ref->idx=%d\n", ref->idx);
            printf("local_decls->len=%d\n", clos->fun->local_decls->len);
            exit(-1);
        }

        // If this an escaping variable (captured by a closure)
        if (ref->decl->esc)
        {
            // Free variables are stored in mutable cells
            // Pointers to the cells are found on the closure object
            cell_t* cell = locals[ref->idx].word.cell;
            value_t value;
            value.word = cell->word;
            value.tag = cell->tag;

            //printf("read value from cell\n");

            return value;
        }

        /*
        printf("reading normal local\n");
        string_print(ref->name);
        printf("\n");
        */

        // Read directly from the stack frame
        return locals[ref->idx];
    }

    if (shape == SHAPE_AST_CONST)
    {
        //printf("constant\n");

        ast_const_t* cst = (ast_const_t*)expr;
        return cst->val;
    }

    if (shape == SHAPE_STRING)
    {
        return value_from_heapptr(expr, TAG_STRING);
    }

    // Array literal expression
    if (shape == SHAPE_ARRAY)
    {
        array_t* array_expr = (array_t*)expr;

        // Array of values to be produced
        array_t* val_array = array_alloc(array_expr->len);

        for (size_t i = 0; i < array_expr->len; ++i)
        {
            heapptr_t expr = array_get(array_expr, i).word.heapptr;
            value_t value = eval_expr(expr, clos, locals);
            array_set(val_array, i, value);
        }

        return value_from_heapptr((heapptr_t)val_array, TAG_ARRAY);
    }

    // Object literal expression
    if (shape == SHAPE_AST_OBJ)
    {
        //printf("obj literal expr\n");

        ast_obj_t* obj_expr = (ast_obj_t*)expr;

        object_t* obj = object_alloc(OBJ_MIN_CAP);

        // TODO: set prototype
        // Do this in object_alloc?

        for (size_t i = 0; i < obj_expr->name_strs->len; ++i)
        {
            string_t* prop_name = array_get(obj_expr->name_strs, i).word.string;
            heapptr_t val_expr = array_get(obj_expr->val_exprs, i).word.heapptr;

            value_t value = eval_expr(val_expr, clos, locals);

            object_set_prop(
                obj,
                prop_name,
                value,
                ATTR_DEFAULT
            );
        }

        return value_from_obj((heapptr_t)obj);
    }

    // Binary operator (e.g. a + b)
    if (shape == SHAPE_AST_BINOP)
    {
        //printf("binop\n");

        ast_binop_t* binop = (ast_binop_t*)expr;

        // Assignment
        if (binop->op == &OP_ASSIGN)
        {
            value_t val = eval_expr(binop->right_expr, clos, locals);

            return eval_assign(
                binop->left_expr, 
                val, 
                clos,
                locals
            );
        }

        value_t v0 = eval_expr(binop->left_expr, clos, locals);
        value_t v1 = eval_expr(binop->right_expr, clos, locals);
        int64_t i0 = v0.word.int64;
        int64_t i1 = v1.word.int64;
        string_t* s0 = v0.word.string;
        string_t* s1 = v1.word.string;

        if (binop->op == &OP_MEMBER)
            return eval_get_prop(v0, v1);

        if (binop->op == &OP_INDEX)
            return eval_get_index(v0, v1);

        if (binop->op == &OP_ADD)
            return value_from_int64(i0 + i1);
        if (binop->op == &OP_SUB)
            return value_from_int64(i0 - i1);
        if (binop->op == &OP_MUL)
            return value_from_int64(i0 * i1);
        if (binop->op == &OP_DIV)
            return value_from_int64(i0 / i1);
        if (binop->op == &OP_MOD)
            return value_from_int64(i0 % i1);

        if (binop->op == &OP_LT)
            return (i0 < i1)? VAL_TRUE:VAL_FALSE;

        if (binop->op == &OP_LE)
        {
            if (v0.tag == TAG_STRING && v1.tag == TAG_STRING)
                return (strcmp(string_cstr(s0), string_cstr(s1)) <= 0)? VAL_TRUE:VAL_FALSE;
            if (v0.tag == TAG_INT64 && v1.tag == TAG_INT64)
                return (i0 <= i1)? VAL_TRUE:VAL_FALSE;
            assert (false);
        }

        if (binop->op == &OP_GT)
            return (i0 > i1)? VAL_TRUE:VAL_FALSE;

        if (binop->op == &OP_GE)
        {
            if (v0.tag == TAG_STRING && v1.tag == TAG_STRING)
                return (strcmp(string_cstr(s0), string_cstr(s1)) >= 0)? VAL_TRUE:VAL_FALSE;
            if (v0.tag == TAG_INT64 && v1.tag == TAG_INT64)
                return (i0 >= i1)? VAL_TRUE:VAL_FALSE;
            assert (false);
        }

        if (binop->op == &OP_EQ)
            return value_equals(v0, v1)? VAL_TRUE:VAL_FALSE;
        if (binop->op == &OP_NE)
            return value_equals(v0, v1)? VAL_FALSE:VAL_TRUE;

        printf("unimplemented binary operator: %s\n", binop->op->str);
        return VAL_FALSE;
    }

    // Unary operator (e.g.: -x, not a)
    if (shape == SHAPE_AST_UNOP)
    {
        ast_unop_t* unop = (ast_unop_t*)expr;

        value_t v0 = eval_expr(unop->expr, clos, locals);

        if (unop->op == &OP_NEG)
            return value_from_int64(-v0.word.int64);

        if (unop->op == &OP_NOT)
            return eval_truth(v0)? VAL_FALSE:VAL_TRUE;

        printf("unimplemented unary operator: %s\n", unop->op->str);
        return VAL_FALSE;
    }

    // Sequence/block expression
    if (shape == SHAPE_AST_SEQ)
    {
        ast_seq_t* seqexpr = (ast_seq_t*)expr;
        array_t* expr_list = seqexpr->expr_list;

        value_t value = VAL_TRUE;

        for (size_t i = 0; i < expr_list->len; ++i)
        {
            heapptr_t expr = array_get(expr_list, i).word.heapptr;
            value = eval_expr(expr, clos, locals);
        }

        // Return the value of the last expression
        return value;
    }

    // If expression
    if (shape == SHAPE_AST_IF)
    {
        ast_if_t* ifexpr = (ast_if_t*)expr;

        value_t t = eval_expr(ifexpr->test_expr, clos, locals);

        if (eval_truth(t))
            return eval_expr(ifexpr->then_expr, clos, locals);
        else
            return eval_expr(ifexpr->else_expr, clos, locals);
    }

    // Function/closure expression
    if (shape == SHAPE_AST_FUN)
    {
        //printf("creating closure\n");

        ast_fun_t* nested = (ast_fun_t*)expr;

        // Allocate a closure of the nested function
        clos_t* new_clos = clos_alloc(nested);

        // For each free (closure) variable of the nested function
        for (size_t i = 0; i < nested->free_vars->len; ++i)
        {
            ast_decl_t* decl = array_get(nested->free_vars, i).word.decl;

            // If the variable is from this function
            if (decl->fun == clos->fun)
            {
                new_clos->cells[i] = locals[decl->idx].word.cell;
            }
            else
            {
                uint32_t free_idx = array_indexof_ptr(clos->fun->free_vars, (heapptr_t)decl);
                assert (free_idx < clos->fun->free_vars->len);
                new_clos->cells[i] = clos->cells[free_idx];
            }
        }

        assert (new_clos->fun == nested);

        return value_from_heapptr((heapptr_t)new_clos, TAG_CLOS);
    }

    // Call expression
    if (shape == SHAPE_AST_CALL)
    {
        //printf("evaluating call\n");

        ast_call_t* callexpr = (ast_call_t*)expr;

        // Evaluate the closure expression
        value_t callee_clos = eval_expr(callexpr->fun_expr, clos, locals);

        if (callee_clos.tag == TAG_CLOS)
        {
            return eval_call(
                callee_clos.word.clos,
                callexpr->arg_exprs,
                clos,
                locals
            );
        }

        if (callee_clos.tag == TAG_HOSTFN)
        {
            return eval_host_call(
                callee_clos.word.hostfn,
                callexpr->arg_exprs,
                clos,
                locals
            );
        }

        printf("invalid callee in function call\n");
        exit(-1);
    }

    printf("eval error, unknown expression type, shapeidx=%d\n", get_shape(expr));
    exit(-1);
}
Exemple #2
0
	bool equals(const Value& a, const Value& b) {
		static const Symbol equal_sign_symbol("=");
		return eval_truth(snow::call(a, get(a, equal_sign_symbol), b).value());
	}