OILS / cpp / frontend_flag_spec.cc View on Github | oilshell.org

231 lines, 161 significant
1// frontend_flag_spec.cc
2
3#include "cpp/frontend_flag_spec.h"
4
5#include "_gen/frontend/arg_types.h"
6#include "mycpp/gc_builtins.h"
7// TODO: This prebuilt header should not be included in the tarball
8// for definition of args::Reader, etc.
9#include "prebuilt/frontend/args.mycpp.h"
10
11namespace flag_util {
12
13using runtime_asdl::flag_type_e;
14using value_asdl::value;
15using value_asdl::value_t;
16
17void _CreateStrList(const char** in, List<BigStr*>* out) {
18 int i = 0;
19 while (true) {
20 const char* s = in[i];
21 if (!s) {
22 break;
23 }
24 // log("a0 %s", s);
25 out->append(StrFromC(s));
26 ++i;
27 }
28}
29
30void _CreateDefaults(DefaultPair_c* in,
31 Dict<BigStr*, value_asdl::value_t*>* out) {
32 int i = 0;
33 while (true) {
34 DefaultPair_c* pair = &(in[i]);
35 if (!pair->name) {
36 break;
37 }
38 value_t* val;
39 switch (pair->typ) {
40 case flag_type_e::Bool:
41 val = Alloc<value::Bool>(pair->val.b);
42 break;
43 case flag_type_e::Int:
44 val = Alloc<value::Int>(pair->val.i);
45 break;
46 case flag_type_e::Float:
47 val = Alloc<value::Float>(pair->val.f);
48 break;
49 case flag_type_e::Str: {
50 const char* s = pair->val.s;
51 if (s == nullptr) {
52 val = value::Undef;
53 } else {
54 val = Alloc<value::Str>(StrFromC(s));
55 }
56 } break;
57 default:
58 FAIL(kShouldNotGetHere);
59 }
60 out->set(StrFromC(pair->name), val);
61 ++i;
62 }
63}
64
65void _CreateActions(Action_c* in, Dict<BigStr*, args::_Action*>* out) {
66 int i = 0;
67 while (true) {
68 Action_c* p = &(in[i]);
69 if (!p->key) {
70 break;
71 }
72 // log("a1 %s", p->name);
73 args::_Action* action = nullptr;
74 switch (p->type) {
75 case ActionType_c::SetToString: {
76 List<BigStr*>* valid = nullptr;
77 if (p->strs) {
78 valid = NewList<BigStr*>();
79 _CreateStrList(p->strs, valid);
80 }
81 auto a = Alloc<args::SetToString>(StrFromC(p->name), false, valid);
82 action = a;
83 } break;
84 case ActionType_c::SetToString_q:
85 action = Alloc<args::SetToString>(StrFromC(p->name), true, nullptr);
86 break;
87 case ActionType_c::SetToInt:
88 action = Alloc<args::SetToInt>(StrFromC(p->name));
89 break;
90 case ActionType_c::SetToFloat:
91 action = Alloc<args::SetToFloat>(StrFromC(p->name));
92 break;
93 case ActionType_c::SetToTrue:
94 action = Alloc<args::SetToTrue>(StrFromC(p->name));
95 break;
96 case ActionType_c::SetAttachedBool:
97 action = Alloc<args::SetAttachedBool>(StrFromC(p->name));
98 break;
99 case ActionType_c::SetOption:
100 action = Alloc<args::SetOption>(StrFromC(p->name));
101 break;
102 case ActionType_c::SetNamedOption: {
103 auto a = Alloc<args::SetNamedOption>(false);
104 if (p->strs) {
105 _CreateStrList(p->strs, a->names);
106 }
107 action = a;
108 } break;
109 case ActionType_c::SetNamedOption_shopt: {
110 auto a = Alloc<args::SetNamedOption>(true);
111 if (p->strs) {
112 _CreateStrList(p->strs, a->names);
113 }
114 action = a;
115 } break;
116 case ActionType_c::SetAction:
117 action = Alloc<args::SetAction>(StrFromC(p->name));
118 break;
119 case ActionType_c::SetNamedAction: {
120 auto a = Alloc<args::SetNamedAction>();
121 if (p->strs) {
122 _CreateStrList(p->strs, a->names);
123 }
124 action = a;
125 } break;
126 }
127
128 if (action) {
129 out->set(StrFromC(p->key), action);
130 }
131 ++i;
132 }
133}
134
135// Convenience function
136template <typename K, typename V>
137Dict<K, V>* NewDict() {
138 return Alloc<Dict<K, V>>();
139}
140
141// "Inflate" the static C data into a heap-allocated ASDL data structure.
142//
143// TODO: Make a GLOBAL CACHE? It could be shared between subinterpreters even?
144flag_spec::_FlagSpec* CreateSpec(FlagSpec_c* in) {
145 auto out = Alloc<flag_spec::_FlagSpec>();
146 out->arity0 = NewList<BigStr*>();
147 out->arity1 = NewDict<BigStr*, args::_Action*>();
148 out->actions_long = NewDict<BigStr*, args::_Action*>();
149 out->plus_flags = NewList<BigStr*>();
150 out->defaults = NewDict<BigStr*, value_asdl::value_t*>();
151
152 if (in->arity0) {
153 _CreateStrList(in->arity0, out->arity0);
154 }
155 if (in->arity1) {
156 _CreateActions(in->arity1, out->arity1);
157 }
158 if (in->actions_long) {
159 _CreateActions(in->actions_long, out->actions_long);
160 }
161 if (in->plus_flags) {
162 _CreateStrList(in->plus_flags, out->plus_flags);
163 }
164 if (in->defaults) {
165 _CreateDefaults(in->defaults, out->defaults);
166 }
167 return out;
168}
169
170flag_spec::_FlagSpecAndMore* CreateSpec2(FlagSpecAndMore_c* in) {
171 auto out = Alloc<flag_spec::_FlagSpecAndMore>();
172 out->actions_short = NewDict<BigStr*, args::_Action*>();
173 out->actions_long = NewDict<BigStr*, args::_Action*>();
174 out->plus_flags = NewList<BigStr*>();
175 out->defaults = NewDict<BigStr*, value_asdl::value_t*>();
176
177 if (in->actions_short) {
178 _CreateActions(in->actions_short, out->actions_short);
179 }
180 if (in->actions_long) {
181 _CreateActions(in->actions_long, out->actions_long);
182 }
183 if (in->plus_flags) {
184 _CreateStrList(in->plus_flags, out->plus_flags);
185 }
186 if (in->defaults) {
187 _CreateDefaults(in->defaults, out->defaults);
188 }
189 return out;
190}
191
192using arg_types::kFlagSpecs;
193using arg_types::kFlagSpecsAndMore;
194
195flag_spec::_FlagSpec* LookupFlagSpec(BigStr* spec_name) {
196 int i = 0;
197 while (true) {
198 const char* name = kFlagSpecs[i].name;
199 if (name == nullptr) {
200 break;
201 }
202 if (str_equals0(name, spec_name)) {
203 // log("%s found", spec_name->data_);
204 return CreateSpec(&kFlagSpecs[i]);
205 }
206
207 i++;
208 }
209 // log("%s not found", spec_name->data_);
210 return nullptr;
211}
212
213flag_spec::_FlagSpecAndMore* LookupFlagSpec2(BigStr* spec_name) {
214 int i = 0;
215 while (true) {
216 const char* name = kFlagSpecsAndMore[i].name;
217 if (name == nullptr) {
218 break;
219 }
220 if (str_equals0(name, spec_name)) {
221 // log("%s found", spec_name->data_);
222 return CreateSpec2(&kFlagSpecsAndMore[i]);
223 }
224
225 i++;
226 }
227 // log("%s not found", spec_name->data_);
228 return nullptr;
229}
230
231} // namespace flag_util