[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
master
Radu Grigore 4 years ago committed by Facebook GitHub Bot
parent 6536919d6a
commit 6a0f16b463

@ -7,6 +7,66 @@
open! IStd open! IStd
module Ast = ErlangAst 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 to_source_and_cfg module_ =
let source = let source =
@ -22,5 +82,10 @@ let to_source_and_cfg module_ =
| Some path -> | Some path ->
SourceFile.create path SourceFile.create path
in 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) (source, cfg)

@ -9,4 +9,6 @@
(flags (flags
(:standard -open Core -open IStdlib -open IStd -open OpenSource -open IBase (:standard -open Core -open IStdlib -open IStd -open OpenSource -open IBase
-open IR)) -open IR))
(libraries core memtrace IStdlib IBase IR)) (libraries core IStdlib IBase IR)
(preprocess
(pps ppx_compare ppx_sexp_conv)))

Loading…
Cancel
Save