| 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 | 
 | 
| 11 | namespace flag_util {
 | 
| 12 | 
 | 
| 13 | using runtime_asdl::flag_type_e;
 | 
| 14 | using value_asdl::value;
 | 
| 15 | using value_asdl::value_t;
 | 
| 16 | 
 | 
| 17 | void _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 | 
 | 
| 30 | void _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 | 
 | 
| 65 | void _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
 | 
| 136 | template <typename K, typename V>
 | 
| 137 | Dict<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?
 | 
| 144 | flag_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 | 
 | 
| 170 | flag_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 | 
 | 
| 192 | using arg_types::kFlagSpecs;
 | 
| 193 | using arg_types::kFlagSpecsAndMore;
 | 
| 194 | 
 | 
| 195 | flag_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 | 
 | 
| 213 | flag_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
 |