From 6a0f16b4633772c1ea48905468639e612ffa93e3 Mon Sep 17 00:00:00 2001 From: Radu Grigore Date: Fri, 14 May 2021 07:24:36 -0700 Subject: [PATCH] [erl-frontend] Build names environment for resolving functions Summary: Collect imports and exports in a data structure ("names environment") that is easy to look up. Background: A function call f(a1,...,an) is shorthand for m:f(a1,...,an) if there is a -import(m, [..., f/n, ...]); otherwise it is shorthand for c:f(a1,...,an) where c is the current module. There is an implicit import of the special "erlang" module. Any ambiguity (e.g., imported twice, or imported and local) is an error. Also, if there is a -export([..., f/n,...]) then f/n should be marked as public (ProcAttributes) Reviewed By: jvillard Differential Revision: D28290252 fbshipit-source-id: f6d777eb6 --- infer/src/erlang/ErlangTranslator.ml | 67 +++++++++++++++++++++++++++- infer/src/erlang/dune | 4 +- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/infer/src/erlang/ErlangTranslator.ml b/infer/src/erlang/ErlangTranslator.ml index ed3a754fb..46460e151 100644 --- a/infer/src/erlang/ErlangTranslator.ml +++ b/infer/src/erlang/ErlangTranslator.ml @@ -7,6 +7,66 @@ open! IStd module Ast = ErlangAst +module L = Logging + +module UnqualifiedFunction = struct + module T = struct + type t = {name: string; arity: int} [@@deriving sexp, compare] + end + + include T + include Comparable.Make (T) +end + +type module_name = string [@@deriving sexp_of] + +(** [exports] are used to determine which functions are public; [imports] and [current_module] are + used to turn unqualified function references into qualified ones *) +type names_env = + { exports: UnqualifiedFunction.Set.t + ; imports: module_name UnqualifiedFunction.Map.t + ; current_module: module_name } +[@@deriving sexp_of] + +let get_environment module_ : names_env = + let unqualified (f : Ast.function_) : UnqualifiedFunction.t = + match f with + | {module_= ModuleMissing; function_= FunctionName name; arity} -> + {name; arity} + | _ -> + L.die InternalError "expected unqualified function" + in + let init = + { exports= UnqualifiedFunction.Set.empty + ; imports= UnqualifiedFunction.Map.empty (* TODO: auto-import from module "erlang" *) + ; current_module= Printf.sprintf "%s:unknown_module" __FILE__ } + in + let f env (form : Ast.form) = + match form.simple_form with + | Export functions -> + let f exports function_ = Set.add exports (unqualified function_) in + let exports = List.fold ~init:env.exports ~f functions in + {env with exports} + | Import {module_name; functions} -> + let f imports function_ = + let key = unqualified function_ in + match Map.add ~key ~data:module_name imports with + | `Ok imports -> + imports + | `Duplicate -> + L.die InternalError "repeated import: %s/%d" key.name key.arity + in + let imports = List.fold ~init:env.imports ~f functions in + {env with imports} + | Module current_module -> + {env with current_module} + | _ -> + env + in + List.fold ~init ~f module_ + + +let translate_functions _names_env _cfg _module = (* TODO *) () let to_source_and_cfg module_ = let source = @@ -22,5 +82,10 @@ let to_source_and_cfg module_ = | Some path -> SourceFile.create path in - let cfg = (* TODO *) Cfg.create () in + let cfg = + let cfg = Cfg.create () in + let names_env = get_environment module_ in + translate_functions names_env cfg module_ ; + cfg + in (source, cfg) diff --git a/infer/src/erlang/dune b/infer/src/erlang/dune index 36cc80baa..35238bcad 100644 --- a/infer/src/erlang/dune +++ b/infer/src/erlang/dune @@ -9,4 +9,6 @@ (flags (:standard -open Core -open IStdlib -open IStd -open OpenSource -open IBase -open IR)) - (libraries core memtrace IStdlib IBase IR)) + (libraries core IStdlib IBase IR) + (preprocess + (pps ppx_compare ppx_sexp_conv)))