File: build/analysis.ml (return to index)



Statistics:  
kind coverage
binding 155 / 158 (98 %)
sequence 20 / 22 (90 %)
for 0 / 0 (- %)
if/then 23 / 31 (74 %)
try 9 / 9 (100 %)
while 0 / 0 (- %)
match/function 208 / 249 (83 %)
kind coverage
class expression 0 / 0 (- %)
class initializer 0 / 0 (- %)
class method 0 / 0 (- %)
class value 0 / 0 (- %)
toplevel expression 0 / 0 (- %)
lazy operator 12 / 12 (100 %)



Source:

fold all unfold all
000001| (**
000002| This program is free software; you can redistribute it and / or modify
000003| it under the terms of the GNU General Public License as published by
000004| the Free Software Foundation; version 3 of the License.
000005|  
000006| This program is distributed in the hope that it will be useful,
000007| but WITHOUT ANY WARRANTY; without even the implied warranty of
000008| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
000009| GNU General Public License for more details.
000010|  
000011| Create an optimized AST from the parsing phase AST
000012|  
000013| Pass 1:
000014| - resolve all variable references, including closure variables
000015| - process imports and add declarations to AST
000016| - builds runtime AST
000017| - convert template definitions / instructions
000018| - evaluate operations on constants and replace with value in AST
000019| - determine if variables are initialized with a constant value (rather than an expression),
000020| if a variable is written after being declared and if it is ever read after being declared
000021| - determine if a function is inlineable
000022|  
000023| Pass 2:
000024| The second pass replaces all non function variables whose value have not been modified
000025| with a constant value, and evaluates operations on constants , eliminates assignment
000026| statements on constant values when the variable is not reassigned and not written,
000027| inline functions
000028|  
000029| @author Tony BenBrahim < tony.benbrahim at gmail.com >
000030|  
000031| *)
000032|  
000033| open Ast
000034| open Environment
000035| open Parser_util
000036| open RuntimeError
000037|  
000038| (**
000039| Prints all errors in an analysis environment and raises FatalExit if there are errors
000040| @param env analysis environment
000041| @returns unit
000042| @raise FatalExit if there are errors in the environment
000043| *)
000044| let check_errors env =
000045|         (*[2]*)List.fold_left (fun _ error -> (*[0]*)print_string ("ERROR: "^error^"\n")) () (List.rev env.errors);
000046|         (*[2]*)if List.length env.errors > 0 then (*[0]*)raise RuntimeError.FatalExit
000047|         else (*[2]*)()
000048|  
000049| (**
000050| Generates additional warnings about unused variables, then prints all warnings
000051| @param env analysis environment
000052| @returns analysis environment with newly added warnings
000053| *)
000054| let check_warnings env =
000055|         (* check for unused templates *)
000056|         (*[2]*)let env = Hashtbl.fold (fun name spec env ->
000057|                                                 (*[2]*)let (_, _, cloc) = spec
000058|                                                 in (*[2]*)Environment.add_warning env cloc ("Template definition '" ^ name ^ "' is never used.")
000059|                         )        env.templates env
000060|         (* check variables usage *)
000061|         in (*[2]*)let rec loop_names env max names = function
000062|                 | n when n = max -> (*[2]*)env
000063|                 | n ->
000064|                                 (*[990]*)let env =
000065|                                         try
000066|                                                 (*[990]*)let varprop = Hashtbl.find env.varprops n
000067|                                                 in (*[916]*)let (_, line) = varprop.declaration_loc
000068|                                                 in match line with
000069|                                                 | 0 -> (*[88]*)env
000070|                                                 | _ ->
000071|                                                                 (*[828]*)let env = if (*[828]*)varprop.read_after_declared = false && (*[72]*)line!= 0 then
000072|                                                                                 (*[72]*)add_warning env varprop.declaration_loc ("Variable "^(List.hd names)^" is never read.")
000073|                                                                         else
000074|                                                                                 (*[756]*)env
000075|                                                                 in (*[828]*)env
000076|                                         with Not_found ->
000077|                                                         (*[74]*)env
000078|                                 in (*[990]*)loop_names env max (List.tl names) (n + 1)
000079|         in (*[2]*)let env = loop_names env (List.length env.names) env.names 0
000080|         (* print warnings *)
000081|         in (*[2]*)List.fold_left (fun _ warning -> (*[74]*)print_string ("WARNING: "^warning^"\n")) () (List.rev env.warnings);
000082|         (*[2]*)env
000083|  
000084| (**
000085| Prints information about names found during analysis
000086| @env analysis environment
000087| @return unit
000088| *)
000089| let print_name_info env =
000090|         (*[2]*)let _ = List.fold_left (fun ind name ->
000091|                                                 (*[990]*)print_int ind;
000092|                                                 (*[990]*)let (read, written, analyzed, (file, line)) =
000093|                                                         try
000094|                                                                 (*[990]*)let vp = Hashtbl.find env.varprops ind
000095|                                                                 in ((*[916]*)vp.read_after_declared, vp.written_after_declared, true, vp.declaration_loc)
000096|                                                         with Not_found -> ((*[74]*)false, false, false, ("", 0))
000097|                                                 in
000098|                                                 (*[990]*)print_string (" "^name^" read="^(string_of_bool read)^" written="^(string_of_bool written)
000099|                                                                 ^ " analyzed="^(string_of_bool analyzed)^" ("
000100|                                                                 ^( Filename.basename file)^","^(string_of_int line)^")\n") ;
000101|                                                 (*[990]*)ind + 1) 0 env.names
000102|         in (*[2]*)()
000103|  
000104| (**
000105| **********************************************************************************************
000106| * FIRST PASS
000107| * - resolve all variable references, including closure variables
000108| * - process imports and add declarations to AST
000109| * - builds runtime AST
000110| * - convert template definitions / instructions
000111| * - evaluate operations on constants and replace with value in AST
000112| * - determine if variables are initialized with a constant value (rather than an expression)
000113| * - determine if a variable is written after being declared and if it is ever read after being declared
000114| * - determine if a function is inlineable
000115| **********************************************************************************************
000116| *)
000117|  
000118| (**internal exception to signal an error in template processing. *)
000119| exception TemplateError of string
000120|  
000121| (**
000122| Checks for invalid nesting in a template specification
000123| @param template_spec the template spec to check
000124| @return an list of tuples containing the label and line offset where conflicts where found
000125| **)
000126| let rec check_template_nesting template_spec =
000127|         (*[4]*)let labels = Hashtbl.create 10
000128|         (* get start and end for each label *)
000129|         in (*[4]*)let (_, errors) = List.fold_left(fun acc spec ->
000130|                                                 (*[32]*)let (line, errors) = acc
000131|                                                 in (*[32]*)let (name_opt, _) = spec
000132|                                                 in match name_opt with
000133|                                                 | None -> ((*[16]*)line + 1, errors)
000134|                                                 | Some label ->
000135|                                                                 (*[16]*)try
000136|                                                                         (*[16]*)let (start, end_start, ending, end_ending) = Hashtbl.find labels label
000137|                                                                         in (*[4]*)let (new_pos, errors) =
000138|                                                                                 if line = end_start + 1 then ((*[0]*)(start, line, line, line), errors)
000139|                                                                                 else (*[4]*)if line = end_ending + 1 then ((*[0]*)(start, end_start, ending, line), errors)
000140|                                                                                 else (*[4]*)if ending = end_start then ((*[4]*)(start, end_start, line, line), errors)
000141|                                                                                 else ((*[0]*)(start, end_start, ending, end_ending), (label, line):: errors)
000142|                                                                         in (*[4]*)Hashtbl.replace labels label new_pos;
000143|                                                                         ((*[4]*)line + 1, errors)
000144|                                                                 with Not_found ->
000145|                                                                                 (*[12]*)Hashtbl.add labels label (line, line, line, line);
000146|                                                                                 ((*[12]*)line + 1, errors))
000147|                         (0,[]) template_spec
000148|         (* find overlapping labels *)
000149|         in (*[4]*)let errors = Hashtbl.fold ( fun label pos list ->
000150|                                                 (*[12]*)let (start1, _, _, ending1) = pos
000151|                                                 in (*[12]*)Hashtbl.fold(fun label pos list ->
000152|                                                                                 (*[36]*)let (start2, _, _, ending2) = pos
000153|                                                                                 in (*[36]*)if (*[36]*)start2 > start1 && (*[12]*)start2 < ending1 && (*[4]*)ending2 > ending1 then (*[0]*)(label, ending2):: list
000154|                                                                                 else (*[36]*)list
000155|                                                         ) labels list
000156|                         ) labels errors
000157|         in ((*[4]*)labels, errors)
000158|  
000159| (**
000160| Generate a set of statements corresponding to a template instruction
000161| @param instruction instruction AST
000162| @env runtime environment
000163| @return a runtime statement for the instruction defining a function
000164| *)
000165| and generate_template_instr_function instruction env =
000166|         (*[2]*)let generate_instructions template_specs labels replacement_list cloc args =
000167|                 (*[2]*)let find_replacement name =
000168|                         (*[6]*)let rec loop = function
000169|                                 | [] -> (*[0]*)raise Not_found
000170|                                 | (n, condexpr, repl):: tl when n = name -> ((*[6]*)condexpr, repl)
000171|                                 | hd:: tl -> (*[6]*)loop tl
000172|                         in (*[6]*)loop replacement_list
000173|                 in (*[2]*)let make_repl_vars replacements =
000174|                         (*[6]*)let rec loop substrings expressions = function
000175|                                 | [] -> ((*[6]*)ArrayExpr(List.rev substrings), ArrayExpr(List.rev expressions))
000176|                                 | hd:: tl ->
000177|                                                 (*[4]*)let (string, expr) = hd
000178|                                                 in (*[4]*)loop (Value(StringValue(string)):: substrings) (expr:: expressions) tl
000179|                         in (*[6]*)loop [] [] replacements
000180|                 in (*[2]*)let array = Array.of_list template_specs
000181|                 in        (*[2]*)let rec loop name result index endindex args target_label substrings_var repl_var =
000182|                         (*[30]*)if index = endindex then
000183|                                 (*[8]*)let result = (Return(Id("result"), cloc)):: result
000184|                                 in (*[8]*)ExpressionStatement(Declaration(Id(name), Value(FunctionValue(args, List.rev result))), cloc)
000185|                         else
000186|                                 (*[22]*)let (label_opt, line) = array.(index)
000187|                                 in match label_opt with
000188|                                 | None ->
000189|                                                 (*[8]*)loop name (ExpressionStatement(Assignment(Id("result"), BinaryOp(Id("result"), Plus, Value(StringValue(line)))), cloc):: result) (index + 1) endindex args target_label substrings_var repl_var
000190|                                 | Some label ->
000191|                                                 (*[14]*)if label = target_label then
000192|                                                         (*[8]*)let call = FunctionCall(MemberExpr(Value(StringValue(line)), Value(StringValue("mreplace"))),[substrings_var; repl_var])
000193|                                                         in (*[8]*)loop name (ExpressionStatement(Assignment(Id("result"), BinaryOp(Id("result"), Plus, call)), cloc):: result) (index + 1) endindex args target_label substrings_var repl_var
000194|                                                 else
000195|                                                         (*[6]*)try
000196|                                                                 (*[6]*)let (condexpr, replacements) = find_replacement label
000197|                                                                 in (*[6]*)let (substrings, replexprs) = make_repl_vars replacements
000198|                                                                 in (*[6]*)let (start, _, _, ending) = Hashtbl.find labels label
000199|                                                                 in (*[6]*)let arg_array = match condexpr with
000200|                                                                         | Once | When(_) -> (*[0]*)[]
000201|                                                                         | Loop(iname, _) | CondLoop(_, iname, _) -> [(*[6]*)iname]
000202|                                                                 in (*[6]*)let earg_array = match condexpr with
000203|                                                                         | Once | When(_) -> (*[0]*)[]
000204|                                                                         | Loop(iname, _) | CondLoop(_, iname, _) -> [(*[6]*)Id(iname)]
000205|                                                                 in (*[6]*)let stmt1 = loop label [ExpressionStatement(Declaration(Id("result"), Value(StringValue(""))), cloc)]
000206|                                                                                 start (ending + 1) arg_array label substrings replexprs
000207|                                                                 in (*[6]*)let call = ExpressionStatement(Assignment(Id("result"), BinaryOp(Id("result"), Plus, FunctionCall(Id(label), earg_array))), cloc)
000208|                                                                 in (*[6]*)let stmt2 = match condexpr with
000209|                                                                         | Once -> (*[0]*)call
000210|                                                                         | When(cexpr) -> (*[0]*)If(cexpr, call, Noop, cloc)
000211|                                                                         | Loop(iname, iexpr) -> (*[6]*)ForEach(iname, iexpr, call, cloc)
000212|                                                                         | CondLoop(cexpr, iname, iexpr) -> (*[0]*)If(cexpr, ForEach(iname, iexpr, call, cloc), Noop, cloc)
000213|                                                                 in (*[6]*)loop name (stmt2:: stmt1:: result) (ending + 1) endindex args target_label substrings_var repl_var
000214|                                                         with Not_found ->
000215|                                                                         (*[0]*)raise(TemplateError ("could not find instruction for label '"^label^"'"))
000216|                 in (*[2]*)let (name, args, specs, cloc) = instruction
000217|                 in (*[2]*)loop name [ExpressionStatement(Declaration(Id("result"), Value(StringValue(""))), cloc)]
000218|                         0 (List.length template_specs) args "" (ArrayExpr([])) (ArrayExpr([]))
000219|         in (*[2]*)let (name, args, replacements, cloc) = instruction
000220|         in        (*[2]*)try
000221|                 (*[2]*)let (template_specs, labels, _) = Hashtbl.find env.templates name
000222|                 in (*[2]*)let (rstmt, env) =
000223|                         try
000224|                                 (*[2]*)let stmt = generate_instructions template_specs labels replacements cloc args
000225|                                 in (*[2]*)analyze_variables env stmt
000226|                         with TemplateError message ->
000227|                                         ((*[0]*)RNoop, Environment.add_error env cloc message)
000228|                 in (*[2]*)Hashtbl.remove env.templates name; ((*[2]*)rstmt, env)
000229|         with
000230|         | Not_found -> ((*[0]*)RNoop, env)
000231|         | Variable_not_found(name) -> ((*[0]*)RNoop, env)
000232| (**
000233| Filters an ast, returning only a list of declaration and import statement
000234| @param stmts the statement list to process
000235| @return a statement list containing only declarations and imports
000236| *)
000237| and filter_imported_ast stmts =
000238|         (*[18]*)let rec loop result = function
000239|                 | [] -> (*[18]*)List.rev result
000240|                 | stmt:: tl ->
000241|                                 (match stmt with
000242|                                         | ExpressionStatement(Declaration(_, _), _) | Import (_, _) ->
000243|                                                         (*[18]*)loop (stmt:: result) tl
000244|                                         | _ -> (*[0]*)loop result tl
000245|                                 ) in
000246|         (*[18]*)loop [] stmts
000247|  
000248| (** find declarations and resolve references to variables. Since declarations are
000249| visible in the entire scope in which they are defined, and not just after they are
000250| declared, a breadth first search is necessary before recursively processing children
000251| statements
000252| @param env an analysis environment
000253| @param ast the intermediate ast
000254| @return an ast where all variables have been resolved to an absolute location, either
000255| on a stack or in the global heap and an environment containing information about all
000256| variables
000257| *)
000258| and analyze_variables env ast =
000259|         (**
000260|         recursively searches an expression for declarations
000261|         @param env the analysis environment
000262|         @param expr the expression to search
000263|         @param cloc the location in code of the expression
000264|         @return an environment with any declared name added
000265|         *)
000266|         (*[1718]*)let rec find_decl_in_expr env expr cloc =
000267|                 match expr with
000268|                 | Declaration(expr1, expr2) ->
000269|                                 (*[426]*)let env = (match expr1 with
000270|                                                 | Id(name) -> (*[424]*)let (env, uid) = Environment.declare_variable env name in (*[424]*)env
000271|                                                 | MemberExpr(_, _) -> (*[2]*)env
000272|                                                 | _ -> (*[0]*)Environment.add_error env cloc "Left side cannot be assigned to")
000273|                                 in (*[426]*)find_decl_in_expr (find_decl_in_expr env expr1 cloc) expr2 cloc
000274|                 | Not(expr) | PostFixSum (expr, _) ->
000275|                                 (*[48]*)find_decl_in_expr env expr cloc
000276|                 | Assignment(expr1, expr2) | BinaryOp(expr1, _, expr2) | CompOp(expr1, _, expr2)
000277|                 | MemberExpr(expr1, expr2) ->
000278|                                 (*[1708]*)find_decl_in_expr (find_decl_in_expr env expr1 cloc) expr2 cloc
000279|                 | TernaryCond(expr1, expr2, expr3) ->
000280|                                 (*[16]*)find_decl_in_expr(find_decl_in_expr (find_decl_in_expr env expr1 cloc) expr2 cloc) expr3 cloc
000281|                 | FunctionCall(expr, expr_list) ->
000282|                                 (*[402]*)List.fold_left (fun env expr ->
000283|                                                                 (*[446]*)find_decl_in_expr env expr cloc) (find_decl_in_expr env expr cloc) expr_list
000284|                 | MapExpr(proplist) ->
000285|                                 (*[370]*)List.fold_left (fun env prop -> (*[712]*)let (_, expr) = prop in (*[712]*)find_decl_in_expr env expr cloc) env proplist
000286|                 | ArrayExpr(expr_list) ->
000287|                                 (*[134]*)List.fold_left (fun env expr -> (*[592]*)find_decl_in_expr env expr cloc) env expr_list
000288|                 | Value(_) | UnboundVar(_) | Id(_) | VarArg(_) -> (*[4740]*)env
000289|         (** finds all the declarations in the statement and registers        them in the environment
000290|         @param env analysis environment
000291|         @param stmt the statement to be analyzed
000292|         @return an analysis environment where all names found in assigments are registered
000293|         *)
000294|         and find_declarations_in_stmt env stmt =
000295|                 match stmt with
000296|                 | ExpressionStatement(expr, cloc) | Throw(expr, cloc) | Switch(expr, _, cloc) | Case(Some expr, cloc)
000297|                 | If(expr, _, _, cloc) | Return(expr, cloc) | ForEach(_, expr, _, cloc) ->
000298|                                 (*[1220]*)find_decl_in_expr env expr cloc
000299|                 | TryFinally(_, _, _) | TryCatch(_, _, _, _) | StatementBlock(_) | Case(None, _) | Continue(_)
000300|                 | Break(_) | Noop | Program(_) | Import(_) | For(_, _, _, _, _) -> (*[488]*)env
000301|                 | Instructions(name, _, _, _) -> (*[2]*)let (env, _) = Environment.declare_variable env name in (*[2]*)env
000302|                 | TemplateDef(name, spec_list , cloc) ->
000303|                                 (*[4]*)let (labels, errors) = check_template_nesting spec_list
000304|                                 in match errors with
000305|                                 | [] -> (*[4]*)Environment.add_template env name spec_list labels cloc
000306|                                 | error_list ->
000307|                                                 (*[0]*)List.fold_left (fun env label_offset ->
000308|                                                                                 (*[0]*)let (label, offset) = label_offset
000309|                                                                                 in (*[0]*)let (file, line) = cloc
000310|                                                                                 in (*[0]*)Environment.add_error env (file, line + offset + 1) ("Invalid nesting of labels for label '"^label^"'")
000311|                                                         ) env error_list
000312|         (**
000313|         Find all all variables in statement list whose stack depth is lower than that given
000314|         @param stmt_list a list of statements to be searched recursively
000315|         @param stack_depth the stack depth for the given statement
000316|         @return Some map of unique id to Void of all variables found or None if none where found
000317|         *)
000318|         and get_closure_vars stmt_list stack_depth =
000319|                 (*[360]*)let add loc = function
000320|                         | None -> (*[18]*)let t = Hashtbl.create 2 in (*[18]*)Hashtbl.replace t loc RUndefined; (*[18]*)Some t
000321|                         | Some t -> (*[4]*)Hashtbl.replace t loc RUndefined; (*[4]*)Some t
000322|                 in
000323|                 (*[360]*)let rec find_in_expr result = function
000324|                         | RVariable(LocalVar(_, sdepth, ind)) | RVarArg(LocalVar(_, sdepth, ind)) ->
000325|                                         (*[1424]*)if sdepth = stack_depth then (*[1402]*)result else (*[22]*)add (sdepth, ind) result
000326|                         | RValue(_) | RVariable(GlobalVar(_, _)) | RVarArg(GlobalVar(_, _)) -> (*[2862]*)result
000327|                         | RPostFixSum(e, _) | RNot(e) -> (*[40]*)find_in_expr result e
000328|                         | RBinaryOp(e1, _, e2) | RCompOp(e1, _, e2) | RAssignment(e1, e2) | RDeclaration(e1, e2)
000329|                         | RMemberExpr(e1, e2) ->
000330|                                         (*[1700]*)find_in_expr (find_in_expr result e1) e2
000331|                         | RTernaryCond(e1, e2, e3) ->
000332|                                         (*[16]*)find_in_expr(find_in_expr (find_in_expr result e1) e2) e3
000333|                         | RArrayExpr(elist) -> (*[134]*)List.fold_left (fun r e -> (*[592]*)find_in_expr r e) result elist
000334|                         | RMapExpr(proplist) ->
000335|                                         (*[370]*)List.fold_left (fun r prop -> (*[712]*)let (_, e) = prop
000336|                                                                         in (*[712]*)find_in_expr r e) result proplist
000337|                         | RFunctionCall(e, elist) ->
000338|                                         (*[394]*)List.fold_left (fun r e -> (*[432]*)find_in_expr r e)
000339|                                                 (find_in_expr result e) elist
000340|                 and process result = function
000341|                         | RNoop | RContinue(_) | RCase(None, _) | RBreak(_) | RFastIterator _ -> (*[86]*)result
000342|                         | RStatementBlock(slist) -> (*[264]*)loop result slist
000343|                         | RTryCatch(s1, _, s2, _) | RTryFinally(s1, s2, _) ->
000344|                                         (*[106]*)process (process result s1) s2
000345|                         | RReturn (e, _) | RThrow(e, _) | RCase(Some e, _) | RExpressionStatement(e, _) ->
000346|                                         (*[1142]*)find_in_expr result e
000347|                         | RFor(e1, e2, e3, stmt, _) ->
000348|                                         (*[36]*)process (find_in_expr(find_in_expr (find_in_expr result e1) e2) e3) stmt
000349|                         | RIf(e, stmt1, stmt2, _) -> (*[36]*)process(process(find_in_expr result e) stmt1)stmt2
000350|                         | RSwitch(e, stmts, _) -> (*[14]*)loop (find_in_expr result e) stmts
000351|                         | RForEach(_, e, stmt, _) -> (*[22]*)process (find_in_expr result e) stmt
000352|                         | RProgram(_) -> (*[0]*)raise (RuntimeError.InternalError "unexpected statement in closure processing")
000353|                 and loop result = function
000354|                         | [] -> (*[638]*)result
000355|                         | stmt:: list -> (*[1364]*)loop (process result stmt) list
000356|                 in (*[360]*)loop None stmt_list
000357|         (**
000358|         Convert a parsing value to a runtime value
000359|         *)
000360|         and convert_value env cloc = function
000361|                 | StringValue(v) -> ((*[1318]*)RStringValue(v), env)
000362|                 | IntegerValue(v) -> ((*[948]*)RIntegerValue(v), env)
000363|                 | FloatValue(v) -> ((*[156]*)RFloatValue(v), env)
000364|                 | BooleanValue(v) -> ((*[272]*)RBooleanValue(v), env)
000365|                 | Void -> ((*[40]*)RVoid, env)
000366|                 | MapValue(h, s) ->
000367|                                 ((*[0]*)RMapValue(Hashtbl.fold (fun k v h ->
000368|                                                                                 (*[0]*)let (repl, env) = convert_value env cloc v
000369|                                                                                 in (*[0]*)Hashtbl.replace h k repl ; (*[0]*)h ) h (Hashtbl.create 10), s), env)
000370|                 | FunctionValue(arg_list, stmt_list) ->
000371|                                 (*[360]*)let rec analyze_vararg has_vararg namelist env = function
000372|                                         | [] -> ((*[360]*)has_vararg, List.rev namelist, env)
000373|                                         | name::[] when is_vararg name -> (*[6]*)analyze_vararg true ((vararg_formalname name):: namelist) env []
000374|                                         | name:: tl ->
000375|                                                         (*[52]*)let env =
000376|                                                                 (if is_vararg name then
000377|                                                                                 (*[0]*)Environment.add_error env cloc "vararg must be last argument"
000378|                                                                         else
000379|                                                                                 (*[52]*)env)
000380|                                                         in (*[52]*)analyze_vararg has_vararg (name:: namelist) env tl
000381|                                 in (*[360]*)let (has_vararg, arg_list, env) = analyze_vararg false [] env arg_list
000382|                                 in (*[360]*)let env = Environment.new_analysis_stackframe env
000383|                                 in (*[360]*)let (env, _) = Environment.declare_variable env "this"
000384|                                 in (*[360]*)let _ = Environment.record_usage env (LocalVar(env.unique_id - 1, 0, 0)) (DeclareOp cloc)
000385|                                 in (*[360]*)let _ = Environment.record_usage env (LocalVar(env.unique_id - 1, 0, 0)) WriteOp
000386|                                 in (*[360]*)let _ = Environment.record_usage env (LocalVar(env.unique_id - 1, 0, 0)) ReadOp
000387|                                 in (*[360]*)let env = List.fold_left
000388|                                                 (fun env name ->
000389|                                                                         (*[58]*)let (env, _) = Environment.declare_variable env name
000390|                                                                         in (*[58]*)let _ = Environment.record_usage env (LocalVar(env.unique_id - 1 , 0, 0)) (DeclareOp cloc)
000391|                                                                         in (*[58]*)let _ = Environment.record_usage env (LocalVar(env.unique_id - 1, 0, 0)) WriteOp
000392|                                                                         in (*[58]*)env) env arg_list
000393|                                 in (*[360]*)let (stmt_list, env) = analyze_variables_in_block env stmt_list
000394|                                 in (*[360]*)let closure_vars = get_closure_vars stmt_list (Environment.get_depth env)
000395|                                 in (*[360]*)let inline_expr = match (stmt_list, closure_vars) with
000396|                                         | (RReturn(expr, _)::[], None) | (RExpressionStatement(expr, _)::[], None) -> (*[66]*)Some expr
000397|                                         | ([], None) -> (*[6]*)Some (RValue(RVoid))
000398|                                         | _ -> (*[288]*)None
000399|                                 in ((*[360]*)RFunctionValue(List.hd env.num_locals, Environment.get_depth env, List.length arg_list, has_vararg,
000400|                                                 stmt_list, closure_vars, inline_expr), Environment.pop_scope env)
000401|         (**
000402|         Replaces all variables in expression with absolute locations
000403|         Also sets up function definitions
000404|         @param env analysis environment
000405|         @param expr expression
000406|         @param location in code
000407|         @return new expression with variables replaced with absolute location
000408|         *)
000409|         and resolve_expr env expr cloc =
000410|                 (*[1330]*)let rec resolve_expr_sub env expr op_type =
000411|                         match expr with
000412|                         | Id(name) ->
000413|                                         (*[1634]*)let loc = Environment.resolve_variable name env
000414|                                         in (*[1634]*)let _ = record_usage env loc op_type
000415|                                         in ((*[1634]*)RVariable(loc), env)
000416|                         | VarArg(name) ->
000417|                                         (*[2]*)let loc = Environment.resolve_variable name env
000418|                                         in ((*[2]*)RVarArg(loc), env)
000419|                         | BinaryOp(e1, op, e2) ->
000420|                                         (*[540]*)let (expr1, env) = resolve_expr_sub env e1 ReadOp
000421|                                         in (*[540]*)let (expr2, env) = resolve_expr_sub env e2 ReadOp
000422|                                         in (match (expr1, expr2) with
000423|                                                 | (RValue(v1), RValue(v2)) ->
000424|                                                                 ((*[226]*)try
000425|                                                                         ((*[226]*)RValue(Expression.evaluate_op v1 v2 op), env)
000426|                                                                 with
000427|                                                                 | Division_by_zero -> ((*[0]*)RBinaryOp(expr1, op, expr2), Environment.add_error env cloc "division by zero")
000428|                                                                 | EInvalidOperation(_, t) ->
000429|                                                                                 ((*[0]*)RBinaryOp(expr1, op, expr2), Environment.add_error env cloc ("invalid operation for "^t^" types"))
000430|                                                                 | EIncompatibleTypes(t1, t2) ->
000431|                                                                                 ((*[0]*)RBinaryOp(expr1, op, expr2), Environment.add_error env cloc ("incompatible types "^t1^" and "^t2))
000432|                                                                 )
000433|                                                 | _ -> ((*[314]*)RBinaryOp(expr1, op, expr2), env))
000434|                         | CompOp(e1, op, e2) ->
000435|                                         (*[620]*)let (expr1, env) = resolve_expr_sub env e1 ReadOp
000436|                                         in (*[620]*)let (expr2, env) = resolve_expr_sub env e2 ReadOp
000437|                                         in (match (expr1, expr2) with
000438|                                                 | (RValue(v1), RValue(v2)) ->
000439|                                                                 ((*[204]*)try
000440|                                                                         ((*[204]*)RValue(Expression.compare v1 op v2), env)
000441|                                                                 with
000442|                                                                 | EInvalidComparaison(_, _, _) ->
000443|                                                                                 ((*[0]*)RCompOp(expr1, op, expr2), Environment.add_error env cloc ("invalid  comparaison"))
000444|                                                                 )
000445|                                                 | _ -> ((*[416]*)RCompOp(expr1, op, expr2), env))
000446|                         | Not(e) ->
000447|                                         (*[38]*)let (expr, env) = resolve_expr_sub env e ReadOp
000448|                                         in (match expr with
000449|                                                 | RValue(RBooleanValue(b)) -> ((*[8]*)RValue(RBooleanValue(not b)), env)
000450|                                                 | _ -> ((*[30]*)RNot(expr), env))
000451|                         | FunctionCall(e, el) ->
000452|                                         (*[402]*)let rec has_unbound_var = function
000453|                                                 | [] -> (*[396]*)false
000454|                                                 | UnboundVar(_):: tl -> (*[6]*)true
000455|                                                 | _:: tl -> (*[438]*)has_unbound_var tl
000456|                                         in (*[402]*)if has_unbound_var el then
000457|                                                 (*[6]*)let rec unbound_list result = function
000458|                                                         | [] -> (*[6]*)List.rev result
000459|                                                         | UnboundVar(name):: tl -> (*[6]*)unbound_list (name:: result) tl
000460|                                                         | _:: tl -> (*[8]*)unbound_list result tl
000461|                                                 in (*[6]*)let rec bound_list result = function
000462|                                                         | [] -> (*[6]*)List.rev result
000463|                                                         | UnboundVar(name):: tl ->
000464|                                                                         (*[6]*)let variable =
000465|                                                                                 if is_vararg name then
000466|                                                                                         (*[2]*)VarArg(vararg_formalname name)
000467|                                                                                 else
000468|                                                                                         (*[4]*)Id(name)
000469|                                                                         in (*[6]*)bound_list (variable:: result) tl
000470|                                                         | expr:: tl -> (*[8]*)bound_list (expr:: result) tl
000471|                                                 in (*[6]*)resolve_expr_sub env (Value(FunctionValue(unbound_list [] el,[Return(FunctionCall(e, bound_list [] el), cloc)]))) ReadOp
000472|                                         else
000473|                                                 (*[396]*)let (expr, env) = resolve_expr_sub env e ReadOp
000474|                                                 in (*[396]*)let (expr_list, env) = List.fold_left(fun acc expr -> (*[432]*)let (lst, env) = acc
000475|                                                                                         in (*[432]*)let (expr, env) = resolve_expr_sub env expr ReadOp in ((*[432]*)expr:: lst, env)) ([], env) el
000476|                                                 in ((*[396]*)RFunctionCall(expr, List.rev expr_list), env)
000477|                         | MapExpr(prop_list) ->
000478|                                         (*[370]*)let (prop_list, env) = List.fold_left(fun acc prop -> (*[712]*)let (lst, env) = acc
000479|                                                                                 in (*[712]*)let (name, expr) = prop
000480|                                                                                 in (*[712]*)let (expr, env) = resolve_expr_sub env expr ReadOp
000481|                                                                                 in ((*[712]*)(name, expr):: lst, env)) ([], env) prop_list
000482|                                         in ((*[370]*)RMapExpr(List.rev prop_list), env)
000483|                         | ArrayExpr(el) ->
000484|                                         (*[134]*)let (expr_list, env) = List.fold_left(fun acc expr -> (*[592]*)let (lst, env) = acc
000485|                                                                                 in (*[592]*)let (expr, env) = resolve_expr_sub env expr ReadOp
000486|                                                                                 in ((*[592]*)expr:: lst, env)) ([], env) el
000487|                                         in ((*[134]*)RArrayExpr(List.rev expr_list), env)
000488|                         | Value(v) -> (*[3094]*)let (repl, env) = convert_value env cloc v in ((*[3094]*)RValue(repl), env)
000489|                         | Assignment(e1, e2) ->
000490|                                         (*[154]*)let (expr1, env) = resolve_expr_sub env e1 WriteOp
000491|                                         in (*[154]*)let (expr2, env) = resolve_expr_sub env e2 ReadOp
000492|                                         in ((*[154]*)RAssignment(expr1, expr2), env)
000493|                         | Declaration(e1, e2) ->
000494|                                         (*[428]*)let (expr1, env) = resolve_expr_sub env e1 (DeclareOp cloc)
000495|                                         in (*[428]*)let (expr2, env) = resolve_expr_sub env e2 ReadOp
000496|                                         in (*[428]*)let _ = match (expr1, expr2) with
000497|                                                 | (RVariable(loc), RValue(value)) ->
000498|                                                                 (*[234]*)let uid = uid_from_loc loc
000499|                                                                 in (*[234]*)Environment.set_constant_value env uid value
000500|                                                 | _ -> (*[194]*)()
000501|                                         in ((*[428]*)RDeclaration(expr1, expr2), env)
000502|                         | TernaryCond(e1, e2, e3) ->
000503|                                         (*[16]*)let (e1, env) = resolve_expr_sub env e1 ReadOp
000504|                                         in (*[16]*)let (e2, env) = resolve_expr_sub env e2 ReadOp
000505|                                         in (*[16]*)let (e3, env) = resolve_expr_sub env e3 ReadOp
000506|                                         in ((*[16]*)RTernaryCond(e1, e2, e3), env)
000507|                         | MemberExpr(e1, e2) ->
000508|                                         (*[394]*)let (expr1, env) = match op_type with
000509|                                                 | DeclareOp(loc) -> (*[2]*)resolve_expr_sub env e1 (DeclareWriteOp(loc))
000510|                                                 | _ -> (*[392]*)resolve_expr_sub env e1 op_type
000511|                                         in (*[394]*)let (expr2, env) = resolve_expr_sub env e2 ReadOp
000512|                                         in ((*[394]*)RMemberExpr(expr1, expr2), env)
000513|                         | PostFixSum(e, inc) ->
000514|                                         (*[10]*)let (expr, env) = resolve_expr_sub env e WriteOp
000515|                                         in ((*[10]*)RPostFixSum(expr, inc), env)
000516|                         | UnboundVar(_) ->
000517|                                         ((*[0]*)RValue(RVoid), Environment.add_error env cloc "Unexpected unbound var")
000518|                 in
000519|                 (*[1330]*)try
000520|                         (*[1330]*)resolve_expr_sub env expr ReadOp
000521|                 with
000522|                 | Variable_not_found(name) -> ((*[0]*)RValue(RVoid), Environment.add_error env cloc ("Undefined variable '"^name^"'"))
000523|         (**
000524|         Replace variables in all statements in a list with an absolute location
000525|         @param env analysis environment
000526|         @param stmt_list the statement list to process
000527|         @return a tuple consisting of a new statement list with all variables replaced with an absolute location
000528|         and an updated environment, possibly containing new errrors
000529|         *)
000530|         and replace_variables_in_block env stmt =
000531|                 (*[640]*)let rec loop env stmt_list new_list =
000532|                         match stmt_list with
000533|                         | [] -> ((*[640]*)List.rev new_list, env)
000534|                         | stmt:: tl ->
000535|                                         (*[1372]*)let (stmt, env) = analyze_variables env stmt
000536|                                         in (*[1372]*)loop env tl (stmt:: new_list)
000537|                 in (*[640]*)loop env stmt []
000538|         (**
000539|         In the given statement list, replace all top level import statements
000540|         @param env analysis enviroment
000541|         @param stmt_list the statement list
000542|         @return a tuple of the statement list with imports replaced by imported statements and
000543|         a new environment, possibly containing new errors
000544|         *)
000545|         and process_imports env stmt_list =
000546|                 (*[658]*)let rec loop result env = function
000547|                         | [] -> ((*[658]*)List.rev result, env)
000548|                         | Import(filename, cloc):: tl ->
000549|                                         ((*[18]*)if Environment.has_import env filename then
000550|                                                         (*[0]*)loop (Noop:: result) env tl
000551|                                                 else (
000552|                                                         (*[18]*)let env = Environment.add_import env filename
000553|                                                         in (*[18]*)let stmt = Parser_util.parse_filename filename
000554|                                                         in (match stmt with
000555|                                                                 | Program(stmts) ->
000556|                                                                                 (*[18]*)let (stmts, env) = process_imports env (filter_imported_ast stmts)
000557|                                                                                 in (*[18]*)let result = List.fold_left (fun lst stmt -> (*[18]*)stmt:: lst) result stmts
000558|                                                                                 in (*[18]*)loop result env tl
000559|                                                                 | _ -> (*[0]*)raise (RuntimeError.InternalError "Unexpected node from import"))))
000560|                         | stmt:: tl -> (*[1372]*)loop (stmt:: result) env tl
000561|                 in (*[658]*)loop [] env stmt_list
000562|         (**
000563|         In the given statement list, find all top level declarations, then resolve all top
000564|         level variables, then recurse into nested statement blocks
000565|         @param env analysis environment
000566|         @param stmt_list the statement list to process
000567|         @return a tuple of modified statements and the modified analysis environment
000568|         **)
000569|         and analyze_variables_in_block env stmt_list =
000570|                 (*[640]*)let (stmt_list, env) = process_imports env stmt_list
000571|                 in (*[640]*)let env = List.fold_left(fun env stmt -> (*[1372]*)find_declarations_in_stmt env stmt) env stmt_list
000572|                 in (*[640]*)replace_variables_in_block env stmt_list
000573|         and analyze_variables_in_stmt env stmt =
000574|                 (*[342]*)let env = find_declarations_in_stmt env stmt
000575|                 in (*[342]*)analyze_variables env stmt
000576|         in
000577|         match ast with
000578|         | Program(stmt_list) ->
000579|                         (*[2]*)let (ast, env) = analyze_variables_in_block env stmt_list
000580|                         in ((*[2]*)RProgram(ast), env)
000581|         | StatementBlock(stmt_list) ->
000582|                         (*[264]*)let newenv = Environment.new_analysis_scope env
000583|                         in (*[264]*)let (ast, newenv) = analyze_variables_in_block newenv stmt_list
000584|                         in ((*[264]*)RStatementBlock(ast), Environment.pop_scope newenv)
000585|         | Switch(expr, stmt_list, cloc) ->
000586|                         (*[14]*)let newenv = Environment.new_analysis_scope env
000587|                         in (*[14]*)let (expr, newenv) = resolve_expr newenv expr cloc
000588|                         in (*[14]*)let (ast, newenv) = analyze_variables_in_block newenv stmt_list
000589|                         in ((*[14]*)RSwitch(expr, ast, cloc), Environment.pop_scope newenv)
000590|         | TryCatch(stmt1, name, stmt2, cloc) ->
000591|                         (*[98]*)let newenv = Environment.new_analysis_scope env
000592|                         in (*[98]*)let (stmt1, newenv) = analyze_variables_in_stmt newenv stmt1
000593|                         in (*[98]*)let newenv = Environment.new_analysis_scope (Environment.pop_scope newenv)
000594|                         in (*[98]*)let (newenv, _) = Environment.declare_variable newenv name
000595|                         in (*[98]*)let (stmt2, newenv) = analyze_variables_in_stmt newenv stmt2
000596|                         in (*[98]*)let loc = Environment.resolve_variable name newenv
000597|                         in ((*[98]*)RTryCatch(stmt1, loc, stmt2, cloc), Environment.pop_scope newenv)
000598|         | If(expr, stmt1, stmt2, cloc) ->
000599|                         (*[36]*)let (expr, env) = resolve_expr env expr cloc
000600|                         in (*[36]*)let newenv = Environment.new_analysis_scope env
000601|                         in (*[36]*)let (stmt1, newenv) = analyze_variables_in_stmt newenv stmt1
000602|                         in (*[36]*)let newenv = Environment.new_analysis_scope (Environment.pop_scope newenv)
000603|                         in (*[36]*)let (stmt2, newenv) = analyze_variables_in_stmt newenv stmt2
000604|                         in ((*[36]*)RIf(expr, stmt1, stmt2, cloc), Environment.pop_scope newenv)
000605|         | TryFinally(stmt1, stmt2, cloc) ->
000606|                         (*[8]*)let newenv = Environment.new_analysis_scope env
000607|                         in (*[8]*)let (stmt1, newenv) = analyze_variables_in_stmt newenv stmt1
000608|                         in (*[8]*)let newenv = Environment.new_analysis_scope (Environment.pop_scope newenv)
000609|                         in (*[8]*)let (stmt2, newenv) = analyze_variables_in_stmt newenv stmt2
000610|                         in ((*[8]*)RTryFinally(stmt1, stmt2, cloc), Environment.pop_scope newenv)
000611|         | ForEach(name, expr, stmt, cloc) ->
000612|                         (*[22]*)let (newenv, _) = Environment.declare_variable (Environment.new_analysis_scope env) name
000613|                         in (*[22]*)let (expr, newenv) = resolve_expr newenv expr cloc
000614|                         in (*[22]*)let (stmt, newenv) = analyze_variables_in_stmt newenv stmt
000615|                         in (*[22]*)let loc = Environment.resolve_variable name newenv
000616|                         in ((*[22]*)RForEach(loc, expr, stmt, cloc), Environment.pop_scope newenv)
000617|         | For(expr1, expr2, expr3, stmt, cloc) ->
000618|                         (*[36]*)let newenv = Environment.new_analysis_scope env
000619|                         in (*[36]*)let newenv = find_decl_in_expr (find_decl_in_expr (find_decl_in_expr newenv expr1 cloc) expr2 cloc) expr3 cloc
000620|                         in (*[36]*)let (expr1, newenv) = resolve_expr newenv expr1 cloc
000621|                         in (*[36]*)let (expr2, newenv) = resolve_expr newenv expr2 cloc
000622|                         in (*[36]*)let (expr3, newenv) = resolve_expr newenv expr3 cloc
000623|                         in (*[36]*)let (stmt, newenv) = analyze_variables_in_stmt newenv stmt
000624|                         in ((*[36]*)RFor(expr1, expr2, expr3, stmt, cloc), Environment.pop_scope newenv)
000625|         | Noop -> ((*[44]*)RNoop, env)
000626|         | ExpressionStatement(e, cloc) ->
000627|                         (*[654]*)let (expr, env) = resolve_expr env e cloc
000628|                         in ((*[654]*)RExpressionStatement(expr, cloc), env)
000629|         | Return(e, cloc) ->
000630|                         (*[454]*)let (e, env) = resolve_expr env e cloc
000631|                         in ((*[454]*)RReturn(e, cloc), env)
000632|         | Case(Some e, cloc) ->
000633|                         (*[30]*)let (e, env) = resolve_expr env e cloc
000634|                         in ((*[30]*)RCase(Some e, cloc), env)
000635|         | Case(None, cloc) -> ((*[14]*)RCase(None, cloc), env)
000636|         | Throw(e, cloc) ->
000637|                         (*[12]*)let (e, env) = resolve_expr env e cloc
000638|                         in ((*[12]*)RThrow(e, cloc), env)
000639|         | Break(cloc) -> ((*[16]*)RBreak(cloc), env)
000640|         | Continue(cloc) -> ((*[8]*)RContinue(cloc), env)
000641|         | Import(_, _) | TemplateDef(_, _, _) -> ((*[4]*)RNoop, env)
000642|         | Instructions(name, args, specs, cloc) ->
000643|                         (*[2]*)generate_template_instr_function (name, args, specs, cloc) env
000644|  
000645| (**
000646| **********************************************************************************************
000647| * SECOND PASS
000648| * - replace all constant declarations with Noop
000649| * - replace all constant variables with their value
000650| * - replace all constant expressions with the computed value
000651| * - replace all calls to inlineable functions with an expression
000652| **********************************************************************************************
000653| *)
000654|  
000655| (** replaces an expression from an inlined function with the corresponding
000656| values from a function call expression list
000657| @param depth the stack depth, for sanity checking
000658| @param numargs the number of arguments
000659| @param repl_exprs the expressions used in the call invocation
000660| @param expr the inline expression
000661| @return the inline expression with the arguments replacing the former local args
000662| *)
000663| let rec inline_expr_replace depth numargs repl_expr expr =
000664|         (*[4]*)let rec loop = function
000665|                 | RVariable(LocalVar(uid, d, ind)) when (*[8]*)d = depth && (*[8]*)ind <= numargs ->
000666|                                 (*[8]*)List.nth repl_expr (ind - 1)
000667|                 | RVariable(_) | RValue(_) | RVarArg(_) as e -> (*[0]*)e
000668|                 | RBinaryOp(expr1, op, expr2) -> (*[4]*)RBinaryOp(loop expr1, op, loop expr2)
000669|                 | RCompOp(e1, op, e2) -> (*[0]*)RCompOp(loop e1, op, loop e2)
000670|                 | RNot(e) -> (*[0]*)RNot(loop e)
000671|                 | RTernaryCond(e1, e2, e3) -> (*[0]*)RTernaryCond(loop e1, loop e2, loop e3)
000672|                 | RDeclaration(e1, e2) -> (*[0]*)RDeclaration(loop e1, loop e2)
000673|                 | RAssignment(e1, e2) -> (*[0]*)RAssignment(loop e1, loop e2)
000674|                 | RMapExpr(props) -> (*[0]*)RMapExpr(List.map (fun p -> (*[0]*)let (name, e) = p in ((*[0]*)name, loop e)) props)
000675|                 | RArrayExpr(elist) -> (*[0]*)RArrayExpr(List.map(fun e -> (*[0]*)loop e) elist)
000676|                 | RFunctionCall(e, elist) -> (*[0]*)RFunctionCall(loop e, List.map(fun e -> (*[0]*)loop e) elist)
000677|                 | RMemberExpr(e1, e2) -> (*[0]*)RMemberExpr(loop e1, loop e2)
000678|                 | RPostFixSum(e, i) -> (*[0]*)RPostFixSum(loop e, i)
000679|         in (*[4]*)loop expr
000680| and
000681| (**
000682| Replace non modified variables with their declared value
000683| @param env analysis environment
000684| @param inline_uids list of inlined functions to avoid recursively inlining recursive inlinable functions
000685| @param expression expression to process
000686| @return an expression with constant variables replaced by their value
000687| *)
000688| replace_constant env inline_uids = function
000689|         |        RVariable(loc) ->
000690|                         (*[1046]*)let uid = uid_from_loc loc
000691|                         in (*[1046]*)if Environment.is_constant env uid then
000692|                                 (*[404]*)try
000693|                                         match (Environment.get_constant_value env uid) with
000694|                                         | RFunctionValue(_) -> (*[80]*)RVariable(loc)
000695|                                         | value -> (*[122]*)RValue(value)
000696|                                 with Not_found -> (*[202]*)RVariable(loc)
000697|                         else (*[642]*)RVariable(loc)
000698|         | RNot(expr) -> (*[30]*)RNot(replace_constant env inline_uids expr)
000699|         | RBinaryOp(expr1, op, expr2) ->
000700|                         (*[318]*)let (e1, e2) = (replace_constant env inline_uids expr1, replace_constant env inline_uids expr2)
000701|                         in ((*[318]*)try match (e1, e2) with
000702|                                 | (RValue(v1), RValue(v2)) -> (*[2]*)RValue(Expression.evaluate_op v1 v2 op)
000703|                                 | _ -> (*[316]*)RBinaryOp(e1, op, e2)
000704|                         with _ -> (*[0]*)RBinaryOp(e1, op, e2))
000705|         | RCompOp(expr1, op, expr2) ->
000706|                         (*[416]*)RCompOp(replace_constant env inline_uids expr1, op, replace_constant env inline_uids expr2)
000707|         | RValue(RFunctionValue(locals, depth, args, vararg, stmts, closvars, inline)) ->
000708|                         (*[358]*)RValue(RFunctionValue(locals, depth, args, vararg, List.map(fun stmt -> (*[836]*)pass2 env stmt) stmts, closvars, inline))
000709|         | RValue(_) | RPostFixSum(_) | RVarArg(_) as value -> (*[2314]*)value
000710|         | RFunctionCall(expr, expr_list) ->
000711|                         (*[396]*)let e = replace_constant env inline_uids expr
000712|                         in (*[396]*)let e_list = List.map(fun e -> (*[432]*)replace_constant env inline_uids e) expr_list
000713|                         in (match e with
000714|                                 | RVariable(GlobalVar(uid, _))
000715|                                 | RVariable(LocalVar(uid, _, _)) when is_constant env uid ->
000716|                                                 (match get_constant_value env uid with
000717|                                                         | RFunctionValue(_, depth, numargs, false, _, None, Some expr) ->
000718|                                                                         (*[4]*)if List.exists (fun i -> (*[0]*)i == uid) inline_uids then
000719|                                                                                 (*[0]*)RFunctionCall(e, e_list)
000720|                                                                         else
000721|                                                                                 (*[4]*)replace_constant env (uid:: inline_uids) (inline_expr_replace depth numargs e_list expr)
000722|                                                         | _ -> (*[62]*)RFunctionCall(e, e_list))
000723|                                 | _ -> (*[330]*)RFunctionCall(e, e_list))
000724|         | RAssignment(expr1, expr2) -> (*[154]*)RAssignment(expr1, replace_constant env inline_uids expr2)
000725|         | RDeclaration(expr1, expr2) ->
000726|                         (*[428]*)let expr2 = replace_constant env inline_uids expr2
000727|                         in (match (expr1, expr2) with
000728|                                 | (RVariable(loc), RValue(value)) ->
000729|                                                 (*[234]*)let uid = uid_from_loc loc
000730|                                                 in (*[234]*)if is_constant env uid then
000731|                                                         match value with
000732|                                                         | RFunctionValue(_) -> (*[48]*)RDeclaration(expr1, expr2)
000733|                                                         | _ -> ((*[88]*)Environment.set_constant_value env uid value; (*[88]*)RValue(RUndefined))
000734|                                                 else
000735|                                                         (*[98]*)RDeclaration(expr1, expr2)
000736|                                 | _ -> (*[194]*)RDeclaration(expr1, expr2))
000737|         | RMemberExpr(expr1, expr2) ->
000738|                         (*[388]*)RMemberExpr(replace_constant env inline_uids expr1, replace_constant env inline_uids expr2)
000739|         | RArrayExpr(expr_list) ->
000740|                         (*[134]*)RArrayExpr(List.map(fun e -> (*[592]*)replace_constant env inline_uids e) expr_list)
000741|         | RMapExpr(prop_list) ->
000742|                         (*[370]*)RMapExpr(List.map (fun prop -> (*[712]*)let (name, e) = prop in ((*[712]*)name, replace_constant env inline_uids e)) prop_list)
000743|         | RTernaryCond(expr1, expr2, expr3) ->
000744|                         (*[16]*)RTernaryCond(replace_constant env inline_uids expr1, replace_constant env inline_uids expr2,
000745|                                 replace_constant env inline_uids expr3)
000746| (**
000747| Looks for expressions where constants can be substituted
000748| @param env analysis environment
000749| @param stmt statement
000750| *)
000751| and pass2 env = function
000752|         | RProgram(stmts) -> (*[2]*)RProgram(List.map (fun stmt -> (*[8]*)pass2 env stmt) stmts)
000753|         | RStatementBlock(stmts) ->        (*[264]*)RStatementBlock(List.map (fun stmt -> (*[442]*)pass2 env stmt) stmts)
000754|         | RThrow(expr, cloc) -> (*[12]*)RThrow(replace_constant env [] expr, cloc)
000755|         | RCase(Some expr, cloc) -> (*[30]*)RCase(Some (replace_constant env [] expr), cloc)
000756|         | RReturn(expr, cloc) -> (*[452]*)RReturn(replace_constant env [] expr, cloc)
000757|         | RContinue(_) | RBreak(_) | RCase(None, _) | RNoop | RFastIterator _ as stmt -> (*[86]*)stmt
000758|         | RExpressionStatement(expr, cloc) ->
000759|                         (match replace_constant env [] expr with
000760|                                 | RValue(RUndefined) -> (*[88]*)RNoop
000761|                                 | expr -> (*[566]*)RExpressionStatement(expr, cloc))
000762|         | RFor(expr1, expr2, expr3, stmt, cloc) ->
000763|                         (*[36]*)let expr1 = replace_constant env [] expr1
000764|                         in (*[36]*)let expr2 = replace_constant env [] expr2
000765|                         in (*[36]*)let expr3 = replace_constant env [] expr3
000766|                         in (*[36]*)let stmt = pass2 env stmt
000767|                         in (match (expr1, expr2, expr3) with
000768|                                 | (RDeclaration(RVariable(vloc1), RValue(RIntegerValue(start))),
000769|                                 RCompOp(RVariable(vloc2), LessThan, RValue(RIntegerValue(max))),
000770|                                 RPostFixSum(RVariable(vloc3), inc)) when (*[4]*)vloc1 = vloc2 && (*[4]*)vloc1 = vloc3 ->
000771|                                                 (*[4]*)RFastIterator(vloc1, start , max , inc, stmt , cloc)
000772|                                 | (RDeclaration(RVariable(vloc1), RValue(RIntegerValue(start))),
000773|                                 RCompOp(RVariable(vloc2), LessThan, RValue(RIntegerValue(max))),
000774|                                 RAssignment(RVariable(vloc3), RBinaryOp(RVariable(vloc4), Plus, RValue(RIntegerValue(inc)))))
000775|                                 when (*[16]*)vloc1 = vloc2 && (*[16]*)vloc1 = vloc3 & (*[16]*)vloc1 = vloc4 ->
000776|                                                 (*[16]*)RFastIterator(vloc1, start , max , inc, stmt , cloc)
000777|                                 | _ -> (*[16]*)RFor(expr1, expr2 , expr3 , stmt , cloc))
000778|         | RIf(expr, stmt1, stmt2, cloc) -> (*[36]*)RIf(replace_constant env [] expr, pass2 env stmt1, pass2 env stmt2, cloc)
000779|         | RTryFinally(stmt1, stmt2, cloc) -> (*[8]*)RTryFinally(pass2 env stmt1, pass2 env stmt2, cloc)
000780|         | RTryCatch(stmt1, v, stmt2, cloc) -> (*[98]*)RTryCatch(pass2 env stmt1, v, pass2 env stmt2, cloc)
000781|         | RSwitch(expr, stmts, cloc) -> (*[14]*)RSwitch(replace_constant env [] expr,
000782|                                 (List.map (fun stmt -> (*[84]*)pass2 env stmt) stmts), cloc)
000783|         | RForEach(v, expr, stmt, cloc) -> (*[22]*)RForEach(v, replace_constant env [] expr, pass2 env stmt, cloc)
000784|  
000785| (**
000786| Analyzes an AST, generates a runtime AST
000787| @param ast a parsing AST
000788| @return a tuple of the runtime AST and analysis environment
000789| *)
000790| let analyze ast =
000791|         (*[2]*)let analyze_all env ast =
000792|                 (*[2]*)let (rast, env) = analyze_variables env ast
000793|                 in (*[2]*)let (rast, env) =
000794|                         (rast, {
000795|                                         globals = env.globals;
000796|                                         num_globals = env.num_globals;
000797|                                         locals = env.locals;
000798|                                         num_locals = env.num_locals;
000799|                                         sdepth = env.sdepth;
000800|                                         max_depth = env.max_depth;
000801|                                         errors = env.errors;
000802|                                         warnings = env.warnings;
000803|                                         unique_id = env.unique_id;
000804|                                         names = List.rev env.names;
000805|                                         varprops = env.varprops;
000806|                                         imported = env.imported;
000807|                                         templates = env.templates;
000808|                                         constants = env.constants;
000809|                                 })
000810|                 in (*[2]*)let (rast, env) = (pass2 env rast, env)
000811|                 in (*[2]*)let _ = check_errors env
000812|                 in (*[2]*)let env = check_warnings env
000813|                 in ((*[2]*)rast, env)
000814|         in (*[2]*)let env = Environment.new_analysis_environment()
000815|         in (*[2]*)let env = Library.register_for_analysis env
000816|         in (*[2]*)analyze_all env ast

Legend:
   some code - line containing no point
   some code - line containing only visited points
   some code - line containing only unvisited points
   some code - line containing both visited and unvisited points