From 94ac375a0baa619efa021388e5fd738873dda855 Mon Sep 17 00:00:00 2001 From: Dave Cunningham Date: Mon, 26 Oct 2015 22:48:15 -0400 Subject: [PATCH] super can now only be used in super.f or super[e] This commit already submitted as 9ade1beb3c079a011d8d6528d0370695dc130e89 but got stuck in the gh-pages branch for some reason --- core/ast.h | 9 ++- core/desugaring.cpp | 4 +- core/parser.cpp | 25 ++++-- core/state.h | 16 ---- core/static_analysis.cpp | 3 +- core/vm.cpp | 85 ++++++++++----------- test_suite/error.static_error_super.jsonnet | 2 +- test_suite/oop.jsonnet | 10 --- test_suite/oop_extra.jsonnet | 21 +---- 9 files changed, 70 insertions(+), 105 deletions(-) diff --git a/core/ast.h b/core/ast.h index 6a9e1a16c..16ac66fb8 100644 --- a/core/ast.h +++ b/core/ast.h @@ -50,7 +50,7 @@ enum ASTType { AST_OBJECT_COMPREHENSION, AST_OBJECT_COMPREHENSION_SIMPLE, AST_SELF, - AST_SUPER, + AST_SUPER_INDEX, AST_UNARY, AST_VAR }; @@ -360,9 +360,10 @@ struct Self : public AST { }; /** Represents the super keyword. */ -struct Super : public AST { - Super(const LocationRange &lr) - : AST(lr, AST_SUPER) +struct SuperIndex : public AST { + AST *index; + SuperIndex(const LocationRange &lr, AST *index) + : AST(lr, AST_SUPER_INDEX), index(index) { } }; diff --git a/core/desugaring.cpp b/core/desugaring.cpp index 1ab026760..e241568bd 100644 --- a/core/desugaring.cpp +++ b/core/desugaring.cpp @@ -294,8 +294,8 @@ class Desugarer { } else if (dynamic_cast(ast_)) { // Nothing to do. - } else if (dynamic_cast(ast_)) { - // Nothing to do. + } else if (auto * ast = dynamic_cast(ast_)) { + desugar(ast->index); } else if (auto *ast = dynamic_cast(ast_)) { desugar(ast->expr); diff --git a/core/parser.cpp b/core/parser.cpp index 38d1fba84..9b76df2f9 100644 --- a/core/parser.cpp +++ b/core/parser.cpp @@ -216,8 +216,8 @@ static std::string unparse(const AST *ast_) } else if (dynamic_cast(ast_)) { ss << "self"; - } else if (dynamic_cast(ast_)) { - ss << "super"; + } else if (auto *ast = dynamic_cast(ast_)) { + ss << "super[" << unparse(ast->index) << "]"; } else if (auto *ast = dynamic_cast(ast_)) { ss << uop_string(ast->op) << "(" << unparse(ast->expr) << ")"; @@ -616,7 +616,7 @@ namespace { } if (plus_sugar) { AST *f = alloc->make(plus_loc, next.data32()); - AST *super_f = alloc->make(plus_loc, alloc->make(LocationRange()), f); + AST *super_f = alloc->make(plus_loc, f); body = alloc->make(body->location, super_f, BOP_PLUS, body); } fields.emplace_back(field_expr, field_hide, body); @@ -832,8 +832,23 @@ namespace { case Token::SELF: return alloc->make(span(tok)); - case Token::SUPER: - return alloc->make(span(tok)); + case Token::SUPER: { + Token next = pop(); + AST *index; + switch (next.kind) { + case Token::DOT: { + Token field_id = popExpect(Token::IDENTIFIER); + index = alloc->make(span(field_id), field_id.data32()); + } break; + case Token::BRACKET_L: { + index = parse(MAX_PRECEDENCE, obj_level); + popExpect(Token::BRACKET_R); + } break; + default: + throw StaticError(tok.location, "Expected . or [ after super."); + } + return alloc->make(span(tok), index); + } } std::cerr << "INTERNAL ERROR: Unknown tok kind: " << tok.kind << std::endl; diff --git a/core/state.h b/core/state.h index c671e8f69..11db9181c 100644 --- a/core/state.h +++ b/core/state.h @@ -192,19 +192,6 @@ namespace { { } }; - /** Objects created by the super construct. */ - struct HeapSuperObject : public HeapObject { - /** The object to bind self when evaluating field bodies when indexing me. */ - HeapObject *root; - - /** The object whose field definitions are used when indexing me. */ - unsigned offset; - - HeapSuperObject(HeapObject *root, unsigned offset) - : root(root), offset(offset) - { } - }; - /** Objects created by the ObjectComprehensionSimple construct. */ struct HeapComprehensionObject : public HeapLeafObject { @@ -365,9 +352,6 @@ namespace { addIfHeapEntity(upv.second, s.children); - } else if (auto *obj = dynamic_cast(curr)) { - addIfHeapEntity(obj->root, s.children); - } else if (auto *arr = dynamic_cast(curr)) { for (auto el : arr->elements) addIfHeapEntity(el, s.children); diff --git a/core/static_analysis.cpp b/core/static_analysis.cpp index 8ad82524e..d2db88f1f 100644 --- a/core/static_analysis.cpp +++ b/core/static_analysis.cpp @@ -140,9 +140,10 @@ static IdSet static_analysis(AST *ast_, bool in_object, const IdSet &vars) if (!in_object) throw StaticError(ast_->location, "Can't use self outside of an object."); - } else if (dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { if (!in_object) throw StaticError(ast_->location, "Can't use super outside of an object."); + append(r, static_analysis(ast->index, in_object, vars)); } else if (auto *ast = dynamic_cast(ast_)) { append(r, static_analysis(ast->expr, in_object, vars)); diff --git a/core/vm.cpp b/core/vm.cpp index da3eaccf1..1ef7ab653 100644 --- a/core/vm.cpp +++ b/core/vm.cpp @@ -54,13 +54,14 @@ namespace { FRAME_IF, // e in if e then a else b FRAME_INDEX_TARGET, // e in e[x] FRAME_INDEX_INDEX, // e in x[e] + FRAME_INVARIANTS, // Caches the thunks that need to be executed one at a time. FRAME_LOCAL, // Stores thunk bindings as we execute e in local ...; e FRAME_OBJECT, // Stores intermediate state as we execute es in { [e]: ..., [e]: ... } FRAME_OBJECT_COMP_ARRAY, // e in {f:a for x in e] FRAME_OBJECT_COMP_ELEMENT, // Stores intermediate state when building object FRAME_STRING_CONCAT, // Stores intermediate state while co-ercing objects + FRAME_SUPER_INDEX, // e in super[e] FRAME_UNARY, // e in -e - FRAME_INVARIANTS // Caches the thunks that need to be executed one at a time. }; /** A frame on the stack. @@ -579,13 +580,6 @@ namespace { if (r) return r; auto *l = findObject(f, root, ext->left, start_from, counter, self); if (l) return l; - } else if (auto *super = dynamic_cast(curr)) { - unsigned counter2 = 0; - auto *needle = findObject(f, super->root, super->root, super->offset, counter2, self); - if (needle != nullptr) { - counter = counter2; - return needle; - } } else { if (counter >= start_from) { if (auto *simp = dynamic_cast(curr)) { @@ -636,10 +630,6 @@ namespace { } } - } else if (auto *obj = dynamic_cast(obj_)) { - unsigned counter2 = 0; - return objectFields(obj->root, counter2, obj->offset, manifesting); - } else if (auto *obj = dynamic_cast(obj_)) { counter++; if (counter <= skip) return r; @@ -742,8 +732,6 @@ namespace { { if (auto *ext = dynamic_cast(obj)) { return countLeaves(ext->left) + countLeaves(ext->right); - } else if (auto *super = dynamic_cast(obj)) { - return countLeaves(super->root); } else { return 1; } @@ -837,9 +825,6 @@ namespace { if (auto *ext = dynamic_cast(curr)) { objectInvariants(ext->right, self, counter, thunks); objectInvariants(ext->left, self, counter, thunks); - } else if (auto *super = dynamic_cast(curr)) { - unsigned counter2 = 0; - objectInvariants(super->root, super->root, counter2, thunks); } else { if (auto *simp = dynamic_cast(curr)) { for (AST *assert : simp->asserts) { @@ -860,11 +845,11 @@ namespace { * \param f The field */ const AST *objectIndex(const LocationRange &loc, HeapObject *obj, - const Identifier *f) + const Identifier *f, unsigned offset) { unsigned found_at = 0; HeapObject *self = nullptr; - HeapLeafObject *found = findObject(f, obj, obj, 0, found_at, self); + HeapLeafObject *found = findObject(f, obj, obj, offset, found_at, self); if (found == nullptr) { throw makeError(loc, "Field does not exist: " + encode_utf8(f->name)); } @@ -888,11 +873,7 @@ namespace { void runInvariants(const LocationRange &loc, HeapObject *self) { - HeapObject *self_marker = self; - while (auto *super = dynamic_cast(self_marker)) { - self_marker = super->root; - } - if (stack.alreadyExecutingInvariants(self_marker)) return; + if (stack.alreadyExecutingInvariants(self)) return; unsigned counter = 0; stack.newFrame(FRAME_INVARIANTS, loc); @@ -1078,16 +1059,11 @@ namespace { scratch.v.h = self; } break; - case AST_SUPER: { - HeapObject *self; - unsigned offset; - stack.getSelfBinding(self, offset); - offset++; - if (offset >= countLeaves(self)) { - throw makeError(ast_->location, - "Attempt to use super when there is no super class."); - } - scratch = makeObject(self, offset); + case AST_SUPER_INDEX: { + const auto &ast = *static_cast(ast_); + stack.newFrame(FRAME_SUPER_INDEX, ast_); + ast_ = ast.index; + goto recurse; } break; case AST_UNARY: { @@ -1850,6 +1826,30 @@ namespace { goto recurse; } break; + case FRAME_SUPER_INDEX: { + const auto &ast = *static_cast(f.ast); + HeapObject *self; + unsigned offset; + stack.getSelfBinding(self, offset); + offset++; + if (offset >= countLeaves(self)) { + throw makeError(ast.location, + "Attempt to use super when there is no super class."); + } + if (scratch.t != Value::STRING) { + throw makeError(ast.location, + "Super index must be string, got " + + type_str(scratch) + "."); + } + + const String &index_name = + static_cast(scratch.v.h)->value; + auto *fid = alloc->makeIdentifier(index_name); + stack.pop(); + ast_ = objectIndex(ast.location, self, fid, offset); + goto recurse; + } break; + case FRAME_INDEX_INDEX: { const auto &ast = *static_cast(f.ast); const Value &target = f.val; @@ -1889,7 +1889,7 @@ namespace { static_cast(scratch.v.h)->value; auto *fid = alloc->makeIdentifier(index_name); stack.pop(); - ast_ = objectIndex(ast.location, obj, fid); + ast_ = objectIndex(ast.location, obj, fid, 0); goto recurse; } else if (target.t == Value::STRING) { auto *obj = static_cast(target.v.h); @@ -1929,17 +1929,10 @@ namespace { f.kind = FRAME_INDEX_INDEX; if (scratch.t == Value::OBJECT) { auto *self = static_cast(scratch.v.h); - auto *self_marker = self; - // Strip supers off of self, they are not relevant for invariant - // checking and as they are not interned, they cause - // stack.alreadyExecutingInvariants to always fail. - while (auto *super = dynamic_cast(self_marker)) { - self_marker = super->root; - } - if (!stack.alreadyExecutingInvariants(self_marker)) { + if (!stack.alreadyExecutingInvariants(self)) { stack.newFrame(FRAME_INVARIANTS, ast.location); Frame &f2 = stack.top(); - f2.self = self_marker; + f2.self = self; unsigned counter = 0; objectInvariants(self, self, counter, f2.thunks); if (f2.thunks.size() > 0) { @@ -2211,7 +2204,7 @@ namespace { const char32_t *prefix = multiline ? U"{\n" : U"{"; for (const auto &f : fields) { // pushes FRAME_CALL - const AST *body = objectIndex(loc, obj, f.second); + const AST *body = objectIndex(loc, obj, f.second, 0); stack.top().val = scratch; evaluate(body, stack.size()); auto vstr = manifestJson(body->location, multiline, indent2); @@ -2265,7 +2258,7 @@ namespace { } for (const auto &f : fields) { // pushes FRAME_CALL - const AST *body = objectIndex(loc, obj, f.second); + const AST *body = objectIndex(loc, obj, f.second, 0); stack.top().val = scratch; evaluate(body, stack.size()); auto vstr = string ? manifestString(body->location) diff --git a/test_suite/error.static_error_super.jsonnet b/test_suite/error.static_error_super.jsonnet index c64b46feb..58a18c2ea 100644 --- a/test_suite/error.static_error_super.jsonnet +++ b/test_suite/error.static_error_super.jsonnet @@ -14,4 +14,4 @@ See the License for the specific language governing permissions and limitations under the License. */ -[super] +[super.f] diff --git a/test_suite/oop.jsonnet b/test_suite/oop.jsonnet index 6874671b4..e373a5780 100644 --- a/test_suite/oop.jsonnet +++ b/test_suite/oop.jsonnet @@ -58,8 +58,6 @@ local A = {name: "A" }, std.assertEqual((A+B) + (C+D), { name: "D", sB: "A", sC: "B", sD: "C" }) && -std.assertEqual((({z:3, y:super}+{x:super})).z, 3) && - // Outer variable local a = { d: 0, @@ -81,14 +79,6 @@ std.assertEqual(({x: 1, y: { a: $.x }} + {x: 2}).y.a, 2) && // DAG std.assertEqual({x: 1, y: 2} + (local A = { x: super.y, y: super.x }; A + A), {x: 1, y: 2}) && -// extending super -std.assertEqual(({x: 0, y: self.x} + {x: 1, y: super + {x : 2}}), {x: 1, y: {x: 2, y: 1} }) && -std.assertEqual(({x: 0, y: self.x} + {x: 1, y: super + {}}), {x: 1, y: {x: 0, y: 1} }) && - -// super edge cases -std.assertEqual(({x: 1, y: 1} + {y: 2}) + {s:super}, {x: 1, y: 2, s: {x: 1, y: 2}}) && -std.assertEqual({x: 1, y: 1} + ({y: 2} + {s:super}), {x: 1, y: 2, s: {x: 1, y: 2}}) && - // Object composition: inheritance std.assertEqual(local f = "x"; {x: 2} + {[f]: 1}, {x: 1}) && diff --git a/test_suite/oop_extra.jsonnet b/test_suite/oop_extra.jsonnet index 77058d788..aa51dd9b6 100644 --- a/test_suite/oop_extra.jsonnet +++ b/test_suite/oop_extra.jsonnet @@ -17,25 +17,6 @@ limitations under the License. // Simple super std.assertEqual(({ x : 0, y : self.x } + { x : 1, y : super.y }).y, 1) && -// returning super -std.assertEqual(({ x : 0, y : self.x } + { x : 1, y : super}).y.y, 1) && - -// extending super on the right -std.assertEqual(({ x : 0, y : self.x } + { x : 1, y : (super + {}).y }).y, 1) && -std.assertEqual(({ x : 0, y : self.x } + { x : 1, y : super + {} }).y.y, 1) && -std.assertEqual(({ x : 0, y : self.x } + { x : 1, y : (super + { x : 2 }).y }).y, 1) && -std.assertEqual(({ x : 0, y : self.x } + { x : 1, y : super + { x : 2 } }).y.y, 1) && - -std.assertEqual(({ x : 0, y : self.x } + { x : 1, y : (super + { x : super.y }).x }).y, 1) && -std.assertEqual(({ x : 0, y : self.x } + { x : 1, y : (super + { x : super.y }) }).y.x, 1) && - -std.assertEqual(({ x : 0, y : self.x } + { x : 1, y : (super + { x : self.y }).x }).y, 1) && -std.assertEqual(({ x : 0, y : self.x } + { x : 1, y : (super + { x : self.y }) }).y.x, 1) && - -// extending super on the left -std.assertEqual(({ x : 0, y : self.x } + { x : 1, y : ({} + super).y }).y, 1) && -std.assertEqual(({ x : 0, y : self.x } + { x : 1, y : {} + super }).y.y, 1) && - // returning self std.assertEqual(({ x : 0, y : self.x } + { x : 1, z : self }).z.y, 1) && @@ -43,7 +24,7 @@ std.assertEqual(({ x : 0, y : self.x } + { x : 1, z : self }).z.y, 1) && std.assertEqual(({ x : 0, y : self.x } + { x : 1, z : (self + {}).y }).z, 1) && std.assertEqual(({ x : 0, y : self.x } + { x : 1, z : (self + {}) }).z.y, 1) && -// extending self on the right has more dynamic binding than extending super on the right +// extending self on the right has dynamic binding std.assertEqual(({ x : 0, y : self.x } + { x : 2, z : (self + { x : 1 }).y }).z, 1) && std.assertEqual(({ x : 0, y : self.x } + { x : 2, z : (self + { x : 1 }) }).z.y, 1) &&