diff options
-rw-r--r-- | perl_checker.src/common.ml | 3 | ||||
-rw-r--r-- | perl_checker.src/common.mli | 1 | ||||
-rw-r--r-- | perl_checker.src/lexer.mll | 17 | ||||
-rw-r--r-- | perl_checker.src/parser.mly | 22 | ||||
-rw-r--r-- | perl_checker.src/perl_checker.ml | 8 | ||||
-rw-r--r-- | perl_checker.src/tree.ml | 129 | ||||
-rw-r--r-- | perl_checker.src/tree.mli | 5 |
7 files changed, 115 insertions, 70 deletions
diff --git a/perl_checker.src/common.ml b/perl_checker.src/common.ml index 439c460..64e123d 100644 --- a/perl_checker.src/common.ml +++ b/perl_checker.src/common.ml @@ -513,6 +513,9 @@ let hashtbl_find f h = let hashtbl_filter f h = Hashtbl.iter (fun v c -> hashtbl_set h v (f v c)) h +let hashtbl_to_list h = + Hashtbl.fold (fun k v l -> (k,v) :: l) h [] + let array_shift a = Array.sub a 1 (Array.length a - 1) let array_last_n n a = let len = Array.length a in diff --git a/perl_checker.src/common.mli b/perl_checker.src/common.mli index 1e8078b..397af3c 100644 --- a/perl_checker.src/common.mli +++ b/perl_checker.src/common.mli @@ -148,6 +148,7 @@ val adjustModUp : int -> int -> int val hashtbl_set : ('a, 'b) Hashtbl.t -> 'a -> 'b -> unit val hashtbl_find : ('a -> 'b -> bool) -> ('a, 'b) Hashtbl.t -> 'a val hashtbl_filter : ('a -> 'b -> 'b) -> ('a, 'b) Hashtbl.t -> unit +val hashtbl_to_list : ('a, 'b) Hashtbl.t -> ('a * 'b) list val array_shift : 'a array -> 'a array val array_last_n : int -> 'a array -> 'a array val array_collect : ('a -> 'b list) -> 'a array -> 'b list diff --git a/perl_checker.src/lexer.mll b/perl_checker.src/lexer.mll index cfd7af9..1e1c875 100644 --- a/perl_checker.src/lexer.mll +++ b/perl_checker.src/lexer.mll @@ -22,8 +22,8 @@ type raw_token = | POD of (string * raw_pos) | LABEL of (string * raw_pos) | COMMAND_STRING of (raw_interpolated_string * raw_pos) - | PRINT_TO_STAR of (string * raw_pos) - | PRINT_TO_SCALAR of (string * raw_pos) + | PRINT_TO_STAR of ((string * string) * raw_pos) + | PRINT_TO_SCALAR of ((string * string) * raw_pos) | QUOTEWORDS of (string * raw_pos) | COMPACT_HASH_SUBSCRIPT of (string * raw_pos) | RAW_HERE_DOC of ((string * raw_pos) ref * raw_pos) @@ -411,6 +411,7 @@ rule token = parse | "BEGIN" { BEGIN(pos lexbuf) } | "END" { END(pos lexbuf) } | "print" { PRINT(lexeme lexbuf, pos lexbuf) } +| "printf" { PRINT(lexeme lexbuf, pos lexbuf) } | "new" { NEW(pos lexbuf) } | "format" { let _ = raw_here_doc_next_line "." in FORMAT(pos lexbuf) } | "defined" { ONE_SCALAR_PARA(lexeme lexbuf, pos lexbuf) } @@ -420,11 +421,19 @@ rule token = parse | "print " ['A'-'Z'] ['A'-'Z' '0'-'9']* ['\n' ' '] { putback lexbuf 1; - PRINT_TO_STAR(skip_n_char 6 (lexeme lexbuf), pos lexbuf) + PRINT_TO_STAR(("print", skip_n_char 6 (lexeme lexbuf)), pos lexbuf) } | "print $" ident ['\n' ' '] { putback lexbuf 1; - PRINT_TO_SCALAR(skip_n_char 7 (lexeme lexbuf), pos lexbuf); + PRINT_TO_SCALAR(("print", skip_n_char 7 (lexeme lexbuf)), pos lexbuf); + } +| "printf " ['A'-'Z'] ['A'-'Z' '0'-'9']* ['\n' ' '] { + putback lexbuf 1; + PRINT_TO_STAR(("printf", skip_n_char 7 (lexeme lexbuf)), pos lexbuf) + } +| "printf $" ident ['\n' ' '] { + putback lexbuf 1; + PRINT_TO_SCALAR(("printf", skip_n_char 8 (lexeme lexbuf)), pos lexbuf); } | ident ' '* "=>" { (* needed so that (if => 1) works *) diff --git a/perl_checker.src/parser.mly b/perl_checker.src/parser.mly index 62e10ea..90eab90 100644 --- a/perl_checker.src/parser.mly +++ b/perl_checker.src/parser.mly @@ -12,7 +12,8 @@ %token <unit * (Types.spaces * Types.raw_pos)> EOF -%token <string * (Types.spaces * Types.raw_pos)> NUM RAW_STRING BAREWORD BAREWORD_PAREN REVISION COMMENT POD LABEL PERL_CHECKER_COMMENT PRINT_TO_STAR PRINT_TO_SCALAR ONE_SCALAR_PARA +%token <string * (Types.spaces * Types.raw_pos)> NUM RAW_STRING BAREWORD BAREWORD_PAREN REVISION COMMENT POD LABEL PERL_CHECKER_COMMENT ONE_SCALAR_PARA +%token <(string * string) * (Types.spaces * Types.raw_pos)> PRINT_TO_STAR PRINT_TO_SCALAR %token <string * (Types.spaces * Types.raw_pos)> QUOTEWORDS COMPACT_HASH_SUBSCRIPT %token <(string * Types.raw_pos) * (Types.spaces * Types.raw_pos)> RAW_HERE_DOC %token <(string * ((int * int) * token) list) list * (Types.spaces * Types.raw_pos)> STRING COMMAND_STRING @@ -257,9 +258,9 @@ term: /* Constructors for anonymous data */ | ARRAYREF ARRAYREF_END {sp_0($2); (P_expr, Ref(I_array, List[])), sp_pos_range $1 $2} -| arrayref_start ARRAYREF_END {(P_expr, Ref(I_array, List(fst $1))), sp_pos_range $1 $2} -| arrayref_start expr ARRAYREF_END {(P_expr, Ref(I_array, List(fst $1 @ [sndfst $2]))), sp_pos_range $1 $3} -| arrayref_start BRACKET expr BRACKET_END ARRAYREF_END {(P_expr, Ref(I_array, List(fst $1 @ [Ref(I_hash, sndfst $3)]))), sp_pos_range $1 $5} +| arrayref_start ARRAYREF_END {(if fst $1 = [] then sp_0 else sp_p)($2) ; (P_expr, Ref(I_array, List(fst $1))), sp_pos_range $1 $2} +| arrayref_start expr ARRAYREF_END {sp_same $2 $3; (P_expr, Ref(I_array, List(fst $1 @ [sndfst $2]))), sp_pos_range $1 $3} +| arrayref_start BRACKET expr BRACKET_END ARRAYREF_END {sp_same $2 $5; (P_expr, Ref(I_array, List(fst $1 @ [Ref(I_hash, sndfst $3)]))), sp_pos_range $1 $5} | BRACKET BRACKET_END {(P_expr, Ref(I_hash, List [])), sp_pos_range $1 $2} /* empty hash */ | BRACKET_HASHREF expr BRACKET_END %prec PREC_HIGH {sp_p($3); (P_expr, Ref(I_hash, sndfst $2)), sp_pos_range $1 $3} /* { foo => "Bar" } */ @@ -300,12 +301,12 @@ term: | NEW word terminal { die_rule "you must parenthesize parameters: \"new Class(...)\" instead of \"new Class ...\"" } | NEW word variable { die_rule "you must parenthesize parameters: \"new Class(...)\" instead of \"new Class ...\"" } -| PRINT { (P_call_no_paren, Call_op("print", var_STDOUT :: [ var_dollar_ ])), snd $1} -| PRINT argexpr {check_parenthesized_first_argexpr (fst $1) $2; (P_call_no_paren, Call_op("print", var_STDOUT :: sndfst $2)), sp_pos_range $1 $2} -| PRINT_TO_SCALAR { (P_call_no_paren, Call_op("print", var_STDOUT :: [ Deref(I_scalar, Ident(None, fst $1, get_pos $1)) ])), snd $1} -| PRINT_TO_SCALAR argexpr { (P_call_no_paren, Call_op("print", Deref(I_scalar, Ident(None, fst $1, get_pos $1)) :: sndfst $2)), sp_pos_range $1 $2} -| PRINT_TO_STAR { (P_call_no_paren, Call_op("print", Deref(I_star, Ident(None, fst $1, get_pos $1)) :: [ var_dollar_ ])), snd $1} -| PRINT_TO_STAR argexpr { (P_call_no_paren, Call_op("print", Deref(I_star, Ident(None, fst $1, get_pos $1)) :: sndfst $2)), sp_pos_range $1 $2} +| PRINT { (P_call_no_paren, Call_op(fst $1, var_STDOUT :: [ var_dollar_ ])), snd $1} +| PRINT argexpr {check_parenthesized_first_argexpr (fst $1) $2; (P_call_no_paren, Call_op(fst $1, var_STDOUT :: sndfst $2)), sp_pos_range $1 $2} +| PRINT_TO_SCALAR { (P_call_no_paren, Call_op(fstfst $1, var_STDOUT :: [ Deref(I_scalar, Ident(None, sndfst $1, get_pos $1)) ])), snd $1} +| PRINT_TO_SCALAR argexpr { (P_call_no_paren, Call_op(fstfst $1, Deref(I_scalar, Ident(None, sndfst $1, get_pos $1)) :: sndfst $2)), sp_pos_range $1 $2} +| PRINT_TO_STAR { (P_call_no_paren, Call_op(fstfst $1, Deref(I_star, Ident(None, sndfst $1, get_pos $1)) :: [ var_dollar_ ])), snd $1} +| PRINT_TO_STAR argexpr { (P_call_no_paren, Call_op(fstfst $1, Deref(I_star, Ident(None, sndfst $1, get_pos $1)) :: sndfst $2)), sp_pos_range $1 $2} | hash PKG_SCOPE {sp_0($2); (P_tok, Too_complex), sp_pos_range $1 $2} /* %main:: */ @@ -371,7 +372,6 @@ my_our: /* Things that can be "my"'d */ | MY_OUR SCALAR_IDENT {My_our(fst $1, [I_scalar, sndfst $2], get_pos $2), sp_pos_range $1 $2} | MY_OUR HASH_IDENT {My_our(fst $1, [I_hash, sndfst $2], get_pos $2), sp_pos_range $1 $2} | MY_OUR ARRAY_IDENT {My_our(fst $1, [I_array, sndfst $2], get_pos $2), sp_pos_range $1 $2} -| MY_OUR STAR_IDENT {if fst $1 <> "our" then die_rule "syntax error"; My_our(fst $1, [I_star, sndfst $2], get_pos $2), sp_pos_range $1 $2} my_our_paren: | MY_OUR PAREN {sp_1($2); ((true, fst $1), []), sp_pos_range $1 $2} diff --git a/perl_checker.src/perl_checker.ml b/perl_checker.src/perl_checker.ml index 9da3726..0247919 100644 --- a/perl_checker.src/perl_checker.ml +++ b/perl_checker.src/perl_checker.ml @@ -32,10 +32,10 @@ let rec parse_file state file = Info.start_a_new_file file ; let tokens = Lexer.get_token Lexer.token lexbuf in let t = Parser_helper.parse_tokens Parser.prog tokens (Some lexbuf) in - let package = get_global_info_from_package t in - Tree.get_global_vars_declaration state package ; + let required_packages, package = get_global_info_from_package t in + Tree.get_vars_declaration state package ; let state = { state with per_package = (package.package_name, package) :: state.per_package } in - let state = List.fold_left parse_package_if_needed state package.uses in + let state = List.fold_left parse_package_if_needed state (required_packages @ List.map (fun (s, (_, pos)) -> s, pos) package.uses) in state with Failure s -> ( prerr_endline s ; @@ -43,7 +43,7 @@ let rec parse_file state file = ) with _ -> failwith ("bad file " ^ file) -and parse_package_if_needed state (package_name, (_, pos)) = +and parse_package_if_needed state (package_name, pos) = if List.mem_assoc package_name state.per_package then state else try let package = snd (List.hd state.per_package) in diff --git a/perl_checker.src/tree.ml b/perl_checker.src/tree.ml index 3f8a949..33cc111 100644 --- a/perl_checker.src/tree.ml +++ b/perl_checker.src/tree.ml @@ -14,6 +14,7 @@ type uses = (string * ((context * string) list option * pos)) list type per_package = { file_name : string ; package_name : string ; has_package_name : bool ; + vars_declared : (context * string, pos) Hashtbl.t ; exports : exports ; uses : uses ; body : fromparser list; @@ -28,7 +29,8 @@ type vars = { my_vars : (context * string) list list ; our_vars : (context * string) list list ; imported : ((context * string) * string) list ; - current_package : string ; + required_vars : (context * string * string) list ; + current_package : per_package ; state : state ; } @@ -139,7 +141,7 @@ let get_exported t = let uses_external_package = function | "vars" | "MDK::Common::Globals" | "Exporter" | "diagnostics" | "strict" | "lib" | "POSIX" - | "Config" | "Socket" | "Net::FTP" | "IO::Socket" | "DynaLoader" -> true + | "Config" | "Socket" | "Net::FTP" | "IO::Socket" | "DynaLoader" | "Data::Dumper" -> true | _ -> false let get_uses t = @@ -153,33 +155,21 @@ let get_uses t = | _ -> uses ) [] t -let get_global_info_from_package t = - let exports = get_exported t in - let uses = get_uses t in - let current_package = get_current_package t in - let package_name = - match current_package with - | None -> - if exports.export_ok <> [] || exports.export_auto <> [] || exports.export_tags <> [] then - die_with_pos (!Info.current_file, 0, 0) "file with no \"package\" wants to export!" - else - (incr anonymous_package_count ; sprintf "anonymous%d" !anonymous_package_count) - | Some name -> name - in { file_name = !Info.current_file ; package_name = package_name; has_package_name = current_package <> None ; exports = exports ; uses = uses ; body = t } - -let get_global_vars_declaration state package = +let get_vars_declaration state package = List.iter (function - | Sub_declaration(Ident(fq, name, pos), _proto, _) -> - Hashtbl.add state.global_vars_declared (I_func, some_or fq package.package_name, name) pos + | Sub_declaration(Ident(None, name, pos), _proto, _) -> + Hashtbl.replace package.vars_declared (I_func, name) pos + | Sub_declaration(Ident(Some fq, name, pos), _proto, _) -> + Hashtbl.replace state.global_vars_declared (I_func, fq, name) pos | List [ Call_op("=", [My_our("our", ours, pos); _]) ] | List [ My_our("our", ours, pos) ] | My_our("our", ours, pos) -> - List.iter (fun (context, name) -> Hashtbl.add state.global_vars_declared (context, package.package_name, name) pos) ours + List.iter (fun (context, name) -> Hashtbl.replace package.vars_declared (context, name) pos) ours | Use(Ident(Some "MDK::Common", "Globals", pos), [ String _ ; ours ]) | Use(Ident(None, "vars", pos), [ours]) -> - List.iter (fun (context, name) -> Hashtbl.add state.global_vars_declared (context, package.package_name, name) pos) (from_qw ours) + List.iter (fun (context, name) -> Hashtbl.replace package.vars_declared (context, name) pos) (from_qw ours) | Use(Ident(None, "vars", pos), _) -> die_with_pos pos "usage: \"use vars qw($var func)\"" | _ -> () @@ -270,12 +260,47 @@ and fold_tree_option f env = function | Some e -> fold_tree f env e +let get_global_info_from_package t = + let exports = get_exported t in + let uses = get_uses t in + let current_package = get_current_package t in + let package_name = + match current_package with + | None -> + if exports.export_ok <> [] || exports.export_auto <> [] || exports.export_tags <> [] then + die_with_pos (!Info.current_file, 0, 0) "file with no \"package\" wants to export!" + else + (incr anonymous_package_count ; sprintf "anonymous%d" !anonymous_package_count) + | Some name -> name + in + let required_packages = List.fold_left (fold_tree (fun l -> + function + | Call(Deref(I_func, Ident (None, "require", pos)), [Raw_string (package, _)]) + when not (uses_external_package package) -> Some((package, pos) :: l) + | _ -> None) + ) [] t in + required_packages, { + file_name = !Info.current_file ; + package_name = package_name; + has_package_name = current_package <> None ; + exports = exports ; + vars_declared = Hashtbl.create 16 ; + uses = uses ; + body = t ; + } + + let is_my_declared vars t = List.exists (List.exists ((=) t)) vars.my_vars let is_our_declared vars t = List.exists (List.exists ((=) t)) vars.our_vars +let is_var_declared vars (context, name) = + List.mem_assoc (context, name) vars.imported || + Hashtbl.mem vars.current_package.vars_declared (context, name) let is_global_var_declared vars (context, fq, name) = - fq = None && List.mem_assoc (context, name) vars.imported || - (let fq = some_or fq vars.current_package in - Hashtbl.mem vars.state.global_vars_declared (context, fq, name)) + Hashtbl.mem vars.state.global_vars_declared (context, fq, name) || + (try + let package = List.assoc fq vars.state.per_package in + Hashtbl.mem package.vars_declared (context, name) + with Not_found -> false) @@ -283,7 +308,7 @@ let is_global_var context ident = match context with | I_scalar -> (match ident with - | "_" | "@" | "!" | ">" | "\\" | "$" | "^A" | "'" | "/" | "?" | "<" | "^W" | "|" | "^I" + | "_" | "@" | "!" | ">" | "\\" | "$" | "^A" | "'" | "/" | "?" | "<" | "^W" | "|" | "^I" | "&" | "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" -> true | _ -> false) | I_array -> @@ -313,7 +338,7 @@ let is_global_var context ident = | "map" | "mkdir" | "next" | "no" | "oct" | "open" | "opendir" | "ord" | "pack" | "pipe" | "pop" | "print" | "printf" | "push" | "quotemeta" | "rand" | "read" | "readdir" | "readlink" | "redo" | "ref" | "rename" | "require" | "return" | "reverse" | "rmdir" - | "scalar" | "select" | "setpwent" | "shift" | "sleep" | "sort" | "splice" | "split" | "sprintf" | "stat" | "substr" + | "scalar" | "seek" | "select" | "setpwent" | "shift" | "sleep" | "sort" | "splice" | "split" | "sprintf" | "stat" | "substr" | "symlink" | "syscall" | "sysopen" | "sysread" | "sysseek" | "system" | "syswrite" | "time" | "uc" | "umask" | "undef" | "unlink" | "unpack" | "unshift" | "utime" | "values" | "vec" | "waitpid" | "wantarray" | "warn" | "write" -> true @@ -325,21 +350,17 @@ let check_variable (context, var) vars = match var with | Ident(Some pkg, _, _) when uses_external_package pkg || List.mem pkg !ignored_packages -> () | Ident(None, ident, pos) -> - if is_my_declared vars (context, ident) || is_our_declared vars (context, ident) || is_global_var context ident || is_global_var_declared vars (context, None, ident) + if is_my_declared vars (context, ident) || is_our_declared vars (context, ident) || is_global_var context ident || is_var_declared vars (context, ident) then () else warn_with_pos pos (if context = I_func then "unknown function " ^ ident else "undeclared variable " ^ variable2s(context, ident)) - | Ident(Some fq, name, pos) when context = I_func -> - if (fq = "CORE") && is_global_var context name || is_global_var_declared vars (context, Some fq, name) - then () - else ( - warn_with_pos pos ("unknown function " ^ Parser_helper.string_of_Ident var) - ) | Ident(Some fq, name, pos) -> - if is_global_var_declared vars (context, Some fq, name) + if (fq = "CORE") && is_global_var context name || is_global_var_declared vars (context, fq, name) then () - else ( - lpush vars.state.global_vars_used ((context, fq, name), pos) - ) + else + if context = I_func then + warn_with_pos pos ("unknown function " ^ Parser_helper.string_of_Ident var) + else + lpush vars.state.global_vars_used ((context, fq, name), pos) | _ -> () let declare_My vars (mys, pos) = @@ -356,7 +377,7 @@ let declare_My vars (mys, pos) = let declare_Our vars (ours, pos) = match vars.our_vars with - | [] -> vars (* we're at the toplevel, already declared in global_vars_declared *) + | [] -> vars (* we're at the toplevel, already declared in vars_declared *) | l_pre :: other -> List.iter (fun v -> if List.exists ((=) v) l_pre then warn_with_pos pos (sprintf "redeclared variable \"%s\"" (variable2s v)) @@ -375,15 +396,13 @@ let check_variables vars t = let rec check_variables_ vars t = fold_tree check vars t and check vars = function | Block l -> - let vars = { vars with my_vars = [] :: vars.my_vars ; our_vars = [] :: vars.our_vars } in - let vars = List.fold_left check_variables_ vars l in - let vars = { vars with my_vars = List.tl vars.my_vars ; our_vars = List.tl vars.our_vars } in + let vars' = { vars with my_vars = [] :: vars.my_vars ; our_vars = [] :: vars.our_vars } in + let _vars' = List.fold_left check_variables_ vars' l in Some vars | Call(Deref(I_func, Ident(None, "sort", _)), (Anonymous_sub(Block f) :: l)) -> let vars = List.fold_left check_variables_ vars l in - let vars = { vars with my_vars = [ I_scalar, "a" ; I_scalar, "b" ] :: vars.my_vars ; our_vars = [] :: vars.our_vars } in - let vars = List.fold_left check_variables_ vars f in - let vars = { vars with my_vars = List.tl vars.my_vars ; our_vars = List.tl vars.our_vars } in + let vars' = { vars with my_vars = [ I_scalar, "a" ; I_scalar, "b" ] :: vars.my_vars ; our_vars = [] :: vars.our_vars } in + let _vars' = List.fold_left check_variables_ vars' f in Some vars | Call_op("foreach my", [my; expr; Block block]) -> @@ -391,10 +410,9 @@ let check_variables vars t = let vars = check_variables_ vars (Block (my :: block)) in Some vars | Call_op(op, cond :: Block first_bl :: other) when op = "if" || op = "while" || op = "unless" || op = "until" -> - let vars = { vars with my_vars = [] :: vars.my_vars ; our_vars = [] :: vars.our_vars } in - let vars = check_variables_ vars cond in - let vars = List.fold_left check_variables_ vars first_bl in - let vars = { vars with my_vars = List.tl vars.my_vars ; our_vars = List.tl vars.our_vars } in + let vars' = { vars with my_vars = [] :: vars.my_vars ; our_vars = [] :: vars.our_vars } in + let vars' = check_variables_ vars' cond in + let _vars' = List.fold_left check_variables_ vars' first_bl in let vars = List.fold_left check_variables_ vars other in Some vars @@ -420,10 +438,23 @@ let check_variables vars t = if op = "=" then (* check e first *) let vars = check_variables_ vars e in + List.iter (fun (context, var) -> + if context = I_hash || context = I_array then die_with_pos pos (sprintf "%s takes all the arguments, %s is undef in any case" (variable2s (context, var)) (variable2s (last mys))) + ) (removelast mys) ; (* mys is never empty *) Some(declare_My_our vars (my_or_our, mys, pos)) else (warn_with_pos pos "weird" ; None) + | Call(Deref(I_func, Ident(None, "require", _)), [Raw_string (package_name, _)]) -> + (try + let package = List.assoc package_name vars.state.per_package in + let required_vars = Hashtbl.fold (fun (context, ident) _ l -> + (context, vars.current_package.package_name, ident) :: l + ) package.vars_declared vars.required_vars in + let vars = { vars with required_vars = required_vars } in + Some vars + with Not_found -> Some vars) + | _ -> None in let vars = List.fold_left check_variables_ { vars with my_vars = [[]] } t in @@ -431,6 +462,6 @@ let check_variables vars t = let check_tree state package = let imports = get_imports state package in - let vars = { my_vars = [[]]; our_vars = []; imported = imports; current_package = package.package_name; state = state } in + let vars = { my_vars = [[]]; our_vars = []; imported = imports; required_vars = []; current_package = package; state = state } in let _vars = check_variables vars package.body in () diff --git a/perl_checker.src/tree.mli b/perl_checker.src/tree.mli index c655994..769b513 100644 --- a/perl_checker.src/tree.mli +++ b/perl_checker.src/tree.mli @@ -13,6 +13,7 @@ type uses = (string * ((context * string) list option * pos)) list type per_package = { file_name : string ; package_name : string ; has_package_name : bool ; + vars_declared : (context * string, pos) Hashtbl.t; exports : exports ; uses : uses ; body : fromparser list; @@ -26,8 +27,8 @@ type state = { val ignored_packages : string list ref val default_state : state -val get_global_info_from_package : fromparser list -> per_package -val get_global_vars_declaration : state -> per_package -> unit +val get_global_info_from_package : fromparser list -> (string * pos) list * per_package +val get_vars_declaration : state -> per_package -> unit val check_tree : state -> per_package -> unit val die_with_pos : string * int * int -> string -> 'a |