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); }
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); } }
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; } } }
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); } } }
ExprC *desugar(const ExprS& root) const { return desugar(&root); }
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(); } }
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(); } }
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; } }
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); }