@@ -4,15 +4,31 @@ defmodule ComponentsGuideWeb.UniversalModulesController do
44 alias ComponentsGuideWeb.UniversalModulesParser , as: Parser
55
66 def index ( conn , _params ) do
7- source = "
7+ source = """
88 const pi = 3.14;
99
10- const answer = 42;
10+ export const answer = 42;
1111 const negativeAnswer = -42;
1212
1313 const isEnabled = true;
1414 const verbose = false;
15- "
15+ const alwaysNull = null;
16+
17+ export const dateFormat = "YYYY/MM/DD";
18+
19+ const array = [1, 2, 3];
20+ const arrayMultiline = [
21+ 4,
22+ 5,
23+ 6
24+ ];
25+ export const flavors = ["vanilla", "chocolate", "caramel", "raspberry"];
26+
27+ const object = { "key": "value" };
28+
29+ function hello() {}
30+ function* gen() {}
31+ """
1632 # decoded = decode_module(source)
1733 decoded = Parser . decode ( source )
1834
@@ -25,123 +41,228 @@ defmodule ComponentsGuideWeb.UniversalModulesController do
2541end
2642
2743defmodule ComponentsGuideWeb.UniversalModulesParser do
28- def switch ( submodule , input , result ) do
44+ def compose ( submodule , input ) do
2945 mod = Module . concat ( __MODULE__ , submodule )
30- apply ( mod , :decode , [ input , result ] )
46+ apply ( mod , :decode , [ input ] )
3147 end
3248
49+ # def decode(input), do: Root.decode(input, [])
3350 def decode ( input ) , do: switch ( Root , input , [ ] )
3451
52+ defp switch ( submodule , input , result ) do
53+ mod = Module . concat ( __MODULE__ , submodule )
54+ apply ( mod , :decode , [ input , result ] )
55+ end
56+
3557 defmodule Root do
58+ defdelegate compose ( submodule , input ) , to: ComponentsGuideWeb.UniversalModulesParser
59+
3660 def decode ( "" , result ) , do: { :ok , Enum . reverse ( result ) }
3761 def decode ( << "\n " , rest :: bitstring >> , result ) , do: decode ( rest , result )
3862 def decode ( << " " , rest :: bitstring >> , result ) , do: decode ( rest , result )
3963 def decode ( << ";" , rest :: bitstring >> , result ) , do: decode ( rest , result )
4064
41- def decode ( << "const " , rest :: bitstring >> , result ) do
42- ComponentsGuideWeb.UniversalModulesParser . switch ( Const , rest , result )
65+ def decode ( << "const " , _ :: bitstring >> = input , result ) do
66+ case compose ( Const , input ) do
67+ { :ok , term , rest } ->
68+ decode ( rest , [ term | result ] )
69+
70+ { :error , reason } ->
71+ { :error , reason }
72+ end
73+ end
74+
75+ def decode ( << "export " , _ :: bitstring >> = input , result ) do
76+ case compose ( Export , input ) do
77+ { :ok , term , rest } ->
78+ decode ( rest , [ term | result ] )
79+
80+ { :error , reason } ->
81+ { :error , reason }
82+ end
83+ end
84+
85+ def decode ( << "function" , _ :: bitstring >> = input , result ) do
86+ case compose ( Function , input ) do
87+ { :ok , term , rest } ->
88+ decode ( rest , [ term | result ] )
89+
90+ { :error , reason } ->
91+ { :error , reason }
92+ end
4393 end
4494
4595 def decode ( input , result ) do
46- { :err , :unexpected_eof , input , result }
96+ { :error , :unexpected_eof , input , result }
4797 end
4898 end
4999
50- defmodule Const do
51- def decode ( input , result ) do
52- decode ( { :expect_identifier , [ ] } , input , result )
100+ defmodule Export do
101+ def decode ( << "export " , rest :: bitstring >> ) do
102+ case ComponentsGuideWeb.UniversalModulesParser . compose ( Const , rest ) do
103+ { :ok , term , rest } ->
104+ { :ok , { :export , term } , rest }
105+
106+ { :error , reason } ->
107+ { :error , reason }
108+ end
109+ end
110+ end
111+
112+ defmodule Function do
113+ def decode ( << "function" , rest :: bitstring >> ) ,
114+ do: decode ( % { generator_mark: nil , name: nil , args: nil , body: nil } , rest )
115+
116+ defp decode ( context , << " " , rest :: bitstring >> ) ,
117+ do: decode ( context , rest )
118+
119+ defp decode ( % { generator_mark: nil , name: nil , args: nil } = context , << "*" , rest :: bitstring >> ) ,
120+ do: decode ( % { context | generator_mark: true } , rest )
121+
122+ defp decode ( % { name: nil , args: nil } = context , << "(" , rest :: bitstring >> ) ,
123+ do: decode ( % { context | args: { :open , [ ] } } , rest )
124+
125+ defp decode ( % { name: reverse_name , args: nil } = context , << "(" , rest :: bitstring >> ) do
126+ name = reverse_name |> Enum . reverse ( ) |> :binary . list_to_bin ( )
127+ decode ( % { context | name: name , args: { :open , [ ] } } , rest )
53128 end
54129
55- defp decode (
56- { :expect_identifier , _ } = context ,
57- << " " , rest :: bitstring >> ,
58- result
59- ) do
60- decode ( context , rest , result )
130+ defp decode ( % { args: { :open , args } } = context , << ")" , rest :: bitstring >> ) ,
131+ do: decode ( % { context | args: { :closed , args } } , rest )
132+
133+ defp decode ( % { args: { :closed , _ } , body: nil } = context , << "{" , rest :: bitstring >> ) ,
134+ do: decode ( % { context | body: { :open , [ ] } } , rest )
135+
136+ defp decode ( % { args: { :closed , args } , name: name , body: { :open , body_items } } = context , << "}" , rest :: bitstring >> ) do
137+ case context . generator_mark do
138+ true ->
139+ { :ok , { :generator_function , name , args , body_items } , rest }
140+
141+ nil ->
142+ { :ok , { :function , name , args , body_items } , rest }
143+ end
61144 end
62145
63- defp decode (
64- { :expect_identifier , reverse_identifier } ,
65- << "=" , rest :: bitstring >> ,
66- result
67- ) do
146+ defp decode ( % { name: nil , args: nil } = context , << char :: utf8 , rest :: bitstring >> ) ,
147+ do: decode ( % { context | name: [ char ] } , rest )
148+
149+ defp decode ( % { name: name , args: nil } = context , << char :: utf8 , rest :: bitstring >> ) do
150+ name = [ char | name ]
151+ decode ( % { context | name: name } , rest )
152+ end
153+ end
154+
155+ defmodule Yield do
156+ def decode ( << "yield " , rest :: bitstring >> ) do
157+ case ComponentsGuideWeb.UniversalModulesParser . compose ( Expression , rest ) do
158+ { :ok , term , rest } ->
159+ { :ok , { :yield , term } , rest }
160+
161+ { :error , reason } ->
162+ { :error , reason }
163+ end
164+ end
165+ end
166+
167+ defmodule Const do
168+ def decode ( << "const " , rest :: bitstring >> ) ,
169+ do: decode ( { :expect_identifier , [ ] } , rest )
170+
171+ defp decode ( { :expect_identifier , _ } = context , << " " , rest :: bitstring >> ) ,
172+ do: decode ( context , rest )
173+
174+ defp decode ( { :expect_identifier , reverse_identifier } , << "=" , rest :: bitstring >> ) do
68175 identifier = reverse_identifier |> Enum . reverse ( ) |> :binary . list_to_bin ( )
69- decode ( { identifier , :expect_expression , [ ] } , rest , result )
176+ decode ( { identifier , :expect_expression , [ ] } , rest )
70177 end
71178
72- defp decode (
73- { :expect_identifier , reverse_identifier } ,
74- << char :: utf8 , rest :: bitstring >> ,
75- result
76- ) do
77- decode ( { :expect_identifier , [ char | reverse_identifier ] } , rest , result )
179+ defp decode ( { :expect_identifier , reverse_identifier } , << char :: utf8 , rest :: bitstring >> ) do
180+ decode ( { :expect_identifier , [ char | reverse_identifier ] } , rest )
78181 end
79182
80183 # Skip whitespace
81- defp decode ( { _ , :expect_expression , [ ] } = context , << " " , rest :: bitstring >> , result ) ,
82- do: decode ( context , rest , result )
83-
84- defp decode (
85- { identifier , :expect_expression , expression } ,
86- << ";" , rest :: bitstring >> ,
87- result
88- ) ,
89- do: Root . decode ( rest , [ { :const , identifier , expression } | result ] )
90-
91- defp decode (
92- { identifier , :expect_expression , [ ] } ,
93- << "true" , rest :: bitstring >> ,
94- result
95- ) do
96- decode ( { identifier , :expect_expression , [ true ] } , rest , result )
97- end
98-
99- defp decode (
100- { identifier , :expect_expression , [ ] } ,
101- << "false" , rest :: bitstring >> ,
102- result
103- ) do
104- decode ( { identifier , :expect_expression , [ false ] } , rest , result )
105- end
106-
107- defp decode (
108- { identifier , :expect_expression , [ ] } ,
109- << "null" , rest :: bitstring >> ,
110- result
111- ) do
112- decode ( { identifier , :expect_expression , [ nil ] } , rest , result )
113- end
114-
115- defp decode (
116- { identifier , :expect_expression , [ ] } = context ,
117- << char :: utf8 , _ :: bitstring >> = source ,
118- result
119- )
120- when char in '0123456789' do
184+ defp decode ( { _ , :expect_expression , [ ] } = context , << " " , rest :: bitstring >> ) ,
185+ do: decode ( context , rest )
186+
187+ defp decode ( { identifier , :expect_expression , expression } , "" ) ,
188+ do: { :ok , { :const , identifier , expression } , "" }
189+
190+ defp decode ( { identifier , :expect_expression , [ ] } , input ) do
191+ case ComponentsGuideWeb.UniversalModulesParser . compose ( Expression , input ) do
192+ { :ok , expression , rest } ->
193+ { :ok , { :const , identifier , expression } , rest }
194+
195+ { :error , error } ->
196+ { :error , { :invalid_expression , error } }
197+ end
198+ end
199+ end
200+
201+ defmodule Expression do
202+ def decode ( input ) , do: decode ( [ ] , input )
203+
204+ defp decode ( expression , << ";" , rest :: bitstring >> ) ,
205+ do: { :ok , expression , rest }
206+
207+ defp decode ( [ ] = context , << " " , rest :: bitstring >> ) , do: decode ( context , rest )
208+ defp decode ( [ ] , << "true" , rest :: bitstring >> ) , do: decode ( true , rest )
209+ defp decode ( [ ] , << "false" , rest :: bitstring >> ) , do: decode ( false , rest )
210+ defp decode ( [ ] , << "null" , rest :: bitstring >> ) , do: decode ( nil , rest )
211+
212+ # TODO: parse JSON by finding the end character followed by a semicolon + newline.
213+ # JSON strings cannoc contain literal newlines (it’s considered to be a control character),
214+ # so instead it must be encoded as "\n". So we can use this fast to know an actual newline is
215+ # outside the JSON value.
216+ # defp decode([], <<"{", rest::bitstring>>), do: decode([nil], rest)
217+ defp decode ( [ ] , << char :: utf8 , _ :: bitstring >> = input ) when char in [ ?[ , ?{ , ?" ] do
218+ [ encoded_json , rest ] = String . split ( input , ";\n " , parts: 2 )
219+ case Jason . decode ( encoded_json ) do
220+ { :ok , value } ->
221+ { :ok , value , rest }
222+
223+ { :error , error } ->
224+ { :error , error }
225+ end
226+ end
227+
228+ defp decode ( [ ] = context , << char :: utf8 , _ :: bitstring >> = source ) when char in '0123456789' do
121229 case Float . parse ( source ) do
122230 :error ->
123- { :err , context , source , result }
231+ { :error , { :invalid_number , context , source } }
124232
125233 { f , rest } ->
126- decode ( { identifier , :expect_expression , [ f ] } , rest , result )
234+ decode ( f , rest )
127235 end
128236 end
129237
130- defp decode (
131- { identifier , :expect_expression , [ ] } = context ,
132- << "-" , char :: utf8 , _ :: bitstring >> = source ,
133- result
134- )
238+ defp decode ( [ ] = context , << "-" , char :: utf8 , _ :: bitstring >> = source )
135239 when char in '0123456789' do
136240 case Float . parse ( source ) do
137241 :error ->
138- { :err , context , source , result }
242+ { :error , { :invalid_number , context , source } }
139243
140244 { f , rest } ->
141- decode ( { identifier , :expect_expression , [ f ] } , rest , result )
245+ decode ( f , rest )
142246 end
143247 end
144248 end
249+
250+ defmodule KnownIdentifier do
251+ defmodule Symbol do
252+ end
253+
254+ defmodule URL do
255+ end
256+
257+ defmodule URLSearchParams do
258+ end
259+
260+ def decode ( << "Symbol" , rest :: bitstring >> ) , do: { :ok , __MODULE__ . Symbol , rest }
261+ def decode ( << "URL" , rest :: bitstring >> ) , do: { :ok , __MODULE__ . URL , rest }
262+ def decode ( << "URLSearchParams" , rest :: bitstring >> ) , do: { :ok , __MODULE__ . URLSearchParams , rest }
263+
264+ def decode ( _ ) , do: { :error , :unknown_identifier }
265+ end
145266end
146267
147268defmodule ComponentsGuideWeb.UniversalModulesView do
0 commit comments