Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEAT: Support default parameters #1640

Merged
merged 1 commit into from
Sep 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading