Statistics: |
|
|
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
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)
000141| else ((*[0]*)(start, end_start, ending, end_ending), (label, line):: errors)
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
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
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]*)[]
000202| in (*[6]*)let earg_array = match condexpr with
000203| | Once | When(_) -> (*[0]*)[]
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)
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^"'"))
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)
000230| | Not_found -> ((*[0]*)RNoop, env)
000231| | Variable_not_found(name) -> ((*[0]*)RNoop, env)
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
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")
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^"'")
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")
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)
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"
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")
000429| ((*[0]*)RBinaryOp(expr1, op, expr2), Environment.add_error env cloc ("invalid operation for "^t^" types"))
000431| ((*[0]*)RBinaryOp(expr1, op, expr2), Environment.add_error env cloc ("incompatible types "^t1^" and "^t2))
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"))
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")
000522| | Variable_not_found(name) -> ((*[0]*)RValue(RVoid), Environment.add_error env cloc ("Undefined variable '"^name^"'"))
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
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"))))
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
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)
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))
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)
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