let rec inline_expr_replace depth numargs repl_expr expr =
let rec loop = function
| RVariable(LocalVar(uid, d, ind)) when d = depth && ind <= numargs ->
List.nth repl_expr (ind - 1)
| RVariable(_) | RValue(_) | RVarArg(_) as e -> e
| RBinaryOp(expr1, op, expr2) -> RBinaryOp(loop expr1, op, loop expr2)
| RCompOp(e1, op, e2) -> RCompOp(loop e1, op, loop e2)
| RNot(e) -> RNot(loop e)
| RTernaryCond(e1, e2, e3) -> RTernaryCond(loop e1, loop e2, loop e3)
| RDeclaration(e1, e2) -> RDeclaration(loop e1, loop e2)
| RAssignment(e1, e2) -> RAssignment(loop e1, loop e2)
| RMapExpr(props) -> RMapExpr(List.map (fun p -> let (name, e) = p in (name, loop e)) props)
| RArrayExpr(elist) -> RArrayExpr(List.map(fun e -> loop e) elist)
| RFunctionCall(e, elist) -> RFunctionCall(loop e, List.map(fun e -> loop e) elist)
| RMemberExpr(e1, e2) -> RMemberExpr(loop e1, loop e2)
| RPostFixSum(e, i) -> RPostFixSum(loop e, i)
in loop expr
and
replace_constant env inline_uids = function
| RVariable(loc) ->
let uid = uid_from_loc loc
in if Environment.is_constant env uid then
try
match (Environment.get_constant_value env uid) with
| RFunctionValue(_) -> RVariable(loc)
| value -> RValue(value)
with Not_found -> RVariable(loc)
else RVariable(loc)
| RNot(expr) -> RNot(replace_constant env inline_uids expr)
| RBinaryOp(expr1, op, expr2) ->
let (e1, e2) = (replace_constant env inline_uids expr1, replace_constant env inline_uids expr2)
in (try match (e1, e2) with
| (RValue(v1), RValue(v2)) -> RValue(Expression.evaluate_op v1 v2 op)
| _ -> RBinaryOp(e1, op, e2)
with _ -> RBinaryOp(e1, op, e2))
| RCompOp(expr1, op, expr2) ->
RCompOp(replace_constant env inline_uids expr1, op, replace_constant env inline_uids expr2)
| RValue(RFunctionValue(locals, depth, args, vararg, stmts, closvars, inline)) ->
RValue(RFunctionValue(locals, depth, args, vararg, List.map(fun stmt -> pass2 env stmt) stmts, closvars, inline))
| RValue(_) | RPostFixSum(_) | RVarArg(_) as value -> value
| RFunctionCall(expr, expr_list) ->
let e = replace_constant env inline_uids expr
in let e_list = List.map(fun e -> replace_constant env inline_uids e) expr_list
in (match e with
| RVariable(GlobalVar(uid, _))
| RVariable(LocalVar(uid, _, _)) when is_constant env uid ->
(match get_constant_value env uid with
| RFunctionValue(_, depth, numargs, false, _, None, Some expr) ->
if List.exists (fun i -> i == uid) inline_uids then
RFunctionCall(e, e_list)
else
replace_constant env (uid:: inline_uids) (inline_expr_replace depth numargs e_list expr)
| _ -> RFunctionCall(e, e_list))
| _ -> RFunctionCall(e, e_list))
| RAssignment(expr1, expr2) -> RAssignment(expr1, replace_constant env inline_uids expr2)
| RDeclaration(expr1, expr2) ->
let expr2 = replace_constant env inline_uids expr2
in (match (expr1, expr2) with
| (RVariable(loc), RValue(value)) ->
let uid = uid_from_loc loc
in if is_constant env uid then
match value with
| RFunctionValue(_) -> RDeclaration(expr1, expr2)
| _ -> (Environment.set_constant_value env uid value; RValue(RUndefined))
else
RDeclaration(expr1, expr2)
| _ -> RDeclaration(expr1, expr2))
| RMemberExpr(expr1, expr2) ->
RMemberExpr(replace_constant env inline_uids expr1, replace_constant env inline_uids expr2)
| RArrayExpr(expr_list) ->
RArrayExpr(List.map(fun e -> replace_constant env inline_uids e) expr_list)
| RMapExpr(prop_list) ->
RMapExpr(List.map (fun prop -> let (name, e) = prop in (name, replace_constant env inline_uids e)) prop_list)
| RTernaryCond(expr1, expr2, expr3) ->
RTernaryCond(replace_constant env inline_uids expr1, replace_constant env inline_uids expr2,
replace_constant env inline_uids expr3)
and pass2 env = function
| RProgram(stmts) -> RProgram(List.map (fun stmt -> pass2 env stmt) stmts)
| RStatementBlock(stmts) -> RStatementBlock(List.map (fun stmt -> pass2 env stmt) stmts)
| RThrow(expr, cloc) -> RThrow(replace_constant env [] expr, cloc)
| RCase(Some expr, cloc) -> RCase(Some (replace_constant env [] expr), cloc)
| RReturn(expr, cloc) -> RReturn(replace_constant env [] expr, cloc)
| RContinue(_) | RBreak(_) | RCase(None, _) | RNoop | RFastIterator _ as stmt -> stmt
| RExpressionStatement(expr, cloc) ->
(match replace_constant env [] expr with
| RValue(RUndefined) -> RNoop
| expr -> RExpressionStatement(expr, cloc))
| RFor(expr1, expr2, expr3, stmt, cloc) ->
let expr1 = replace_constant env [] expr1
in let expr2 = replace_constant env [] expr2
in let expr3 = replace_constant env [] expr3
in let stmt = pass2 env stmt
in (match (expr1, expr2, expr3) with
| (RDeclaration(RVariable(vloc1), RValue(RIntegerValue(start))),
RCompOp(RVariable(vloc2), LessThan, RValue(RIntegerValue(max))),
RPostFixSum(RVariable(vloc3), inc)) when vloc1 = vloc2 && vloc1 = vloc3 ->
RFastIterator(vloc1, start , max , inc, stmt , cloc)
| (RDeclaration(RVariable(vloc1), RValue(RIntegerValue(start))),
RCompOp(RVariable(vloc2), LessThan, RValue(RIntegerValue(max))),
RAssignment(RVariable(vloc3), RBinaryOp(RVariable(vloc4), Plus, RValue(RIntegerValue(inc)))))
when vloc1 = vloc2 && vloc1 = vloc3 & vloc1 = vloc4 ->
RFastIterator(vloc1, start , max , inc, stmt , cloc)
| _ -> RFor(expr1, expr2 , expr3 , stmt , cloc))
| RIf(expr, stmt1, stmt2, cloc) -> RIf(replace_constant env [] expr, pass2 env stmt1, pass2 env stmt2, cloc)
| RTryFinally(stmt1, stmt2, cloc) -> RTryFinally(pass2 env stmt1, pass2 env stmt2, cloc)
| RTryCatch(stmt1, v, stmt2, cloc) -> RTryCatch(pass2 env stmt1, v, pass2 env stmt2, cloc)
| RSwitch(expr, stmts, cloc) -> RSwitch(replace_constant env [] expr,
(List.map (fun stmt -> pass2 env stmt) stmts), cloc)
| RForEach(v, expr, stmt, cloc) -> RForEach(v, replace_constant env [] expr, pass2 env stmt, cloc)