Exemple #1
0
    void desugarFile(AST *&ast)
    {
        desugar(ast, 0);

        // Now, implement the std library by wrapping in a local construct.
        Tokens tokens = jsonnet_lex("std.jsonnet", STD_CODE);
        AST *std_ast = jsonnet_parse(alloc, tokens);
        desugar(std_ast, 0);
        auto *std_obj = dynamic_cast<DesugaredObject*>(std_ast);
        if (std_obj == nullptr) {
            std::cerr << "INTERNAL ERROR: std.jsonnet not an object." << std::endl;
            std::abort();
        }

        // Bind 'std' builtins that are implemented natively.
        DesugaredObject::Fields &fields = std_obj->fields;
        for (unsigned long c=0 ; c <= max_builtin ; ++c) {
            const auto &decl = jsonnet_builtin_decl(c);
            Identifiers params;
            for (const auto &p : decl.params)
                params.push_back(alloc->makeIdentifier(p));
            fields.emplace_back(
                ObjectField::HIDDEN,
                str(decl.name),
                alloc->make<BuiltinFunction>(E, c, params));
        }
        fields.emplace_back(
            ObjectField::HIDDEN,
            str(U"thisFile"),
            str(decode_utf8(ast->location.file)));

        ast = alloc->make<Local>(ast->location, EF, singleBind(id(U"std"), std_obj), ast);
    }
Exemple #2
0
void desugar (AST::TypePtr& ty)
{
	if (auto param = dynamic_cast<AST::ParamType*>(ty.get()))
	{
		for (auto& ty2 : param->ifaces)
			desugar(ty2);
		return;
	}
	else if (auto conc = dynamic_cast<AST::ConcreteType*>(ty.get()))
	{
		desugarName(conc->name);
		for (auto& ty2 : conc->subtypes)
			desugar(ty2);
	}
}
Exemple #3
0
void desugar (AST::PatPtr& p)
{
	if (auto epat = dynamic_cast<AST::EnumPat*>(p.get()))
	{
		if (epat->kind == AST::EnumPat::Enum)
			desugarName(epat->name);

		for (auto& p2 : epat->args)
			desugar(p2);

		// build linked list right to left
		if (epat->kind == AST::EnumPat::List)
		{
			auto res = AST::Pat::nil(epat->span);

			for (size_t i = 0, len = epat->args.size(); i < len; i++)
			{
				auto elem = epat->args[len - i - 1];
				res = AST::Pat::cons(elem->span, elem, res);
			}
			res->rootPosition = epat->rootPosition;

			p = res;
		}
	}
}
Exemple #4
0
void desugar (AST::DeclPtr& decl)
{
	if (auto fndecl = dynamic_cast<AST::FuncDecl*>(decl.get()))
	{
		if (fndecl->impl.type != nullptr)
			desugar(fndecl->impl.type);
		for (auto& a : fndecl->args)
			desugar(a.type);

		if (fndecl->isExtern)
			desugar(fndecl->ret);
		else
			desugar(fndecl->body);
	}
	else if (auto tydecl = dynamic_cast<AST::TypeDecl*>(decl.get()))
	{
		for (auto& m : tydecl->fields)
			desugar(m.type);
		for (auto& efn : tydecl->enumfns)
			for (auto& ty : efn.args)
				desugar(ty);
	}
	else if (auto constdecl = dynamic_cast<AST::ConstDecl*>(decl.get()))
	{
		if (constdecl->type != nullptr)
			desugar(constdecl->type);
		else
			desugar(constdecl->init);
	}
	else if (auto ifacedecl = dynamic_cast<AST::IFaceDecl*>(decl.get()))
	{
		for (auto& fn : ifacedecl->funcs)
		{
			for (auto& ty : fn.args)
				desugar(ty);
			desugar(fn.ret);
		}
	}
}
Exemple #5
0
 ExprC *desugar(const ExprS& root) const
 {
     return desugar(&root);
 }
