Skip to content

Commit 114a3e7

Browse files
committed
Fix #244 super/self in +: desugaring
1 parent de9b782 commit 114a3e7

File tree

10 files changed

+681
-418
lines changed

10 files changed

+681
-418
lines changed

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ LIB_SRC = \
4747
core/lexer.cpp \
4848
core/libjsonnet.cpp \
4949
core/parser.cpp \
50+
core/pass.cpp \
5051
core/static_analysis.cpp \
5152
core/string_utils.cpp \
5253
core/vm.cpp

core/BUILD

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ cc_library(
88
"lexer.cpp",
99
"libjsonnet.cpp",
1010
"parser.cpp",
11+
"pass.cpp",
1112
"static_analysis.cpp",
1213
"string_utils.cpp",
1314
"vm.cpp",
@@ -19,6 +20,7 @@ cc_library(
1920
"json.h",
2021
"lexer.h",
2122
"parser.h",
23+
"pass.h",
2224
"state.h",
2325
"static_analysis.h",
2426
"static_error.h",

core/ast.h

+6
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,12 @@ class Allocator {
750750
allocated.push_back(r);
751751
return r;
752752
}
753+
754+
template <class T> T *clone(T * ast) {
755+
auto r = new T(*ast);
756+
allocated.push_back(r);
757+
return r;
758+
}
753759
/** Returns interned identifiers.
754760
*
755761
* The location used in the Identifier AST is that of the first one parsed.

core/desugarer.cpp

+74-12
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ limitations under the License.
2020
#include "desugarer.h"
2121
#include "lexer.h"
2222
#include "parser.h"
23+
#include "pass.h"
2324
#include "string_utils.h"
2425

2526
static const Fodder EF; // Empty fodder.
@@ -199,7 +200,11 @@ class Desugarer {
199200
}
200201
}
201202

202-
void desugarFields(AST *ast, ObjectFields &fields, unsigned obj_level)
203+
// For all occurrences, records the identifier that will replace super[e]
204+
// If self occurs, also map the self identifier to nullptr.
205+
typedef std::vector<std::pair<const Identifier *, AST *>> SuperVars;
206+
207+
SuperVars desugarFields(AST *ast, ObjectFields &fields, unsigned obj_level)
203208
{
204209
// Desugar children
205210
for (auto &field : fields) {
@@ -283,15 +288,59 @@ class Desugarer {
283288
}
284289
}
285290

291+
class SubstituteSelfSuper : public CompilerPass {
292+
Desugarer *desugarer;
293+
SuperVars &superVars;
294+
unsigned &counter;
295+
const Identifier *newSelf;
296+
public:
297+
SubstituteSelfSuper(Desugarer *desugarer, SuperVars &super_vars, unsigned &counter)
298+
: CompilerPass(*desugarer->alloc), desugarer(desugarer), superVars(super_vars),
299+
counter(counter), newSelf(nullptr)
300+
{
301+
}
302+
void visitExpr(AST *&expr)
303+
{
304+
if (dynamic_cast<Self*>(expr)) {
305+
if (newSelf == nullptr) {
306+
newSelf = desugarer->id(U"$outer_self");
307+
superVars.emplace_back(newSelf, nullptr);
308+
}
309+
expr = alloc.make<Var>(expr->location, expr->openFodder, newSelf);
310+
} else if (auto *super_index = dynamic_cast<SuperIndex*>(expr)) {
311+
StringStream ss;
312+
ss << "$outer_super" << (counter++);
313+
const Identifier *super_var = desugarer->id(ss.str());
314+
AST *index = super_index->index;
315+
// Desugaring of expr should already have occurred.
316+
assert(index != nullptr);
317+
// Re-use super_index since we're replacing it here.
318+
superVars.emplace_back(super_var, super_index);
319+
expr = alloc.make<Var>(expr->location, expr->openFodder, super_var);
320+
}
321+
CompilerPass::visitExpr(expr);
322+
}
323+
};
324+
325+
SuperVars super_vars;
326+
unsigned counter;
327+
286328
// Remove +:
287329
for (auto &field : fields) {
288330
if (!field.superSugar) continue;
289-
AST *super_f = make<SuperIndex>(field.expr1->location, EF, EF, field.expr1, EF,
290-
nullptr);
291-
field.expr2 = make<Binary>(ast->location, EF, super_f, EF, BOP_PLUS,
292-
field.expr2);
331+
// We have to bind self/super from expr1 outside the class, as we copy the expression
332+
// into the field body.
333+
AST *index = field.expr1;
334+
// Clone it so that we maintain the AST as a tree.
335+
ClonePass(*alloc).expr(index);
336+
// This will remove self/super.
337+
SubstituteSelfSuper(this, super_vars, counter).expr(index);
338+
AST *super_f = make<SuperIndex>(field.expr1->location, EF, EF, index, EF, nullptr);
339+
field.expr2 = make<Binary>(ast->location, EF, super_f, EF, BOP_PLUS, field.expr2);
293340
field.superSugar = false;
294341
}
342+
343+
return super_vars;
295344
}
296345

297346
void desugar(AST *&ast_, unsigned obj_level)
@@ -305,7 +354,7 @@ class Desugarer {
305354
desugar(ast->left, obj_level);
306355
desugar(ast->right, obj_level);
307356
ast_ = make<Binary>(ast->location, ast->openFodder,
308-
ast->left, EF, BOP_PLUS, ast->right);
357+
ast->left, EF, BOP_PLUS, ast->right);
309358

310359
} else if (auto *ast = dynamic_cast<Array*>(ast_)) {
311360
for (auto &el : ast->elements)
@@ -406,11 +455,11 @@ class Desugarer {
406455
[[[...out...]]]
407456
else
408457
local [[[...var...]]] = $l[i_{i}];
409-
[[[...in...]]];`
410-
if std.type($l) != "array" then
411-
error "In comprehension, can only iterate over array.."
458+
[[[...in...]]];
459+
if std.type($l) == "array" then
460+
aux_{i}(0, $r) tailstrict
412461
else
413-
aux_{i}(0, r) tailstrict;
462+
error "In comprehension, can only iterate over array..";
414463
*/
415464
in = make<Local>(
416465
ast->location,
@@ -635,7 +684,7 @@ class Desugarer {
635684
ast->fields.push_back(ObjectField::Local(EF, EF, hidden_var, EF, body, EF));
636685
}
637686

638-
desugarFields(ast, ast->fields, obj_level);
687+
SuperVars svs = desugarFields(ast, ast->fields, obj_level);
639688

640689
DesugaredObject::Fields new_fields;
641690
ASTs new_asserts;
@@ -650,6 +699,19 @@ class Desugarer {
650699
}
651700
}
652701
ast_ = make<DesugaredObject>(ast->location, new_asserts, new_fields);
702+
if (svs.size() > 0) {
703+
Local::Binds binds;
704+
for (const auto &pair : svs) {
705+
if (pair.second == nullptr) {
706+
// Self binding
707+
binds.push_back(bind(pair.first, make<Self>(E, EF)));
708+
} else {
709+
// Super binding
710+
binds.push_back(bind(pair.first, pair.second));
711+
}
712+
}
713+
ast_ = make<Local>(ast->location, EF, binds, ast_);
714+
}
653715

654716
} else if (auto *ast = dynamic_cast<ObjectComprehension*>(ast_)) {
655717
// Hidden variable to allow outer/top binding.
@@ -659,7 +721,7 @@ class Desugarer {
659721
ast->fields.push_back(ObjectField::Local(EF, EF, hidden_var, EF, body, EF));
660722
}
661723

662-
desugarFields(ast, ast->fields, obj_level);
724+
SuperVars svs = desugarFields(ast, ast->fields, obj_level);
663725

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

0 commit comments

Comments
 (0)