types.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296
  1. /* Definitions for the type system interface.
  2. This file is part of khipu.
  3. khipu is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as published by
  5. the Free Software Foundation; either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  13. #include <cstdio>
  14. #include "khipu.hpp"
  15. #include "utils/sorted_list.hpp"
  16. KP_DECLS_BEGIN
  17. #define TYPE(name) \
  18. static object name##_type
  19. // builtin types.
  20. TYPE (typespec);
  21. TYPE (int);
  22. TYPE (char);
  23. TYPE (cons);
  24. TYPE (float);
  25. TYPE (bvector);
  26. TYPE (str);
  27. TYPE (array);
  28. TYPE (table);
  29. TYPE (tuple);
  30. TYPE (stream);
  31. TYPE (symbol);
  32. TYPE (fct);
  33. TYPE (coro);
  34. TYPE (thread);
  35. TYPE (pkg);
  36. #undef TYPE
  37. // Offsets into a typespec definition.
  38. enum
  39. {
  40. TSPEC_NAME,
  41. TSPEC_PARENTS,
  42. TSPEC_SLOTDEFS,
  43. TSPEC_NSLOTS,
  44. TSPEC_SHARED,
  45. TSPEC_NUM_MEMBERS
  46. };
  47. static inline object&
  48. tspec_name (object ts)
  49. {
  50. return (xaref (as_instance(ts)->tspec, TSPEC_NAME));
  51. }
  52. static inline object&
  53. tspec_parents (object ts)
  54. {
  55. return (xaref (as_instance(ts)->tspec, TSPEC_PARENTS));
  56. }
  57. static inline object&
  58. tspec_slotdefs (object ts)
  59. {
  60. return (xaref (as_instance(ts)->tspec, TSPEC_SLOTDEFS));
  61. }
  62. static inline object&
  63. tspec_nslots (object ts)
  64. {
  65. return (xaref (as_instance(ts)->tspec, TSPEC_NSLOTS));
  66. }
  67. static inline object&
  68. tspec_shared (object ts)
  69. {
  70. return (xaref (as_instance(ts)->tspec, TSPEC_SHARED));
  71. }
  72. // Offsets into a slot definition.
  73. enum
  74. {
  75. SLOTDEF_NAME,
  76. SLOTDEF_TYPE,
  77. SLOTDEF_INIT,
  78. SLOTDEF_FLAGS,
  79. SLOTDEF_PROPS,
  80. SLOTDEF_INDEX,
  81. SLOTDEF_NUM_MEMBERS
  82. };
  83. // Slot definition flags.
  84. enum
  85. {
  86. SLOTDEF_SHARED_FLG = 0x1,
  87. SLOTDEF_GETTER_FLG = 0x2,
  88. SLOTDEF_CONST_FLG = 0x4
  89. };
  90. static inline object&
  91. slotdef_name (object slotdef)
  92. {
  93. return (xaref (slotdef, SLOTDEF_NAME));
  94. }
  95. static inline object&
  96. slotdef_type (object slotdef)
  97. {
  98. return (xaref (slotdef, SLOTDEF_TYPE));
  99. }
  100. static inline object&
  101. slotdef_init (object slotdef)
  102. {
  103. return (xaref (slotdef, SLOTDEF_INIT));
  104. }
  105. static inline object&
  106. slotdef_flags (object slotdef)
  107. {
  108. return (xaref (slotdef, SLOTDEF_FLAGS));
  109. }
  110. static inline object&
  111. slotdef_props (object slotdef)
  112. {
  113. return (xaref (slotdef, SLOTDEF_PROPS));
  114. }
  115. static inline object&
  116. slotdef_index (object slotdef)
  117. {
  118. return (xaref (slotdef, SLOTDEF_INDEX));
  119. }
  120. struct slot_cmp
  121. {
  122. int operator() (intptr_t left, intptr_t right) const
  123. {
  124. return ((intptr_t)slotdef_name (left) - (intptr_t)slotdef_name (right));
  125. }
  126. };
  127. typedef sorted_list<slot_cmp> slotname_list_t;
  128. static result<int>
  129. add_slot_names (interpreter *interp, object tx,
  130. slotname_list_t& lst, uint32_t idx)
  131. {
  132. const array *sp = as_array (tspec_slotdefs (tx));
  133. for (uint32_t i = 0; i < sp->len; ++i)
  134. if (sp->data[i] != fixint (0) &&
  135. !lst.add (sp->data[i], idx))
  136. return (interp->raise ("arg-error",
  137. KP_SPRINTF (interp, "got repeated slot: %Q",
  138. slotdef_name (sp->data[i]))));
  139. return (0);
  140. }
  141. static result<object>
  142. sorted_list_toarray (interpreter *interp, sorted_list_base& lst)
  143. {
  144. object ret = KP_TRY (alloc_array (interp, lst.len ()));
  145. uint32_t ix = 0;
  146. for (sorted_list_base::iterator it (lst); it.valid (); ++it)
  147. xaref(ret, ix++) = it.key ();
  148. return (ret);
  149. }
  150. static inline int
  151. slot_spec_index (const string *sp)
  152. {
  153. if (sp->nbytes != 4)
  154. return (-1);
  155. else if (memcmp (sp->data, "type", 4) == 0)
  156. return (SLOTDEF_TYPE);
  157. else if (memcmp (sp->data, "init", 4) == 0)
  158. return (SLOTDEF_INIT);
  159. return (-1);
  160. }
  161. static inline result<int>
  162. parse_slotdef (interpreter *interp, object slotdef,
  163. object elem, object val, uintptr_t& xflags)
  164. {
  165. const string *sp = as_str (symname (elem));
  166. int idx = slot_spec_index (sp);
  167. if (idx >= 0)
  168. {
  169. if (idx == SLOTDEF_INIT)
  170. xflags |= instance::init_flag;
  171. xaref(slotdef, idx) = val;
  172. }
  173. else if (sp->nbytes == 6 && (*sp->data == 'g' || *sp->data == 's') &&
  174. memcmp (sp->data + 1, "etter", 5) == 0)
  175. {
  176. object *p = &xaref(slotdef, SLOTDEF_PROPS);
  177. if (*p == UNBOUND)
  178. { *p = KP_TRY (alloc_array (interp, 2)); }
  179. xaref(*p, *sp->data != 'g') = val;
  180. xaref(slotdef, SLOTDEF_FLAGS) |= fixint (SLOTDEF_GETTER_FLG);
  181. }
  182. else if (sp->nbytes == 6 && memcmp (sp->data, "shared", 6) == 0 && val != NIL)
  183. xaref(slotdef, SLOTDEF_FLAGS) |= fixint (SLOTDEF_SHARED_FLG);
  184. else if (sp->nbytes == 5 && memcmp (sp->data, "const", 6) == 0 && val != NIL)
  185. xaref(slotdef, SLOTDEF_FLAGS) |= fixint (SLOTDEF_CONST_FLG);
  186. else
  187. return (interp->raise ("arg-error",
  188. KP_SPRINTF (interp,
  189. "'%Q' is not a valid slot specification",
  190. elem)));
  191. return (0);
  192. }
  193. static inline result<uintptr_t>
  194. validate_slotdef (interpreter *interp, object slotdef, uintptr_t& xflags)
  195. {
  196. object *ptr = &slotdef_name(slotdef);
  197. if (!nksymbol_p (*ptr))
  198. return (interp->raise ("type-error",
  199. KP_SPRINTF (interp,
  200. "expected a symbol as slot name, got %Q",
  201. *ptr)));
  202. // Store slot name as a keyword if it's not uninterned
  203. if (!nil_p (sympkg (*ptr)))
  204. { *ptr = KP_TRY (symbol::make_kword (interp, symname (*ptr))); }
  205. // Verify slot initializer.
  206. ptr = &slotdef_init(slotdef);
  207. if (*ptr == UNBOUND)
  208. ;
  209. else if (!fct_p (*ptr))
  210. return (interp->raise ("type-error",
  211. KP_SPRINTF (interp, "expected a function as slot "
  212. "initializer, got %Q", *ptr)));
  213. else if (slotdef_flags (slotdef) & fixint (SLOTDEF_SHARED_FLG))
  214. xflags &= ~instance::init_flag;
  215. // Verify slot type.
  216. ptr = &slotdef_type(slotdef);
  217. if (*ptr != UNBOUND && !typespec_p (*ptr))
  218. return (interp->raise ("type-error",
  219. KP_SPRINTF (interp, "expected a typespec as slot "
  220. "type, got %Q", *ptr)));
  221. // Verify getter and setter.
  222. ptr = &slotdef_props(slotdef);
  223. if (*ptr != UNBOUND)
  224. {
  225. ptr = &xaref(*ptr, 0);
  226. if ((*ptr != UNBOUND && !fct_p (*ptr)) ||
  227. (*++ptr != UNBOUND && !fct_p (*ptr)))
  228. return (interp->raise ("type-error",
  229. KP_SPRINTF (interp, "expected a function as "
  230. "getter/setter, got %Q",
  231. *ptr)));
  232. }
  233. return (xflags);
  234. }
  235. static inline void
  236. init_local_slotdef (object slotdef)
  237. {
  238. slotdef_type(slotdef) = slotdef_init(slotdef) =
  239. slotdef_props(slotdef) = UNBOUND;
  240. slotdef_name(slotdef) = slotdef_flags(slotdef) = fixint (0);
  241. slotdef_index(slotdef) = fixint (-1);
  242. }
  243. static inline uint32_t
  244. hash_slot_name (interpreter *interp, object name)
  245. {
  246. uint32_t ret = hash_s (interp, symname (name));
  247. if (kp_unlikely (nil_p (sympkg (name))))
  248. ret = ~ret;
  249. return (ret);
  250. }
  251. static uint32_t
  252. slots_insert (interpreter *interp, object sdef, object *ptr, uint32_t size)
  253. {
  254. uint32_t pos = hash_slot_name (interp, slotdef_name (sdef)) & (size - 1);
  255. uint32_t probe = 1;
  256. while (true)
  257. {
  258. if (ptr[pos] == fixint (0))
  259. {
  260. ptr[pos] = sdef;
  261. return (pos);
  262. }
  263. pos = (pos + probe++) & (size - 1);
  264. }
  265. }
  266. static result<object>
  267. make_slotdefs (interpreter *interp, object slotdefs,
  268. slotname_list_t& lst, uintptr_t& xflags, object ts)
  269. {
  270. valref cur (interp), elem (interp), ar (interp, NIL);
  271. local_varobj<array> lsdef;
  272. object space[SLOTDEF_NUM_MEMBERS];
  273. lsdef.local_init (space, KP_NELEM (space));
  274. valref local_sd (interp, lsdef.as_obj ());
  275. for (cons::iterator sd { interp, slotdefs }; sd.valid (); ++sd)
  276. {
  277. init_local_slotdef (*local_sd);
  278. uintptr_t lf = 0;
  279. *cur = *sd;
  280. if (nksymbol_p (*cur))
  281. {
  282. auto& ld = slotdef_name (*local_sd);
  283. ld = KP_TRY (nil_p (sympkg (*cur)) ?
  284. *cur : symbol::make_kword (interp, symname (*cur)));
  285. }
  286. else if (xcons_p (*cur))
  287. {
  288. cons::iterator sub { interp, *cur };
  289. slotdef_name(*local_sd) = *sub;
  290. while ((++sub).valid ())
  291. {
  292. *elem = *sub;
  293. if (!keyword_p (*elem))
  294. return (interp->raise ("type-error",
  295. KP_SPRINTF (interp, "slot option must be"
  296. " a keyword, got %Q",
  297. *elem)));
  298. else if (!(++sub).valid ())
  299. return (interp->raise ("arg-error",
  300. "slot options must come in pairs"));
  301. KP_VTRY (parse_slotdef (interp, *local_sd, *elem, *sub, lf));
  302. }
  303. xflags |= KP_TRY (validate_slotdef (interp, *local_sd, lf));
  304. }
  305. else
  306. return (interp->raise ("type-error",
  307. KP_SPRINTF (interp, "expected a symbol or cons "
  308. "for the slot, got %Q",
  309. *cur)));
  310. *elem = KP_TRY (alloc_array (interp, SLOTDEF_NUM_MEMBERS));
  311. copy_objs (&xaref(*elem, 0), lsdef.data, lsdef.len);
  312. slotdef_index(*elem) = *ar;
  313. if (!lst.add (*elem, 0))
  314. return (interp->raise ("arg-error",
  315. KP_SPRINTF (interp, "got repeated slot: %Q",
  316. slotdef_name (*local_sd))));
  317. *ar = *elem;
  318. }
  319. if (!lst.len ())
  320. kp_return (deref (alloc_array (interp, 0)));
  321. uint32_t size = upsize (lst.len () + 1), ix = 0, nshared = 0;
  322. *cur = KP_TRY (alloc_array (interp, size, fixint (0)));
  323. object *ptr = &xaref(*cur, 0);
  324. for (slotname_list_t::iterator it (lst); it.valid (); ++it)
  325. {
  326. object tmp = it.key ();
  327. if (fixint_p (slotdef_index (tmp)))
  328. { // This slot comes from a parent type.
  329. tmp = KP_TRY (copy_a (interp, tmp, false));
  330. *elem = tmp;
  331. }
  332. slots_insert (interp, tmp, ptr, size);
  333. if (slotdef_flags (tmp) & fixint (SLOTDEF_SHARED_FLG))
  334. {
  335. ++nshared;
  336. if (fixint_p (slotdef_index (tmp)))
  337. { // Inherited shared slot.
  338. int ipos = as_int (slotdef_index (tmp)) & 0x3fff;
  339. slotdef_index(tmp) = fixint (ipos | (it.val () << 14));
  340. }
  341. }
  342. else
  343. slotdef_index(tmp) = slotdef_flags (tmp) & fixint (SLOTDEF_GETTER_FLG) ?
  344. NIL : fixint (ix++);
  345. }
  346. if (nshared)
  347. {
  348. nshared = nshared < 4 ? 4 : upsize (nshared);
  349. object sh = KP_TRY (alloc_array (interp, nshared, fixint (0)));
  350. xaref(ts, TSPEC_SHARED) = sh;
  351. for (uint32_t j = 0; j < len_a (*cur); ++j)
  352. {
  353. object tmp = ptr[j];
  354. if (tmp == fixint (0) ||
  355. !(slotdef_flags (tmp) & fixint (SLOTDEF_SHARED_FLG)))
  356. continue;
  357. *elem = KP_TRY (copy_a (interp, tmp, false));
  358. auto off = slots_insert (interp, *elem, &xaref(sh, 0), nshared);
  359. if (!fixint_p (slotdef_index (tmp)))
  360. { // A shared slot that belongs to this type.
  361. slotdef_index(tmp) = fixint (off);
  362. slotdef_index(*elem) = UNBOUND;
  363. slotdef_flags(*elem) &= ~fixint (SLOTDEF_SHARED_FLG);
  364. if (slotdef_init (tmp) != UNBOUND)
  365. xflags |= instance::ishared_flag;
  366. }
  367. }
  368. }
  369. else
  370. xaref(ts, TSPEC_SHARED) = deref (alloc_array (interp, 0));
  371. xaref(ts, TSPEC_NSLOTS) = fixint (ix);
  372. kp_return (*cur);
  373. }
  374. static inline bool
  375. lst_addend (sorted_list<>& lst, object x)
  376. {
  377. for (sorted_list<>::iterator it (lst); it.valid (); ++it)
  378. if ((object)it.key () == x)
  379. return (false);
  380. lst.add_end (x, 0);
  381. return (true);
  382. }
  383. static inline void
  384. array_del_pos (array *ap, int pos)
  385. {
  386. move_objs (&ap->data[pos], &ap->data[pos + 1], ap->len - pos - 1);
  387. --ap->len;
  388. }
  389. static void
  390. insert_type (sorted_list<>& out, object obj)
  391. {
  392. for (sorted_list<>::iterator it (out); it.valid (); ++it)
  393. {
  394. object ty = it.key ();
  395. int dist = subtype_p (ty, obj);
  396. if (!dist)
  397. continue;
  398. for (++it; it.valid (); ++it)
  399. if (subtype_p (obj, it.key ()) < dist)
  400. break;
  401. out.insert (it.link()->prev, obj, 0);
  402. return;
  403. }
  404. out.add_end (obj, 0);
  405. }
  406. static result<object>
  407. c3_merge_aux (interpreter *interp, array *heads, sorted_list<>& out)
  408. {
  409. bool found = false;
  410. object h1 = fixint (0);
  411. for (uint32_t ix = 0; ix < heads->len; ++ix)
  412. {
  413. array *ap = as_array (heads->data[ix]);
  414. h1 = fixint (0);
  415. if (!ap->len)
  416. continue;
  417. h1 = ap->data[0];
  418. for (uint32_t jx = 0; jx < heads->len; ++jx)
  419. {
  420. if (ix == jx)
  421. continue;
  422. array *p2 = as_array (heads->data[jx]);
  423. for (uint32_t kx = 1; kx < p2->len; ++kx)
  424. if (p2->data[kx] == h1)
  425. goto skip;
  426. }
  427. found = true;
  428. for (uint32_t jx = 0; jx < heads->len; ++jx)
  429. {
  430. array *p2 = as_array (heads->data[jx]);
  431. if (p2->len && p2->data[0] == h1)
  432. array_del_pos (p2, 0);
  433. }
  434. break;
  435. skip: ;
  436. }
  437. if (h1 == fixint (0))
  438. return (sorted_list_toarray (interp, out));
  439. else if (!found)
  440. return (interp->raise ("type-error",
  441. KP_SPRINTF (interp, "inconsistency in base types "
  442. "when adding %Q",
  443. tspec_name (h1))));
  444. insert_type (out, h1);
  445. return (c3_merge_aux (interp, heads, out));
  446. }
  447. static result<object>
  448. c3_merge (interpreter *interp, sorted_list<>& parents)
  449. {
  450. if (parents.len () == 0)
  451. return (alloc_array (interp, 0));
  452. else if (parents.len () == 1)
  453. return (alloc_array (interp, 1, parents.root.next->key));
  454. tmp_allocator ta { interp };
  455. object *bp = (object *)ta.alloc ((parents.len () + 1) * sizeof (*bp));
  456. local_varobj<array> heads;
  457. heads.local_init (bp, parents.len () + 1);
  458. memset (bp, 0, heads.len * sizeof (*bp));
  459. valref lheads (interp, heads.as_obj ());
  460. heads.data[0] = KP_TRY (sorted_list_toarray (interp, parents));
  461. int ix = 0;
  462. sorted_list<> out;
  463. for (sorted_list<>::iterator it (parents); it.valid (); ++it)
  464. {
  465. const array *inp = as_array (tspec_parents (it.key ()));
  466. KP_VTRY (alloc_array (interp, inp->len + 1, it.key ()));
  467. array *tp = as_array (interp->alval);
  468. copy_objs (&tp->data[1], inp->data, inp->len);
  469. heads.data[++ix] = tp->as_obj ();
  470. }
  471. object ret = KP_TRY (c3_merge_aux (interp, &heads, out));
  472. return (ret);
  473. }
  474. result<object> type (interpreter *interp, object name,
  475. object parents, object slotdefs)
  476. {
  477. if (!nksymbol_p (name))
  478. return (interp->raise ("type-error",
  479. KP_SPRINTF (interp, "name argument must be a "
  480. "symbol, got: %Q", name)));
  481. sorted_list<> p;
  482. uintptr_t xflags = 0;
  483. object builtin = UNBOUND;
  484. if (!xcons_p (parents))
  485. return (interp->raise ("type-error",
  486. KP_SPRINTF (interp, "parent types must be a list, "
  487. "got: %Q", parents)));
  488. for (cons::iterator it (interp, parents); it.valid (); ++it)
  489. {
  490. object px = *it;
  491. if (!typespec_p (px))
  492. return (interp->raise ("type-error", "parent must be a typespec"));
  493. else if (!lst_addend (p, px))
  494. return (interp->raise ("arg-error",
  495. KP_SPRINTF (interp, "duplicate base type: %Q",
  496. tspec_name (px))));
  497. else if (as_instance(px)->flagged_p (instance::init_flag))
  498. xflags |= instance::init_flag;
  499. if (as_instance(px)->builtin == UNBOUND)
  500. ;
  501. else if (builtin != UNBOUND && builtin != as_instance(px)->builtin)
  502. return (interp->raise ("arg-error", "cannot use more than one builtin "
  503. "type as a parent"));
  504. else
  505. builtin = as_instance(px)->builtin;
  506. }
  507. auto eg = KP_TRY (evh_guard::make (interp));
  508. valref ts = KP_TRY (alloc_array (interp, TSPEC_NUM_MEMBERS));
  509. valref tmp = KP_TRY (c3_merge (interp, p));
  510. slotname_list_t slots;
  511. for (uint32_t tidx = 0; tidx < len_a (*tmp); ++tidx)
  512. KP_VTRY (add_slot_names (interp, xaref (*tmp, tidx), slots, tidx + 1));
  513. xaref(*ts, TSPEC_NAME) = name;
  514. xaref(*ts, TSPEC_PARENTS) = *tmp;
  515. xaref(*ts, TSPEC_SLOTDEFS) = KP_TRY (make_slotdefs (interp, slotdefs,
  516. slots, xflags, *ts));
  517. instance *ret = alloch<instance> ();
  518. ret->ptype = typespec_type;
  519. ret->slots = deref (alloc_array (interp, 0));
  520. ret->tspec = *ts;
  521. ret->builtin = builtin;
  522. ret->vo_full |= xflags | (builtin != UNBOUND ? instance::init_flag : 0);
  523. interp->alval = ret->as_obj ();
  524. gc_register (interp, ret, sizeof (*ret));
  525. if (xflags & instance::ishared_flag)
  526. {
  527. auto shared = as_array (xaref (*ts, TSPEC_SHARED));
  528. *tmp = interp->alval;
  529. for (uint32_t tidx = 0; tidx < shared->len; ++tidx)
  530. {
  531. object tmp = shared->data[tidx];
  532. if (tmp == fixint (0) || slotdef_init (tmp) == UNBOUND)
  533. continue;
  534. KP_VTRY (interp->push (slotdef_init (tmp)));
  535. slotdef_index(tmp) = KP_TRY (call_n (interp, 0));
  536. deref (gc_wbarrier (interp, tmp, interp->retval));
  537. }
  538. interp->alval = *tmp;
  539. }
  540. kp_return (interp->alval);
  541. }
  542. object type (object obj)
  543. {
  544. switch (itype (obj))
  545. {
  546. #define DISPATCH_1(code, type) \
  547. case typecode::code: \
  548. return (type##_type)
  549. #define DISPATCH_2(code_1, code_2, type) \
  550. case typecode::code_1: \
  551. DISPATCH_1 (code_2, type)
  552. DISPATCH_2 (INT, BIGINT, int);
  553. DISPATCH_1 (CHAR, char);
  554. DISPATCH_1 (CONS, cons);
  555. DISPATCH_2 (FLOAT, BIGFLOAT, float);
  556. DISPATCH_1 (BVECTOR, bvector);
  557. DISPATCH_1 (STR, str);
  558. DISPATCH_1 (ARRAY, array);
  559. DISPATCH_1 (TABLE, table);
  560. DISPATCH_1 (TUPLE, tuple);
  561. DISPATCH_1 (STREAM, stream);
  562. DISPATCH_1 (SYMBOL, symbol);
  563. DISPATCH_1 (FCT, fct);
  564. DISPATCH_1 (CORO, coro);
  565. DISPATCH_1 (THREAD, thread);
  566. DISPATCH_1 (PKG, pkg);
  567. case typecode::INSTANCE:
  568. return (as_instance(obj)->ptype);
  569. case typecode::CUSTOM:
  570. return (as_custom(obj)->type ());
  571. #undef DISPATCH_1
  572. #undef DISPATCH_2
  573. }
  574. return (NIL);
  575. }
  576. static const array*
  577. slotdef_get (interpreter *interp, object ts,
  578. object name, const array *defs)
  579. {
  580. if (defs->len == 0)
  581. return (nullptr);
  582. uint32_t pos = hash_slot_name (interp, name);
  583. uint32_t nprobe = 1, len_m1 = defs->len - 1;
  584. for (pos &= len_m1 ; ; pos = (pos + nprobe++) & len_m1)
  585. {
  586. if (defs->data[pos] == fixint (0))
  587. return (nullptr);
  588. const array *entry = as_array (defs->data[pos]);
  589. if (entry->data[SLOTDEF_NAME] == name)
  590. return (entry);
  591. }
  592. }
  593. static inline object*
  594. slot_at_ts (const array *entry, object inst)
  595. {
  596. if (entry->data[SLOTDEF_FLAGS] & fixint (SLOTDEF_SHARED_FLG))
  597. { // Inherited shared slot.
  598. int ix = as_int (entry->data[SLOTDEF_INDEX]);
  599. int i1 = ix & 0x3fff, i2 = ix >> 14;
  600. inst = xaref (tspec_parents (inst), i2 - 1);
  601. entry = as_array (xaref (tspec_shared (inst), i1));
  602. }
  603. return (&entry->data[SLOTDEF_INDEX]);
  604. }
  605. static object*
  606. slot_ptr_ts (interpreter *interp, object inst,
  607. object name, const array **outpp)
  608. {
  609. auto entry = slotdef_get (interp, as_instance(inst)->tspec, name,
  610. as_array (tspec_shared (inst)));
  611. if (!entry)
  612. return (nullptr);
  613. *outpp = entry;
  614. return (slot_at_ts (entry, inst));
  615. }
  616. static inline object*
  617. slot_at (const array *entry, object inst, object ts)
  618. {
  619. int ix = as_int (entry->data[SLOTDEF_INDEX]);
  620. if (kp_unlikely (ix == -1))
  621. return (&as_instance(inst)->builtin);
  622. else if (entry->data[SLOTDEF_FLAGS] & fixint (SLOTDEF_SHARED_FLG))
  623. { // Inherited shared slot.
  624. int i1 = ix & 0x3fff, i2 = ix >> 14;
  625. if (i2 != 0)
  626. ts = xaref (tspec_parents (ts), i2 - 1);
  627. object def = xaref (tspec_shared (ts), i1);
  628. return (&xaref(def, SLOTDEF_INDEX));
  629. }
  630. return (&xaref(as_instance(inst)->slots, ix));
  631. }
  632. static object*
  633. slot_ptr (interpreter *interp, object inst,
  634. object name, const array **outpp)
  635. {
  636. if (typespec_p (inst))
  637. return (slot_ptr_ts (interp, inst, name, outpp));
  638. object ts = as_instance(inst)->ptype;
  639. auto entry = slotdef_get (interp, ts, name,
  640. as_array (tspec_slotdefs (ts)));
  641. if (!entry)
  642. return (nullptr);
  643. *outpp = entry;
  644. return (slot_at (entry, inst, ts));
  645. }
  646. instance::slotdef_iter::slotdef_iter (interpreter *interp, object inst) :
  647. slotdefs (interp, tspec_slotdefs (as_instance(inst)->ptype)),
  648. idx (-1), builtin (interp, UNBOUND)
  649. {
  650. static_assert (KP_NELEM (this->bt_room) >= SLOTDEF_NUM_MEMBERS,
  651. "insufficient room for builtin slot definition");
  652. const auto ptype = as_instance (as_instance(inst)->ptype);
  653. if (ptype->builtin != UNBOUND)
  654. {
  655. this->bt_room[SLOTDEF_NAME] =
  656. this->bt_room[SLOTDEF_TYPE] = ptype->builtin;
  657. this->bt_room[SLOTDEF_INIT] = as_instance(ptype->builtin)->slots;
  658. this->bt_room[SLOTDEF_FLAGS] = fixint (0);
  659. this->bt_room[SLOTDEF_PROPS] = UNBOUND;
  660. this->bt_room[SLOTDEF_INDEX] = fixint (-1);
  661. this->bt_mem.local_init (this->bt_room, KP_NELEM (this->bt_room));
  662. *this->builtin = this->bt_mem.as_obj ();
  663. }
  664. else
  665. ++*this;
  666. }
  667. object instance::slotdef_iter::operator* () const
  668. {
  669. if (*this->builtin != UNBOUND)
  670. return (*this->builtin);
  671. return (xaref (*this->slotdefs, this->idx));
  672. }
  673. instance::slotdef_iter& instance::slotdef_iter::operator++ ()
  674. {
  675. *this->builtin = UNBOUND;
  676. while (++this->idx < len_a (*this->slotdefs))
  677. {
  678. object sdef = xaref (*this->slotdefs, this->idx);
  679. if (sdef != fixint (0))
  680. return (*this);
  681. }
  682. *this->slotdefs = UNBOUND;
  683. return (*this);
  684. }
  685. instance::slotdef_iter instance::slotdef_iter::operator++ (int)
  686. {
  687. slotdef_iter ret { interpreter::self (), *this };
  688. ++*this;
  689. return (ret);
  690. }
  691. static result<bool>
  692. nput_slot (interpreter *interp, object inst, object key, object val,
  693. const array *sdef, object *ptr)
  694. {
  695. if (!ptr)
  696. return (interp->raise ("unbound-error",
  697. KP_SPRINTF (interp, "object has no slot named %Q",
  698. key)));
  699. else if (sdef->data[SLOTDEF_FLAGS] & fixint (SLOTDEF_GETTER_FLG))
  700. {
  701. KP_VTRY (interp->growstk (3));
  702. *interp->stkend++ = xaref (sdef->data[SLOTDEF_PROPS], 1);
  703. if (interp->stktop () == UNBOUND)
  704. return (interp->raise ("arg-error",
  705. KP_SPRINTF (interp, "no setter defined for "
  706. "slot %Q", key)));
  707. *interp->stkend++ = inst;
  708. *interp->stkend++ = val;
  709. KP_TRY (call_n (interp, 2));
  710. return (false);
  711. }
  712. else if (kp_unlikely (sdef->data[SLOTDEF_TYPE] != UNBOUND &&
  713. instanceof (val, sdef->data[SLOTDEF_TYPE]) < 1))
  714. return (interp->raise ("type-error",
  715. KP_SPRINTF (interp, "slot %Q must be of type %Q, "
  716. "got %Q",
  717. key, sdef->data[SLOTDEF_TYPE],
  718. type (val))));
  719. *ptr = val;
  720. return (true);
  721. }
  722. static inline bool
  723. slot_name_p (object x)
  724. {
  725. if (!symbol_p (x))
  726. return (false);
  727. x = sympkg (x);
  728. return (x == kword_package || nil_p (x));
  729. }
  730. static result<bool>
  731. nput_helper (interpreter *interp, object inst, object key,
  732. object val, object cflag = fixint (SLOTDEF_CONST_FLG))
  733. {
  734. if (builtin_typespec_p (key) &&
  735. key == type (as_instance(inst)->builtin))
  736. {
  737. instance::slotdef_iter it { interp, inst };
  738. return (nput_slot (interp, inst, key, val,
  739. as_array (*it), &as_instance(inst)->builtin));
  740. }
  741. else if (!slot_name_p (key))
  742. return (interp->raise ("type-error", "slot name must be a keyword or "
  743. "uninterned symbol"));
  744. const array *sdef = nullptr;
  745. object *ptr = slot_ptr (interp, inst, key, &sdef);
  746. if (sdef->data[SLOTDEF_FLAGS] & cflag)
  747. return (interp->raise ("const-error",
  748. KP_SPRINTF (interp, "cannot set read-only slot %Q",
  749. key)));
  750. return (nput_slot (interp, inst, key, val, sdef, ptr));
  751. }
  752. enum
  753. {
  754. pack_idx_typespec,
  755. pack_idx_int,
  756. pack_idx_char,
  757. pack_idx_cons,
  758. pack_idx_float,
  759. pack_idx_bvector,
  760. pack_idx_str,
  761. pack_idx_array,
  762. pack_idx_table,
  763. pack_idx_tuple,
  764. pack_idx_stream,
  765. pack_idx_symbol,
  766. pack_idx_fct,
  767. pack_idx_coro,
  768. pack_idx_thread,
  769. pack_idx_pkg,
  770. };
  771. static inline result<object>
  772. builtin_slot_init (interpreter *interp, const array *sdef)
  773. {
  774. int idx = as_int (sdef->data[SLOTDEF_INIT]);
  775. switch (idx)
  776. {
  777. case pack_idx_int:
  778. kp_return (fixint (0));
  779. case pack_idx_char:
  780. kp_return (charobj ('\0'));
  781. case pack_idx_cons:
  782. kp_return (NIL);
  783. case pack_idx_float:
  784. kp_return (fltobj::make (interp, 0));
  785. case pack_idx_bvector:
  786. kp_return (deref (alloc_bvector (interp, 0)));
  787. case pack_idx_str:
  788. kp_return (deref (alloc_str (interp, 0)));
  789. case pack_idx_array:
  790. kp_return (deref (alloc_array (interp, 0)));
  791. case pack_idx_table:
  792. return (KP_CALL (interp, table_fct, NIL, NIL));
  793. case pack_idx_tuple:
  794. return (KP_CALL (interp, tuple_fct, NIL));
  795. default:
  796. return (interp->raise ("arg-error",
  797. KP_SPRINTF (interp, "cannot default initialize "
  798. "builtin slot of type %Q",
  799. sdef->data[SLOTDEF_NAME])));
  800. }
  801. }
  802. result<object> alloc_inst (interpreter *interp, object type,
  803. object *argv, int argc)
  804. {
  805. if (!typespec_p (type))
  806. return (interp->raise ("type-error",
  807. KP_SPRINTF (interp, "expected a type, got %Q",
  808. type)));
  809. auto eg = KP_TRY (evh_guard::make (interp));
  810. instance *inst = alloch<instance> ();
  811. inst->ptype = type;
  812. inst->slots = KP_TRY (alloc_array (interp, as_int (tspec_nslots (type))));
  813. inst->tspec = inst->builtin = UNBOUND;
  814. interp->alval = inst->as_obj ();
  815. gc_register (interp, inst, sizeof (*inst));
  816. valref saved (interp, interp->alval);
  817. for (int i = 0; i < argc; i += 2)
  818. {
  819. if (i + 1 >= argc)
  820. return (interp->raise ("arg-error", "expected an even number of "
  821. "slot initializers"));
  822. KP_VTRY (nput_helper (interp, *saved, argv[i], argv[i + 1], 0));
  823. }
  824. if (!as_instance(type)->flagged_p (instance::init_flag))
  825. return (interp->alval);
  826. // We may need to run additional slot initializers.
  827. valref value (interp);
  828. instance::slotdef_iter it { interp, interp->alval };
  829. for (; it.valid (); ++it)
  830. {
  831. const array *sdef = as_array (*it);
  832. if (sdef->data[SLOTDEF_INIT] == UNBOUND ||
  833. (sdef->data[SLOTDEF_FLAGS] & fixint (SLOTDEF_SHARED_FLG |
  834. SLOTDEF_GETTER_FLG)))
  835. continue;
  836. object *ptr = slot_at (sdef, *saved, type);
  837. if (*ptr != UNBOUND)
  838. continue;
  839. else if (fixint_p (sdef->data[SLOTDEF_INIT]))
  840. { *value = KP_TRY (builtin_slot_init (interp, sdef)); }
  841. else
  842. {
  843. KP_VTRY (interp->push (sdef->data[SLOTDEF_INIT]));
  844. *value = KP_TRY (call_n (interp, 0));
  845. }
  846. bool rv = KP_TRY (nput_slot (interp, *saved, sdef->data[SLOTDEF_NAME],
  847. *value, sdef, ptr));
  848. if (rv)
  849. deref (gc_wbarrier (interp, *saved, *value));
  850. }
  851. return (interp->alval = *saved);
  852. }
  853. result<object> get_w (interpreter *interp, object inst,
  854. object key, object dfl)
  855. {
  856. if (kp_unlikely (dfl != UNBOUND))
  857. return (interp->raise_nargs (2, 2, 3));
  858. else if (builtin_typespec_p (key) &&
  859. key == type (as_instance(inst)->builtin))
  860. kp_return (as_instance(inst)->builtin);
  861. else if (!slot_name_p (key))
  862. return (interp->raise ("type-error", "slot name must be a keyword or "
  863. "uninterned symbol"));
  864. const array *sdef = nullptr;
  865. object *ptr = slot_ptr (interp, inst, key, &sdef);
  866. if (sdef)
  867. {
  868. if (sdef->data[SLOTDEF_FLAGS] & fixint (SLOTDEF_GETTER_FLG))
  869. {
  870. object getter = xaref (sdef->data[SLOTDEF_PROPS], 0);
  871. if (getter == UNBOUND)
  872. return (interp->raise ("arg-error",
  873. KP_SPRINTF (interp,
  874. "no getter defined for slot %Q",
  875. key)));
  876. KP_PUSH_ALL (interp, getter, inst);
  877. KP_TRY (call_n (interp, 1));
  878. if (kp_unlikely (sdef->data[SLOTDEF_TYPE] != UNBOUND &&
  879. instanceof (interp->retval,
  880. sdef->data[SLOTDEF_TYPE]) < 1))
  881. return (interp->raise ("type-error",
  882. KP_SPRINTF (interp, "slot %Q must be of type"
  883. " %Q, got %Q",
  884. key, sdef->data[SLOTDEF_TYPE],
  885. type (interp->retval))));
  886. return (interp->retval);
  887. }
  888. else if (*ptr != UNBOUND)
  889. kp_return (*ptr);
  890. }
  891. return (interp->raise ("unbound-error",
  892. KP_SPRINTF (interp, "slot %Q is unbound", key)));
  893. }
  894. result<object> nput_w (interpreter *interp, object inst,
  895. object key, object val)
  896. {
  897. if (kp_unlikely (as_varobj(inst)->flagged_p (FLAGS_CONST)))
  898. return (interp->raise_const ());
  899. bool rv = KP_TRY (nput_helper (interp, inst, key, val));
  900. if (!rv)
  901. return (interp->retval);
  902. deref (gc_wbarrier (interp, inst, val));
  903. kp_return (val);
  904. }
  905. result<int64_t> write_w (interpreter *interp, stream *strm,
  906. object x, io_info& info)
  907. {
  908. int64_t ret = KP_TRY (strm->write (interp, "#<", 2));
  909. const instance *inst = as_instance (x);
  910. if (inst->tspec == UNBOUND)
  911. {
  912. ret += KP_TRY (xwrite (interp, strm, tspec_name (inst->ptype), info));
  913. char buf[64];
  914. ret += KP_TRY (strm->write (interp, buf,
  915. sprintf (buf, " object at %p",
  916. (const void *)inst)));
  917. }
  918. else
  919. {
  920. if (!fixint_p (inst->slots))
  921. { ret += KP_TRY (strm->write (interp, "type ", 5)); }
  922. ret += KP_TRY (xwrite (interp, strm,
  923. xaref (inst->tspec, TSPEC_NAME), info));
  924. }
  925. ret += KP_TRY (strm->putb (interp, '>'));
  926. return (ret);
  927. }
  928. static inline result<int64_t>
  929. maybe_pack (interpreter *interp, stream *strm, object obj, pack_info& info)
  930. {
  931. if (obj == UNBOUND)
  932. obj = NIL;
  933. return (xpack (interp, strm, obj, info));
  934. }
  935. result<int64_t> pack_w (interpreter *interp, stream *strm,
  936. object obj, pack_info& info)
  937. {
  938. const instance *inst = as_instance (obj);
  939. int64_t ret = KP_TRY (maybe_pack (interp, strm, inst->ptype, info));
  940. ret += KP_TRY (maybe_pack (interp, strm, inst->slots, info));
  941. ret += KP_TRY (maybe_pack (interp, strm, inst->tspec, info));
  942. ret += KP_TRY (xpack (interp, strm, inst->builtin == UNBOUND ?
  943. fixint (0) : inst->builtin, info));
  944. return (ret);
  945. }
  946. unsigned int instance::type_code () const
  947. {
  948. return (fixint_p (this->slots) ? as_int (this->slots) : 0xff);
  949. }
  950. result<object> unpack_w (interpreter *interp, stream *strm,
  951. pack_info& info, bool save)
  952. {
  953. valref ptype (interp), slots (interp), tspec (interp), builtin (interp);
  954. *ptype = KP_TRY (xunpack (interp, strm, info));
  955. if (!array_p (*ptype))
  956. return (info.error ("invalid parent type read"));
  957. *slots = KP_TRY (xunpack (interp, strm, info));
  958. if (!array_p (*slots))
  959. return (info.error ("invalid slots read"));
  960. *tspec = KP_TRY (xunpack (interp, strm, info));
  961. if (*tspec == NIL)
  962. *tspec = UNBOUND;
  963. else if (!array_p (*tspec))
  964. return (info.error ("invalid typespec read"));
  965. *builtin = KP_TRY (xunpack (interp, strm, info));
  966. if (*builtin == fixint (0))
  967. *builtin = UNBOUND;
  968. else if (!builtin_typespec_p (*builtin))
  969. return (info.error ("invalid builtin specifier read"));
  970. auto inst = alloch<instance> ();
  971. inst->ptype = *ptype;
  972. inst->slots = *slots;
  973. inst->tspec = *tspec;
  974. inst->builtin = *builtin;
  975. interp->retval = inst->as_obj ();
  976. gc_register (interp, inst);
  977. if (save)
  978. KP_VTRY (info.add_mapping (interp, *info.offset, inst->as_obj ()));
  979. kp_return (inst->as_obj ());
  980. }
  981. object builtin_type (unsigned int code)
  982. {
  983. switch (code)
  984. {
  985. #define TYPE(name) \
  986. case pack_idx_##name: \
  987. return (name##_type)
  988. TYPE (typespec);
  989. TYPE (int);
  990. TYPE (char);
  991. TYPE (cons);
  992. TYPE (float);
  993. TYPE (bvector);
  994. TYPE (str);
  995. TYPE (array);
  996. TYPE (table);
  997. TYPE (tuple);
  998. TYPE (stream);
  999. TYPE (symbol);
  1000. TYPE (fct);
  1001. TYPE (coro);
  1002. TYPE (thread);
  1003. TYPE (pkg);
  1004. default:
  1005. return (UNBOUND);
  1006. #undef TYPE
  1007. }
  1008. }
  1009. static inline int
  1010. isa_1 (object objtype, object tspec)
  1011. {
  1012. if (objtype == tspec)
  1013. return (1);
  1014. const auto ptypes = as_array (tspec_parents (objtype));
  1015. for (uint32_t i = 0; i < ptypes->len; ++i)
  1016. if (ptypes->data[i] == tspec)
  1017. return ((int)(i + 2));
  1018. return (0);
  1019. }
  1020. int subtype_p (object ty, object ts)
  1021. {
  1022. return (typespec_p (ts) ? isa_1 (ty, ts) : -1);
  1023. }
  1024. int instanceof (object obj, object ts)
  1025. {
  1026. return (subtype_p (type (obj), ts));
  1027. }
  1028. object type_name (object obj)
  1029. {
  1030. return (typespec_p (obj) ? tspec_name (obj) : NIL);
  1031. }
  1032. object builtin_member (object obj)
  1033. {
  1034. return (instance_p (obj) ? as_instance(obj)->builtin : obj);
  1035. }
  1036. struct builtin_typespec
  1037. {
  1038. const char *name;
  1039. object *outp;
  1040. int pack_idx;
  1041. void init (interpreter *interp)
  1042. {
  1043. valref ts (interp, deref (alloc_array (interp, TSPEC_NUM_MEMBERS)));
  1044. valref sym (interp, deref (intern (interp, this->name, nullptr,
  1045. FLAGS_CONST | symbol::literal_flag)));
  1046. xaref(*ts, TSPEC_NAME) = *sym;
  1047. xaref(*ts, TSPEC_PARENTS) = xaref(*ts, TSPEC_SHARED) =
  1048. xaref(*ts, TSPEC_SLOTDEFS) = deref (alloc_array (interp, 0));
  1049. xaref(*ts, TSPEC_NSLOTS) = fixint (0);
  1050. instance *inst = alloch<instance> ();
  1051. *this->outp = inst->as_obj ();
  1052. inst->ptype = typespec_type;
  1053. inst->slots = fixint (this->pack_idx);
  1054. inst->tspec = *ts;
  1055. inst->builtin = this->pack_idx == pack_idx_typespec ?
  1056. UNBOUND : inst->as_obj ();
  1057. inst->vo_full |= FLAGS_CONST;
  1058. interp->alval = *this->outp;
  1059. gc_register (interp, inst, sizeof (*inst));
  1060. symval(*sym) = *this->outp;
  1061. }
  1062. };
  1063. static int
  1064. do_init_types (interpreter *interp)
  1065. {
  1066. int ret = init_op::call_deps (interp, &init_symbols, &init_array);
  1067. if (ret != init_op::result_ok)
  1068. return (ret);
  1069. builtin_typespec builtin_types[] =
  1070. {
  1071. // typespec must come first.
  1072. { "typespec", &typespec_type, pack_idx_typespec },
  1073. #define TYPE(name) \
  1074. { #name "-t", &name##_type, pack_idx_##name }
  1075. TYPE (int), TYPE (char), TYPE (cons), TYPE (float), TYPE (bvector),
  1076. TYPE (str), TYPE (array), TYPE (table), TYPE (tuple), TYPE (stream),
  1077. TYPE (symbol), TYPE (fct), TYPE (coro), TYPE (thread), TYPE (pkg)
  1078. };
  1079. evh_safeguard eg { interp };
  1080. for (size_t i = 0; i < KP_NELEM (builtin_types); ++i)
  1081. builtin_types[i].init (interp);
  1082. #undef TYPE
  1083. return (init_op::result_ok);
  1084. }
  1085. init_op init_types (do_init_types, "types");
  1086. KP_DECLS_END