-
Notifications
You must be signed in to change notification settings - Fork 0
/
ast.gleam
148 lines (138 loc) · 3.8 KB
/
ast.gleam
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import glance.{
type Module as AST, Definition, Discarded, Function, Import, Module as AST,
Named, UnqualifiedImport,
}
import gleam/dict
import gleam/list
import gleam/option.{None, Some}
import gleam/string
import internal/fs.{FileContent, FilesDir, ModuleFullName}
pub type FileAst {
FileAst(AST)
}
pub type AnotherFilesAst {
AnotherFilesAst(List(FileAst))
}
pub type ModuleName {
ModuleName(String)
}
type ImportedInfo {
ModuleImported(ModuleName)
ImportedAsAlias
}
pub type PublicMember {
PublicFun(String)
PublicConst(String)
PublicType(String)
}
pub fn files_ast(files_contents) {
use content <- list.map(files_contents)
let assert FileContent(content) = content
let assert Ok(ast) = glance.module(content)
FileAst(ast)
}
pub fn files_paths_with_ast(dir, test_dir) {
let file_paths = fs.files_paths(dir)
let file_paths_idx =
file_paths
|> list.index_map(fn(fp, i) { #(i, fp) })
|> dict.from_list
let flle_contents = fs.files_contents(file_paths)
let test_file_contents = case test_dir {
Some(FilesDir(_) as test_dir) -> {
fs.files_paths(test_dir)
|> fs.files_contents
}
None -> []
}
let ast_list =
flle_contents
|> list.append(test_file_contents)
|> files_ast
let ast_list_idx =
ast_list
|> list.index_map(fn(ast, i) { #(i, ast) })
|> dict.from_list
let indexes = list.range(0, list.length(ast_list) - 1)
use index <- list.filter_map(indexes)
case dict.get(file_paths_idx, index) {
Ok(file_path) -> {
let assert Ok(file_ast) = dict.get(ast_list_idx, index)
Ok(#(
file_path,
file_ast,
AnotherFilesAst(
list.filter_map(indexes, fn(idx) {
case idx == index {
True -> Error(Nil)
False -> dict.get(ast_list_idx, idx)
}
}),
),
))
}
Error(Nil) -> Error(Nil)
}
}
fn imported_info(imports, module_full_name, exported) {
list.filter_map(imports, fn(imp) {
case imp {
Definition(_, Import(import_name, module_alias, type_aliases, aliases))
if ModuleFullName(import_name) == module_full_name
->
case
aliases
|> list.append(type_aliases)
|> list.any(fn(alias) {
let assert UnqualifiedImport(imported, _) = alias
PublicFun(imported) == exported
|| PublicConst(imported) == exported
|| PublicType(imported) == exported
})
{
True -> Ok(ImportedAsAlias)
False ->
case module_alias {
Some(Named(alias)) -> Ok(ModuleImported(ModuleName(alias)))
Some(Discarded(_)) -> Error(Nil)
None ->
Ok(
ModuleImported(module_full_name_to_module_name(
module_full_name,
)),
)
}
}
_ -> Error(Nil)
}
})
}
pub fn is_pub_member_used(
files_ast,
pub_member_name,
module_full_name,
check_usage,
) {
let assert AnotherFilesAst(files_ast) = files_ast
use file_ast <- list.find_map(files_ast)
let assert FileAst(ast) = file_ast
let assert AST(imports, _, _, _, fns) = ast
let imported_info_list =
imported_info(imports, module_full_name, pub_member_name)
use imported_info <- list.find_map(imported_info_list)
case imported_info {
ImportedAsAlias -> Ok(Nil)
ModuleImported(module_name) -> {
use fun_def <- list.find_map(fns)
let assert Definition(_, Function(_, _, _, _, statements, _)) = fun_def
check_usage(statements, pub_member_name, module_name)
}
}
}
fn module_full_name_to_module_name(module_full_name) {
let assert ModuleFullName(module_full_name) = module_full_name
let assert Ok(module_name) =
string.split(module_full_name, "/")
|> list.last
ModuleName(module_name)
}