14
14
15
15
-module (r2j_compile ).
16
16
17
- -export ([scan_file /2 , scan_string /2 ]).
18
17
-export ([simplify_fields /1 ]).
19
18
-export ([type_declaration /2 , export_type_declaration /2 , export_declaration /2 , export_declaration /3 , additional_funcs /3 ]).
20
19
34
33
-define (log (Msg ), ? log (Msg , [])).
35
34
-endif .
36
35
37
- scan_file (Hrl , Opts ) ->
38
- Imports = proplists :get_value (imports_dir , Opts , []),
39
- {ok , Handle } = epp :open (Hrl , Imports , []),
40
- {ok , Forms } = read_epp_forms (Handle ),
41
- Modules = analyze_forms (Forms , Opts ),
42
- output (Modules , proplists :get_value (output_dir , Opts , " ." )).
43
-
44
- read_epp_forms (Handle ) ->
45
- read_epp_forms (Handle , []).
46
-
47
- read_epp_forms (Handle , Acc ) ->
48
- case epp :parse_erl_form (Handle ) of
49
- {ok , Form } ->
50
- read_epp_forms (Handle , [Form | Acc ]);
51
- {eof , _L } ->
52
- {ok , lists :reverse (Acc )}
53
- end .
54
-
55
- scan_string (Str , Opts ) ->
56
- % Imports = proplists:get_value(imports_dir, Opts, []),
57
- {ok , Tokens , _Lines } = erl_scan :string (Str ),
58
- LineTokens = split_tokens_by_dots (Tokens ),
59
- Forms = parse_forms (LineTokens ),
60
- Modules = analyze_forms (Forms , Opts ),
61
- output (Modules , proplists :get_value (output_dir , Opts , " ." )).
62
-
63
- split_tokens_by_dots (Tokens ) ->
64
- split_tokens_by_dots (Tokens , []).
65
-
66
- split_tokens_by_dots ([], Acc ) ->
67
- lists :reverse (Acc );
68
-
69
- split_tokens_by_dots (Tokens , Acc ) ->
70
- {SansDot , [Dot | Rest ]} = lists :splitwith (fun is_not_dot /1 , Tokens ),
71
- HasDot = SansDot ++ [Dot ],
72
- split_tokens_by_dots (Rest , [HasDot | Acc ]).
73
-
74
- is_not_dot ({dot , _ }) -> false ;
75
- is_not_dot (_ ) -> true .
76
-
77
- parse_forms (TokenList ) ->
78
- parse_forms (TokenList , []).
79
-
80
- parse_forms ([], Acc ) ->
81
- lists :reverse (Acc );
82
-
83
- parse_forms ([Tokens | Tail ], Acc ) ->
84
- {ok , Form } = erl_parse :parse_form (Tokens ),
85
- parse_forms (Tail , [Form | Acc ]).
86
-
87
- output (Modules , OutputDir ) ->
88
- lists :foreach (fun (Module ) ->
89
- try_write_module (Module , OutputDir )
90
- end , Modules ).
91
-
92
- try_write_module (Module , OutputDir ) ->
93
- case compile :forms (Module , [return ]) of
94
- {ok , ModName , Bin , _Warings } ->
95
- File = filename :join (OutputDir , atom_to_list (ModName ) ++ " .beam" ),
96
- ok = file :write_file (File , Bin );
97
- Else ->
98
- error ({compile_failed , Else , Module })
99
- end .
100
-
101
- analyze_forms (Forms , Params ) ->
102
- analyze_forms (Forms , [], Params ).
103
-
104
- analyze_forms ([], Acc , _Params ) ->
105
- lists :reverse (Acc );
106
-
107
- analyze_forms ([Form | Forms ], Acc , Params ) ->
108
- case erl_syntax :type (Form ) of
109
- attribute ->
110
- case erl_syntax_lib :analyze_attribute (Form ) of
111
- {record , {RecordName , _RecordFields }} ->
112
- SimpleFields = simplify_fields (Form ),
113
- Mod = create_module (RecordName , SimpleFields , Form , Params ),
114
- analyze_forms (Forms , [Mod | Acc ], Params );
115
- _ ->
116
- analyze_forms (Forms , Acc , Params )
117
- end ;
118
- _ ->
119
- analyze_forms (Forms , Acc , Params )
120
- end .
121
-
122
36
simplify_fields ({attribute , _Line , record , {_RecName , Fields }}) ->
123
37
simplify_fields (Fields , []).
124
38
@@ -128,7 +42,7 @@ simplify_fields([], Acc) ->
128
42
simplify_fields ([{record_field , Line , NameForm } | Tail ], Acc ) ->
129
43
Name = erl_parse :normalise (NameForm ),
130
44
FieldRec = # record_field {name = Name , name_form = NameForm ,
131
- default_form = undefined_default (Line ) },
45
+ default_form = undefined_default (Line ), typelist = [ undefined ] },
132
46
simplify_fields (Tail , [FieldRec | Acc ]);
133
47
134
48
simplify_fields ([{record_field , _Line , NameForm , Default } | Tail ], Acc ) ->
@@ -145,7 +59,7 @@ simplify_fields([{typed_record_field, {record_field, Line, NameForm}, Type} | Ta
145
59
end ,
146
60
FieldRec = # record_field {name = Name , name_form = NameForm ,
147
61
default_form = undefined_default (Line ), allow_any = AllowAny ,
148
- typelist = Types },
62
+ typelist = [ undefined | Types ] },
149
63
simplify_fields (Tail , [FieldRec | Acc ]);
150
64
151
65
simplify_fields ([{typed_record_field , {record_field , _L1 , NameForm , Default }, Type } | Tail ], Acc ) ->
@@ -197,7 +111,7 @@ extract_types([{type, _L1, list, ListTypes} | Tail], Acc) ->
197
111
% usual {type, L, record, RecordName}.
198
112
extract_types ([{type , _L1 , record , [{atom , _L2 , RecordName }]} | Tail ], Acc ) ->
199
113
% no way to know if it's a rec2json compiled record, so we'll just go with
200
- % it. If it's not (no to/from json), there's a catch for undef in the
114
+ % it. If it's not (no to/from json), there's a catch for undef in the
201
115
% rec2json module.
202
116
extract_types (Tail , [{record , RecordName } | Acc ]);
203
117
extract_types ([{type , _L1 , Type , TypeArgs } | Tail ], Acc ) ->
@@ -245,14 +159,6 @@ supported_type(record, _) ->
245
159
supported_type (_ ,_ ) ->
246
160
false .
247
161
248
- create_module (RecordName , Fields , RecordDecl , Params ) ->
249
- {ok , ModuleDeclaration } = module_declaration (RecordName ),
250
- {ok , Type } = type_declaration (RecordName , Params ),
251
- {ok , ExportType } = export_type_declaration (RecordName , Params ),
252
- {ok , ExportDeclaration } = export_declaration (RecordName , Fields , Params ),
253
- {ok , NewFunctions } = additional_funcs (RecordName , Fields , Params ),
254
- [ModuleDeclaration , RecordDecl , ExportDeclaration ] ++ Type ++ ExportType ++ NewFunctions .
255
-
256
162
type_declaration (RecordName , Params ) ->
257
163
case proplists :get_value (generate_type , Params , true ) of
258
164
false ->
@@ -298,7 +204,6 @@ additional_funcs(RecordName, Fields, Params) ->
298
204
{ok , FromJsonA1 } = from_json_arity1_func (RecordName , Fields ),
299
205
{ok , FromJsonA2 } = from_json_arity2_func (RecordName , Fields ),
300
206
{ok , FromJsonA3 } = from_json_arity3_func (),
301
- ScrubKeys = scrub_keys_func (Fields ),
302
207
GrandFuncList = []
303
208
++ AccessorFuncs
304
209
++ SetterFuncs
@@ -310,12 +215,8 @@ additional_funcs(RecordName, Fields, Params) ->
310
215
++ [FromJsonA1 ]
311
216
++ [FromJsonA2 ]
312
217
++ [FromJsonA3 ]
313
- ++ ScrubKeys
314
218
, {ok , GrandFuncList }.
315
219
316
- module_declaration (Name ) ->
317
- {ok , {attribute , 1 , module , Name }}.
318
-
319
220
export_declaration (RecordName , Fields ) ->
320
221
export_declaration (RecordName , Fields , []).
321
222
@@ -476,113 +377,84 @@ blank_record(RecName, Fields) ->
476
377
ElementList = [{atom , ? LINE , RecName } | ValueListSansName ],
477
378
{tuple , ? LINE , ElementList }.
478
379
479
- scrub_keys_func (Fields ) ->
480
- TopScrub = {function , ? LINE , scrub_keys , 1 , [
481
- {clause , ? LINE , [{var , ? LINE , 'Json' }], [], [
482
- {call , ? LINE , {atom , ? LINE , scrub_keys }, [{var , ? LINE , 'Json' }, {nil , ? LINE }]}
483
- ]}
484
- ]},
485
- EndScrubClause = scrub_key_end (),
486
- CatchBinClauses = lists :map (fun scrub_key_clause /1 , Fields ),
487
- CatchAtomClause = scrub_key_catch_atom (),
488
- CatchAllClause = scrub_key_catch_all (),
489
- AllClauses = [EndScrubClause ] ++ CatchBinClauses ++ [CatchAtomClause , CatchAllClause ],
490
-
491
- ScrubKeys = {function , ? LINE , scrub_keys , 2 , AllClauses },
492
-
493
- [TopScrub , ScrubKeys ].
494
-
495
- scrub_key_catch_atom () ->
496
- KeyValueMatch = {match , ? LINE , {tuple , ? LINE , [{var , ? LINE , 'Key' }, {var , ? LINE , '_' }]}, {var , ? LINE , 'Head' }},
497
- Arg1 = {cons , ? LINE , KeyValueMatch , {var , ? LINE , 'Tail' }},
498
- Arg2 = {var , ? LINE , 'Acc' },
499
- ArgsList = [Arg1 , Arg2 ],
500
- GuardList = [[{call , ? LINE , {atom , ? LINE , is_atom }, [{var , ? LINE , 'Key' }]}]],
501
- CallList = [
502
- {call , ? LINE , {atom , ? LINE , scrub_keys }, [
503
- {var , ? LINE , 'Tail' }, {cons , ? LINE , {var , ? LINE , 'Head' }, {var , ? LINE , 'Acc' }}
504
- ]}
505
- ],
506
- {clause , ? LINE , ArgsList , GuardList , CallList }.
507
-
508
- scrub_key_catch_all () ->
509
- {clause , ? LINE , [{cons , ? LINE , {var , ? LINE , '_' }, {var , ? LINE , 'Tail' }}, {var , ? LINE , 'Acc' }], [], [
510
- {call , ? LINE , {atom , ? LINE , scrub_keys }, [{var , ? LINE , 'Tail' }, {var , ? LINE , 'Acc' }]}
511
- ]}.
512
-
513
- scrub_key_end () ->
514
- {clause , ? LINE , [{nil , ? LINE }, {var , ? LINE , 'Acc' }], [], [
515
- {call , ? LINE , {remote , ? LINE , {atom , ? LINE , lists }, {atom , ? LINE , reverse }}, [{var , ? LINE , 'Acc' }]}
516
- ]}.
517
-
518
- scrub_key_clause (FieldRec ) ->
519
- NameAsBin = {bin , ? LINE , [
520
- {bin_element , ? LINE , {string , ? LINE , atom_to_list (FieldRec # record_field .name ) }, default , default }
521
- ]},
522
- ArgOneHead = {tuple , ? LINE , [NameAsBin , {var , ? LINE , 'Value' }]},
523
- ArgOneTail = {var , ? LINE , 'Tail' },
524
- ArgOne = {cons , ? LINE , ArgOneHead , ArgOneTail },
525
- ArgsList = [ArgOne , {var , ? LINE , 'Acc' }],
526
-
527
- AccOnTop = {cons , ? LINE , {tuple , ? LINE , [{atom , ? LINE , FieldRec # record_field .name }, {var , ? LINE , 'Value' }]}, {var , ? LINE , 'Acc' }},
528
-
529
- RecursiveCall = {call , ? LINE , {atom , ? LINE , scrub_keys }, [{var , ? LINE , 'Tail' }, AccOnTop ]},
530
- {clause , ? LINE , ArgsList , [], [RecursiveCall ]}.
531
-
532
380
from_json_arity1_func (RecName , Fields ) ->
533
381
BlankTuple = blank_record (RecName , Fields ),
534
382
{ok , {function , ? LINE , from_json , 1 , [
535
383
{clause , ? LINE , [{var , ? LINE , 'Json' }], [], [
536
- {match , ? LINE , {var , ? LINE , 'Json2' }, {call , ? LINE , {atom , ? LINE , scrub_keys }, [{var , ? LINE , 'Json' }]}},
537
- {call , ? LINE , {remote , ? LINE , {atom , ? LINE , rec2json }, {atom , ? LINE , from_json }}, [BlankTuple , {var , ? LINE , 'Json2' }, {nil , ? LINE }]}
384
+ {call , ? LINE , {remote , ? LINE , {atom , ? LINE , rec2json }, {atom , ? LINE , from_json }}, [BlankTuple , {var , ? LINE , 'Json' }, {nil , ? LINE }]}
538
385
]}
539
386
]}}.
540
387
541
388
from_json_arity2_func (RecName , Fields ) ->
542
389
BlankRec = blank_record (RecName , Fields ),
543
390
{ok ,{function , ? LINE ,from_json ,2 , [
544
- from_json_arity2_clause1 (BlankRec ),
545
- from_json_arity2_clause2 (),
546
- from_json_arity2_clause3 ()
391
+ from_json_arity2_no_seed_json_first (BlankRec ),
392
+ from_json_arity2_no_seed_json_second (BlankRec ),
393
+ from_json_arity2_seed_first (),
394
+ from_json_arity2_seed_second ()
547
395
]}}.
548
-
549
- from_json_arity2_clause1 (BlankRec ) ->
396
+
397
+ from_json_arity2_no_seed_json_first (BlankRec ) ->
550
398
Args = [{var , ? LINE , 'Json' }, {var , ? LINE , 'Opts' }],
551
399
Guards = [[
552
- {call , ? LINE , {atom , ? LINE , is_list }, [{var , ? LINE , 'Json' }]},
400
+ {call , ? LINE , {atom , ? LINE , is_map }, [{var , ? LINE , 'Json' }]},
553
401
{call , ? LINE , {atom , ? LINE , is_list }, [{var , ? LINE , 'Opts' }]}
554
402
]],
555
403
Expressions = [
556
404
{call , ? LINE , {atom , ? LINE , from_json }, [BlankRec , {var , ? LINE , 'Json' }, {var , ? LINE , 'Opts' }]}
557
405
],
558
406
{clause , ? LINE , Args , Guards , Expressions }.
559
407
560
- from_json_arity2_clause2 () ->
408
+ from_json_arity2_no_seed_json_second (BlankRec ) ->
409
+ Args = [{var , ? LINE , 'Opts' }, {var , ? LINE , 'Json' }],
410
+ Guards = [[
411
+ {call , ? LINE , {atom , ? LINE , is_map }, [{var , ? LINE , 'Json' }]},
412
+ {call , ? LINE , {atom , ? LINE , is_list }, [{var , ? LINE , 'Opts' }]}
413
+ ]],
414
+ Expressions = [
415
+ {call , ? LINE , {atom , ? LINE , from_json }, [BlankRec , {var , ? LINE , 'Json' }, {var , ? LINE , 'Opts' }]}
416
+ ],
417
+ {clause , ? LINE , Args , Guards , Expressions }.
418
+
419
+ from_json_arity2_seed_first () ->
561
420
Args = [{var , ? LINE , 'Struct' }, {var , ? LINE , 'Json' }],
562
421
Guards = [[
563
- {call , ? LINE , {atom , ? LINE , is_tuple }, [{var , ? LINE , 'Struct' }]}
422
+ {call , ? LINE , {atom , ? LINE , is_tuple }, [{var , ? LINE , 'Struct' }]},
423
+ {call , ? LINE , {atom , ? LINE , is_map }, [{var , ? LINE , 'Json' }]}
564
424
]],
565
425
Expressions = [
566
426
{call , ? LINE , {atom , ? LINE , from_json }, [{var , ? LINE , 'Struct' }, {var , ? LINE , 'Json' }, {nil , ? LINE }]}
567
427
],
568
428
{clause , ? LINE , Args , Guards , Expressions }.
569
-
570
- from_json_arity2_clause3 () ->
429
+
430
+ from_json_arity2_seed_second () ->
571
431
Args = [{var , ? LINE , 'Json' }, {var , ? LINE , 'Struct' }],
572
- Guards = [],
432
+ Guards = [[
433
+ {call , ? LINE , {atom , ? LINE , is_tuple }, [{var , ? LINE , 'Struct' }]},
434
+ {call , ? LINE , {atom , ? LINE , is_map }, [{var , ? LINE , 'Json' }]}
435
+ ]],
573
436
Expressions = [
574
437
{call , ? LINE , {atom , ? LINE , from_json }, [{var , ? LINE , 'Struct' }, {var , ? LINE , 'Json' }, {nil , ? LINE }]}
575
438
],
576
439
{clause , ? LINE , Args , Guards , Expressions }.
577
440
578
441
from_json_arity3_func () ->
579
- {ok ,{function , ? LINE , from_json ,3 , [
580
- {clause , ? LINE , [{var , ? LINE , 'Struct' },{var , ? LINE , 'Json' },{var , ? LINE , 'Opts' }], [[{call , ? LINE , {atom , ? LINE , is_list },[{var , ? LINE , 'Opts' }]}]], [
581
- {call , ? LINE , {atom , ? LINE , from_json }, [{var , ? LINE , 'Json' }, {var , ? LINE , 'Opts' }, {var , ? LINE , 'Struct' }]}
582
- ]},
583
- {clause , ? LINE , [{var , ? LINE , 'Json' },{var , ? LINE , 'Opts' },{var , ? LINE , 'Struct' }], [], [
584
- {match , ? LINE , {var , ? LINE , 'Json2' }, {call , ? LINE , {atom , ? LINE , scrub_keys },[{var , ? LINE , 'Json' }]}},
585
- {call , ? LINE , {remote , ? LINE , {atom , ? LINE , rec2json },{atom , ? LINE , from_json }}, [{var , ? LINE , 'Struct' }, {var , ? LINE , 'Json2' }, {var , ? LINE , 'Opts' }]}
586
- ]}
587
- ]}}.
588
-
442
+ Gaurds = [[
443
+ {call , ? LINE , {atom , ? LINE , is_tuple }, [{var , ? LINE , 'Struct' }]},
444
+ {call , ? LINE , {atom , ? LINE , is_map }, [{var , ? LINE , 'Json' }]},
445
+ {call , ? LINE , {atom , ? LINE , is_list }, [{var , ? LINE , 'Opts' }]}
446
+ ]],
447
+ RemoteCall = {call , ? LINE , {remote , ? LINE , {atom , ? LINE , rec2json },{atom ,? LINE ,from_json }}, [{var , ? LINE , 'Struct' }, {var , ? LINE , 'Json' }, {var , ? LINE , 'Opts' }]},
448
+ ArgOrders = [
449
+ ['Struct' , 'Json' , 'Opts' ],
450
+ ['Struct' , 'Opts' , 'Json' ],
451
+ ['Json' , 'Struct' , 'Opts' ],
452
+ ['Json' , 'Opts' , 'Struct' ],
453
+ ['Opts' , 'Json' , 'Struct' ],
454
+ ['Opts' , 'Struct' , 'Json' ]
455
+ ],
456
+ Clauses = lists :map (fun (Args ) ->
457
+ Vars = [{var , ? LINE , A } || A <- Args ],
458
+ {clause , ? LINE , Vars , Gaurds , [RemoteCall ]}
459
+ end , ArgOrders ),
460
+ {ok , {function , ? LINE , from_json , 3 , Clauses }}.
0 commit comments