Minsky
typescriptAPI_base.h
Go to the documentation of this file.
1 #ifndef TYPESCRIPT_API_BASE_H
2 #define TYPESCRIPT_API_BASE_H
3 #include "classdesc.h"
4 #include "function.h"
5 #include "stringKeyMap.h"
6 #include <algorithm>
7 #include <numeric>
8 
9 namespace minsky
10 {
11  template <class T, class B> struct ItemT;
12 }
13 
14 namespace classdesc
15 {
16  template< class... > using void_t = void;
17 
18  template <class T> struct is_map: public false_type {};
19  template <class K, class V> struct is_map<std::map<K,V>>: public true_type {};
20 
21 // template <class T, class = void> struct is_iterator: public std::false_type {};
22 //#ifndef MAC_OSX_TK
23 // template <class T, class U> struct is_iterator<__gnu_cxx::__normal_iterator<T,U>>: public true_type {};
24 //#endif
25 
26  // general is_iterator class https://stackoverflow.com/questions/4335962/how-to-check-if-a-template-parameter-is-an-iterator-type-or-not doesn't seem to work
27 // template <class T>
28 // struct is_iterator<T, void_t<typename std::iterator_traits<T>::iterator_category>>:
29 // public std::true_type {};
30 
31  template <class T> struct is_itemT: public false_type {};
32  template <class T, class B> struct is_itemT<minsky::ItemT<T,B>>: public true_type {};
33 
34  template <class T> string typescriptType();
35 
36  // typescriptTypep is for "specialisations" using type_traits
37  template <class T>
38  inline typename enable_if<
39  And<
40  is_arithmetic<T>,
41  And<
42  Not<is_const<T>>,
43  Not<is_same<T,bool>>
44  >
45  >, string>::T
46  typescriptTypep() {return "number";}
47 
48  template <class T>
49  typename enable_if<is_same<T,bool>,string>::T
50  typescriptTypep() {return "boolean";}
51 
52  template <class T>
53  inline typename enable_if<is_function<T>, string>::T
54  typescriptTypep() {return "minsky__dummy";}
55 
57  template <class T>
58  typename enable_if<
59  And<
60  And<
61  is_class<T>,
62  And<
63  Not<is_reference<T>>,
64  Not<is_const<T>>
65  >
66  >,
67  And<
68  And<
69  Not<is_string<T>>,
70  And<
71  Not<is_pointer<T>>,
72  Not<is_itemT<T>>
73  >
74  >,
75  And<
76  And<
77  Not<is_container<T>>,
78  Not<is_iterator<T>>
79  >,
80  And<
81  Not<is_smart_ptr<T>>,
82  Not<is_pair<T>>
83  >
84  >
85  >
86  >, std::string>::T
88  auto cppName=classdesc::typeName<T>();
89  // strip leading "::"
90  if (cppName.substr(0,2)=="::") cppName=cppName.substr(2);
91 
92  // minsky namespaced types to global namespace
93  auto n=cppName.find("minsky::");
94  if (n==0)
95  {
96  int numColons=0;
97  for (char c: cppName)
98  numColons += c==':';
99  if (numColons==2) // not in a sub namespace
100  return cppName.substr(strlen("minsky::"));
101  }
102 
103  std::replace(cppName.begin(), cppName.end(), ':', '_');
104  cppName.erase(std::remove(cppName.begin(), cppName.end(),' '), cppName.end());
105  return cppName;
106  }
107 
108  // enums look like strings to TS
109  template <class T>
110  typename enable_if<is_enum<T>, string>::T
111  typescriptTypep() {return "string";}
112 
113  template <class T>
114  typename enable_if<is_reference<T>, string>::T
115  typescriptTypep() {return typescriptType<typename remove_reference<T>::type>();}
116 
117  template <class T>
118  typename enable_if<is_pointer<T>, string>::T
119  typescriptTypep() {return typescriptType<typename remove_pointer<T>::type>();}
120 
121  template <class T>
122  typename enable_if<is_const<T>,std::string>::T
123  typescriptTypep() {return typescriptType<typename remove_const<T>::type>();}
124 
125  template <class T>
126  typename enable_if<And<is_iterator<T>,Not<is_pointer<T>>>,std::string>::T
127  typescriptTypep() {return "minsky__dummy";}
128 
129  template <class T>
130  typename enable_if<
131  And<
132  And<
133  is_sequence<T>,
134  Not<is_const<T>>
135  >,
136  And<
137  Not<is_arithmetic<typename T::value_type>>,
138  Not<is_string<typename T::value_type>>
139  >
140  >,std::string>::T
141 
142  typescriptTypep() {return "Sequence<"+typescriptType<typename T::value_type>()+">";}
143 
144  template <class T>
145  typename enable_if<
146  And<
147  is_sequence<T>,
148  And<
149  Not<is_const<T>>,
150  Or<is_arithmetic<typename T::value_type>, is_string<typename T::value_type>>
151  >
152  >,std::string>::T
153  typescriptTypep() {return typescriptType<typename T::value_type>()+"[]";}
154 
155  template <class T>
156  typename enable_if<
157  And<
158  And<
159  is_associative_container<T>,
160  Not<is_map<T>>
161  >,
162  Not<is_const<T>>
163  >,std::string>::T
164  typescriptTypep() {return "Container<"+typescriptType<typename T::value_type>()+">";}
165 
166  template <class T>
167  typename enable_if<
168  And<
169  is_map<T>,
170  Not<is_const<T>>
171  >,std::string>::T
173  auto k=typescriptType<typename T::key_type>();
174  auto v=typescriptType<typename T::mapped_type>();
175  return "Map<"+k+","+v+">";}
176 
177  template <class T>
178  typename enable_if<
179  And<
180  is_smart_ptr<T>,
181  Not<is_const<T>>
182  >,std::string>::T
183  typescriptTypep() {return typescriptType<typename T::element_type>();}
184 
185  template <class T>
186  typename enable_if<
187  And<
188  is_pair<T>,
189  Not<is_const<T>>
190  >,std::string>::T
191  typescriptTypep() {return "Pair<"+typescriptType<typename T::first_type>()+","
192  +typescriptType<typename T::second_type>()+">";}
193 
194  // don't process ItemT because of clone return type.
195  template <class T>
196  typename enable_if<is_itemT<T>, std::string>::T
197  typescriptTypep() {return "Item";}
198 
199  template <class T> string typescriptType() {return typescriptTypep<T>();}
200 
201  template <> inline string typescriptType<string>() {return "string";}
202  template <> inline string typescriptType<void>() {return "void";}
203 
204 }
205 
206 namespace classdesc
207 {
208  namespace typescriptAPI_ns
209  {
211  using namespace classdesc::functional;
212 
213  // arrange for sequences to be passed as javascript arrays or objects
214  template <class T>
215  typename enable_if<
216  And<
217  Not<is_container<T>>,
218  Or<Not<is_class<T>>,is_string<T>>
219  >,string>::T
220  parameterType() {return typescriptType<T>();}
221 
222  template <class T>
223  typename enable_if<
224  And<
225  is_class<T>,
226  And<Not<is_container<T>>, Not<is_string<T>>>
227  >,string>::T
228  parameterType() {return "object";}
229 
230  template <class T>
231  typename enable_if<
232  And<
233  is_container<T>,
234  Not<is_map<T>>
235  >, string>::T
236  parameterType() {return parameterType<typename T::value_type>()+"[]";}
237 
238  template <class T>
239  typename enable_if<
240  And<
241  is_container<T>,
242  is_map<T>
243  >, string>::T
244  parameterType() {return "object";}
245 
246  template <class T>
247  typename enable_if<
248  And<
249  is_container<T>,
250  is_same<T, StringKeyMap<T>>
251  >, string>::T
252  parameterType() {return "object";}
253 
254  struct Property
255  {
256  std::string type;
257  std::string construction;
258  Property(const std::string& type={}, const std::string& construction={}):
259  type(type), construction(construction) {}
260  };
261 
262  struct ArgDetail
263  {
264  std::string name, type;
265  ArgDetail(const std::string& name={}, const std::string& type={}):
266  name(name), type(type) {}
267  bool operator==(const ArgDetail& x) const {return type==x.type;}
268  bool operator!=(const ArgDetail& x) const {return !operator==(x);}
269  };
270 
271  struct Method
272  {
273  std::string returnType;
274  std::vector<ArgDetail> args;
275  template <class M, int N>
276  struct AddArgs
277  {
278  static void addArgs(std::vector<ArgDetail>& args)
279  {
280  constexpr int i=Arity<M>::value-N+1;
281  args.emplace_back("a"+std::to_string(i), parameterType<typename Arg<M,i>::T>());
283  }
284  };
285  // recursion stop
286  template <class M> struct AddArgs<M, 0> {
287  static void addArgs(std::vector<ArgDetail>&) {}
288  };
289  template <class M> void addArgs() {AddArgs<M,Arity<M>::value>::addArgs(args);}
290  };
291 
292  struct ClassType
293  {
294  std::string super;
295  std::string valueType; // used for container to instantiate proxies around elements
296  std::map<std::string,Property> properties;
297  std::map<std::string, Method> methods;
298  };
299  }
300 }
301 
302 
303 
304 namespace classdesc
305 {
306  struct typescriptAPI_t: public std::map<std::string, typescriptAPI_ns::ClassType>
307  {
308  template <class T> void addClass();
309  template <class T, class Base> void addSubclass();
310  };
311 
314 
315  template <class C, class B>
316  typename enable_if<Not<is_map<B>>, void>::T
317  typescriptAPI(typescriptAPI_t&,const std::string&);
318 
319  template <class C, class B>
320  typename enable_if<is_map<B>, void>::T
321  typescriptAPI(typescriptAPI_t& t,const std::string&)
322  {
323  if (typescriptType<C>().substr(0,4)!="Map<")
324  t[typescriptType<C>()].super="Map<"+typescriptType<typename B::key_type>()+","+
325  typescriptType<typename B::mapped_type>()+">";
326  }
327 
328  template <class C, class B, class T>
329  typename enable_if<is_arithmetic<T>, void>::T
330  typescriptAPI_type(typescriptAPI_t& t, const std::string& d, T(B::*))
331  {
332  t[typescriptType<C>()].methods.emplace(tail(d), typescriptAPI_ns::Method{parameterType<T>(), {{"...args",typescriptType<T>()+"[]"}}});
333  }
334 
335 
336 
337  template <class C, class B, class T>
338  typename enable_if<is_arithmetic<T>, void>::T
339  typescriptAPI_type(typescriptAPI_t& t, const std::string& d, T*)
340  {
341  t[typescriptType<C>()].methods.emplace(tail(d), typescriptAPI_ns::Method{typescriptType<T>(), {{"...args",typescriptType<T>()+"[]"}}});
342  }
343 
344  template <class VT>
345  std::string construct(const std::string& container, const std::string name)
346  {
347  string tn=typescriptType<VT>();
348  return "new "+container+"(this.$prefix()+'."+name+"'"+
349  ((is_string<VT>::value || is_enum<VT>::value || is_arithmetic<VT>::value)?"":","+tn)+");";
350  }
351 
352  template <class C, class B, class T>
353  typename enable_if<is_sequence<T>, void>::T
354  typescriptAPI_type(typescriptAPI_t& t, const std::string& d, T*)
355  {
356  auto tn=typescriptType<typename T::value_type>();
357  t[typescriptType<C>()].properties.emplace
359  {"Sequence<"+tn+">", construct<typename T::value_type>("Sequence<"+tn+">", tail(d))});
360  }
361 
362  template <class C, class B, class T>
363  typename enable_if<is_sequence<T>, void>::T
364  typescriptAPI_type(typescriptAPI_t& t, const std::string& d, T (B::*))
365  {typescriptAPI_type<C,B>(t,d,(T*){});}
366 
367  template <class C, class B, class T>
368  typename enable_if<Or<is_same<typename remove_const<T>::type,std::string>,
369  is_enum<typename remove_const<T>::type>>, void>::T
370  typescriptAPI_type(typescriptAPI_t& t, const std::string& d, T(B::*))
371  {
372  t[typescriptType<C>()].methods.emplace
373  (tail(d), typescriptAPI_ns::Method{"string",{{"...args","string[]"}}});
374  }
375 
376  template <class C, class B, class T>
377  typename enable_if<Or<is_same<typename remove_const<T>::type,std::string>,
378  is_enum<typename remove_const<T>::type>>, void>::T
379  typescriptAPI_type(typescriptAPI_t& t, const std::string& d, T*)
380  {
381  t[typescriptType<C>()].methods.emplace(tail(d), typescriptAPI_ns::Method{"string", {{"...args","string[]"}}});
382  }
383 
384  template <class C, class B>
385  void typescriptAPI_type(typescriptAPI_t& t, const std::string& d, const char**)
386  {typescriptAPI_type<C,B>(t,d,static_cast<const std::string*>(nullptr));}
387 
388  template <class C, class B, class T>
389  void typescriptAPI_type(typescriptAPI_t& t, const std::string& d, std::set<T>(B::*))
390  {
391  string tn=typescriptType<T>();
392  t[typescriptType<C>()].properties.emplace
393  (tail(d), typescriptAPI_ns::Property{"Container<"+tn+">", construct<T>("Container<"+tn+">", tail(d))});
394  }
395 
396  template <class C, class B, class K, class V>
397  void typescriptAPI_type(typescriptAPI_t& t, const std::string& d, std::map<K,V>(B::*))
398  {
399  string k=typescriptType<K>();
400  string v=typescriptType<V>();
401  t[typescriptType<C>()].properties.emplace
403  {"Map<"+k+","+v+">", construct<V>("Map<"+k+","+v+">",tail(d))});
404  }
405 
406  template <class C, class B, class V>
407  void typescriptAPI_type(typescriptAPI_t& t, const std::string& d, StringKeyMap<V>(B::*))
408  {
409  string v=typescriptType<V>();
410  t[typescriptType<C>()].properties.emplace
411  (tail(d), typescriptAPI_ns::Property{"Map<string,"+v+">",construct<V>("Map<string,"+v+">",tail(d))});
412  }
413 
414  template <class C, class B, class M>
415  typename enable_if<functional::is_function<M>, void>::T
416  typescriptAPI_type(typescriptAPI_t& t, const std::string& d, M)
417  {
418  auto& methods=t[typescriptType<C>()].methods;
419  auto iter=methods.find(typeName<C>());
420  if (iter==methods.end())
421  {
422  auto res=methods.emplace
423  (tail(d),
424  typescriptAPI_ns::Method{parameterType<typename functional::Return<M>::T>()});
425  if (res.second) // first occurance of this method
426  {
427  typescriptAPI_ns::Method& m=res.first->second;
428  m.addArgs<M>();
429  }
430  else // method seen before
431  {
432  auto oldArgs=std::move(res.first->second.args);
433  typescriptAPI_ns::Method& m=res.first->second;
434  m.addArgs<M>();
435  auto newArgs=res.first->second.args;
436  // check if arguments are same, in which case leave the method call
437  if (oldArgs!=res.first->second.args) // overloaded method
438  {
439  res.first->second.args={{"...args","any[]"}}; // set up general case or arbitrary args
440  //check if all arguments are the same (ie just numbers of arguments differ)
441  auto firstArg=!oldArgs.empty()? oldArgs[0]: res.first->second.args[0];
442  if (firstArg.type=="any[]") return;
443  if (firstArg.name=="...args") firstArg.type.erase(firstArg.type.length()-2); //strip off []
444  for (auto& i: oldArgs)
445  if (i!=firstArg) return;
446  for (auto& i: newArgs)
447  if (i!=firstArg) return;
448  res.first->second.args={{"...args",firstArg.type+"[]"}}; //restrict to common type
449  }
450  }
451  }
452  }
453 
454  template <class C, class B, class T>
455  typename enable_if<
456  And<
457  And<
458  is_class<T>,
459  Not<is_same<typename remove_const<T>::type,std::string>>
460  >,
461  And<
462  Not<is_sequence<T>>,
463  Not<is_excluded<T>>
464  >
465  >, void>::T
466  typescriptAPI_type(typescriptAPI_t& t, const std::string& d, T(B::*))
467  {
468  typescriptAPI<T,T>(t,d);
469  t[typescriptType<C>()].properties.emplace(tail(d), typescriptType<T>());
470  }
471 
472  template <class C, class B, class T>
473  typename enable_if<is_excluded<T>, void>::T
474  typescriptAPI_type(typescriptAPI_t& t, const std::string& d, T(B::*)) {}
475 
476 
477  template <class C, class B, class T>
478  typename enable_if<
479  And<
480  And<
481  is_class<T>,
482  Not<is_same<typename remove_const<T>::type,std::string>>
483  >,
484  Not<is_sequence<T>>
485  >, void>::T
486  typescriptAPI_type(typescriptAPI_t& t, const std::string& d, T*)
487  {
488  typescriptAPI<T,T>(t,d);
489  t[typescriptType<C>()].properties.emplace(tail(d), typescriptType<T>());
490  }
491 
492 
493 
494  template <class T> void typescriptAPI(typescriptAPI_t&,const std::string&,T,...) {} //not used
495 
496  inline void typescriptAPI_onbase(typescriptAPI_t&,...) {} //not used
497 
498  template <class C, class B>
499  void typescriptAPI_type(typescriptAPI_t&,const std::string&,is_constructor,...) {} //not used
500 
501  template <class C, class B, class T>
502  void typescriptAPI_type(typescriptAPI_t& t,const std::string& d,is_const_static,T a)
503  {typescriptAPI_type<C,B>(t,d,a);}
504 
505 }
506 
507 namespace classdesc_access
508 {
509  template <class T> struct access_typescriptAPI;
510 
511  template <class T> struct access_typescriptAPI<std::shared_ptr<T>>
512  {
513  template <class U>
514  void type(classdesc::typescriptAPI_t& t,const std::string& d)
515  {classdesc::typescriptAPI<U,T>(t,d);}
516  };
517 }
518 
521 #endif
std::map< std::string, Method > methods
Property(const std::string &type={}, const std::string &construction={})
bool operator!=(const ArgDetail &x) const
ArgDetail(const std::string &name={}, const std::string &type={})
enable_if< is_arithmetic< T >, void >::T typescriptAPI_type(typescriptAPI_t &t, const std::string &d, T(B::*))
STL namespace.
enable_if< And< is_arithmetic< T >, And< Not< is_const< T > >, Not< is_same< T, bool > > > >, string >::T typescriptTypep()
enable_if< And< Not< is_container< T > >, Or< Not< is_class< T > >, is_string< T > > >, string >::T parameterType()
void typescriptAPI_onbase(typescriptAPI_t &,...)
string typescriptType< string >()
void remove(std::vector< T > &x, const V &v)
remove an element from a vector. V must be comparable to a T
Definition: str.h:89
Creation and access to the minskyTCL_obj object, which has code to record whenever Minsky&#39;s state cha...
Definition: constMap.h:22
bool operator==(const ArgDetail &x) const
std::string construct(const std::string &container, const std::string name)
static void addArgs(std::vector< ArgDetail > &)
enable_if< Not< is_map< B > >, void >::T typescriptAPI(typescriptAPI_t &, const std::string &)
static void addArgs(std::vector< ArgDetail > &args)
string typescriptType< void >()
string typescriptType()
std::map< std::string, Property > properties
string to_string(CONST84 char *x)
Definition: minskyTCLObj.h:33
void type(classdesc::typescriptAPI_t &t, const std::string &d)