1+ export @meta
2+
3+ """
4+ write_meta_specification(backend, entries)
5+ """
6+ function write_meta_specification end
7+
8+ """
9+ write_meta_specification_entry(backend, F, N, meta)
10+ """
11+ function write_meta_specification_entry end
12+
13+ macro meta (meta_specification)
14+ return generate_meta_expression (__get_current_backend (), meta_specification)
15+ end
16+
17+ struct MetaSpecificationLHSInfo
18+ hash :: UInt
19+ checkname :: Symbol
20+ end
21+
22+ function generate_meta_expression (backend, meta_specification)
23+
24+ if isblock (meta_specification)
25+ generatedfname = gensym (:constraints )
26+ generatedfbody = :(function $ (generatedfname)() $ meta_specification end )
27+ return :($ (generate_meta_expression (backend, generatedfbody))())
28+ end
29+
30+ @capture (meta_specification, (function cs_name_ (cs_args__; cs_kwargs__) cs_body_ end ) | (function cs_name_ (cs_args__) cs_body_ end )) ||
31+ error (" Meta specification language requires full function definition" )
32+
33+ cs_args = cs_args === nothing ? [] : cs_args
34+ cs_kwargs = cs_kwargs === nothing ? [] : cs_kwargs
35+
36+ lhs_dict = Dict {UInt, MetaSpecificationLHSInfo} ()
37+
38+ meta_spec_symbol = gensym (:meta )
39+ meta_spec_symbol_init = :($ meta_spec_symbol = ())
40+
41+ cs_body = postwalk (cs_body) do expression
42+ if @capture (expression, f_ (args__) = meta_)
43+
44+ if ! issymbol (f) || any (a -> ! issymbol (a), args)
45+ error (" Invalid meta specification $(expression) " )
46+ end
47+
48+ lhs = :($ f ($ (args... )))
49+ lhs_hash = hash (lhs)
50+ lhs_info = if haskey (lhs_dict, lhs_hash)
51+ lhs_dict[ lhs_hash ]
52+ else
53+ lhs_checkname = gensym (f)
54+ lhs_info = MetaSpecificationLHSInfo (lhs_hash, lhs_checkname)
55+ lhs_dict[lhs_hash] = lhs_info
56+ end
57+
58+ lhs_checkname = lhs_info. checkname
59+ error_msg = " Meta specification $lhs has been redefined"
60+ meta_entry = write_meta_specification_entry (backend, QuoteNode (f), :(($ (map (QuoteNode, args)... ), )), meta)
61+
62+ return quote
63+ ($ lhs_checkname) && error ($ error_msg)
64+ $ meta_spec_symbol = ($ meta_spec_symbol... , $ meta_entry)
65+ $ lhs_checkname = true
66+ end
67+ end
68+ return expression
69+ end
70+
71+ lhs_checknames_init = map (collect (pairs (lhs_dict))) do pair
72+ lhs_info = last (pair)
73+ lhs_checkname = lhs_info. checkname
74+ return quote
75+ $ lhs_checkname = false
76+ end
77+ end
78+
79+ ret_meta_specification = write_meta_specification (backend, meta_spec_symbol)
80+
81+ res = quote
82+ function $cs_name ($ (cs_args... ); $ (cs_kwargs... ))
83+ $ meta_spec_symbol_init
84+ $ (lhs_checknames_init... )
85+ $ cs_body
86+ $ ret_meta_specification
87+ end
88+ end
89+
90+ return esc (res)
91+ end
0 commit comments