You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

773 lines
19 KiB

  1. #pragma once
  2. #include <variant>
  3. #include <memory>
  4. #include <vector>
  5. #include <sstream>
  6. #include <functional>
  7. #include <cassert>
  8. #include <iostream>
  9. #include <iomanip>
  10. #include <unordered_map>
  11. #include <cstdlib>
  12. #include <cmath>
  13. namespace lispy {
  14. class cons;
  15. class function;
  16. struct empty {};
  17. struct cons_start{};
  18. struct cons_end{};
  19. struct atom {
  20. int value;
  21. };
  22. struct sp_coords {
  23. bool is_relative = false;
  24. size_t x, y;
  25. };
  26. struct sp_range {
  27. bool is_relative = false;
  28. size_t x, y;
  29. size_t width, height;
  30. };
  31. using lvalue = std::variant<int64_t, double, std::string, atom, empty, std::shared_ptr<cons>, sp_coords, sp_range, std::shared_ptr<function>>;
  32. using token = std::variant<cons_start, cons_end, lvalue>;
  33. struct context {
  34. std::unordered_map<std::string, int> atoms;
  35. int last_atom = 0;
  36. bool error_crash = false;
  37. bool print_parse_results = false;
  38. std::unordered_map<int, std::shared_ptr<function>> function_table;
  39. std::unordered_map<int, lvalue> variable_table;
  40. int get_atom(const std::string& key)
  41. {
  42. if(atoms.count(key)) {
  43. return atoms[key];
  44. } else {
  45. return atoms[key] = ++last_atom;
  46. }
  47. }
  48. };
  49. class cons {
  50. public:
  51. lvalue self = empty{};
  52. std::shared_ptr<cons> other{};
  53. cons()
  54. {
  55. self = empty{};
  56. other = std::shared_ptr<cons>{};
  57. }
  58. cons(lvalue first)
  59. : self(first)
  60. , other()
  61. { }
  62. cons(std::vector<lvalue> data)
  63. {
  64. if(data.size() == 0) {
  65. self = empty{};
  66. other = std::shared_ptr<cons>{};
  67. } else if(data.size() >= 1) {
  68. self = data[0];
  69. for(auto it = data.begin()+1; it != data.end(); ++it)
  70. this->append(*it);
  71. }
  72. }
  73. cons(const cons& oth)
  74. : self(oth.self)
  75. , other(oth.other ? std::make_shared<cons>(*(oth.other)) : nullptr)
  76. {}
  77. void operator=(const cons& oth)
  78. {
  79. self = oth.self;
  80. if(oth.other) {
  81. other = std::make_shared<cons>(*oth.other);
  82. } else {
  83. other = std::shared_ptr<cons>{};
  84. }
  85. }
  86. cons(cons&& oth)
  87. : self(oth.self)
  88. , other(oth.other ? std::move(std::make_shared<cons>(*(oth.other))) : std::shared_ptr<cons>{})
  89. {}
  90. void append(lvalue value)
  91. {
  92. if(!other) {
  93. other = std::make_shared<cons>(value);
  94. } else {
  95. other->append(value);
  96. }
  97. }
  98. };
  99. class function {
  100. public:
  101. virtual lvalue operator() (const std::shared_ptr<cons> arguments, lispy::context& ctx) = 0;
  102. virtual ~function(){};
  103. };
  104. inline char hexdigit(char v)
  105. {
  106. if(v >= '0' && v<='9') {
  107. return v - '0';
  108. } else if(v >= 'a' && v <= 'f') {
  109. return 10 + v - 'a';
  110. } else if(v >= 'A' && v <= 'F') {
  111. return 10 + v - 'A';
  112. }
  113. return -1;
  114. }
  115. inline std::string escape(std::string_view v)
  116. {
  117. auto it = v.begin();
  118. std::stringstream stream;
  119. stream<<'"';
  120. while(it != v.end())
  121. {
  122. switch(*it)
  123. {
  124. case '"':
  125. {
  126. stream << "\\\"";
  127. }
  128. break;
  129. case '\n':
  130. {
  131. stream << "\\n";
  132. }
  133. break;
  134. case '\t':
  135. {
  136. stream << "\\t";
  137. }
  138. break;
  139. case '\v':
  140. {
  141. stream << "\\v";
  142. }
  143. break;
  144. case '\a':
  145. {
  146. stream << "\\a";
  147. }
  148. break;
  149. default:
  150. stream << *it;
  151. }
  152. ++it;
  153. }
  154. stream<<'"';
  155. return stream.str();
  156. }
  157. inline void print_visitor(std::ostream& stream, const lvalue& value, const context& ctx) {
  158. std::visit([&](auto arg) {
  159. using T = std::decay_t<decltype(arg)>;
  160. if constexpr (std::is_same_v<T, int64_t>) {
  161. stream << arg;
  162. } else if constexpr (std::is_same_v<T, double>) {
  163. stream << arg;
  164. } else if constexpr (std::is_same_v<T, empty>) {
  165. stream << "()";
  166. } else if constexpr (std::is_same_v<T, std::shared_ptr<function>>) {
  167. stream << "#func"<<&*arg;
  168. } else if constexpr (std::is_same_v<T, std::string>) {
  169. stream << escape(arg);
  170. } else if constexpr (std::is_same_v<T, std::shared_ptr<cons>>) {
  171. stream << "(";
  172. bool is_first = true;
  173. cons p = *arg;
  174. do{
  175. if(!is_first)
  176. {
  177. p = *p.other;
  178. }
  179. print_visitor(stream, p.self, ctx);
  180. if(p.other)
  181. {
  182. stream << " ";
  183. }
  184. is_first = false;
  185. } while(p.other);
  186. stream << ")";
  187. }
  188. else if constexpr (std::is_same_v<T, sp_coords>){
  189. stream << (arg.is_relative ? "$[" : "@[") << arg.x << "," << arg.y << "]";
  190. } else if constexpr (std::is_same_v<T, sp_range>){
  191. stream << (arg.is_relative ? "$[" : "@[") << arg.x << "," << arg.y << "," << arg.width << "," << arg.height << "]";
  192. } else if constexpr (std::is_same_v<T, atom>) {
  193. for(auto& v : ctx.atoms)
  194. {
  195. if(v.second == arg.value)
  196. {
  197. stream << v.first;
  198. return;
  199. }
  200. }
  201. assert(false);
  202. } else {
  203. std::cerr << typeid(T).name() << " detected in print_visitor ?" << std::endl;
  204. if(ctx.error_crash)
  205. {
  206. std::exit(-1);
  207. }
  208. }
  209. }, value);
  210. }
  211. inline void print_types_visitor(std::ostream& stream, const lvalue& value, const context& ctx) {
  212. std::visit([&](auto arg) {
  213. using T = std::decay_t<decltype(arg)>;
  214. if constexpr (std::is_same_v<T, int64_t>) {
  215. stream << "integer";
  216. } else if constexpr (std::is_same_v<T, double>) {
  217. stream << "double";
  218. } else if constexpr (std::is_same_v<T, empty>) {
  219. stream << "nil";
  220. } else if constexpr (std::is_same_v<T, std::shared_ptr<function>>) {
  221. stream << "function";
  222. } else if constexpr (std::is_same_v<T, std::string>) {
  223. stream << "string";
  224. } else if constexpr (std::is_same_v<T, std::shared_ptr<cons>>){
  225. stream << "(";
  226. bool is_first = true;
  227. cons p = *arg;
  228. do{
  229. if(!is_first)
  230. {
  231. p = *p.other;
  232. }
  233. print_types_visitor(stream, p.self, ctx);
  234. if(p.other)
  235. {
  236. stream << " ";
  237. }
  238. is_first = false;
  239. } while(p.other);
  240. stream << ")";
  241. } else if constexpr (std::is_same_v<T, sp_coords>){
  242. stream << "coords";
  243. } else if constexpr (std::is_same_v<T, sp_range>){
  244. stream << "range";
  245. } else if constexpr (std::is_same_v<T, atom>) {
  246. stream << "atom";
  247. } else {
  248. std::cerr << typeid(T).name() << " detected in print_types_visitor ?" << std::endl;
  249. if(ctx.error_crash)
  250. {
  251. std::exit(-1);
  252. }
  253. }
  254. }, value);
  255. }
  256. inline std::pair<lvalue, std::string_view> parse_string(std::string_view data)
  257. {
  258. auto it = data.begin();
  259. assert(*it == '\"');
  260. ++it;
  261. std::stringstream value(std::string(data.begin(), data.end()));
  262. std::string ret;
  263. value >> std::quoted(ret);
  264. return std::make_pair<lvalue, std::string_view>(ret, std::string_view{data.begin(), (size_t)value.rdbuf()->in_avail()});
  265. }
  266. inline std::pair<lvalue, std::string_view> parse_atom(std::string_view data, context& ctx)
  267. {
  268. assert(!iswspace(data[0]));
  269. size_t idx = 1;
  270. while(!iswspace(data[idx]))
  271. {
  272. idx++;
  273. }
  274. atom v;
  275. v.value = ctx.get_atom(std::string(data.begin(), data.begin()+idx));
  276. return std::make_pair(lvalue{v}, std::string_view{data.begin(), idx});
  277. }
  278. inline std::pair<lvalue, std::string_view> parse_number(std::string_view data)
  279. {
  280. char* end_f;
  281. char* end_d;
  282. double try_f = strtod (data.data(), &end_f);
  283. int err_f = errno;
  284. int64_t try_d = strtoll(data.data(), &end_d, 10);
  285. int err_d = errno;
  286. if(err_d == ERANGE)
  287. {
  288. return std::make_pair(lvalue{(double)try_f}, std::string_view{data.begin(), (size_t)(end_f-data.data())});
  289. }
  290. if(try_f != std::trunc(try_f))
  291. {
  292. return std::make_pair(lvalue{(double)try_f}, std::string_view{data.begin(), (size_t)(end_f-data.data())});
  293. }
  294. return std::make_pair(lvalue{int64_t(try_d)}, std::string_view{data.begin(), (size_t)(end_f-data.data())});
  295. }
  296. inline std::pair<size_t,sp_coords> get_coords_from_id(const std::string_view id) {
  297. size_t x = 0;
  298. size_t y = 0;
  299. auto c = id.begin();
  300. while(*c >= 'A' && *c <= 'Z')
  301. {
  302. x += *c-'A'+1;
  303. x *= 26;
  304. c++;
  305. }
  306. x /= 26;
  307. while(*c >= '0' && *c <= '9')
  308. {
  309. y += *c-'0';
  310. y *= 10;
  311. c++;
  312. }
  313. y /= 10;
  314. sp_coords ret;
  315. ret.x = x;
  316. ret.y = y;
  317. return std::make_pair((size_t)(c-id.begin()) ,ret);
  318. }
  319. inline std::pair<lvalue, std::string_view> parse_selector(std::string_view data)
  320. {
  321. auto it = data.begin();
  322. auto is_rel = *it == '$';
  323. ++it;
  324. auto a = get_coords_from_id(std::string_view{it, data.size()-1});
  325. a.second.is_relative = is_rel;
  326. it += a.first;
  327. if(*it == ':')
  328. {
  329. auto b = get_coords_from_id(std::string_view{++it, data.size()-1});
  330. it += b.first;
  331. sp_range ret;
  332. a.second.is_relative = is_rel;
  333. ret.x = a.second.x;
  334. ret.y = a.second.y;
  335. ret.width = b.second.x;
  336. ret.height = b.second.y;
  337. return std::make_pair(lvalue{ret}, std::string_view{data.begin(), (size_t)(it - data.begin())});
  338. } else {
  339. return std::make_pair(lvalue{a.second}, std::string_view{data.begin(), (size_t)(it - data.begin())});
  340. }
  341. }
  342. inline size_t find_matching(const std::basic_string_view<token>& data, const size_t idx)
  343. {
  344. size_t try_idx = idx;
  345. int mass = 1;
  346. do{
  347. try_idx++;
  348. std::visit([&](auto arg) {
  349. using T = std::decay_t<decltype(arg)>;
  350. if constexpr (std::is_same_v<T, cons_start>) {
  351. ++mass;
  352. } else if constexpr (std::is_same_v<T, cons_end>) {
  353. --mass;
  354. } else {}
  355. }, data[try_idx]);
  356. } while(mass != 0 && try_idx < data.size());
  357. if(try_idx<data.size())
  358. {
  359. return try_idx;
  360. }
  361. return idx;
  362. }
  363. inline std::pair<size_t, lvalue> parse(const std::basic_string_view<token>& data, context& ctx)
  364. {
  365. auto ret = std::make_shared<cons>();
  366. size_t sz = 0;
  367. if(data.size() == 0)
  368. {
  369. return std::make_pair(0,(lvalue)empty{});
  370. }
  371. size_t skip = 0;
  372. size_t idx = 0;
  373. while(idx < data.size())
  374. {
  375. if(skip)
  376. {
  377. skip--;
  378. ++idx;
  379. continue;
  380. }
  381. std::visit([&](const auto& arg) {
  382. using T = std::decay_t<decltype(arg)>;
  383. if constexpr (std::is_same_v<T, cons_start>) {
  384. auto matching = find_matching(data, idx);
  385. auto res = parse(std::basic_string_view<token>{data.begin()+idx+1, matching-idx-1}, ctx);
  386. ret->append(res.second);
  387. skip = matching - idx;
  388. ++sz;
  389. } else if constexpr (std::is_same_v<T, cons_end>) {
  390. std::cerr << typeid(T).name() << " mismatched parenthesis" << std::endl;
  391. } else if constexpr (std::is_same_v<T, lvalue>) {
  392. ret->append(arg);
  393. ++sz;
  394. } else {
  395. std::cerr << typeid(T).name() << " cat in the parser ?" << std::endl;
  396. if(ctx.error_crash)
  397. {
  398. std::exit(-1);
  399. }
  400. }
  401. }, data[idx]);
  402. ++idx;
  403. }
  404. return std::make_pair(sz, (lvalue)(std::make_shared<cons>(*ret->other)));
  405. }
  406. inline std::vector<token> lex(const std::string_view data, context& ctx)
  407. {
  408. std::vector<token> ret;
  409. auto it = data.begin();
  410. bool is_done = false;
  411. do{
  412. if (it == data.end()) {
  413. is_done = true;
  414. } else if(isdigit(*it) || (*it == '-' && isdigit(*(it+1)))) {
  415. auto value = parse_number(std::string_view{it, (size_t)(data.end() - it)});
  416. ret.push_back(value.first);
  417. it += value.second.size();
  418. } else if(*it == '\"') {
  419. auto value = parse_string(std::string_view{it, (size_t)(data.end() - it)});
  420. ret.push_back(value.first);
  421. size_t forward_jump = std::string_view{it, (size_t)(data.end() - it)}.size()-value.second.size();
  422. it += forward_jump;
  423. } else if (*it == '(') {
  424. ret.push_back(cons_start{});
  425. ++it;
  426. } else if (*it == ')') {
  427. ret.push_back(cons_end{});
  428. ++it;
  429. } else if (iswspace(*it)) {
  430. ++it;
  431. } else if (*it == '$' || *it == '@') {
  432. auto value = parse_selector(std::string_view{it, (size_t)(data.end() - it)});
  433. ret.push_back(value.first);
  434. it += value.second.size()+1;
  435. } else {
  436. auto value = parse_atom(std::string_view{it, (size_t)(data.end() - it)}, ctx);
  437. ret.push_back(value.first);
  438. it += value.second.size();
  439. }
  440. }while(!is_done);
  441. return ret;
  442. }
  443. inline lvalue eval(lvalue& data, context& ctx)
  444. {
  445. lvalue ret = empty{};
  446. std::visit([&](auto& arg) {
  447. using T = std::decay_t<decltype(arg)>;
  448. if constexpr (std::is_same_v<T, std::shared_ptr<cons>>) {
  449. auto it = arg;
  450. auto evaluated = std::make_shared<cons>();
  451. auto iterated = evaluated;
  452. do{
  453. iterated->self = eval(it->self, ctx);
  454. if(it->other)
  455. {
  456. iterated->other = std::make_shared<cons>();
  457. iterated = iterated->other;
  458. }
  459. it = it->other;
  460. } while(it);
  461. std::visit([&](auto arg) {
  462. using T = std::decay_t<decltype(arg)>;
  463. if constexpr (std::is_same_v<T, std::shared_ptr<function>>) {
  464. ret = (*arg)(evaluated->other, ctx);
  465. } else {
  466. ret = evaluated;
  467. }
  468. }, evaluated->self);
  469. } else if constexpr (std::is_same_v<T, atom>) {
  470. if(ctx.function_table.count(arg.value))
  471. {
  472. ret = ctx.function_table[arg.value];
  473. } else if (ctx.variable_table.count(arg.value)) {
  474. ret = ctx.variable_table[arg.value];
  475. } else {
  476. ret = arg;
  477. }
  478. } else {
  479. ret = arg;
  480. }
  481. }, data);
  482. return ret;
  483. }
  484. inline lvalue eval(const std::string_view& data, context& ctx)
  485. {
  486. auto n = lex(data, ctx);
  487. auto p = parse(std::basic_string_view<token>(n.data(), n.size()), ctx);
  488. if(ctx.print_parse_results)
  489. {
  490. print_types_visitor(std::cerr, p.second, ctx);
  491. std::cerr << std::endl;
  492. print_visitor(std::cerr, p.second, ctx);
  493. std::cerr << std::endl;
  494. }
  495. return eval(p.second, ctx);
  496. }
  497. }
  498. namespace lispy_math {
  499. int64_t next_as_int(std::shared_ptr<lispy::cons>& arguments, lispy::context& ctx) {
  500. int64_t ret = 0;
  501. if(!arguments)
  502. {
  503. std::cerr << "no argument provided, number expected" << std::endl;
  504. if(ctx.error_crash)
  505. {
  506. std::exit(-1);
  507. }
  508. return ret;
  509. }
  510. std::visit([&](auto arg) {
  511. using T = std::decay_t<decltype(arg)>;
  512. if constexpr (std::is_same_v<T, int64_t>) {
  513. ret = arg;
  514. } else if constexpr (std::is_same_v<T, double>) {
  515. ret = arg;
  516. } else {
  517. std::cerr << "bad argument provided, number expected" << std::endl;
  518. if(ctx.error_crash)
  519. {
  520. std::exit(-1);
  521. }
  522. }
  523. }, arguments->self);
  524. arguments = arguments->other;
  525. return ret;
  526. }
  527. double next_as_floating(std::shared_ptr<lispy::cons>& arguments, lispy::context& ctx) {
  528. double ret = 0;
  529. if(!arguments)
  530. {
  531. std::cerr << "no argument provided, number expected" << std::endl;
  532. if(ctx.error_crash)
  533. {
  534. std::exit(-1);
  535. }
  536. return ret;
  537. }
  538. std::visit([&](auto arg) {
  539. using T = std::decay_t<decltype(arg)>;
  540. if constexpr (std::is_same_v<T, int64_t>) {
  541. ret = arg;
  542. } else if constexpr (std::is_same_v<T, double>) {
  543. ret = arg;
  544. } else {
  545. std::cerr << "bad argument provided, number expected" << std::endl;
  546. if(ctx.error_crash)
  547. {
  548. std::exit(-1);
  549. }
  550. }
  551. }, arguments->self);
  552. arguments = arguments->other;
  553. return ret;
  554. }
  555. namespace integer_functions {
  556. class plus : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  557. auto p = arguments;
  558. int64_t a = next_as_int(p, ctx);
  559. int64_t b = next_as_int(p, ctx);
  560. if(p)
  561. {
  562. std::cerr << "expected arity of 2 but more arguments provided" << std::endl;
  563. if(ctx.error_crash)
  564. {
  565. std::exit(-1);
  566. }
  567. }
  568. return a+b;
  569. }};
  570. class minus : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  571. auto p = arguments;
  572. int64_t a = next_as_int(p, ctx);
  573. if(!p) {
  574. return -a;
  575. }
  576. int64_t b = next_as_int(p, ctx);
  577. if(p)
  578. {
  579. std::cerr << "expected arity of 1 or 2 but more arguments provided" << std::endl;
  580. if(ctx.error_crash)
  581. {
  582. std::exit(-1);
  583. }
  584. }
  585. return a-b;
  586. }};
  587. class product : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  588. auto p = arguments;
  589. int64_t a = next_as_int(p, ctx);
  590. int64_t b = next_as_int(p, ctx);
  591. if(p)
  592. {
  593. std::cerr << "expected arity of 2 but more arguments provided" << std::endl;
  594. if(ctx.error_crash)
  595. {
  596. std::exit(-1);
  597. }
  598. }
  599. return a*b;
  600. }};
  601. class divide : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  602. auto p = arguments;
  603. int64_t a = next_as_int(p, ctx);
  604. int64_t b = next_as_int(p, ctx);
  605. if(p)
  606. {
  607. std::cerr << "expected arity of 2 but more arguments provided" << std::endl;
  608. if(ctx.error_crash)
  609. {
  610. std::exit(-1);
  611. }
  612. }
  613. return a/b;
  614. }};
  615. class remainder : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  616. auto p = arguments;
  617. int64_t a = next_as_int(p, ctx);
  618. int64_t b = next_as_int(p, ctx);
  619. if(p)
  620. {
  621. std::cerr << "expected arity of 2 but more arguments provided" << std::endl;
  622. if(ctx.error_crash)
  623. {
  624. std::exit(-1);
  625. }
  626. }
  627. return a%b;
  628. }};
  629. };
  630. namespace float_functions {
  631. class plus : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  632. auto p = arguments;
  633. double a = next_as_floating(p, ctx);
  634. double b = next_as_floating(p, ctx);
  635. if(p)
  636. {
  637. std::cerr << "expected arity of 2 but more arguments provided" << std::endl;
  638. if(ctx.error_crash)
  639. {
  640. std::exit(-1);
  641. }
  642. }
  643. return a+b;
  644. }};
  645. class minus : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  646. auto p = arguments;
  647. double a = next_as_floating(p, ctx);
  648. if(!p) {
  649. return -a;
  650. }
  651. double b = next_as_floating(p, ctx);
  652. if(p)
  653. {
  654. std::cerr << "expected arity of 1 or 2 but more arguments provided" << std::endl;
  655. if(ctx.error_crash)
  656. {
  657. std::exit(-1);
  658. }
  659. }
  660. return a-b;
  661. }};
  662. class product : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  663. auto p = arguments;
  664. double a = next_as_floating(p, ctx);
  665. double b = next_as_floating(p, ctx);
  666. if(p)
  667. {
  668. std::cerr << "expected arity of 2 but more arguments provided" << std::endl;
  669. if(ctx.error_crash)
  670. {
  671. std::exit(-1);
  672. }
  673. }
  674. return a*b;
  675. }};
  676. class divide : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  677. auto p = arguments;
  678. double a = next_as_floating(p, ctx);
  679. double b = next_as_floating(p, ctx);
  680. if(p)
  681. {
  682. std::cerr << "expected arity of 2 but more arguments provided" << std::endl;
  683. if(ctx.error_crash)
  684. {
  685. std::exit(-1);
  686. }
  687. }
  688. return a/b;
  689. }};
  690. };
  691. inline void add_integer_functions(lispy::context& ctx) {
  692. using func_ptr = std::shared_ptr<lispy::function>;
  693. ctx.function_table[ctx.get_atom("+")] = func_ptr{(lispy::function*)new integer_functions::plus()};
  694. ctx.function_table[ctx.get_atom("-")] = func_ptr{(lispy::function*)new integer_functions::minus()};
  695. ctx.function_table[ctx.get_atom("*")] = func_ptr{(lispy::function*)new integer_functions::product()};
  696. ctx.function_table[ctx.get_atom("/")] = func_ptr{(lispy::function*)new integer_functions::divide()};
  697. ctx.function_table[ctx.get_atom("%")] = func_ptr{(lispy::function*)new integer_functions::remainder()};
  698. }
  699. inline void add_floatingp_functions(lispy::context& ctx) {
  700. using func_ptr = std::shared_ptr<lispy::function>;
  701. ctx.function_table[ctx.get_atom("+.")] = func_ptr{(lispy::function*)new float_functions::plus()};
  702. ctx.function_table[ctx.get_atom("-.")] = func_ptr{(lispy::function*)new float_functions::minus()};
  703. ctx.function_table[ctx.get_atom("*.")] = func_ptr{(lispy::function*)new float_functions::product()};
  704. ctx.function_table[ctx.get_atom("/.")] = func_ptr{(lispy::function*)new float_functions::divide()};
  705. }
  706. }