Exemple #6
0
    void desugar(AST *&ast_)
    {
        if (auto *ast = dynamic_cast<Apply*>(ast_)) {
                
            desugar(ast->target);
            for (AST *&arg : ast->arguments)
                desugar(arg);

        } else if (auto *ast = dynamic_cast<Array*>(ast_)) {
            for (AST *&el : ast->elements)
                desugar(el);

        } else if (auto *ast = dynamic_cast<ArrayComprehension*>(ast_)) {
            for (ComprehensionSpec &spec : ast->specs)
                desugar(spec.expr);
            desugar(ast->body);

            int n = ast->specs.size();
            AST *zero = make<LiteralNumber>(E, 0.0);
            AST *one = make<LiteralNumber>(E, 1.0);
            auto *_r = id(U"$r");
            auto *_l = id(U"$l");
            std::vector<const Identifier*> _i(n);
            for (int i = 0; i < n ; ++i) {
                StringStream ss;
                ss << U"$i_" << i;
                _i[i] = id(ss.str());
            }
            std::vector<const Identifier*> _aux(n);
            for (int i = 0; i < n ; ++i) {
                StringStream ss;
                ss << U"$aux_" << i;
                _aux[i] = id(ss.str());
            }

            // Build it from the inside out.  We keep wrapping 'in' with more ASTs.
            assert(ast->specs[0].kind == ComprehensionSpec::FOR);

            int last_for = n - 1;
            while (ast->specs[last_for].kind != ComprehensionSpec::FOR)
                last_for--;
            // $aux_{last_for}($i_{last_for} + 1, $r + [body])
            AST *in = make<Apply>(
                ast->body->location,
                var(_aux[last_for]),
                std::vector<AST*> {
                    make<Binary>(E, var(_i[last_for]), BOP_PLUS, one),
                    make<Binary>(E, var(_r), BOP_PLUS, singleton(ast->body))
                },
                true  // tailstrict
            );
            for (int i = n - 1; i >= 0 ; --i) {
                const ComprehensionSpec &spec = ast->specs[i];
                AST *out;
                if (i > 0) {
                    int prev_for = i - 1;
                    while (ast->specs[prev_for].kind != ComprehensionSpec::FOR)
                        prev_for--;

                    // aux_{prev_for}($i_{prev_for} + 1, $r)
                    out = make<Apply>(  // False branch.
                        E,
                        var(_aux[prev_for]), 
                        std::vector<AST*> {
                            make<Binary>(E, var(_i[prev_for]), BOP_PLUS, one), var(_r)},
                        true  // tailstrict
                    );
                } else {
                    out = var(_r);
                }
                switch (spec.kind) {
                    case ComprehensionSpec::IF: {
                        /*
                            if [[[...cond...]]] then
                                [[[...in...]]]
                            else
                                [[[...out...]]]
                        */
                        in = make<Conditional>(
                            ast->location,
                            spec.expr,
                            in,  // True branch.
                            out);  // False branch.
                    } break;
                    case ComprehensionSpec::FOR: {
                        /*
                            local $l = [[[...array...]]];
                            local aux_{i}(i_{i}, r) =
                                if i_{i} >= std.length(l) then
                                    [[[...out...]]]
                                else
                                    local [[[...var...]]] = l[i_{i}];
                                    [[[...in...]]]
                            aux_{i}(0, r) tailstrict;
                        */
                        in = make<Local>(
                            ast->location,
                            Local::Binds {
                                {_l, spec.expr},
                                {_aux[i], make<Function>(
                                    ast->location,
                                    std::vector<const Identifier*>{_i[i], _r},
                                    make<Conditional>(
                                        ast->location, 
                                        make<Binary>(
                                            E, var(_i[i]), BOP_GREATER_EQ, length(var(_l))),
                                        out,
                                        make<Local>(
                                            ast->location,
                                            Local::Binds {{
                                                spec.var,
                                                make<Index>(E, var(_l), var(_i[i]))
                                            }},
                                            in)
                                    )
                                )}},
                                make<Apply>(
                                    E,
                                    var(_aux[i]),
                                    std::vector<AST*> {
                                        zero,
                                        i == 0 ? make<Array>(E, std::vector<AST*>{})
                                               : static_cast<AST*>(var(_r))
                                    },
                                    true));  // tailstrict
                    } break;
                }
            }
                    
            ast_ = in;

        } else if (auto *ast = dynamic_cast<Binary*>(ast_)) {
            desugar(ast->left);
            desugar(ast->right);

        } else if (dynamic_cast<const BuiltinFunction*>(ast_)) {
            // Nothing to do.

        } else if (auto *ast = dynamic_cast<Conditional*>(ast_)) {
            desugar(ast->cond);
            desugar(ast->branchTrue);
            desugar(ast->branchFalse);

        } else if (auto *ast = dynamic_cast<Error*>(ast_)) {
            desugar(ast->expr);

        } else if (auto *ast = dynamic_cast<Function*>(ast_)) {
            desugar(ast->body);

        } else if (dynamic_cast<const Import*>(ast_)) {
            // Nothing to do.

        } else if (dynamic_cast<const Importstr*>(ast_)) {
            // Nothing to do.

        } else if (auto *ast = dynamic_cast<Index*>(ast_)) {
            desugar(ast->target);
            desugar(ast->index);

        } else if (auto *ast = dynamic_cast<Local*>(ast_)) {
            for (auto &bind: ast->binds)
                desugar(bind.second);
            desugar(ast->body);

        } else if (dynamic_cast<const LiteralBoolean*>(ast_)) {
            // Nothing to do.

        } else if (dynamic_cast<const LiteralNumber*>(ast_)) {
            // Nothing to do.

        } else if (dynamic_cast<const LiteralString*>(ast_)) {
            // Nothing to do.

        } else if (dynamic_cast<const LiteralNull*>(ast_)) {
            // Nothing to do.

        } else if (auto *ast = dynamic_cast<Object*>(ast_)) {
            for (auto &assert : ast->asserts) {
                desugar(assert);
            }
            for (auto &field : ast->fields) {
                desugar(field.name);
                desugar(field.body);
            }

        } else if (auto *ast = dynamic_cast<ObjectComprehension*>(ast_)) {
            for (ComprehensionSpec &spec : ast->specs)
                desugar(spec.expr);
            desugar(ast->field);
            desugar(ast->value);

            /*  {
                    [arr[0]]: local x = arr[1], y = arr[2], z = arr[3]; val_expr
                    for arr in [ [key_expr, x, y, z] for ...  ]
                }
            */
            auto *_arr = id(U"$arr");
            AST *zero = make<LiteralNumber>(E, 0.0);
            int counter = 1;
            Local::Binds binds;
            auto arr_e = std::vector<AST*> {ast->field};
            for (ComprehensionSpec &spec : ast->specs) {
                if (spec.kind == ComprehensionSpec::FOR) {
                    binds[spec.var] =
                        make<Index>(E, var(_arr), make<LiteralNumber>(E, double(counter++)));
                    arr_e.push_back(var(spec.var));
                }
            }
            AST *arr = make<ArrayComprehension>(
                ast->location,
                make<Array>(ast->location, arr_e),
                ast->specs);
            desugar(arr);
            ast_ = make<ObjectComprehensionSimple>(
                ast->location,
                make<Index>(E, var(_arr), zero),
                make<Local>(
                    ast->location,
                    binds,
                    ast->value),
                _arr,
                arr);

        } else if (auto *ast = dynamic_cast<ObjectComprehensionSimple*>(ast_)) {
            desugar(ast->field);
            desugar(ast->value);
            desugar(ast->array);

        } else if (dynamic_cast<const Self*>(ast_)) {
            // Nothing to do.

        } else if (dynamic_cast<const Super*>(ast_)) {
            // Nothing to do.

        } else if (auto *ast = dynamic_cast<Unary*>(ast_)) {
            desugar(ast->expr);

        } else if (dynamic_cast<const Var*>(ast_)) {
            // Nothing to do.

        } else {
            std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_ << std::endl;
            std::abort();

        }
    }
