Skip to content

Commit 4309510

Browse files
andreabergia0xe
andcommitted
Allow super in eval
Co-authored-by: Satish Srinivasan <satish.srinivasan@servicenow.com>
1 parent f82d9aa commit 4309510

File tree

8 files changed

+192
-18
lines changed

8 files changed

+192
-18
lines changed

rhino/src/main/java/org/mozilla/javascript/CompilerEnvirons.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,15 @@ public boolean getAllowSharpComments() {
221221
return allowSharpComments;
222222
}
223223

224+
/** Allows usage of "super" everywhere, simulating that we are inside a method. */
225+
public void setAllowSuper(boolean allowSuper) {
226+
this.allowSuper = allowSuper;
227+
}
228+
229+
public boolean isAllowSuper() {
230+
return allowSuper;
231+
}
232+
224233
/**
225234
* Returns a {@code CompilerEnvirons} suitable for using Rhino in an IDE environment. Most
226235
* features are enabled by default. The {@link ErrorReporter} is set to an {@link
@@ -257,5 +266,6 @@ public static CompilerEnvirons ideEnvirons() {
257266
private boolean warnTrailingComma;
258267
private boolean ideMode;
259268
private boolean allowSharpComments;
269+
private boolean allowSuper;
260270
Set<String> activationNames;
261271
}

rhino/src/main/java/org/mozilla/javascript/Context.java

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.util.Optional;
2929
import java.util.Set;
3030
import java.util.TimeZone;
31+
import java.util.function.Consumer;
3132
import java.util.function.UnaryOperator;
3233
import org.mozilla.classfile.ClassFileWriter.ClassFileFormatException;
3334
import org.mozilla.javascript.ast.AstRoot;
@@ -1367,6 +1368,16 @@ public final Script compileReader(
13671368
*/
13681369
public final Script compileReader(
13691370
Reader in, String sourceName, int lineno, Object securityDomain) throws IOException {
1371+
return compileReader(in, sourceName, lineno, securityDomain, null);
1372+
}
1373+
1374+
public Script compileReader(
1375+
Reader in,
1376+
String sourceName,
1377+
int lineno,
1378+
Object securityDomain,
1379+
Consumer<CompilerEnvirons> compilerEnvironsProcessor)
1380+
throws IOException {
13701381
if (lineno < 0) {
13711382
// For compatibility IllegalArgumentException can not be thrown here
13721383
lineno = 0;
@@ -1381,7 +1392,8 @@ public final Script compileReader(
13811392
securityDomain,
13821393
false,
13831394
null,
1384-
null);
1395+
null,
1396+
compilerEnvironsProcessor);
13851397
}
13861398

