Skip to content

Commit

Permalink
Implement ES6 Arrow Function
Browse files Browse the repository at this point in the history
  • Loading branch information
uchida authored and tuchida committed Jun 18, 2015
1 parent 2124086 commit 318da76
Show file tree
Hide file tree
Showing 16 changed files with 474 additions and 22 deletions.
75 changes: 75 additions & 0 deletions src/org/mozilla/javascript/ArrowFunction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.javascript;

/**
* The class for Arrow Function Definitions
* EcmaScript 6 Rev 14, March 8, 2013 Draft spec , 13.2
*/
public class ArrowFunction extends BaseFunction {

static final long serialVersionUID = -7377989503697220633L;

private final Callable targetFunction;
private final Scriptable boundThis;

public ArrowFunction(Context cx, Scriptable scope, Callable targetFunction, Scriptable boundThis)
{
this.targetFunction = targetFunction;
this.boundThis = boundThis;

ScriptRuntime.setFunctionProtoAndParent(this, scope);

Function thrower = ScriptRuntime.typeErrorThrower();
NativeObject throwing = new NativeObject();
throwing.put("get", throwing, thrower);
throwing.put("set", throwing, thrower);
throwing.put("enumerable", throwing, false);
throwing.put("configurable", throwing, false);
throwing.preventExtensions();

this.defineOwnProperty(cx, "caller", throwing, false);
this.defineOwnProperty(cx, "arguments", throwing, false);
}

@Override
public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args)
{
Scriptable callThis = boundThis != null ? boundThis : ScriptRuntime.getTopCallScope(cx);
return targetFunction.call(cx, scope, callThis, args);
}

@Override
public Scriptable construct(Context cx, Scriptable scope, Object[] args) {
throw ScriptRuntime.typeError1("msg.not.ctor", decompile(0, 0));
}

@Override
public boolean hasInstance(Scriptable instance) {
if (targetFunction instanceof Function) {
return ((Function) targetFunction).hasInstance(instance);
}
throw ScriptRuntime.typeError0("msg.not.ctor");
}

@Override
public int getLength() {
if (targetFunction instanceof BaseFunction) {
return ((BaseFunction) targetFunction).getLength();
}
return 0;
}