Exemple #7
0
    void desugar(AST *&ast_, unsigned obj_level)
    {
        if (auto *ast = dynamic_cast<Apply*>(ast_)) {
            desugar(ast->target, obj_level);
            for (Apply::Arg &arg : ast->args)
                desugar(arg.expr, obj_level);

        } else if (auto *ast = dynamic_cast<ApplyBrace*>(ast_)) {
            desugar(ast->left, obj_level);
            desugar(ast->right, obj_level);
            ast_ = alloc->make<Binary>(ast->location, ast->openFodder,
                                       ast->left, EF, BOP_PLUS, ast->right);

        } else if (auto *ast = dynamic_cast<Array*>(ast_)) {
            for (auto &el : ast->elements)
                desugar(el.expr, obj_level);

        } else if (auto *ast = dynamic_cast<ArrayComprehension*>(ast_)) {
            for (ComprehensionSpec &spec : ast->specs)
                desugar(spec.expr, obj_level);
            desugar(ast->body, obj_level + 1);

            int n = ast->specs.size();
            AST *zero = make<LiteralNumber>(E, EF, "0.0");
            AST *one = make<LiteralNumber>(E, EF, "1.0");
            auto *_r = id(U"$r");
            auto *_l = id(U"$l");
            std::vector<const Identifier*> _i(n);
            for (int i = 0; i < n ; ++i) {
                StringStream ss;
                ss << U"$i_" << i;
                _i[i] = id(ss.str());
            }
            std::vector<const Identifier*> _aux(n);
            for (int i = 0; i < n ; ++i) {
                StringStream ss;
                ss << U"$aux_" << i;
                _aux[i] = id(ss.str());
            }

            // Build it from the inside out.  We keep wrapping 'in' with more ASTs.
            assert(ast->specs[0].kind == ComprehensionSpec::FOR);

            int last_for = n - 1;
            while (ast->specs[last_for].kind != ComprehensionSpec::FOR)
                last_for--;
            // $aux_{last_for}($i_{last_for} + 1, $r + [body])
            AST *in = make<Apply>(
                ast->body->location,
                EF,
                var(_aux[last_for]),
                EF,
                Apply::Args {
                    { make<Binary>(E, EF, var(_i[last_for]), EF, BOP_PLUS, one), EF},
                    { make<Binary>(E, EF, var(_r), EF, BOP_PLUS, singleton(ast->body)), EF}
                },
                false,  // trailingComma
                EF,
                EF,
                true  // tailstrict
            );
            for (int i = n - 1; i >= 0 ; --i) {
                const ComprehensionSpec &spec = ast->specs[i];
                AST *out;
                if (i > 0) {
                    int prev_for = i - 1;
                    while (ast->specs[prev_for].kind != ComprehensionSpec::FOR)
                        prev_for--;

                    // aux_{prev_for}($i_{prev_for} + 1, $r)
                    out = make<Apply>(  // False branch.
                        E,
                        EF,
                        var(_aux[prev_for]),
                        EF,
                        Apply::Args {
                            { make<Binary>(E, EF, var(_i[prev_for]), EF, BOP_PLUS, one), EF, },
                            { var(_r), EF, }
                        },
                        false, // trailingComma
                        EF,
                        EF,
                        true  // tailstrict
                    );
                } else {
                    out = var(_r);
                }
                switch (spec.kind) {
                    case ComprehensionSpec::IF: {
                        /*
                            if [[[...cond...]]] then
                                [[[...in...]]]
                            else
                                [[[...out...]]]
                        */
                        in = make<Conditional>(
                            ast->location,
                            EF,
                            spec.expr,
                            EF,
                            in,  // True branch.
                            EF,
                            out);  // False branch.
                    } break;
                    case ComprehensionSpec::FOR: {
                        /*
                            local $l = [[[...array...]]]
                                  aux_{i}(i_{i}, r) =
                                if i_{i} >= std.length($l) then
                                    [[[...out...]]]
                                else
                                    local [[[...var...]]] = $l[i_{i}];
                                    [[[...in...]]];`
                            if std.type($l) != "array" then
                                error "In comprehension, can only iterate over array.."
                            else
                                aux_{i}(0, r) tailstrict;
                        */
                        in = make<Local>(
                            ast->location,
                            EF,
                            Local::Binds {
                                bind(_l, spec.expr),  // Need to check expr is an array
                                bind(_aux[i], make<Function>(
                                    ast->location,
                                    EF,
                                    EF,
                                    std::vector<Param>{Param(EF, _i[i], EF), Param(EF, _r, EF)},
                                    false,  // trailingComma
                                    EF,
                                    make<Conditional>(
                                        ast->location,
                                        EF,
                                        make<Binary>(
                                            E, EF, var(_i[i]), EF, BOP_GREATER_EQ, length(var(_l))),
                                        EF,
                                        out,
                                        EF,
                                        make<Local>(
                                            ast->location,
                                            EF,
                                            singleBind(
                                                spec.var,
                                                make<Index>(E, EF, var(_l), EF, false, var(_i[i]),
                                                            EF, nullptr, EF, nullptr, EF)
                                            ),
                                            in)
                                    )
                                ))},
                            make<Conditional>(
                                ast->location,
                                EF,
                                equals(ast->location, type(var(_l)), str(U"array")),
                                EF,
                                make<Apply>(
                                    E,
                                    EF,
                                    var(_aux[i]),
                                    EF,
                                    Apply::Args {
                                        {zero, EF},
                                        {
                                            i == 0
                                            ? make<Array>(E, EF, Array::Elements{}, false, EF)
                                            : static_cast<AST*>(var(_r)),
                                            EF,
                                        }
                                    },
                                    false,  // trailingComma
                                    EF,
                                    EF,
                                    true),  // tailstrict
                                EF,
                                error(ast->location,
                                      U"In comprehension, can only iterate over array.")));
                    } break;
                }
            }

            ast_ = in;

        } else if (auto *ast = dynamic_cast<Assert*>(ast_)) {
            desugar(ast->cond, obj_level);
            if (ast->message == nullptr) {
                ast->message = str(U"Assertion failed.");
            }
            desugar(ast->message, obj_level);
            desugar(ast->rest, obj_level);

            // if cond then rest else error msg
            AST *branch_false = alloc->make<Error>(ast->location, EF, ast->message);
            ast_ = alloc->make<Conditional>(ast->location, ast->openFodder,
                                            ast->cond, EF, ast->rest, EF, branch_false);

        } else if (auto *ast = dynamic_cast<Binary*>(ast_)) {
            desugar(ast->left, obj_level);
            desugar(ast->right, obj_level);

            bool invert = false;

            switch (ast->op) {
                case BOP_PERCENT: {
                    AST *f_mod = alloc->make<Index>(E, EF, std(), EF, false, str(U"mod"), EF,
                                                    nullptr, EF, nullptr, EF);
                    Apply::Args args = {{ast->left, EF}, {ast->right, EF}};
                    ast_ = alloc->make<Apply>(ast->location, ast->openFodder, f_mod, EF, args,
                                              false, EF, EF, false);
                } break;

                case BOP_MANIFEST_UNEQUAL:
                invert = true;
                case BOP_MANIFEST_EQUAL: {
                    ast_ = equals(ast->location, ast->left, ast->right);
                    if (invert)
                        ast_ = alloc->make<Unary>(ast->location, ast->openFodder, UOP_NOT, ast_);
                }
                break;

                default:;
                // Otherwise don't change it.
            }

        } else if (dynamic_cast<const BuiltinFunction*>(ast_)) {
            // Nothing to do.

        } else if (auto *ast = dynamic_cast<Conditional*>(ast_)) {
            desugar(ast->cond, obj_level);
            desugar(ast->branchTrue, obj_level);
            if (ast->branchFalse == nullptr)
                ast->branchFalse = alloc->make<LiteralNull>(LocationRange(), EF);
            desugar(ast->branchFalse, obj_level);

        } else if (auto *ast = dynamic_cast<Dollar*>(ast_)) {
            if (obj_level == 0) {
                throw StaticError(ast->location, "No top-level object found.");
            }
            ast_ = alloc->make<Var>(ast->location, EF, alloc->makeIdentifier(U"$"));

        } else if (auto *ast = dynamic_cast<Error*>(ast_)) {
            desugar(ast->expr, obj_level);

        } else if (auto *ast = dynamic_cast<Function*>(ast_)) {
            desugar(ast->body, obj_level);

        } else if (dynamic_cast<const Import*>(ast_)) {
            // Nothing to do.

        } else if (dynamic_cast<const Importstr*>(ast_)) {
            // Nothing to do.

        } else if (auto *ast = dynamic_cast<Index*>(ast_)) {
            desugar(ast->target, obj_level);
            if (ast->isSlice) {
                if (ast->index == nullptr)
                    ast->index = make<LiteralNull>(ast->location, EF);
                desugar(ast->index, obj_level);

                if (ast->end == nullptr)
                    ast->end = make<LiteralNull>(ast->location, EF);
                desugar(ast->end, obj_level);

                if (ast->step == nullptr)
                    ast->step = make<LiteralNull>(ast->location, EF);
                desugar(ast->step, obj_level);

                ast_ = make<Apply>(
                    ast->location,
                    EF,
                    make<Index>(
                        E, EF, std(), EF, false, str(U"slice"), EF, nullptr, EF, nullptr, EF),
                    EF,
                    std::vector<Apply::Arg>{
                        {ast->target, EF},
                        {ast->index, EF},
                        {ast->end, EF},
                        {ast->step, EF},
                    },
                    false,  // trailing comma
                    EF,
                    EF,
                    false  // tailstrict
                );
            } else {
                if (ast->id != nullptr) {
                    assert(ast->index == nullptr);
                    ast->index = str(ast->id->name);
                    ast->id = nullptr;
                }
                desugar(ast->index, obj_level);
            }

        } else if (auto *ast = dynamic_cast<Local*>(ast_)) {
            for (auto &bind: ast->binds)
                desugar(bind.body, obj_level);
            desugar(ast->body, obj_level);

            for (auto &bind: ast->binds) {
                if (bind.functionSugar) {
                    bind.body = alloc->make<Function>(
                        ast->location, ast->openFodder, bind.parenLeftFodder, bind.params, false,
                        bind.parenRightFodder, bind.body);
                    bind.functionSugar = false;
                    bind.params.clear();
                }
            }

        } else if (dynamic_cast<const LiteralBoolean*>(ast_)) {
            // Nothing to do.

        } else if (dynamic_cast<const LiteralNumber*>(ast_)) {
            // Nothing to do.

        } else if (auto *ast = dynamic_cast<LiteralString*>(ast_)) {
            if (ast->tokenKind != LiteralString::BLOCK) {
                ast->value = jsonnet_string_unescape(ast->location, ast->value);
            }
            ast->tokenKind = LiteralString::DOUBLE;
            ast->blockIndent.clear();

        } else if (dynamic_cast<const LiteralNull*>(ast_)) {
            // Nothing to do.

        } else if (auto *ast = dynamic_cast<DesugaredObject*>(ast_)) {
            for (auto &field : ast->fields) {
                desugar(field.name, obj_level);
                desugar(field.body, obj_level + 1);
            }
            for (AST *assert : ast->asserts) {
                desugar(assert, obj_level + 1);
            }

        } else if (auto *ast = dynamic_cast<Object*>(ast_)) {
            // Hidden variable to allow outer/top binding.
            if (obj_level == 0) {
                const Identifier *hidden_var = alloc->makeIdentifier(U"$");
                auto *body = alloc->make<Self>(E, EF);
                ast->fields.push_back(ObjectField::Local(EF, EF, hidden_var, EF, body, EF));
            }

            desugarFields(ast, ast->fields, obj_level);

            DesugaredObject::Fields new_fields;
            ASTs new_asserts;
            for (const ObjectField &field : ast->fields) {
                if (field.kind == ObjectField::ASSERT) {
                    new_asserts.push_back(field.expr2);
                } else if (field.kind == ObjectField::FIELD_EXPR) {
                    new_fields.emplace_back(field.hide, field.expr1, field.expr2);
                } else {
                    std::cerr << "INTERNAL ERROR: field should have been desugared: "
                              << field.kind << std::endl;
                }
            }
            ast_ = alloc->make<DesugaredObject>(ast->location, new_asserts, new_fields);

        } else if (auto *ast = dynamic_cast<ObjectComprehension*>(ast_)) {
            // Hidden variable to allow outer/top binding.
            if (obj_level == 0) {
                const Identifier *hidden_var = alloc->makeIdentifier(U"$");
                auto *body = alloc->make<Self>(E, EF);
                ast->fields.push_back(ObjectField::Local(EF, EF, hidden_var, EF, body, EF));
            }

            desugarFields(ast, ast->fields, obj_level);

            for (ComprehensionSpec &spec : ast->specs)
                desugar(spec.expr, obj_level);

            AST *field = ast->fields.front().expr1;
            AST *value = ast->fields.front().expr2;

            /*  {
                    [arr[0]]: local x = arr[1], y = arr[2], z = arr[3]; val_expr
                    for arr in [ [key_expr, x, y, z] for ...  ]
                }
            */
            auto *_arr = id(U"$arr");
            AST *zero = make<LiteralNumber>(E, EF, "0.0");
            int counter = 1;
            Local::Binds binds;
            Array::Elements arr_e {Array::Element(field, EF)};
            for (ComprehensionSpec &spec : ast->specs) {
                if (spec.kind == ComprehensionSpec::FOR) {
                    std::stringstream num;
                    num << counter++;
                    binds.push_back(bind(
                        spec.var,
                        make<Index>(E, EF, var(_arr), EF, false,
                                    make<LiteralNumber>(E, EF, num.str()), EF, nullptr, EF, nullptr,
                                    EF)));
                    arr_e.emplace_back(var(spec.var), EF);
                }
            }
            AST *arr = make<ArrayComprehension>(
                ast->location,
                EF,
                make<Array>(ast->location, EF, arr_e, false, EF),
                EF,
                false,
                ast->specs,
                EF);
            desugar(arr, obj_level);
            ast_ = make<ObjectComprehensionSimple>(
                ast->location,
                make<Index>(E, EF, var(_arr), EF, false, zero, EF, nullptr, EF, nullptr, EF),
                make<Local>(
                    ast->location,
                    EF,
                    binds,
                    value),
                _arr,
                arr);

        } else if (auto *ast = dynamic_cast<ObjectComprehensionSimple*>(ast_)) {
            desugar(ast->field, obj_level);
            desugar(ast->value, obj_level + 1);
            desugar(ast->array, obj_level);

        } else if (auto *ast = dynamic_cast<Parens*>(ast_)) {
            // Strip parens.
            desugar(ast->expr, obj_level);
            ast_ = ast->expr;

        } else if (dynamic_cast<const Self*>(ast_)) {
            // Nothing to do.

        } else if (auto * ast = dynamic_cast<SuperIndex*>(ast_)) {
            if (ast->id != nullptr) {
                assert(ast->index == nullptr);
                ast->index = str(ast->id->name);
                ast->id = nullptr;
            }
            desugar(ast->index, obj_level);

        } else if (auto *ast = dynamic_cast<Unary*>(ast_)) {
            desugar(ast->expr, obj_level);

        } else if (dynamic_cast<const Var*>(ast_)) {
            // Nothing to do.

        } else {
            std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_ << std::endl;
            std::abort();

        }
    }
