Skip to content

Commit cac786f

Browse files
author
John Messerly
committed
fixes #173, ability to use native JS indexers
dom_experimental could opt-in to use this [email protected] Review URL: https://codereview.chromium.org/1145833004
1 parent 89b3d92 commit cac786f

File tree

8 files changed

+88
-27
lines changed

8 files changed

+88
-27
lines changed

pkg/dev_compiler/lib/src/codegen/js_codegen.dart

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
109109
if (unit.directives.isNotEmpty) {
110110
var libraryDir = unit.directives.first;
111111
if (libraryDir is LibraryDirective) {
112-
var jsName = getAnnotationValue(libraryDir, _isJsNameAnnotation);
112+
var jsName = findAnnotation(libraryDir.element, _isJsNameAnnotation);
113113
jsDefaultValue = getConstantField(jsName, 'name', types.stringType);
114114
}
115115
}
@@ -328,7 +328,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
328328
// If we've already emitted this class, skip it.
329329
var classElem = node.element;
330330
var type = classElem.type;
331-
var jsName = getAnnotationValue(node, _isJsNameAnnotation);
331+
var jsName = findAnnotation(classElem, _isJsNameAnnotation);
332332

333333
if (jsName != null) return _emitJsType(node.name.name, jsName);
334334

@@ -349,7 +349,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
349349
_classHeritage(classElem), _emitClassMethods(node, ctors, fields));
350350

351351
String jsPeerName;
352-
var jsPeer = getAnnotationValue(node, _isJsPeerInterface);
352+
var jsPeer = findAnnotation(classElem, _isJsPeerInterface);
353353
if (jsPeer != null) {
354354
jsPeerName = getConstantField(jsPeer, 'name', types.stringType);
355355
}
@@ -474,7 +474,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
474474
jsMethods.add(_emitImplicitConstructor(node, fields));
475475
}
476476

477-
bool hasJsPeer = getAnnotationValue(node, _isJsPeerInterface) != null;
477+
bool hasJsPeer = findAnnotation(element, _isJsPeerInterface) != null;
478478

