py_range.c 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. #include "pocketpy/pocketpy.h"
  2. #include "pocketpy/common/utils.h"
  3. #include "pocketpy/objects/object.h"
  4. #include "pocketpy/interpreter/vm.h"
  5. typedef struct Range {
  6. py_i64 start;
  7. py_i64 stop;
  8. py_i64 step;
  9. } Range;
  10. static bool range__new__(int argc, py_Ref argv) {
  11. Range* ud = py_newobject(py_retval(), tp_range, 0, sizeof(Range));
  12. switch(argc - 1) { // skip cls
  13. case 1: {
  14. PY_CHECK_ARG_TYPE(1, tp_int);
  15. ud->start = 0;
  16. ud->stop = py_toint(py_arg(1));
  17. ud->step = 1;
  18. break;
  19. }
  20. case 2:
  21. PY_CHECK_ARG_TYPE(1, tp_int);
  22. PY_CHECK_ARG_TYPE(2, tp_int);
  23. ud->start = py_toint(py_arg(1));
  24. ud->stop = py_toint(py_arg(2));
  25. ud->step = 1;
  26. break;
  27. case 3:
  28. PY_CHECK_ARG_TYPE(1, tp_int);
  29. PY_CHECK_ARG_TYPE(2, tp_int);
  30. PY_CHECK_ARG_TYPE(3, tp_int);
  31. ud->start = py_toint(py_arg(1));
  32. ud->stop = py_toint(py_arg(2));
  33. ud->step = py_toint(py_arg(3));
  34. break;
  35. default: return TypeError("range() expected at most 3 arguments, got %d", argc - 1);
  36. }
  37. if(ud->step == 0) return ValueError("range() step must not be zero");
  38. return true;
  39. }
  40. static bool range__iter__(int argc, py_Ref argv) {
  41. PY_CHECK_ARGC(1);
  42. return py_tpcall(tp_range_iterator, 1, argv);
  43. }
  44. py_Type pk_range__register() {
  45. py_Type type = pk_newtype("range", tp_object, NULL, NULL, false, true);
  46. py_bindmagic(type, __new__, range__new__);
  47. py_bindmagic(type, __iter__, range__iter__);
  48. return type;
  49. }
  50. typedef struct RangeIterator {
  51. Range range;
  52. py_i64 current;
  53. } RangeIterator;
  54. static bool range_iterator__new__(int argc, py_Ref argv) {
  55. PY_CHECK_ARGC(2);
  56. PY_CHECK_ARG_TYPE(1, tp_range);
  57. RangeIterator* ud = py_newobject(py_retval(), tp_range_iterator, 0, sizeof(RangeIterator));
  58. ud->range = *(Range*)py_touserdata(py_arg(1));
  59. ud->current = ud->range.start;
  60. return true;
  61. }
  62. bool range_iterator__next__(int argc, py_Ref argv) {
  63. PY_CHECK_ARGC(1);
  64. RangeIterator* ud = py_touserdata(argv);
  65. if(ud->range.step > 0) {
  66. if(ud->current >= ud->range.stop) return StopIteration();
  67. } else {
  68. if(ud->current <= ud->range.stop) return StopIteration();
  69. }
  70. py_newint(py_retval(), ud->current);
  71. ud->current += ud->range.step;
  72. return true;
  73. }
  74. py_Type pk_range_iterator__register() {
  75. py_Type type = pk_newtype("range_iterator", tp_object, NULL, NULL, false, true);
  76. py_bindmagic(type, __new__, range_iterator__new__);
  77. py_bindmagic(type, __iter__, pk_wrapper__self);
  78. py_bindmagic(type, __next__, range_iterator__next__);
  79. return type;
  80. }