Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

981 rader
24 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. std::function<lvalue(sp_coords)> resolve_coords = [&](sp_coords) -> lvalue {
  41. std::cerr << "no coord system provided" << std::endl;
  42. if(error_crash)
  43. {
  44. std::exit(-1);
  45. }
  46. return (int64_t)0;
  47. };
  48. std::function<lvalue(sp_range)> resolve_range = [&](sp_range) -> lvalue {
  49. std::cerr << "no coord system provided" << std::endl;
  50. if(error_crash)
  51. {
  52. std::exit(-1);
  53. }
  54. return empty{};
  55. };
  56. int get_atom(const std::string& key)
  57. {
  58. if(atoms.count(key)) {
  59. return atoms[key];
  60. } else {
  61. return atoms[key] = ++last_atom;
  62. }
  63. }
  64. };
  65. class cons {
  66. public:
  67. lvalue self = empty{};
  68. std::shared_ptr<cons> other{};
  69. cons()
  70. {
  71. self = empty{};
  72. other = std::shared_ptr<cons>{};
  73. }
  74. cons(lvalue first)
  75. : self(first)
  76. , other()
  77. { }
  78. cons(std::vector<lvalue> data)
  79. {
  80. if(data.size() == 0) {
  81. self = empty{};
  82. other = std::shared_ptr<cons>{};
  83. } else if(data.size() >= 1) {
  84. self = data[0];
  85. for(auto it = data.begin()+1; it != data.end(); ++it)
  86. this->append(*it);
  87. }
  88. }
  89. cons(const cons& oth)
  90. : self(oth.self)
  91. , other(oth.other ? std::make_shared<cons>(*(oth.other)) : nullptr)
  92. {}
  93. void operator=(const cons& oth)
  94. {
  95. self = oth.self;
  96. if(oth.other) {
  97. other = std::make_shared<cons>(*oth.other);
  98. } else {
  99. other = std::shared_ptr<cons>{};
  100. }
  101. }
  102. cons(cons&& oth)
  103. : self(oth.self)
  104. , other(oth.other ? std::make_shared<cons>(*(oth.other)) : std::shared_ptr<cons>{})
  105. {}
  106. void append(lvalue value)
  107. {
  108. if(!other) {
  109. other = std::make_shared<cons>(value);
  110. } else {
  111. other->append(value);
  112. }
  113. }
  114. };
  115. class function {
  116. public:
  117. virtual lvalue operator() (const std::shared_ptr<cons> arguments, lispy::context& ctx) = 0;
  118. virtual ~function(){};
  119. };
  120. inline char hexdigit(char v)
  121. {
  122. if(v >= '0' && v<='9') {
  123. return v - '0';
  124. } else if(v >= 'a' && v <= 'f') {
  125. return 10 + v - 'a';
  126. } else if(v >= 'A' && v <= 'F') {
  127. return 10 + v - 'A';
  128. }
  129. return -1;
  130. }
  131. inline std::string escape(std::string_view v)
  132. {
  133. auto it = v.begin();
  134. std::stringstream stream;
  135. stream<<'"';
  136. while(it != v.end())
  137. {
  138. switch(*it)
  139. {
  140. case '"':
  141. {
  142. stream << "\\\"";
  143. }
  144. break;
  145. case '\n':
  146. {
  147. stream << "\\n";
  148. }
  149. break;
  150. case '\t':
  151. {
  152. stream << "\\t";
  153. }
  154. break;
  155. case '\v':
  156. {
  157. stream << "\\v";
  158. }
  159. break;
  160. case '\a':
  161. {
  162. stream << "\\a";
  163. }
  164. break;
  165. default:
  166. stream << *it;
  167. }
  168. ++it;
  169. }
  170. stream<<'"';
  171. return stream.str();
  172. }
  173. inline void print_visitor(std::ostream& stream, const lvalue& value, const context& ctx) {
  174. std::visit([&](auto arg) {
  175. using T = std::decay_t<decltype(arg)>;
  176. if constexpr (std::is_same_v<T, int64_t>) {
  177. stream << arg;
  178. } else if constexpr (std::is_same_v<T, double>) {
  179. stream << arg;
  180. } else if constexpr (std::is_same_v<T, empty>) {
  181. stream << "()";
  182. } else if constexpr (std::is_same_v<T, std::shared_ptr<function>>) {
  183. stream << "#func"<<&*arg;
  184. } else if constexpr (std::is_same_v<T, std::string>) {
  185. stream << escape(arg);
  186. } else if constexpr (std::is_same_v<T, std::shared_ptr<cons>>) {
  187. stream << "(";
  188. bool is_first = true;
  189. cons p = *arg;
  190. do{
  191. if(!is_first)
  192. {
  193. p = *p.other;
  194. }
  195. print_visitor(stream, p.self, ctx);
  196. if(p.other)
  197. {
  198. stream << " ";
  199. }
  200. is_first = false;
  201. } while(p.other);
  202. stream << ")";
  203. }
  204. else if constexpr (std::is_same_v<T, sp_coords>){
  205. stream << (arg.is_relative ? "$[" : "@[") << arg.x << "," << arg.y << "]";
  206. } else if constexpr (std::is_same_v<T, sp_range>){
  207. stream << (arg.is_relative ? "$[" : "@[") << arg.x << "," << arg.y << "," << arg.width << "," << arg.height << "]";
  208. } else if constexpr (std::is_same_v<T, atom>) {
  209. for(auto& v : ctx.atoms)
  210. {
  211. if(v.second == arg.value)
  212. {
  213. stream << v.first;
  214. return;
  215. }
  216. }
  217. assert(false);
  218. } else {
  219. std::cerr <<
  220. #ifdef __cpp_rtti
  221. typeid(T).name()
  222. #else
  223. "unknown type"
  224. #endif
  225. << " detected in print_visitor ?" << std::endl;
  226. if(ctx.error_crash)
  227. {
  228. std::exit(-1);
  229. }
  230. }
  231. }, value);
  232. }
  233. inline void print_types_visitor(std::ostream& stream, const lvalue& value, const context& ctx) {
  234. std::visit([&](auto arg) {
  235. using T = std::decay_t<decltype(arg)>;
  236. if constexpr (std::is_same_v<T, int64_t>) {
  237. stream << "integer";
  238. } else if constexpr (std::is_same_v<T, double>) {
  239. stream << "double";
  240. } else if constexpr (std::is_same_v<T, empty>) {
  241. stream << "nil";
  242. } else if constexpr (std::is_same_v<T, std::shared_ptr<function>>) {
  243. stream << "function";
  244. } else if constexpr (std::is_same_v<T, std::string>) {
  245. stream << "string";
  246. } else if constexpr (std::is_same_v<T, std::shared_ptr<cons>>){
  247. stream << "(";
  248. bool is_first = true;
  249. cons p = *arg;
  250. do{
  251. if(!is_first)
  252. {
  253. p = *p.other;
  254. }
  255. print_types_visitor(stream, p.self, ctx);
  256. if(p.other)
  257. {
  258. stream << " ";
  259. }
  260. is_first = false;
  261. } while(p.other);
  262. stream << ")";
  263. } else if constexpr (std::is_same_v<T, sp_coords>){
  264. stream << "coords";
  265. } else if constexpr (std::is_same_v<T, sp_range>){
  266. stream << "range";
  267. } else if constexpr (std::is_same_v<T, atom>) {
  268. stream << "atom";
  269. } else {
  270. std::cerr <<
  271. #ifdef __cpp_rtti
  272. typeid(T).name()
  273. #else
  274. "unknown type"
  275. #endif
  276. << " detected in print_types_visitor ?" << std::endl;
  277. if(ctx.error_crash)
  278. {
  279. std::exit(-1);
  280. }
  281. }
  282. }, value);
  283. }
  284. inline std::pair<lvalue, std::string_view> parse_string(std::string_view data)
  285. {
  286. auto it = data.begin();
  287. assert(*it == '\"');
  288. ++it;
  289. std::stringstream value(std::string(data.begin(), data.end()));
  290. std::string ret;
  291. value >> std::quoted(ret);
  292. return std::make_pair<lvalue, std::string_view>(ret, std::string_view{data.begin(), (size_t)value.rdbuf()->in_avail()});
  293. }
  294. inline std::pair<lvalue, std::string_view> parse_atom(std::string_view data, context& ctx)
  295. {
  296. assert(!iswspace(data[0]));
  297. size_t idx = 1;
  298. while(!iswspace(data[idx]))
  299. {
  300. idx++;
  301. }
  302. atom v;
  303. v.value = ctx.get_atom(std::string(data.begin(), data.begin()+idx));
  304. return std::make_pair(lvalue{v}, std::string_view{data.begin(), idx});
  305. }
  306. inline std::pair<lvalue, std::string_view> parse_number(std::string_view data)
  307. {
  308. char* end_f;
  309. char* end_d;
  310. double try_f = strtod (data.data(), &end_f);
  311. int64_t try_d = strtoll(data.data(), &end_d, 10);
  312. int err_d = errno;
  313. if(err_d == ERANGE)
  314. {
  315. return std::make_pair(lvalue{(double)try_f}, std::string_view{data.begin(), (size_t)(end_f-data.data())});
  316. }
  317. if(try_f != std::trunc(try_f))
  318. {
  319. return std::make_pair(lvalue{(double)try_f}, std::string_view{data.begin(), (size_t)(end_f-data.data())});
  320. }
  321. return std::make_pair(lvalue{int64_t(try_d)}, std::string_view{data.begin(), (size_t)(end_f-data.data())});
  322. }
  323. inline std::pair<size_t,sp_coords> get_coords_from_id(const std::string_view id) {
  324. size_t x = 0;
  325. size_t y = 0;
  326. auto c = id.begin();
  327. while(*c >= 'A' && *c <= 'Z')
  328. {
  329. x += *c-'A'+1;
  330. x *= 26;
  331. c++;
  332. }
  333. x /= 26;
  334. while(*c >= '0' && *c <= '9')
  335. {
  336. y += *c-'0';
  337. y *= 10;
  338. c++;
  339. }
  340. y /= 10;
  341. sp_coords ret;
  342. ret.x = x;
  343. ret.y = y;
  344. return std::make_pair((size_t)(c-id.begin()) ,ret);
  345. }
  346. inline std::pair<lvalue, std::string_view> parse_selector(std::string_view data)
  347. {
  348. auto it = data.begin();
  349. auto is_rel = *it == '$';
  350. ++it;
  351. auto a = get_coords_from_id(std::string_view{it, data.size()-1});
  352. a.second.is_relative = is_rel;
  353. it += a.first;
  354. if(*it == ':')
  355. {
  356. auto b = get_coords_from_id(std::string_view{++it, data.size()-1});
  357. it += b.first;
  358. sp_range ret;
  359. a.second.is_relative = is_rel;
  360. ret.x = a.second.x;
  361. ret.y = a.second.y;
  362. ret.width = b.second.x;
  363. ret.height = b.second.y;
  364. return std::make_pair(lvalue{ret}, std::string_view{data.begin(), (size_t)(it - data.begin())});
  365. } else {
  366. return std::make_pair(lvalue{a.second}, std::string_view{data.begin(), (size_t)(it - data.begin())});
  367. }
  368. }
  369. inline size_t find_matching(const std::basic_string_view<token>& data, const size_t idx)
  370. {
  371. size_t try_idx = idx;
  372. int mass = 1;
  373. do{
  374. try_idx++;
  375. std::visit([&](auto arg) {
  376. using T = std::decay_t<decltype(arg)>;
  377. if constexpr (std::is_same_v<T, cons_start>) {
  378. ++mass;
  379. } else if constexpr (std::is_same_v<T, cons_end>) {
  380. --mass;
  381. } else {}
  382. }, data[try_idx]);
  383. } while(mass != 0 && try_idx < data.size());
  384. if(try_idx<data.size())
  385. {
  386. return try_idx;
  387. }
  388. return idx;
  389. }
  390. inline std::pair<size_t, lvalue> parse(const std::basic_string_view<token>& data, context& ctx)
  391. {
  392. auto ret = std::make_shared<cons>();
  393. size_t sz = 0;
  394. if(data.size() == 0)
  395. {
  396. return std::make_pair(0,(lvalue)empty{});
  397. }
  398. size_t skip = 0;
  399. size_t idx = 0;
  400. while(idx < data.size())
  401. {
  402. if(skip)
  403. {
  404. skip--;
  405. ++idx;
  406. continue;
  407. }
  408. std::visit([&](const auto& arg) {
  409. using T = std::decay_t<decltype(arg)>;
  410. if constexpr (std::is_same_v<T, cons_start>) {
  411. auto matching = find_matching(data, idx);
  412. auto res = parse(std::basic_string_view<token>{data.begin()+idx+1, matching-idx-1}, ctx);
  413. ret->append(res.second);
  414. skip = matching - idx;
  415. ++sz;
  416. } else if constexpr (std::is_same_v<T, cons_end>) {
  417. std::cerr <<
  418. #ifdef __cpp_rtti
  419. typeid(T).name()
  420. #else
  421. "unknown type"
  422. #endif
  423. << " mismatched parenthesis" << std::endl;
  424. } else if constexpr (std::is_same_v<T, lvalue>) {
  425. ret->append(arg);
  426. ++sz;
  427. } else {
  428. std::cerr <<
  429. #ifdef __cpp_rtti
  430. typeid(T).name()
  431. #else
  432. "unknown type"
  433. #endif
  434. << " cat in the parser ?" << std::endl;
  435. if(ctx.error_crash)
  436. {
  437. std::exit(-1);
  438. }
  439. }
  440. }, data[idx]);
  441. ++idx;
  442. }
  443. return std::make_pair(sz, (lvalue)(std::make_shared<cons>(*ret->other)));
  444. }
  445. inline std::vector<token> lex(const std::string_view data, context& ctx)
  446. {
  447. std::vector<token> ret;
  448. auto it = data.begin();
  449. bool is_done = false;
  450. do{
  451. if (it == data.end()) {
  452. is_done = true;
  453. } else if(isdigit(*it) || (*it == '-' && isdigit(*(it+1)))) {
  454. auto value = parse_number(std::string_view{it, (size_t)(data.end() - it)});
  455. ret.push_back(value.first);
  456. it += value.second.size();
  457. } else if(*it == '\"') {
  458. auto value = parse_string(std::string_view{it, (size_t)(data.end() - it)});
  459. ret.push_back(value.first);
  460. size_t forward_jump = std::string_view{it, (size_t)(data.end() - it)}.size()-value.second.size();
  461. it += forward_jump;
  462. } else if (*it == '(') {
  463. ret.push_back(cons_start{});
  464. ++it;
  465. } else if (*it == ')') {
  466. ret.push_back(cons_end{});
  467. ++it;
  468. } else if (iswspace(*it)) {
  469. ++it;
  470. } else if (*it == '$' || *it == '@') {
  471. auto value = parse_selector(std::string_view{it, (size_t)(data.end() - it)});
  472. ret.push_back(value.first);
  473. it += value.second.size();
  474. } else {
  475. auto value = parse_atom(std::string_view{it, (size_t)(data.end() - it)}, ctx);
  476. ret.push_back(value.first);
  477. it += value.second.size();
  478. }
  479. }while(!is_done);
  480. return ret;
  481. }
  482. inline lvalue eval(lvalue& data, context& ctx)
  483. {
  484. lvalue ret = empty{};
  485. std::visit([&](auto& arg) {
  486. using T = std::decay_t<decltype(arg)>;
  487. if constexpr (std::is_same_v<T, std::shared_ptr<cons>>) {
  488. auto it = arg;
  489. auto evaluated = std::make_shared<cons>();
  490. auto iterated = evaluated;
  491. do{
  492. iterated->self = eval(it->self, ctx);
  493. if(it->other)
  494. {
  495. iterated->other = std::make_shared<cons>();
  496. iterated = iterated->other;
  497. }
  498. it = it->other;
  499. } while(it);
  500. std::visit([&](auto arg) {
  501. using T = std::decay_t<decltype(arg)>;
  502. if constexpr (std::is_same_v<T, std::shared_ptr<function>>) {
  503. ret = (*arg)(evaluated->other, ctx);
  504. } else {
  505. ret = evaluated;
  506. }
  507. }, evaluated->self);
  508. } else if constexpr (std::is_same_v<T, atom>) {
  509. if(ctx.function_table.count(arg.value))
  510. {
  511. ret = ctx.function_table[arg.value];
  512. } else if (ctx.variable_table.count(arg.value)) {
  513. ret = ctx.variable_table[arg.value];
  514. } else {
  515. ret = arg;
  516. }
  517. } else {
  518. ret = arg;
  519. }
  520. }, data);
  521. return ret;
  522. }
  523. inline lvalue eval(const std::string_view& data, context& ctx)
  524. {
  525. auto n = lex(data, ctx);
  526. auto p = parse(std::basic_string_view<token>(n.data(), n.size()), ctx);
  527. if(ctx.print_parse_results)
  528. {
  529. print_types_visitor(std::cerr, p.second, ctx);
  530. std::cerr << std::endl;
  531. print_visitor(std::cerr, p.second, ctx);
  532. std::cerr << std::endl;
  533. }
  534. return eval(p.second, ctx);
  535. }
  536. }
  537. namespace lispy_math {
  538. int64_t next_as_int(std::shared_ptr<lispy::cons>& arguments, lispy::context& ctx) {
  539. int64_t ret = 0;
  540. if(!arguments)
  541. {
  542. std::cerr << "no argument provided, number expected" << std::endl;
  543. if(ctx.error_crash)
  544. {
  545. std::exit(-1);
  546. }
  547. return ret;
  548. }
  549. auto extractor = [&](auto arg) {
  550. using T = std::decay_t<decltype(arg)>;
  551. if constexpr (std::is_same_v<T, int64_t>) {
  552. ret = arg;
  553. } else if constexpr (std::is_same_v<T, double>) {
  554. ret = arg;
  555. } else {
  556. std::cerr << "bad argument provided, number expected" << std::endl;
  557. if(ctx.error_crash)
  558. {
  559. std::exit(-1);
  560. }
  561. }
  562. };
  563. std::visit([&](auto arg) {
  564. using T = std::decay_t<decltype(arg)>;
  565. if constexpr (std::is_same_v<T, lispy::sp_coords>) {
  566. std::visit(extractor, ctx.resolve_coords(arg));
  567. } else {
  568. std::visit(extractor, arguments->self);
  569. }
  570. }, arguments->self);
  571. arguments = arguments->other;
  572. return ret;
  573. }
  574. double next_as_floating(std::shared_ptr<lispy::cons>& arguments, lispy::context& ctx) {
  575. double ret = 0;
  576. if(!arguments)
  577. {
  578. std::cerr << "no argument provided, number expected" << std::endl;
  579. if(ctx.error_crash)
  580. {
  581. std::exit(-1);
  582. }
  583. return ret;
  584. }
  585. auto extractor = [&](auto arg) {
  586. using T = std::decay_t<decltype(arg)>;
  587. if constexpr (std::is_same_v<T, int64_t>) {
  588. ret = arg;
  589. } else if constexpr (std::is_same_v<T, double>) {
  590. ret = arg;
  591. } else {
  592. std::cerr << "bad argument provided, number expected" << std::endl;
  593. if(ctx.error_crash)
  594. {
  595. std::exit(-1);
  596. }
  597. }
  598. };
  599. std::visit([&](auto arg) {
  600. using T = std::decay_t<decltype(arg)>;
  601. if constexpr (std::is_same_v<T, lispy::sp_coords>) {
  602. std::visit(extractor, ctx.resolve_coords(arg));
  603. } else {
  604. std::visit(extractor, arguments->self);
  605. }
  606. }, arguments->self);
  607. arguments = arguments->other;
  608. return ret;
  609. }
  610. lispy::lvalue next_as_floating_aggregate(std::shared_ptr<lispy::cons>& arguments, lispy::context& ctx) {
  611. lispy::lvalue src = lispy::empty{};
  612. if(!arguments)
  613. {
  614. std::cerr << "no argument provided, s-exp or range expected" << std::endl;
  615. if(ctx.error_crash)
  616. {
  617. std::exit(-1);
  618. }
  619. return src;
  620. }
  621. auto extractor = [&](auto arg) {
  622. using T = std::decay_t<decltype(arg)>;
  623. if constexpr (std::is_same_v<T, lispy::empty>) {
  624. src = arg;
  625. } else if constexpr (std::is_same_v<T, std::shared_ptr<lispy::cons>>) {
  626. src = arg;
  627. } else {
  628. std::cerr << "bad argument provided, s-exp or range expected" << std::endl;
  629. if(ctx.error_crash)
  630. {
  631. std::exit(-1);
  632. }
  633. }
  634. };
  635. std::visit([&](auto arg) {
  636. using T = std::decay_t<decltype(arg)>;
  637. if constexpr (std::is_same_v<T, lispy::sp_range>) {
  638. std::visit(extractor, ctx.resolve_range(arg));
  639. } else if constexpr (std::is_same_v<T, std::shared_ptr<lispy::cons>>) {
  640. std::visit(extractor, arguments->self);
  641. } else {
  642. std::cerr << "bad argument provided, s-exp or range expected" << std::endl;
  643. if(ctx.error_crash)
  644. {
  645. std::exit(-1);
  646. }
  647. }
  648. }, arguments->self);
  649. std::shared_ptr<lispy::cons> dest;
  650. std::visit([&](auto arg) {
  651. using T = std::decay_t<decltype(arg)>;
  652. if constexpr (std::is_same_v<T, lispy::empty>) {}
  653. else if constexpr (std::is_same_v<T, std::shared_ptr<lispy::cons>>) {
  654. dest = std::make_shared<lispy::cons>(lispy_math::next_as_floating(arg, ctx));
  655. while(arg){
  656. dest->append(lispy_math::next_as_floating(arg, ctx));
  657. }
  658. } else {
  659. std::cerr << "bad argument provided, s-exp or range expected" << std::endl;
  660. if(ctx.error_crash)
  661. {
  662. std::exit(-1);
  663. }
  664. }
  665. }, src);
  666. arguments = arguments->other;
  667. if(dest)
  668. {
  669. return dest;
  670. }
  671. return lispy::empty{};
  672. }
  673. namespace integer_functions {
  674. class plus : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  675. auto p = arguments;
  676. int64_t a = next_as_int(p, ctx);
  677. int64_t b = next_as_int(p, ctx);
  678. if(p)
  679. {
  680. std::cerr << "expected arity of 2 but more arguments provided" << std::endl;
  681. if(ctx.error_crash)
  682. {
  683. std::exit(-1);
  684. }
  685. }
  686. return a+b;
  687. }};
  688. class minus : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  689. auto p = arguments;
  690. int64_t a = next_as_int(p, ctx);
  691. if(!p) {
  692. return -a;
  693. }
  694. int64_t b = next_as_int(p, ctx);
  695. if(p)
  696. {
  697. std::cerr << "expected arity of 1 or 2 but more arguments provided" << std::endl;
  698. if(ctx.error_crash)
  699. {
  700. std::exit(-1);
  701. }
  702. }
  703. return a-b;
  704. }};
  705. class product : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  706. auto p = arguments;
  707. int64_t a = next_as_int(p, ctx);
  708. int64_t b = next_as_int(p, ctx);
  709. if(p)
  710. {
  711. std::cerr << "expected arity of 2 but more arguments provided" << std::endl;
  712. if(ctx.error_crash)
  713. {
  714. std::exit(-1);
  715. }
  716. }
  717. return a*b;
  718. }};
  719. class divide : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  720. auto p = arguments;
  721. int64_t a = next_as_int(p, ctx);
  722. int64_t b = next_as_int(p, ctx);
  723. if(p)
  724. {
  725. std::cerr << "expected arity of 2 but more arguments provided" << std::endl;
  726. if(ctx.error_crash)
  727. {
  728. std::exit(-1);
  729. }
  730. }
  731. return a/b;
  732. }};
  733. class remainder : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  734. auto p = arguments;
  735. int64_t a = next_as_int(p, ctx);
  736. int64_t b = next_as_int(p, ctx);
  737. if(p)
  738. {
  739. std::cerr << "expected arity of 2 but more arguments provided" << std::endl;
  740. if(ctx.error_crash)
  741. {
  742. std::exit(-1);
  743. }
  744. }
  745. return a%b;
  746. }};
  747. class iota : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  748. auto p = arguments;
  749. int64_t a = next_as_int(p, ctx);
  750. int64_t b = next_as_int(p, ctx);
  751. if(p)
  752. {
  753. std::cerr << "expected arity of 2 but more arguments provided" << std::endl;
  754. if(ctx.error_crash)
  755. {
  756. std::exit(-1);
  757. }
  758. }
  759. if(b<=a)
  760. {
  761. std::cerr << "expected first argument lower than second" << std::endl;
  762. if(ctx.error_crash)
  763. {
  764. std::exit(-1);
  765. }
  766. return lispy::empty{};
  767. }
  768. std::shared_ptr<lispy::cons> ret = std::make_shared<lispy::cons>(a);
  769. a+=1;
  770. for(;a<b;a++)
  771. {
  772. ret->append(a);
  773. }
  774. return ret;
  775. }};
  776. };
  777. namespace float_functions {
  778. class plus : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  779. auto p = arguments;
  780. double a = next_as_floating(p, ctx);
  781. double b = next_as_floating(p, ctx);
  782. if(p)
  783. {
  784. std::cerr << "expected arity of 2 but more arguments provided" << std::endl;
  785. if(ctx.error_crash)
  786. {
  787. std::exit(-1);
  788. }
  789. }
  790. return a+b;
  791. }};
  792. class minus : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  793. auto p = arguments;
  794. double a = next_as_floating(p, ctx);
  795. if(!p) {
  796. return -a;
  797. }
  798. double b = next_as_floating(p, ctx);
  799. if(p)
  800. {
  801. std::cerr << "expected arity of 1 or 2 but more arguments provided" << std::endl;
  802. if(ctx.error_crash)
  803. {
  804. std::exit(-1);
  805. }
  806. }
  807. return a-b;
  808. }};
  809. class product : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  810. auto p = arguments;
  811. double a = next_as_floating(p, ctx);
  812. double b = next_as_floating(p, ctx);
  813. if(p)
  814. {
  815. std::cerr << "expected arity of 2 but more arguments provided" << std::endl;
  816. if(ctx.error_crash)
  817. {
  818. std::exit(-1);
  819. }
  820. }
  821. return a*b;
  822. }};
  823. class divide : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  824. auto p = arguments;
  825. double a = next_as_floating(p, ctx);
  826. double b = next_as_floating(p, ctx);
  827. if(p)
  828. {
  829. std::cerr << "expected arity of 2 but more arguments provided" << std::endl;
  830. if(ctx.error_crash)
  831. {
  832. std::exit(-1);
  833. }
  834. }
  835. return a/b;
  836. }};
  837. };
  838. namespace aggregate_functions {
  839. class sum : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr<lispy::cons> arguments, lispy::context& ctx) {
  840. auto p = arguments;
  841. lispy::lvalue cells = next_as_floating_aggregate(p, ctx);
  842. if(p)
  843. {
  844. std::cerr << "expected arity of 1 but more arguments provided" << std::endl;
  845. if(ctx.error_crash)
  846. {
  847. std::exit(-1);
  848. }
  849. }
  850. double ret = 0;
  851. while(std::get<std::shared_ptr<lispy::cons>>(cells)) {
  852. ret += lispy_math::next_as_floating(std::get<std::shared_ptr<lispy::cons>>(cells), ctx);
  853. }
  854. return ret;
  855. }};
  856. };
  857. inline void add_integer_functions(lispy::context& ctx) {
  858. using func_ptr = std::shared_ptr<lispy::function>;
  859. ctx.function_table[ctx.get_atom("+")] = func_ptr{(lispy::function*)new integer_functions::plus()};
  860. ctx.function_table[ctx.get_atom("-")] = func_ptr{(lispy::function*)new integer_functions::minus()};
  861. ctx.function_table[ctx.get_atom("*")] = func_ptr{(lispy::function*)new integer_functions::product()};
  862. ctx.function_table[ctx.get_atom("/")] = func_ptr{(lispy::function*)new integer_functions::divide()};
  863. ctx.function_table[ctx.get_atom("%")] = func_ptr{(lispy::function*)new integer_functions::remainder()};
  864. ctx.function_table[ctx.get_atom("iota")] = func_ptr{(lispy::function*)new integer_functions::iota()};
  865. }
  866. inline void add_floatingp_functions(lispy::context& ctx) {
  867. using func_ptr = std::shared_ptr<lispy::function>;
  868. ctx.function_table[ctx.get_atom("+.")] = func_ptr{(lispy::function*)new float_functions::plus()};
  869. ctx.function_table[ctx.get_atom("-.")] = func_ptr{(lispy::function*)new float_functions::minus()};
  870. ctx.function_table[ctx.get_atom("*.")] = func_ptr{(lispy::function*)new float_functions::product()};
  871. ctx.function_table[ctx.get_atom("/.")] = func_ptr{(lispy::function*)new float_functions::divide()};
  872. }
  873. inline void add_aggregate_functions(lispy::context& ctx) {
  874. using func_ptr = std::shared_ptr<lispy::function>;
  875. ctx.function_table[ctx.get_atom("sum")] = func_ptr{(lispy::function*)new aggregate_functions::sum()};
  876. }
  877. }