summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--perl_checker.src/common.ml3
-rw-r--r--perl_checker.src/common.mli1
-rw-r--r--perl_checker.src/lexer.mll17
-rw-r--r--perl_checker.src/parser.mly22
-rw-r--r--perl_checker.src/perl_checker.ml8
-rw-r--r--perl_checker.src/tree.ml129
-rw-r--r--perl_checker.src/tree.mli5
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