13871399
/**
@@ -1405,7 +1417,7 @@ public final Script compileString(
14051417
// For compatibility IllegalArgumentException can not be thrown here
14061418
lineno = 0;
14071419
}
1408-
return compileString(source, null, null, sourceName, lineno, securityDomain);
1420+
return compileString(source, null, null, sourceName, lineno, securityDomain, null);
14091421
}
14101422

14111423
final Script compileString(
@@ -1414,7 +1426,8 @@ final Script compileString(
14141426
ErrorReporter compilationErrorReporter,
14151427
String sourceName,
14161428
int lineno,
1417-
Object securityDomain) {
1429+
Object securityDomain,
1430+
Consumer<CompilerEnvirons> compilerEnvironsProcessor) {
14181431
return (Script)
14191432
compileImpl(
14201433
null,
@@ -1424,7 +1437,8 @@ final Script compileString(
14241437
securityDomain,
14251438
false,
14261439
compiler,
1427-
compilationErrorReporter);
1440+
compilationErrorReporter,
1441+
compilerEnvironsProcessor);
14281442
}
14291443

14301444
/**
@@ -1465,7 +1479,8 @@ final Function compileFunction(
14651479
securityDomain,
14661480
true,
14671481
compiler,
1468-
compilationErrorReporter);
1482+
compilationErrorReporter,
1483+
null);
14691484
}
14701485

14711486
/**
@@ -2424,7 +2439,8 @@ protected Object compileImpl(
24242439
Object securityDomain,
24252440
boolean returnFunction,
24262441
Evaluator compiler,
2427-
ErrorReporter compilationErrorReporter) {
2442+
ErrorReporter compilationErrorReporter,
2443+
Consumer<CompilerEnvirons> compilerEnvironProcessor) {
24282444
if (sourceName == null) {
24292445
sourceName = "unnamed script";
24302446
}
@@ -2441,6 +2457,9 @@ protected Object compileImpl(
24412457
if (compilationErrorReporter == null) {
24422458
compilationErrorReporter = compilerEnv.getErrorReporter();
24432459
}
2460+
if (compilerEnvironProcessor != null) {
2461+
compilerEnvironProcessor.accept(compilerEnv);
2462+
}
24442463

24452464
ScriptNode tree =
24462465
parse(

rhino/src/main/java/org/mozilla/javascript/IRFactory.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -889,9 +889,9 @@ private Node transformLetNode(LetNode node) {
889889

890890
private Node transformLiteral(AstNode node) {
891891
// Trying to call super as a function. See 15.4.2 Static Semantics: HasDirectSuper
892-
if (node.getParent() instanceof FunctionCall
893-
&& node.getType() == Token.SUPER
894-
&& parser.currentScriptOrFn.isMethodDefinition())
892+
// Note that this will need to change when classes are implemented, because in a class
893+
// constructor calling "super()" _is_ allowed.
894+
if (node.getParent() instanceof FunctionCall && node.getType() == Token.SUPER)
895895
parser.reportError("msg.super.shorthand.function");
896896
return node;
897897
}

rhino/src/main/java/org/mozilla/javascript/NativeScript.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ private static Script compile(Context cx, String source) {
162162
}
163163
ErrorReporter reporter;
164164
reporter = DefaultErrorReporter.forEval(cx.getErrorReporter());
165-
return cx.compileString(source, null, reporter, filename, linep[0], null);
165+
return cx.compileString(source, null, reporter, filename, linep[0], null, null);
166166
}
167167

168168
@Override

rhino/src/main/java/org/mozilla/javascript/Parser.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3390,7 +3390,7 @@ private AstNode primaryExpr() throws IOException {
33903390
}
33913391

33923392
case Token.SUPER:
3393-
if (insideFunction() && insideMethod) {
3393+
if ((insideFunction() && insideMethod) || compilerEnv.isAllowSuper()) {
33943394
consumeToken();
33953395
pos = ts.tokenBeg;
33963396
end = ts.tokenEnd;

rhino/src/main/java/org/mozilla/javascript/ScriptRuntime.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.util.Optional;
1919
import java.util.ResourceBundle;
2020
import java.util.function.BiConsumer;
21+
import java.util.function.Consumer;
2122
import org.mozilla.javascript.ast.FunctionNode;
2223
import org.mozilla.javascript.v8dtoa.DoubleConversion;
2324
import org.mozilla.javascript.v8dtoa.FastDtoa;
@@ -3229,7 +3230,25 @@ public static Object evalSpecial(
32293230

32303231
// Compile with explicit interpreter instance to force interpreter
32313232
// mode.
3232-
Script script = cx.compileString(x.toString(), evaluator, reporter, sourceName, 1, null);
3233+
Consumer<CompilerEnvirons> compilerEnvironsProcessor =
3234+
compilerEnvs -> {
3235+
// If we are inside a method, we need to allow super. Methods have the home
3236+
// object set and propagated via the activation (i.e. the NativeCall),
3237+
// but non-methods will have the home object set to null.
3238+
boolean isInsideMethod =
3239+
scope instanceof NativeCall
3240+
&& ((NativeCall) scope).getHomeObject() != null;
3241+
compilerEnvs.setAllowSuper(isInsideMethod);
3242+
};
3243+
Script script =
3244+
cx.compileString(
3245+
x.toString(),
3246+
evaluator,
3247+
reporter,
3248+
sourceName,
3249+
1,
3250+
null,
3251+
compilerEnvironsProcessor);
32333252
evaluator.setEvalScriptFlag(script);
32343253
Callable c = (Callable) script;
32353254
Scriptable thisObject =

rhino/src/test/java/org/mozilla/javascript/SuperTest.java

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ void superIsAKeywordInES6AndCannotBeUsedAsVariableName() {
2929
}
3030

3131
@Test
32-
void isSyntaxErrorIfHasDirectSuperOfMethodDefinitionIsTrue() {
32+
void isSyntaxErrorIfHasSuperCall() {
3333
assertIsSyntaxErrorES6(
3434
"({ method() { super(); }});",
3535
"super should be inside a shorthand function (test#1)");
@@ -63,6 +63,13 @@ void superCannotHaveOptionalPropertyAccess() {
6363
"super is not allowed in an optional chaining expression (test#1)");
6464
}
6565

66+
@Test
67+
void superNestedInAFunctionInsideAMethodIsNotAllowed() {
68+
assertIsSyntaxErrorES6(
69+
"var o = { f() {\n" + " (function() { super.x; })() \n" + "} }",
70+
"super should be inside a shorthand function (test#2)");
71+
}
72+
6673
private void assertIsSyntaxErrorES6(String source, String expected) {
6774
try (Context cx = Context.enter()) {
6875
cx.setLanguageVersion(Context.VERSION_ES6);
@@ -942,4 +949,126 @@ void doublyNestedLambdaCaptureSuper() {
942949
Utils.assertWithAllOptimizationLevelsES6("object", script);
943950
}
944951
}
952+
953+
@Nested
954+
class Eval {
955+
@Test
956+
void evalInsideMethodCanAccessSuper() {
957+
String script =
958+
""
959+
+ "var proto = {\n"
960+
+ " x: 'proto'\n"
961+
+ "};\n"
962+
+ "var object = {\n"
963+
+ " x: 'object',\n"
964+
+ " f() {\n"
965+
+ " return eval('super.x');\n"
966+
+ " }\n"
967+
+ "};\n"
968+
+ "Object.setPrototypeOf(object, proto);\n"
969+
+ "object.f();";
970+
Utils.assertWithAllOptimizationLevelsES6("proto", script);
971+
}
972+
973+
@Test
974+
void evalFromLambdaInMethodCanAccessSuper() {
975+
String script =
976+
""
977+
+ "var proto = {\n"
978+
+ " x: 'proto'\n"
979+
+ "};\n"
980+
+ "var object = {\n"
981+
+ " x: 'object',\n"
982+
+ " f() {\n"
983+
+ " return () => eval('super.x');\n"
984+
+ " }\n"
985+
+ "};\n"
986+
+ "Object.setPrototypeOf(object, proto);\n"
987+
+ "object.f()();";
988+
Utils.assertWithAllOptimizationLevelsES6("proto", script);
989+
}
990+
991+
@Test
992+
void superCannotBeUsedAsMethodInEval() {
993+
String script =
994+
""
995+
+ "o = {\n"
996+
+ " f() {\n"
997+
+ " eval('super(42)')"
998+
+ " }\n"
999+
+ "};"
1000+
+ "o.f();";
1001+
Utils.runWithAllOptimizationLevels(
1002+
cx -> {
1003+
cx.setLanguageVersion(Context.VERSION_ES6);
1004+
EcmaError error =
1005+
assertThrows(
1006+
EcmaError.class,
1007+
() ->
1008+
cx.evaluateString(
1009+
cx.initStandardObjects(),
1010+
script,
1011+
"test",
1012+
1,
1013+
null));
1014+
assertEquals(
1015+
"SyntaxError: super should be inside a shorthand function (test#3(eval)#1)",
1016+
error.getMessage());
1017+
return null;
1018+
});
1019+
}
1020+
1021+
@Test
1022+
void evalOutsideMethodCannotAccessSuper() {
1023+
String script = "eval('super.x')";
1024+
Utils.runWithAllOptimizationLevels(
1025+
cx -> {
1026+
cx.setLanguageVersion(Context.VERSION_ES6);
1027+
EcmaError error =
1028+
assertThrows(
1029+
EcmaError.class,
1030+
() ->
1031+
cx.evaluateString(
1032+
cx.initStandardObjects(),
1033+
script,
1034+
"test",
1035+
1,
1036+
null));
1037+
assertEquals(
1038+
"SyntaxError: super should be inside a shorthand function (test#1(eval)#1)",
1039+
error.getMessage());
1040+
return null;
1041+
});
1042+
}
1043+
1044+
@Test
1045+
void evalInFunctionInsideMethodDoesNotAllowSuper() {
1046+
String script =
1047+
""
1048+
+ "o = {\n"
1049+
+ " f() {\n"
1050+
+ " (function() { eval('super(42)') })();"
1051+
+ " }\n"
1052+
+ "};"
1053+
+ "o.f();";
1054+
Utils.runWithAllOptimizationLevels(
1055+
cx -> {
1056+
cx.setLanguageVersion(Context.VERSION_ES6);
1057+
EcmaError error =
1058+
assertThrows(
1059+
EcmaError.class,
1060+
() ->
1061+
cx.evaluateString(
1062+
cx.initStandardObjects(),
1063+
script,
1064+
"test",
1065+
1,
1066+
null));
1067+
assertEquals(
1068+
"SyntaxError: super should be inside a shorthand function (test#3(eval)#1)",
1069+
error.getMessage());
1070+
return null;
1071+
});
1072+
}
1073+
}
9451074
}

tests/testsrc/test262.properties

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3552,7 +3552,7 @@ language/directive-prologue 18/62 (29.03%)
35523552
14.1-9-s.js {non-strict: [-1]}
35533553
func-decl-inside-func-decl-parse.js non-strict
35543554

3555-
language/eval-code 242/347 (69.74%)
3555+
language/eval-code 241/347 (69.45%)
35563556
direct/arrow-fn-a-following-parameter-is-named-arguments-arrow-func-declare-arguments-assign.js non-strict
35573557
direct/arrow-fn-a-following-parameter-is-named-arguments-arrow-func-declare-arguments-assign-incl-def-param-arrow-arguments.js non-strict
35583558
direct/arrow-fn-a-preceding-parameter-is-named-arguments-arrow-func-declare-arguments-assign.js non-strict
@@ -3756,7 +3756,6 @@ language/eval-code 242/347 (69.74%)
37563756
direct/new.target-arrow.js {unsupported: [new.target]}
37573757
direct/new.target-fn.js {unsupported: [new.target]}
37583758
direct/non-definable-global-var.js non-strict
3759-
direct/super-prop-method.js
37603759
direct/switch-case-decl-eval-source-is-strict-nostrict.js non-strict
37613760
direct/switch-case-decl-eval-source-is-strict-onlystrict.js strict
37623761
direct/switch-case-decl-onlystrict.js strict
@@ -5820,7 +5819,7 @@ language/expressions/strict-equals 0/30 (0.0%)
58205819
language/expressions/subtraction 1/38 (2.63%)
58215820
order-of-evaluation.js
58225821

5823-
language/expressions/super 70/86 (81.4%)
5822+
language/expressions/super 68/86 (79.07%)
58245823
call-arg-evaluation-err.js {unsupported: [class]}
58255824
call-bind-this-value.js {unsupported: [class]}
58265825
call-bind-this-value-twice.js {unsupported: [class]}
@@ -5877,7 +5876,6 @@ language/expressions/super 70/86 (81.4%)
58775876
prop-dot-cls-val.js {unsupported: [class]}
58785877
prop-dot-cls-val-from-arrow.js {unsupported: [class]}
58795878
prop-dot-cls-val-from-eval.js {unsupported: [class]}
5880-
prop-dot-obj-val-from-eval.js
58815879
prop-expr-cls-err.js {unsupported: [class]}
58825880
prop-expr-cls-key-err.js {unsupported: [class]}
58835881
prop-expr-cls-null-proto.js {unsupported: [class]}
@@ -5888,7 +5886,6 @@ language/expressions/super 70/86 (81.4%)
58885886
prop-expr-cls-val.js {unsupported: [class]}
58895887
prop-expr-cls-val-from-arrow.js {unsupported: [class]}
58905888
prop-expr-cls-val-from-eval.js {unsupported: [class]}
5891-
prop-expr-obj-val-from-eval.js
58925889
realm.js {unsupported: [Reflect]}
58935890
super-reference-resolution.js {unsupported: [class]}
58945891

0 commit comments

Comments
 (0)