Skip to content

Commit

Permalink
add ForInStatementTransformCommand
Browse files Browse the repository at this point in the history
  • Loading branch information
nyuichi committed May 14, 2014
1 parent 4b80872 commit 4b99bdf
Showing 1 changed file with 169 additions and 1 deletion.
170 changes: 169 additions & 1 deletion src/transformer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,24 @@ class _Util {
return new FunctionExpression(identity.getToken(), identity);
}

static function instantiateBuiltinTemplate (compiler : Compiler, name : string, typeArgs : Type[]) : ClassDefinition {

function createContext(parser : Parser) : AnalysisContext {
return new AnalysisContext(
[], // errors
parser,
function (parser : Parser, classDef : ClassDefinition) : ClassDefinition {
classDef.setAnalysisContextOfVariables(createContext(parser));
classDef.analyze(createContext(parser));
return classDef;
});
};

var context = createContext(compiler.getBuiltinParsers()[0]);

return Util.instantiateTemplate(context, null, name, typeArgs);
}

}

abstract class TransformCommand {
Expand Down Expand Up @@ -251,12 +269,20 @@ class FixedExpressionTransformCommand extends ExpressionTransformCommand {

abstract class StatementTransformCommand extends FunctionTransformCommand {

var _funcDef : MemberFunctionDefinition;

function constructor(compiler : Compiler, identifier : string) {
super(compiler, identifier);
}

override function transformFunction(funcDef : MemberFunctionDefinition) : void {
funcDef.forEachStatement((stmt, replaceCb) -> this.touchStatement(stmt, replaceCb));
var prev = this._funcDef;
try {
this._funcDef = funcDef;
funcDef.forEachStatement((stmt, replaceCb) -> this.touchStatement(stmt, replaceCb));
} finally {
this._funcDef = prev;
}
}

function touchStatement(stmt : Statement, replaceCb : (Statement) -> void) : boolean {
Expand All @@ -267,6 +293,10 @@ abstract class StatementTransformCommand extends FunctionTransformCommand {
return true;
}

function getProcessingFuncDef () : MemberFunctionDefinition {
return this._funcDef;
}

}

class NormalizeTryStatementTransformCommand extends StatementTransformCommand {
Expand Down Expand Up @@ -348,3 +378,141 @@ class NormalizeTryStatementTransformCommand extends StatementTransformCommand {
}

}

class ForInStatementTransformCommand extends StatementTransformCommand {

static const IDENTIFIER = "transform-for-in";

function constructor(compiler : Compiler) {
super(compiler, __CLASS__.IDENTIFIER);
}

override function touchStatement (statement : Statement, replaceCb : (Statement) -> void) : boolean {
var funcDef = this.getProcessingFuncDef();

if (statement instanceof ForInStatement) {
super.touchStatement(statement, replaceCb);

replaceCb(this._transformForIn(funcDef, statement as ForInStatement));

return true;
}

// default handler
return super.touchStatement(statement, replaceCb);
}

function _transformForIn (funcDef : MemberFunctionDefinition, forInStmt : ForInStatement) : Statement {

var listExpr = forInStmt.getListExpr();
var vLocal = (forInStmt.getLHSExpr() as LocalExpression).getLocal();

/*
for (v in list) {
...
}
||
\/
do {
$list = list;
$props = new string[];
for (var $prop in $list) {
$props.push($prop);
}
for (var $index = 0; $index < $props.length; $index++) {
v = $props[$index];
if (! (v in $list))
continue;
...
}
} while (0);
*/

var listLocal = _Util._createFreshLocalVariable(listExpr.getType());
var propsLocal = _Util._createFreshLocalVariable(new ObjectType(_Util.instantiateBuiltinTemplate(this._compiler, "Array", [ Type.stringType ])));
var propLocal = _Util._createFreshLocalVariable(Type.stringType);
var indexLocal = _Util._createFreshLocalVariable(Type.integerType);

funcDef.getLocals().push(listLocal, propsLocal, propLocal, indexLocal);

var statements = [
new ExpressionStatement(
new AssignmentExpression(
new Token("=", false),
new LocalExpression(listLocal.getName(), listLocal),
listExpr)),
new ExpressionStatement(
new AssignmentExpression(
new Token("=", false),
new LocalExpression(propsLocal.getName(), propsLocal),
new ArrayLiteralExpression(
new Token("[", false),
[],
propsLocal.getType()))),
new ForInStatement(
new Token("for", false),
null,
new LocalExpression(propLocal.getName(), propLocal),
new LocalExpression(listLocal.getName(), listLocal),
[
new ExpressionStatement(
new CallExpression(
new Token("(", false),
new PropertyExpression(
new Token(".", false),
new LocalExpression(propsLocal.getName(), propsLocal),
new Token("push", true),
[],
propsLocal.getType().getClassDef().getMemberTypeByName([], null, "push", false, [], ClassDefinition.GET_MEMBER_MODE_ALL)),
[ new LocalExpression(propLocal.getName(), propLocal) ]))
]),
new ForStatement(
new Token("for", false),
null,
new AssignmentExpression(
new Token("=", false),
new LocalExpression(indexLocal.getName(), indexLocal),
new IntegerLiteralExpression(new Token("0", false))),
new BinaryNumberExpression(
new Token("<", false),
new LocalExpression(indexLocal.getName(), indexLocal),
new PropertyExpression(
new Token(".", false),
new LocalExpression(propsLocal.getName(), propsLocal),
new Token("length", true),
[],
Type.integerType)),
new PreIncrementExpression(
new Token("++", false),
new LocalExpression(indexLocal.getName(), indexLocal)),
[
new ExpressionStatement(
new AssignmentExpression(
new Token("=", false),
new LocalExpression(vLocal.getName(), vLocal),
new ArrayExpression(
new Token("[", false),
new LocalExpression(propsLocal.getName(), propsLocal),
new LocalExpression(indexLocal.getName(), indexLocal),
vLocal.getType()))),
new IfStatement(
new Token("if", false),
new LogicalNotExpression(
new Token("!", false),
new InExpression(
new Token("in", false),
new LocalExpression(vLocal.getName(), vLocal),
new LocalExpression(listLocal.getName(), listLocal))),
[ new ContinueStatement(new Token("continue", false), null) ],
[]),
].concat(forInStmt.getStatements()))
];

return new DoWhileStatement(new Token("do", false), null, new BooleanLiteralExpression(new Token("false", false)), statements);
}

}

0 comments on commit 4b99bdf

Please sign in to comment.