Exemple #8
0
    void desugarFields(AST *ast, ObjectFields &fields, unsigned obj_level)
    {
        // Desugar children
        for (auto &field : fields) {
            if (field.expr1 != nullptr) desugar(field.expr1, obj_level);
            desugar(field.expr2, obj_level + 1);
            if (field.expr3 != nullptr) desugar(field.expr3, obj_level + 1);
        }

        // Simplify asserts
        for (auto &field : fields) {
            if (field.kind != ObjectField::ASSERT) continue;
            AST *msg = field.expr3;
            field.expr3 = nullptr;
            if (msg == nullptr) {
                auto msg_str = U"Object assertion failed.";
                msg = alloc->make<LiteralString>(field.expr2->location, EF, msg_str,
                                                 LiteralString::DOUBLE, "", "");
            }

            // if expr2 then true else error msg
            field.expr2 = alloc->make<Conditional>(
                ast->location,
                EF,
                field.expr2,
                EF,
                alloc->make<LiteralBoolean>(E, EF, true),
                EF,
                error(msg));
        }

        // Remove methods
        for (auto &field : fields) {
            if (!field.methodSugar) continue;
            field.expr2 = alloc->make<Function>(
                field.expr2->location, EF, field.fodderL, field.params, field.trailingComma,
                field.fodderR, field.expr2);
            field.methodSugar = false;
            field.params.clear();
        }


        // Remove object-level locals
        auto copy = fields;
        fields.clear();
        Local::Binds binds;
        for (auto &local : copy) {
            if (local.kind != ObjectField::LOCAL) continue;
            binds.push_back(bind(local.id, local.expr2));
        }
        for (auto &field : copy) {
            if (field.kind == ObjectField::LOCAL) continue;
            if (!binds.empty())
                field.expr2 = alloc->make<Local>(field.expr2->location, EF, binds, field.expr2);
            fields.push_back(field);
        }

        // Change all to FIELD_EXPR
        for (auto &field : fields) {
            switch (field.kind) {
                case ObjectField::ASSERT:
                // Nothing to do.
                break;

                case ObjectField::FIELD_ID:
                field.expr1 = str(field.id->name);
                field.kind = ObjectField::FIELD_EXPR;
                break;

                case ObjectField::FIELD_EXPR:
                // Nothing to do.
                break;

                case ObjectField::FIELD_STR:
                // Just set the flag.
                field.kind = ObjectField::FIELD_EXPR;
                break;

                case ObjectField::LOCAL:
                std::cerr << "Locals should be removed by now." << std::endl;
                abort();
            }
        }

        // Remove +:
        for (auto &field : fields) {
            if (!field.superSugar) continue;
            AST *super_f = alloc->make<SuperIndex>(field.expr1->location, EF, EF, field.expr1, EF,
                                                   nullptr);
            field.expr2 = alloc->make<Binary>(ast->location, EF, super_f, EF, BOP_PLUS,
                                              field.expr2);
            field.superSugar = false;
        }
    }
