Skip to content

Commit

Permalink
super can now only be used in super.f or super[e]
Browse files Browse the repository at this point in the history
This commit already submitted as 9ade1be but got stuck in the
gh-pages branch for some reason
  • Loading branch information
sparkprime committed Oct 27, 2015
1 parent 73005cd commit 94ac375
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 105 deletions.
9 changes: 5 additions & 4 deletions core/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ enum ASTType {
AST_OBJECT_COMPREHENSION,
AST_OBJECT_COMPREHENSION_SIMPLE,
AST_SELF,
AST_SUPER,
AST_SUPER_INDEX,
AST_UNARY,
AST_VAR
};
Expand Down Expand Up @@ -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)
{ }
};

Expand Down
4 changes: 2 additions & 2 deletions core/desugaring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,8 @@ class Desugarer {
} 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<SuperIndex*>(ast_)) {
desugar(ast->index);

} else if (auto *ast = dynamic_cast<Unary*>(ast_)) {
desugar(ast->expr);
Expand Down
25 changes: 20 additions & 5 deletions core/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,8 @@ static std::string unparse(const AST *ast_)
} else if (dynamic_cast<const Self*>(ast_)) {
ss << "self";

} else if (dynamic_cast<const Super*>(ast_)) {
ss << "super";
} else if (auto *ast = dynamic_cast<const SuperIndex*>(ast_)) {
ss << "super[" << unparse(ast->index) << "]";

} else if (auto *ast = dynamic_cast<const Unary*>(ast_)) {
ss << uop_string(ast->op) << "(" << unparse(ast->expr) << ")";
Expand Down Expand Up @@ -616,7 +616,7 @@ namespace {
}
if (plus_sugar) {
AST *f = alloc->make<LiteralString>(plus_loc, next.data32());
AST *super_f = alloc->make<Index>(plus_loc, alloc->make<Super>(LocationRange()), f);
AST *super_f = alloc->make<SuperIndex>(plus_loc, f);
body = alloc->make<Binary>(body->location, super_f, BOP_PLUS, body);
}
fields.emplace_back(field_expr, field_hide, body);
Expand Down Expand Up @@ -832,8 +832,23 @@ namespace {
case Token::SELF:
return alloc->make<Self>(span(tok));

case Token::SUPER:
return alloc->make<Super>(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<LiteralString>(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<SuperIndex>(span(tok), index);
}
}

std::cerr << "INTERNAL ERROR: Unknown tok kind: " << tok.kind << std::endl;
Expand Down
16 changes: 0 additions & 16 deletions core/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -365,9 +352,6 @@ namespace {
addIfHeapEntity(upv.second, s.children);


} else if (auto *obj = dynamic_cast<HeapSuperObject*>(curr)) {
addIfHeapEntity(obj->root, s.children);

} else if (auto *arr = dynamic_cast<HeapArray*>(curr)) {
for (auto el : arr->elements)
addIfHeapEntity(el, s.children);
Expand Down
3 changes: 2 additions & 1 deletion core/static_analysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const Super*>(ast_)) {
} else if (auto *ast = dynamic_cast<const SuperIndex*>(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<const Unary*>(ast_)) {
append(r, static_analysis(ast->expr, in_object, vars));
Expand Down
85 changes: 39 additions & 46 deletions core/vm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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<HeapSuperObject*>(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<HeapSimpleObject*>(curr)) {
Expand Down Expand Up @@ -636,10 +630,6 @@ namespace {
}
}

} else if (auto *obj = dynamic_cast<const HeapSuperObject*>(obj_)) {
unsigned counter2 = 0;
return objectFields(obj->root, counter2, obj->offset, manifesting);

} else if (auto *obj = dynamic_cast<const HeapComprehensionObject*>(obj_)) {
counter++;
if (counter <= skip) return r;
Expand Down Expand Up @@ -742,8 +732,6 @@ namespace {
{
if (auto *ext = dynamic_cast<HeapExtendedObject*>(obj)) {
return countLeaves(ext->left) + countLeaves(ext->right);
} else if (auto *super = dynamic_cast<HeapSuperObject*>(obj)) {
return countLeaves(super->root);
} else {
return 1;
}
Expand Down Expand Up @@ -837,9 +825,6 @@ namespace {
if (auto *ext = dynamic_cast<HeapExtendedObject*>(curr)) {
objectInvariants(ext->right, self, counter, thunks);
objectInvariants(ext->left, self, counter, thunks);
} else if (auto *super = dynamic_cast<HeapSuperObject*>(curr)) {
unsigned counter2 = 0;
objectInvariants(super->root, super->root, counter2, thunks);
} else {
if (auto *simp = dynamic_cast<HeapSimpleObject*>(curr)) {
for (AST *assert : simp->asserts) {
Expand All @@ -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));
}
Expand All @@ -888,11 +873,7 @@ namespace {

void runInvariants(const LocationRange &loc, HeapObject *self)
{
HeapObject *self_marker = self;
while (auto *super = dynamic_cast<HeapSuperObject*>(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);
Expand Down Expand Up @@ -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<HeapSuperObject>(self, offset);
case AST_SUPER_INDEX: {
const auto &ast = *static_cast<const SuperIndex*>(ast_);
stack.newFrame(FRAME_SUPER_INDEX, ast_);
ast_ = ast.index;
goto recurse;
} break;

case AST_UNARY: {
Expand Down Expand Up @@ -1850,6 +1826,30 @@ namespace {
goto recurse;
} break;

case FRAME_SUPER_INDEX: {
const auto &ast = *static_cast<const SuperIndex*>(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<HeapString*>(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<const Index*>(f.ast);
const Value &target = f.val;
Expand Down Expand Up @@ -1889,7 +1889,7 @@ namespace {
static_cast<HeapString*>(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<HeapString*>(target.v.h);
Expand Down Expand Up @@ -1929,17 +1929,10 @@ namespace {
f.kind = FRAME_INDEX_INDEX;
if (scratch.t == Value::OBJECT) {
auto *self = static_cast<HeapObject*>(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<HeapSuperObject*>(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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion test_suite/error.static_error_super.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

[super]
[super.f]
10 changes: 0 additions & 10 deletions test_suite/oop.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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}) &&
Expand Down
21 changes: 1 addition & 20 deletions test_suite/oop_extra.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,14 @@ 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) &&

// extending self on the right
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) &&

Expand Down

0 comments on commit 94ac375

Please sign in to comment.