Skip to content

Commit

Permalink
FEAT: Support default parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
0xe committed Sep 21, 2024
1 parent caa1efb commit 9ca1469
Show file tree
Hide file tree
Showing 19 changed files with 1,562 additions and 1,073 deletions.
6 changes: 6 additions & 0 deletions rhino/src/main/java/org/mozilla/javascript/Arguments.java
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ private boolean sharedWithActivation(int index) {
return false;
}
NativeFunction f = activation.function;

// Check if default arguments are present
if (f == null || f.hasDefaultParameters()) {
return false;
}

int definedCount = f.getParamCount();
if (index < definedCount) {
// Check if argument is not hidden by later argument with the same
Expand Down
5 changes: 5 additions & 0 deletions rhino/src/main/java/org/mozilla/javascript/BaseFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ protected boolean isGeneratorFunction() {
return isGeneratorFunction;
}

// Generated code will override this
protected boolean hasDefaultParameters() {
return false;
}

/**
* Gets the value returned by calling the typeof operator on this object.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ private void generateICodeFromTree(Node tree) {
itsData.argIsConst = scriptOrFn.getParamAndVarConst();
itsData.argCount = scriptOrFn.getParamCount();
itsData.argsHasRest = scriptOrFn.hasRestParameter();
itsData.argsHasDefaults = scriptOrFn.getDefaultParams() != null;

itsData.rawSourceStart = scriptOrFn.getRawSourceStart();
itsData.rawSourceEnd = scriptOrFn.getRawSourceEnd();
Expand Down
67 changes: 44 additions & 23 deletions rhino/src/main/java/org/mozilla/javascript/IRFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,44 @@ private Node transformFunction(FunctionNode fn) {
++parser.nestingOfFunction; // only for body, not params
Node body = transform(fn.getBody());

/* Process simple default parameters */
List<Object> defaultParams = fn.getDefaultParams();
if (defaultParams != null) {
for (int i = defaultParams.size() - 1; i > 0; ) {
if (defaultParams.get(i) instanceof AstNode
&& defaultParams.get(i - 1) instanceof String) {
AstNode rhs = (AstNode) defaultParams.get(i);
String name = (String) defaultParams.get(i - 1);
body.addChildToFront(
createIf(
createBinary(
Token.SHEQ,
parser.createName(name),
parser.createName("undefined")),
new Node(
Token.EXPR_VOID,
createAssignment(
Token.ASSIGN,
parser.createName(name),
transform(rhs)),
body.getLineno()),
null,
body.getLineno()));
}
i -= 2;
}
}

/* transform nodes used as default parameters */
List<Node[]> dfns = fn.getDestructuringRvalues();
if (dfns != null) {
for (var i : dfns) {
Node a = i[0];
AstNode b = (AstNode) i[1];
a.replaceChild(b, transform(b));
}
}

if (destructuring != null) {
body.addChildToFront(new Node(Token.EXPR_VOID, destructuring, lineno));
}
Expand Down Expand Up @@ -859,7 +897,7 @@ private Node transformObjectLiteral(ObjectLiteral node) {
int size = elems.size(), i = 0;
properties = new Object[size];
for (ObjectProperty prop : elems) {
Object propKey = getPropKey(prop.getLeft());
Object propKey = Parser.getPropKey(prop.getLeft());
if (propKey == null) {
Node theId = transform(prop.getLeft());
properties[i++] = theId;
Expand All @@ -882,23 +920,6 @@ private Node transformObjectLiteral(ObjectLiteral node) {
return object;
}

private Object getPropKey(Node id) {
Object key;
if (id instanceof Name) {
String s = ((Name) id).getIdentifier();
key = ScriptRuntime.getIndexObject(s);
} else if (id instanceof StringLiteral) {
String s = ((StringLiteral) id).getValue();
key = ScriptRuntime.getIndexObject(s);
} else if (id instanceof NumberLiteral) {
double n = ((NumberLiteral) id).getNumber();
key = ScriptRuntime.getIndexObject(n);
} else {
key = null; // Filled later
}
return key;
}

private Node transformParenExpr(ParenthesizedExpression node) {
AstNode expr = node.getExpression();
while (expr instanceof ParenthesizedExpression) {
Expand Down Expand Up @@ -1133,7 +1154,9 @@ private Node transformVariableInitializers(VariableDeclaration node) {
} else {
astNodePos.push(var);
try {
Node d = parser.createDestructuringAssignment(node.getType(), left, right);
Node d =
parser.createDestructuringAssignment(
node.getType(), left, right, this::transform);
node.addChildToBack(d);
} finally {
astNodePos.pop();
Expand Down Expand Up @@ -1501,8 +1524,7 @@ private Node createForIn(
Node assign;
if (destructuring != -1) {
assign =
parser.createDestructuringAssignment(
declType, lvalue, id, (AstNode node) -> transform(node));
parser.createDestructuringAssignment(declType, lvalue, id, this::transform);
if (!isForEach
&& !isForOf
&& (destructuring == Token.OBJECTLIT || destructuringLen != 2)) {
Expand Down Expand Up @@ -2079,8 +2101,7 @@ private Node createAssignment(int assignType, Node left, Node right) {
parser.reportError("msg.bad.destruct.op");
return right;
}
return parser.createDestructuringAssignment(
-1, left, right, (AstNode node) -> transform(node));
return parser.createDestructuringAssignment(-1, left, right, this::transform);
}
parser.reportError("msg.bad.assign.left");
return right;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,9 @@ boolean hasFunctionNamed(String name) {
}
return true;
}

@Override
public boolean hasDefaultParameters() {
return idata.argsHasDefaults;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ private void init() {
boolean[] argIsConst;
int argCount;
boolean argsHasRest;
boolean argsHasDefaults;

int itsMaxCalleeArgs;

Expand Down
3 changes: 2 additions & 1 deletion rhino/src/main/java/org/mozilla/javascript/Node.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ public class Node implements Iterable<Node> {
ARROW_FUNCTION_PROP = 26,
TEMPLATE_LITERAL_PROP = 27,
TRAILING_COMMA = 28,
LAST_PROP = 28;
OBJECT_LITERAL_DESTRUCTURING = 29,
LAST_PROP = 29;

// values of ISNUMBER_PROP to specify
// which of the children are Number types
Expand Down
11 changes: 11 additions & 0 deletions rhino/src/main/java/org/mozilla/javascript/NodeTransformer.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@

package org.mozilla.javascript;

import static org.mozilla.javascript.Context.reportError;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import org.mozilla.javascript.ast.FunctionNode;
import org.mozilla.javascript.ast.Jump;
import org.mozilla.javascript.ast.Name;
import org.mozilla.javascript.ast.Scope;
import org.mozilla.javascript.ast.ScriptNode;

Expand Down Expand Up @@ -343,6 +346,14 @@ private void transformCompilationUnit_r(
case Token.SETNAME:
if (inStrictMode) {
node.setType(Token.STRICT_SETNAME);
if (node.getFirstChild().getType() == Token.BINDNAME) {
Node name = node.getFirstChild();
if (name instanceof Name
&& ((Name) name).getIdentifier().equals("eval")) {
// Don't allow set of `eval` in strict mode
reportError("syntax error");
}
}
}
/* fall through */
case Token.NAME:
Expand Down
Loading

0 comments on commit 9ca1469

Please sign in to comment.