@@ -14,32 +14,53 @@ defmodule ComponentsGuideWeb.UniversalModulesController do
14
14
const verbose = false;
15
15
const alwaysNull = null;
16
16
17
+ const debug = verbose;
18
+
17
19
export const dateFormat = "YYYY/MM/DD";
18
20
21
+ const exampleDotOrg = new URL("https://example.org");
22
+
19
23
const array = [1, 2, 3];
20
24
const arrayMultiline = [
21
25
4,
22
26
5,
23
27
6
24
28
];
25
29
export const flavors = ["vanilla", "chocolate", "caramel", "raspberry"];
30
+ export const flavorsSet = new Set(["vanilla", "chocolate", "caramel", "raspberry"]);
26
31
27
32
const object = { "key": "value" };
28
33
29
34
function hello() {}
30
- function* gen() {}
35
+ function* gen() {
36
+ const a = 1;
37
+ yield [1, 2, 3];
38
+ }
31
39
"""
32
40
# decoded = decode_module(source)
33
41
decoded = Parser . decode ( source )
42
+ identifiers = ComponentsGuideWeb.UniversalModulesInspector . list_identifiers ( elem ( decoded , 1 ) )
34
43
35
44
render ( conn , "index.html" ,
36
45
page_title: "Universal Modules" ,
37
46
source: source ,
38
- decoded: inspect ( decoded )
47
+ decoded: inspect ( decoded ) ,
48
+ identifiers: inspect ( identifiers ) ,
39
49
)
40
50
end
41
51
end
42
52
53
+ defmodule ComponentsGuideWeb.UniversalModulesInspector do
54
+ def is_identifier ( { :const , _ , _ } ) , do: true
55
+ def is_identifier ( { :function , _ , _ , _ } ) , do: true
56
+ def is_identifier ( { :generator_function , _ , _ , _ } ) , do: true
57
+ def is_identifier ( _ ) , do: false
58
+
59
+ def list_identifiers ( module_body ) do
60
+ for statement <- module_body , is_identifier ( statement ) , do: statement
61
+ end
62
+ end
63
+
43
64
defmodule ComponentsGuideWeb.UniversalModulesParser do
44
65
def compose ( submodule , input ) do
45
66
mod = Module . concat ( __MODULE__ , submodule )
@@ -110,6 +131,8 @@ defmodule ComponentsGuideWeb.UniversalModulesParser do
110
131
end
111
132
112
133
defmodule Function do
134
+ defdelegate compose ( submodule , input ) , to: ComponentsGuideWeb.UniversalModulesParser
135
+
113
136
def decode ( << "function" , rest :: bitstring >> ) ,
114
137
do: decode ( % { generator_mark: nil , name: nil , args: nil , body: nil } , rest )
115
138
@@ -136,10 +159,33 @@ defmodule ComponentsGuideWeb.UniversalModulesParser do
136
159
defp decode ( % { args: { :closed , args } , name: name , body: { :open , body_items } } = context , << "}" , rest :: bitstring >> ) do
137
160
case context . generator_mark do
138
161
true ->
139
- { :ok , { :generator_function , name , args , body_items } , rest }
162
+ { :ok , { :generator_function , name , args , Enum . reverse ( body_items ) } , rest }
140
163
141
164
nil ->
142
- { :ok , { :function , name , args , body_items } , rest }
165
+ { :ok , { :function , name , args , Enum . reverse ( body_items ) } , rest }
166
+ end
167
+ end
168
+
169
+ defp decode ( % { body: { :open , _ } } = context , << char :: utf8 , rest :: bitstring >> ) when char in [ ?\n , ?\t , ?; ] ,
170
+ do: decode ( context , rest )
171
+
172
+ defp decode ( % { body: { :open , body_items } } = context , << "const " , _ :: bitstring >> = input ) do
173
+ case compose ( Const , input ) do
174
+ { :ok , term , rest } ->
175
+ decode ( % { context | body: { :open , [ term | body_items ] } } , rest )
176
+
177
+ { :error , reason } ->
178
+ { :error , { reason , body_items } }
179
+ end
180
+ end
181
+
182
+ defp decode ( % { body: { :open , body_items } } = context , << "yield " , _ :: bitstring >> = input ) do
183
+ case compose ( Yield , input ) do
184
+ { :ok , term , rest } ->
185
+ decode ( % { context | body: { :open , [ term | body_items ] } } , rest )
186
+
187
+ { :error , reason } ->
188
+ { :error , { reason , body_items } }
143
189
end
144
190
end
145
191
@@ -168,6 +214,9 @@ defmodule ComponentsGuideWeb.UniversalModulesParser do
168
214
def decode ( << "const " , rest :: bitstring >> ) ,
169
215
do: decode ( { :expect_identifier , [ ] } , rest )
170
216
217
+ def decode ( << _ :: bitstring >> ) ,
218
+ do: { :error , :expected_const }
219
+
171
220
defp decode ( { :expect_identifier , _ } = context , << " " , rest :: bitstring >> ) ,
172
221
do: decode ( context , rest )
173
222
@@ -199,16 +248,47 @@ defmodule ComponentsGuideWeb.UniversalModulesParser do
199
248
end
200
249
201
250
defmodule Expression do
251
+ import Unicode.Guards
252
+
202
253
def decode ( input ) , do: decode ( [ ] , input )
203
254
255
+ defp finalize ( [ { :found_identifier , reverse_identifier } | context_rest ] ) do
256
+ identifier = reverse_identifier |> Enum . reverse ( ) |> :binary . list_to_bin ( )
257
+ [ { :ref , identifier } | context_rest ]
258
+ end
259
+
260
+ defp finalize ( expression ) , do: expression
261
+
204
262
defp decode ( expression , << ";" , rest :: bitstring >> ) ,
205
- do: { :ok , expression , rest }
263
+ do: { :ok , finalize ( expression ) , rest }
206
264
207
265
defp decode ( [ ] = context , << " " , rest :: bitstring >> ) , do: decode ( context , rest )
208
266
defp decode ( [ ] , << "true" , rest :: bitstring >> ) , do: decode ( true , rest )
209
267
defp decode ( [ ] , << "false" , rest :: bitstring >> ) , do: decode ( false , rest )
210
268
defp decode ( [ ] , << "null" , rest :: bitstring >> ) , do: decode ( nil , rest )
211
269
270
+ defp decode ( [ ] , << "new URL(" , rest :: bitstring >> ) do
271
+ [ encoded_json , rest ] = String . split ( rest , ");\n " , parts: 2 )
272
+ case Jason . decode ( encoded_json ) do
273
+ { :ok , value } ->
274
+ { :ok , { :url , value } , rest }
275
+
276
+ { :error , error } ->
277
+ { :error , error }
278
+ end
279
+ end
280
+
281
+ defp decode ( [ ] , << "new Set(" , rest :: bitstring >> ) do
282
+ [ encoded_json , rest ] = String . split ( rest , ");\n " , parts: 2 )
283
+ case Jason . decode ( encoded_json ) do
284
+ { :ok , value } ->
285
+ { :ok , { :set , value } , rest }
286
+
287
+ { :error , error } ->
288
+ { :error , error }
289
+ end
290
+ end
291
+
212
292
# TODO: parse JSON by finding the end character followed by a semicolon + newline.
213
293
# JSON strings cannoc contain literal newlines (it’s considered to be a control character),
214
294
# so instead it must be encoded as "\n". So we can use this fast to know an actual newline is
@@ -245,6 +325,14 @@ defmodule ComponentsGuideWeb.UniversalModulesParser do
245
325
decode ( f , rest )
246
326
end
247
327
end
328
+
329
+ defp decode ( [ ] , << char :: utf8 , rest :: bitstring >> ) when is_lower ( char ) or is_upper ( char ) ,
330
+ do: decode ( [ { :found_identifier , [ char ] } ] , rest )
331
+
332
+ defp decode ( [ { :found_identifier , reverse_identifier } | context_rest ] , << char :: utf8 , rest :: bitstring >> )
333
+ when is_lower ( char ) or is_upper ( char ) or is_digit ( char ) do
334
+ decode ( [ { :found_identifier , [ char | reverse_identifier ] } | context_rest ] , rest )
335
+ end
248
336
end
249
337
250
338
defmodule KnownIdentifier do
0 commit comments