Exemple #9
0
void desugar (AST::ExpPtr& e)
{
	auto span = e->span;

	if (auto var = dynamic_cast<AST::VarExp*>(e.get()))
	{
		desugarName(var->name);
	}
	else if (auto let = dynamic_cast<AST::LetExp*>(e.get()))
	{
		desugar(let->pattern);
	}
	else if (auto assign = dynamic_cast<AST::AssignExp*>(e.get()))
	{
		auto lh = assign->children[0];
		auto rh = assign->children[1];
		bool okay = false;

		if (auto mem = dynamic_cast<AST::MemberExp*>(lh.get()))
		{
			auto obj = mem->children[0];
			auto what = mem->children[1];
			auto span = assign->span;

			if (mem->kind == AST::MemberExp::Get)
			{
				// a[b] = c   ->   a.set(b, c)
				e = AST::methodCall(span, obj, Names::Set, { what, rh });
				okay = true;
			}
		}
		else if (lh->is<AST::VarExp>() || lh->is<AST::PropertyExp>())
			okay = true;

		if (!okay)
			throw SourceError("invalid left-hand of assignment", lh->span);
	}
	else if (auto mem = dynamic_cast<AST::MemberExp*>(e.get()))
	{
		auto obj = mem->children[0];
		auto args = mem->children;

		// a[b]   ->   a.get(b)
		// a[b,]  ->   a.sub_from(b)
		// a[,b]  ->   a.sub_to(b)
		// a[b,c] ->   a.sub(b, c)
		switch (mem->kind)
		{
		case AST::MemberExp::Slice:
			e = AST::methodCall(span, obj, Names::Slice, { args[1], args[2] });
			break;
		case AST::MemberExp::SliceFrom:
			e = AST::methodCall(span, obj, Names::SliceFrom, { args[1] });
			break;
		case AST::MemberExp::SliceTo:
			e = AST::methodCall(span, obj, Names::SliceTo, { args[1] });
			break;
		case AST::MemberExp::Get:
		default:
			e = AST::methodCall(span, obj, Names::Get, { args[1] });
			break;
		}
	}
	else if (auto cmp = dynamic_cast<AST::CompareExp*>(e.get()))
	{
		AST::ExpPtr res;
		auto a = cmp->children[0];
		auto b = cmp->children[1];

		// a == b   ->   a.equal(b) == true
		// a != b   ->   a.equal(b) == false
		// a > b    ->   a.cmp(b) > 0
		// a < b    ->   a.cmp(b) < 0
		// etc.
		if (cmp->kind == AST::CompareExp::Eq ||
				cmp->kind == AST::CompareExp::NotEq)
			res = AST::methodCall(span, a, Names::Equal, { b });
		else
			res = AST::methodCall(span, a, Names::Compare, { b });

		e = AST::ExpPtr(new AST::CompareExp(res, cmp->kind));
		e->span = span;
	}
	else if (auto obj = dynamic_cast<AST::ObjectExp*>(e.get()))
	{
		desugar(obj->objType);
	}
	else if (auto lam = dynamic_cast<AST::LambdaExp*>(e.get()))
	{
		for (auto arg : lam->args)
			if (arg.type != nullptr)
				desugar(arg.type);
	}
	else if (dynamic_cast<AST::ListExp*>(e.get()))
	{
		auto elems = e->children;

		// build linked list right to left
		auto res = AST::Exp::nil(span);

		for (size_t i = 0, len = elems.size(); i < len; i++)
		{
			auto elem = elems[len - i - 1];
			res = AST::Exp::cons(elem->span, elem, res);
		}

		e = res;
		desugar(e); // again!
		return;
	}
	else if (auto block = dynamic_cast<AST::BlockExp*>(e.get()))
	{
		for (auto& c : e->children)
		{
			if (c == block->last)
			{
				desugar(block->last);
				c = block->last;
			}
			else
				desugar(c);
		}
		return;
	}
	else if (auto match = dynamic_cast<AST::MatchExp*>(e.get()))
	{
		for (auto& pat : match->patterns)
			desugar(pat);
	}

	for (auto& c : e->children)
		desugar(c);
}