@Override
String decompile(int indent, int flags)
{
if (targetFunction instanceof BaseFunction) {
return ((BaseFunction)targetFunction).decompile(indent, flags);
}
return super.decompile(indent, flags);
}
}
3 changes: 2 additions & 1 deletion src/org/mozilla/javascript/CodeGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,8 @@ private void visitExpression(Node node, int contextFlags)
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
FunctionNode fn = scriptOrFn.getFunctionNode(fnIndex);
// See comments in visitStatement for Token.FUNCTION case
if (fn.getFunctionType() != FunctionNode.FUNCTION_EXPRESSION) {
if (fn.getFunctionType() != FunctionNode.FUNCTION_EXPRESSION &&
fn.getFunctionType() != FunctionNode.ARROW_FUNCTION) {
throw Kit.codeBug();
}
addIndexOp(Icode_CLOSURE_EXPR, fnIndex);
Expand Down
10 changes: 8 additions & 2 deletions src/org/mozilla/javascript/Decompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,10 @@ int getCurrentOffset()
int markFunctionStart(int functionType)
{
int savedOffset = getCurrentOffset();
addToken(Token.FUNCTION);
append((char)functionType);
if (functionType != FunctionNode.ARROW_FUNCTION) {
addToken(Token.FUNCTION);
append((char)functionType);
}
return savedOffset;
}

Expand Down Expand Up @@ -792,6 +794,10 @@ else if (nextToken == Token.NAME) {
result.append("debugger;\n");
break;

case Token.ARROW:
result.append(" => ");
break;

default:
// If we don't know how to decompile it, raise an exception.
throw new RuntimeException("Token: " +
Expand Down
18 changes: 15 additions & 3 deletions src/org/mozilla/javascript/IRFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -943,8 +943,11 @@ private Node transformRegExp(RegExpLiteral node) {

private Node transformReturn(ReturnStatement node) {
boolean expClosure = Boolean.TRUE.equals(node.getProp(Node.EXPRESSION_CLOSURE_PROP));
boolean isArrow = Boolean.TRUE.equals(node.getProp(Node.ARROW_FUNCTION_PROP));
if (expClosure) {
decompiler.addName(" ");
if (!isArrow) {
decompiler.addName(" ");
}
} else {
decompiler.addToken(Token.RETURN);
}
Expand Down Expand Up @@ -2272,15 +2275,24 @@ Node decompileFunctionHeader(FunctionNode fn) {
} else if (fn.getMemberExprNode() != null) {
mexpr = transform(fn.getMemberExprNode());
}
decompiler.addToken(Token.LP);
boolean isArrow = fn.getFunctionType() == FunctionNode.ARROW_FUNCTION;
boolean noParen = isArrow && fn.getLp() == -1;
if (!noParen) {
decompiler.addToken(Token.LP);
}
List<AstNode> params = fn.getParams();
for (int i = 0; i < params.size(); i++) {
decompile(params.get(i));
if (i < params.size() - 1) {
decompiler.addToken(Token.COMMA);
}
}
decompiler.addToken(Token.RP);
if (!noParen) {
decompiler.addToken(Token.RP);
}
if (isArrow) {
decompiler.addToken(Token.ARROW);
}
if (!fn.isExpressionClosure()) {
decompiler.addEOL(Token.LC);
}
Expand Down
18 changes: 13 additions & 5 deletions src/org/mozilla/javascript/Interpreter.java
Original file line number Diff line number Diff line change
Expand Up @@ -1711,9 +1711,14 @@ private static Object interpretLoop(Context cx, CallFrame frame,
stack[indexReg] = frame.scope;
continue Loop;
case Icode_CLOSURE_EXPR :
stack[++stackTop] = InterpretedFunction.createFunction(cx, frame.scope,
frame.fnOrScript,
indexReg);
InterpretedFunction fn = InterpretedFunction.createFunction(cx, frame.scope,
frame.fnOrScript,
indexReg);
if (fn.idata.itsFunctionType == FunctionNode.ARROW_FUNCTION) {
stack[++stackTop] = new ArrowFunction(cx, frame.scope, fn, frame.thisObj);
} else {
stack[++stackTop] = fn;
}
continue Loop;
case Icode_CLOSURE_STMT :
initFunction(cx, frame.scope, frame.fnOrScript, indexReg);
Expand Down Expand Up @@ -2750,8 +2755,11 @@ private static void initFrame(Context cx, Scriptable callerScope,
scope = fnOrScript.getParentScope();

if (useActivation) {
scope = ScriptRuntime.createFunctionActivation(
fnOrScript, scope, args);
if (idata.itsFunctionType == FunctionNode.ARROW_FUNCTION) {
scope = ScriptRuntime.createArrowFunctionActivation(fnOrScript, scope, args);
} else {
scope = ScriptRuntime.createFunctionActivation(fnOrScript, scope, args);
}
}
} else {
scope = callerScope;
Expand Down
7 changes: 6 additions & 1 deletion src/org/mozilla/javascript/NativeCall.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ static void init(Scriptable scope, boolean sealed)
NativeCall() { }

NativeCall(NativeFunction function, Scriptable scope, Object[] args)
{
this(function, scope, args, false);
}

NativeCall(NativeFunction function, Scriptable scope, Object[] args, boolean isArrow)
{
this.function = function;

Expand All @@ -51,7 +56,7 @@ static void init(Scriptable scope, boolean sealed)

// initialize "arguments" property but only if it was not overridden by
// the parameter with the same name
if (!super.has("arguments", this)) {
if (!super.has("arguments", this) && !isArrow) {
defineProperty("arguments", new Arguments(this), PERMANENT);
}

Expand Down
3 changes: 2 additions & 1 deletion src/org/mozilla/javascript/Node.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ public class Node implements Iterable<Node>
JSDOC_PROP = 24,
EXPRESSION_CLOSURE_PROP = 25, // JS 1.8 expression closure pseudo-return
DESTRUCTURING_SHORTHAND = 26, // JS 1.8 destructuring shorthand
LAST_PROP = 26;
ARROW_FUNCTION_PROP = 27,
LAST_PROP = 27;

// values of ISNUMBER_PROP to specify
// which of the children are Number types
Expand Down
Loading

0 comments on commit 318da76

Please sign in to comment.