479479
bool hasIterator = false;
480480
for (var m in node.members) {
@@ -1404,7 +1404,12 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
14041404

14051405
JS.Expression _emitSet(Expression lhs, Expression rhs) {
14061406
if (lhs is IndexExpression) {
1407-
return _emitSend(_getTarget(lhs), '[]=', [lhs.index, rhs]);
1407+
var target = _getTarget(lhs);
1408+
if (_useNativeJsIndexer(target.staticType)) {
1409+
return js.call(
1410+
'#[#] = #', [_visit(target), _visit(lhs.index), _visit(rhs)]);
1411+
}
1412+
return _emitSend(target, '[]=', [lhs.index, rhs]);
14081413
}
14091414

14101415
Expression target = null;
@@ -2195,9 +2200,18 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
21952200

21962201
@override
21972202
visitIndexExpression(IndexExpression node) {
2198-
return _emitSend(_getTarget(node), '[]', [node.index]);
2203+
var target = _getTarget(node);
2204+
if (_useNativeJsIndexer(target.staticType)) {
2205+
return new JS.PropertyAccess(_visit(target), _visit(node.index));
2206+
}
2207+
return _emitSend(target, '[]', [node.index]);
21992208
}
22002209

2210+
// TODO(jmesserly): ideally we'd check the method and see if it is marked
2211+
// `external`, but that doesn't work because it isn't in the element model.
2212+
bool _useNativeJsIndexer(DartType type) =>
2213+
findAnnotation(type.element, _isJsNameAnnotation) != null;
2214+
22012215
/// Gets the target of a [PropertyAccess] or [IndexExpression].
22022216
/// Those two nodes are special because they're both allowed on left side of
22032217
/// an assignment expression and cascades.

pkg/dev_compiler/lib/src/utils.dart

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -357,13 +357,10 @@ String resourceOutputPath(Uri resourceUri, Uri entryUri) {
357357
///
358358
/// (v) => v.type.name == 'Deprecated' && v.type.element.library.isDartCore
359359
///
360-
DartObjectImpl getAnnotationValue(
361-
AnnotatedNode node, bool test(DartObjectImpl value)) {
362-
for (var metadata in node.metadata) {
363-
ElementAnnotationImpl element = metadata.elementAnnotation;
364-
if (element == null) continue;
365-
366-
var evalResult = element.evaluationResult;
360+
DartObjectImpl findAnnotation(
361+
Element element, bool test(DartObjectImpl value)) {
362+
for (var metadata in element.metadata) {
363+
var evalResult = metadata.evaluationResult;
367364
if (evalResult == null) continue;
368365

369366
var value = evalResult.value;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
library domtest;
6+
7+
import 'sunflower/dom.dart';
8+
9+
// https://github.com/dart-lang/dev_compiler/issues/173
10+
testNativeIndexers() {
11+
var nodes = document.querySelector('body').childNodes;
12+
for (int i = 0; i < nodes.length; i++) {
13+
var old = nodes[i];
14+
nodes[i] = document.createElement('div');
15+
print(nodes[i] == old);
16+
}
17+
}

pkg/dev_compiler/test/codegen/expect/DeltaBlue.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ var core = dart.import(core);
3434
return dart.notNull(s1.value) > dart.notNull(s2.value);
3535
}
3636
static weakest(s1, s2) {
37-
return Strength.weaker(s1, s2) ? s1 : s2;
37+
return dart.notNull(Strength.weaker(s1, s2)) ? s1 : s2;
3838
}
3939
static strongest(s1, s2) {
40-
return Strength.stronger(s1, s2) ? s1 : s2;
40+
return dart.notNull(Strength.stronger(s1, s2)) ? s1 : s2;
4141
}
4242
}
4343
dart.setSignature(Strength, {
@@ -86,7 +86,7 @@ var core = dart.import(core);
8686
return overridden;
8787
}
8888
destroyConstraint() {
89-
if (this.isSatisfied())
89+
if (dart.notNull(this.isSatisfied()))
9090
exports.planner.incrementalRemove(this);
9191
this.removeFromGraph();
9292
}
@@ -127,7 +127,7 @@ var core = dart.import(core);
127127
recalculate() {
128128
this.myOutput.walkStrength = this.strength;
129129
this.myOutput.stay = !dart.notNull(this.isInput());
130-
if (this.myOutput.stay)
130+
if (dart.notNull(this.myOutput.stay))
131131
this.execute();
132132
}
133133
markUnsatisfied() {
@@ -197,10 +197,10 @@ var core = dart.import(core);
197197
if (this.v2.mark == mark) {
198198
this.direction = this.v1.mark != mark && dart.notNull(Strength.stronger(this.strength, this.v1.walkStrength)) ? BACKWARD : NONE;
199199
}
200-
if (Strength.weaker(this.v1.walkStrength, this.v2.walkStrength)) {
201-
this.direction = Strength.stronger(this.strength, this.v1.walkStrength) ? BACKWARD : NONE;
200+
if (dart.notNull(Strength.weaker(this.v1.walkStrength, this.v2.walkStrength))) {
201+
this.direction = dart.notNull(Strength.stronger(this.strength, this.v1.walkStrength)) ? BACKWARD : NONE;
202202
} else {
203-
this.direction = Strength.stronger(this.strength, this.v2.walkStrength) ? FORWARD : BACKWARD;
203+
this.direction = dart.notNull(Strength.stronger(this.strength, this.v2.walkStrength)) ? FORWARD : BACKWARD;
204204
}
205205
}
206206
addToGraph() {
@@ -224,15 +224,15 @@ var core = dart.import(core);
224224
let ihn = this.input(), out = this.output();
225225
out.walkStrength = Strength.weakest(this.strength, ihn.walkStrength);
226226
out.stay = ihn.stay;
227-
if (out.stay)
227+
if (dart.notNull(out.stay))
228228
this.execute();
229229
}
230230
markUnsatisfied() {
231231
this.direction = NONE;
232232
}
233233
inputsKnown(mark) {
234234
let i = this.input();
235-
return i.mark == mark || dart.notNull(i.stay) || dart.notNull(i.determinedBy == null);
235+
return i.mark == mark || dart.notNull(i.stay) || i.determinedBy == null;
236236
}
237237
removeFromGraph() {
238238
if (this.v1 != null)
@@ -290,7 +290,7 @@ var core = dart.import(core);
290290
let ihn = this.input(), out = this.output();
291291
out.walkStrength = Strength.weakest(this.strength, ihn.walkStrength);
292292
out.stay = dart.notNull(ihn.stay) && dart.notNull(this.scale.stay) && dart.notNull(this.offset.stay);
293-
if (out.stay)
293+
if (dart.notNull(out.stay))
294294
this.execute();
295295
}
296296
}
@@ -415,7 +415,7 @@ var core = dart.import(core);
415415
let determining = v.determinedBy;
416416
for (let i = 0; dart.notNull(i) < dart.notNull(v.constraints.length); i = dart.notNull(i) + 1) {
417417
let next = v.constraints[dartx.get](i);
418-
if (dart.notNull(!dart.equals(next, determining)) && dart.notNull(next.isSatisfied())) {
418+
if (!dart.equals(next, determining) && dart.notNull(next.isSatisfied())) {
419419
next.recalculate();
420420
todo[dartx.add](next.output());
421421
}
@@ -427,7 +427,7 @@ var core = dart.import(core);
427427
let determining = v.determinedBy;
428428
for (let i = 0; dart.notNull(i) < dart.notNull(v.constraints.length); i = dart.notNull(i) + 1) {
429429
let c = v.constraints[dartx.get](i);
430-
if (dart.notNull(!dart.equals(c, determining)) && dart.notNull(c.isSatisfied()))
430+
if (!dart.equals(c, determining) && dart.notNull(c.isSatisfied()))
431431
coll[dartx.add](c);
432432
}
433433
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
var domtest = dart.defineLibrary(domtest, {});
2+
var dom = dart.import(dom);
3+
var core = dart.import(core);
4+
(function(exports, dom, core) {
5+
'use strict';
6+
function testNativeIndexers() {
7+
let nodes = dom.document.querySelector('body').childNodes;
8+
for (let i = 0; dart.notNull(i) < dart.notNull(nodes.length); i = dart.notNull(i) + 1) {
9+
let old = nodes[i];
10+
nodes[i] = dom.document.createElement('div');
11+
core.print(dart.equals(nodes[i], old));
12+
}
13+
}
14+
dart.fn(testNativeIndexers);
15+
// Exports:
16+
exports.testNativeIndexers = testNativeIndexers;
17+
})(domtest, dom, core);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// Messages from compiling domtest.dart

pkg/dev_compiler/test/codegen/expect/sunflower/dom.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ var core = dart.import(core);
2020
});
2121
let overload = dart.const(new Overload());
2222
let EventListener = dart.typedef('EventListener', () => dart.functionType(dart.void, [Event]));
23-
class Event extends core.Object {}
2423
let InputElement = HTMLInputElement;
2524
let CanvasElement = HTMLCanvasElement;
2625
class RenderingContext extends core.Object {}
@@ -42,7 +41,6 @@ var core = dart.import(core);
4241
exports.Overload = Overload;
4342
exports.overload = overload;
4443
exports.EventListener = EventListener;
45-
exports.Event = Event;
4644
exports.InputElement = InputElement;
4745
exports.CanvasElement = CanvasElement;
4846
exports.RenderingContext = RenderingContext;

pkg/dev_compiler/test/codegen/sunflower/dom.dart

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,34 @@ external Document get document;
2323

2424
@JsName(name: 'Document')
2525
abstract class Document {
26+
Element createElement(String name);
2627
Element querySelector(String selector);
2728
}
2829

2930
@JsName(name: 'Element')
3031
abstract class Element {
3132
void addEventListener(String type, EventListener callback, [bool capture]);
3233
String textContent;
34+
NodeList get childNodes;
35+
}
36+
37+
@JsName()
38+
class Node {}
39+
40+
@JsName()
41+
class NodeList {
42+
external NodeList();
43+
external num get length;
44+
external set length(num _);
45+
external Node item(num index);
46+
47+
external Node operator [](num index);
48+
external void operator []=(num index, Node);
3349
}
3450

3551
typedef void EventListener(Event e);
3652

53+
@JsName()
3754
abstract class Event {}
3855

3956
@JsName(name: 'HTMLInputElement')

0 commit comments

Comments
 (0)