Exemple #1
0
bool file_getLine_delim(FILE *file, string_t *str, char delim)
{
    string_clear(str);
    bool v = file_readLine_delim(file, str, delim);
    string_cstr(str);
    return v;
}
Exemple #2
0
bool file_getLine(FILE *file, string_t *str)
{
    string_clear(str);
    bool v = file_readLine(file, str);
    string_cstr(str);
    return v;
}
Exemple #3
0
/**
Initialize the runtime
*/
void init_runtime()
{
    // Parse the global unit
    ast_fun_t* unit_fun = parse_check_error(parse_file("global.zeta"));

    // Get the list of expressions in the function body
    assert (get_shape(unit_fun->body_expr) == SHAPE_AST_SEQ);
    array_t* exprs = ((ast_seq_t*)unit_fun->body_expr)->expr_list;

    // Initialize the host function wrappers
    array_t* host_fns = init_api_core();

    // Prepend wrapper function definitions to the unit
    for (size_t i = 0; i < host_fns->len; ++i)
    {
        hostfn_t* fn = array_get(host_fns, i).word.hostfn;

        value_t fn_val;
        fn_val.word.hostfn = fn;
        fn_val.tag = TAG_HOSTFN;

        // Prepend a $ character to the function name
        char name[64];
        sprintf(name, "$%s", string_cstr(fn->name));

        heapptr_t decl = ast_decl_alloc((heapptr_t)vm_get_cstr(name), true);
        heapptr_t cst = ast_const_alloc(fn_val);
        heapptr_t assg = ast_binop_alloc(&OP_ASSIGN, decl, cst);
        array_prepend_obj(exprs, assg);
    }

    // Resolve all variables in the global unit
    var_res_pass(unit_fun, NULL);

    // Initialize the global unit
    // This returns a closure which captures all global variables
    value_t global_clos = eval_unit(unit_fun);
    assert (global_clos.tag == TAG_CLOS);

    // Store a pointer to the global unit closure in the VM object
    vm.global_clos = global_clos.word.clos;
}
Exemple #4
0
/**
Evaluate a property read
*/
value_t eval_get_prop(
    value_t base,
    value_t prop_name
)
{
    if (prop_name.tag != TAG_STRING)
    {
        printf("non-string property name in property read\n");
        exit(-1);
    }

    string_t* name_str = prop_name.word.string;

    if (base.tag == TAG_OBJECT)
    {
        return object_get_prop(base.word.object, name_str);
    }

    if (base.tag == TAG_STRING)
    {
        if (name_str == vm_get_cstr("length"))
            return value_from_int64(base.word.string->len);

        assert (false);
    }

    if (base.tag == TAG_ARRAY)
    {
        if (name_str == vm_get_cstr("length"))
            return value_from_int64(base.word.array->len);

        assert (false);
    }

    printf(
        "invalid base in property read with key \"%s\"\n",
        string_cstr(name_str)
    );
    exit(-1);
}
Exemple #5
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 #6
0
/**
Evaluate a host function call
*/
value_t eval_host_call(
    hostfn_t* callee,
    array_t* arg_exprs,
    clos_t* caller,
    value_t* caller_locals
)
{
    value_t* arg_vals = alloca(sizeof(value_t) * arg_exprs->len);

    if (arg_exprs->len != callee->num_params)
    {
        printf(
            "argument count mismatch in call to %s, got %d, expected %d\n",
            string_cstr(callee->name),
            arg_exprs->len,
            callee->num_params
        );
        exit(-1);
    }

    // Evaluate the argument values
    for (size_t i = 0; i < arg_exprs->len; ++i)
    {
        //printf("evaluating arg %ld\n", i);

        // Evaluate the parameter value
        arg_vals[i] = eval_expr(
            array_get_ptr(arg_exprs, i),
            caller,
            caller_locals
        );
    }

    // Type test signature
    if (callee->sig_str == vm_get_cstr("bool(tag)"))
    {
        bool (*fptr)(tag_t) = callee->fptr;
        return fptr(arg_vals[0].tag)? VAL_TRUE:VAL_FALSE;
    }

    if (callee->sig_str == vm_get_cstr("void(int)"))
    {
        void (*fptr)(int) = callee->fptr;
        fptr(arg_vals[0].word.int32);
        return VAL_TRUE;
    }

    if (callee->sig_str == vm_get_cstr("void(int64)"))
    {
        void (*fptr)(int64_t) = callee->fptr;
        fptr(arg_vals[0].word.int64);
        return VAL_TRUE;
    }

    if (callee->sig_str == vm_get_cstr("void(string)"))
    {
        void (*fptr)(string_t*) = callee->fptr;
        fptr(arg_vals[0].word.string);
        return VAL_TRUE;
    }

    if (callee->sig_str == vm_get_cstr("string()"))
    {
        string_t* (*fptr)() = callee->fptr;
        string_t* str = fptr();
        return value_from_heapptr((heapptr_t)str, TAG_STRING);
    }

    if (callee->sig_str == vm_get_cstr("string(string)"))
    {
        string_t* (*fptr)(string_t*) = callee->fptr;
        string_t* str = fptr(arg_vals[0].word.string);
        return value_from_heapptr((heapptr_t)str, TAG_STRING);
    }

    printf("unsupported host function signature\n");
    exit(-1);
}
Exemple #7
0
void var_res(heapptr_t expr, ast_fun_t* fun)
{
    // Get the shape of the AST node
    shapeidx_t shape = get_shape(expr);

    // Constants and strings, do nothing
    if (shape == SHAPE_AST_CONST ||
        shape == SHAPE_STRING)
    {
        return;
    }

    // Array literal expression
    if (shape == SHAPE_ARRAY)
    {
        array_t* array_expr = (array_t*)expr;
        for (size_t i = 0; i < array_expr->len; ++i)
            var_res(array_get(array_expr, i).word.heapptr, fun);

        return;
    }

    // Object literal expression
    if (shape == SHAPE_AST_OBJ)
    {
        ast_obj_t* obj_expr = (ast_obj_t*)expr;

        if (obj_expr->proto_expr)
            var_res(obj_expr->proto_expr, fun);

        for (size_t i = 0; i < obj_expr->val_exprs->len; ++i)
            var_res(array_get(obj_expr->val_exprs, i).word.heapptr, fun);

        return;
    }

    // Variable declaration, do nothing
    if (shape == SHAPE_AST_DECL)
    {
        return;
    }

    // Variable reference
    if (shape == SHAPE_AST_REF)
    {
        ast_ref_t* ref = (ast_ref_t*)expr;

        // Find the declaration for this reference
        ast_decl_t* decl = find_decl(ref, fun);

        if (decl == NULL)
        {
            printf("unresolved reference to \"%s\"\n", string_cstr(ref->name));
            exit(-1);
        }

        // Store the declaration on the reference
        assert (decl->fun != NULL);
        ref->decl = decl;

        // If the variable is from this scope
        if (decl->fun == fun)
        {
            // Store the index of this local
            assert (decl->idx < fun->local_decls->len);
            ref->idx = decl->idx;
        }
        else
        {
            // Mark the variable as escaping
            decl->esc = true;

            // Thread the escaping variable through nested functions
            thread_esc_var(ref, fun, fun);

            // Find the mutable cell index for the variable
            ref->idx = array_indexof_ptr(fun->free_vars, (heapptr_t)ref->decl);
            assert (ref->idx < fun->free_vars->len);
        }

        return;
    }

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

        for (size_t i = 0; i < expr_list->len; ++i)
            var_res(array_get_ptr(expr_list, i), fun);

        return;
    }

    // Binary operator (e.g. a + b)
    if (shape == SHAPE_AST_BINOP)
    {
        ast_binop_t* binop = (ast_binop_t*)expr;

        var_res(binop->left_expr, fun);
        var_res(binop->right_expr, fun);
        return;
    }

    // Unary operator (e.g. -a)
    if (shape == SHAPE_AST_UNOP)
    {
        ast_unop_t* unop = (ast_unop_t*)expr;
        var_res(unop->expr, fun);
        return;
    }

    // If expression
    if (shape == SHAPE_AST_IF)
    {
        ast_if_t* ifexpr = (ast_if_t*)expr;
        var_res(ifexpr->test_expr, fun);
        var_res(ifexpr->then_expr, fun);
        var_res(ifexpr->else_expr, fun);
        return;
    }

    // Function/closure expression
    if (shape == SHAPE_AST_FUN)
    {
        ast_fun_t* child_fun = (ast_fun_t*)expr;

        // Resolve variable references in the nested child function
        var_res_pass(child_fun, fun);

        return;
    }

    // Function call
    if (shape == SHAPE_AST_CALL)
    {
        ast_call_t* callexpr = (ast_call_t*)expr;
        array_t* arg_exprs = callexpr->arg_exprs;

        var_res(callexpr->fun_expr, fun);

        for (size_t i = 0; i < arg_exprs->len; ++i)
            var_res(array_get_ptr(arg_exprs, i), fun);

        return;
    }

    // Unsupported AST node type
    assert (false);
}
Exemple #8
0
void color_print_package (void * p, printpkgfn f)
{
	string_t *cstr;
	static int number=0;
	const char *info, *lver;
	char *ver=NULL;
	int aur=(f == aur_get_str);
	int grp=(f == alpm_grp_get_str);
	cstr=string_new ();

	/* Numbering list */
	if (config.numbering)
		cstr = string_fcat (cstr, "%s%d%s ",
		    color (C_NB), ++number, color (C_NO));

	/* repo/name */
	if (config.aur_foreign)
		info = f(p, 'r');
	else
		info = f(p, 's');
	if (info)
	{
		if (config.get_res) dprintf (FD_RES, "%s/", info);
		cstr = string_fcat (cstr, "%s%s/%s",
		    color_repo (info), info, color(C_NO));
	}
	info=f(p, 'n');
	if (config.get_res) dprintf (FD_RES, "%s\n", info);
	cstr = string_fcat (cstr, "%s%s%s ", color(C_PKG), info, color(C_NO));

	if (grp)
	{
		/* no more output for groups */
		fprintf (stdout, "%s\n", string_cstr (cstr));
		string_free (cstr);
		return;
	}

	/* Version
	 * different colors:
	 *   C_ORPHAN if package exists in AUR and is orphaned
	 *   C_OD if package exists and is out of date
	 *   C_VER otherwise
	 */
	lver = alpm_local_pkg_get_str (info, 'l');
	info = f(p, (config.aur_upgrades) ? 'V' : 'v');
	ver = STRDUP (info);
	info = (aur) ? f(p, 'm') : NULL;
	if (config.aur_foreign)
	{
		/* Compare foreign package with AUR */
		if (aur)
		{
			const char *lver_color = NULL;
			if (!info)
				lver_color=color(C_ORPHAN);
			else
			{
				info = f(p, 'o');
				if (info && info[0]=='1')
					lver_color=color(C_OD);
			}
			cstr = string_fcat (cstr, "%s%s%s",
			    (lver_color) ? lver_color : color(C_VER),
			    lver, color (C_NO));
			if (alpm_pkg_vercmp (ver, lver)>0)
				cstr = string_fcat (cstr, " ( aur: %s )", ver);
			fprintf (stdout, "%s\n", string_cstr (cstr));
			FREE (ver);
		}
		else
			fprintf (stdout, "%s %s%s%s\n", string_cstr (cstr),
				color(C_VER), lver, color(C_NO));
		string_free (cstr);
		return;
	}
	if (aur && !info)
		cstr = string_fcat (cstr, "%s%s%s", color(C_ORPHAN), ver, color (C_NO));
	else
		cstr = string_fcat (cstr, "%s%s%s", color(C_VER), ver, color (C_NO));

	/* show size */
	if (config.show_size)
	{
		info = f(p, 'r');
		if (info)
		{
			if (strcmp (info, "aur")!=0)
				cstr = string_fcat (cstr, " [%.2f M]",
				    (double) get_size_pkg (p) / (1024.0 * 1024));
		}
	}

	if (config.aur_upgrades)
	{
		fprintf (stdout, "%s\n", string_cstr (cstr));
		string_free (cstr);
		FREE (ver);
		return;
	}

	/* show groups */
	info = f(p, 'g');
	if (info)
	{
		cstr = string_fcat (cstr, " %s(%s)%s", color(C_GRP), info, color(C_NO));
	}

	/* show install information */
	if (lver)
	{
		info = f(p, 'r');
		if (info && strcmp (info, "local")!=0)
		{
			cstr = string_fcat (cstr, " %s[%s",
			    color(C_INSTALLED), _("installed"));
			if (strcmp (ver, lver)!=0)
			{
				cstr = string_fcat (cstr, ": %s%s%s%s",
				    color(C_LVER), lver, color (C_NO), color(C_INSTALLED));
			}
			cstr = string_fcat (cstr, "]%s", color(C_NO));
		}
	}
	/* ver no more needed */
	FREE (ver);

	/* Out of date status & votes */
	if (aur)
	{
		info = f(p, 'o');
		if (info && info[0]=='1')
		{
			cstr = string_fcat (cstr, " %s(%s)%s",
				color(C_OD), _("Out of Date"), color(C_NO));
		}
		info = f(p, 'w');
		if (info)
		{
			cstr = string_fcat (cstr, " %s(%s)%s",
			    color(C_VOTES), info, color(C_NO));
		}
	}

	/* Display computed string */
	fprintf (stdout, "%s\n", string_cstr (cstr));
	string_free (cstr);

	/* Description
	 * if -Q or -Sl or -Sg <target>, don't display description
	 */
	if (config.op != OP_SEARCH && config.op != OP_LIST_REPO_S) return;
	fprintf (stdout, "%s", color(C_DSC));
	indent (f(p, 'd'));
	fprintf (stdout, "%s", color(C_NO));
}