From 0b649f3befa101662ced92375606314b2f513818 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 4 Aug 2024 22:45:00 +0800 Subject: [PATCH] ... --- include/pocketpy/pocketpy.h | 2 +- python/functools.py | 9 ++++----- src/common/_generated.c | 2 +- src/common/sstream.c | 13 ++++++++++--- src2/main.c | 2 +- tests/{44_decorator.py => 42_decorator.py} | 0 tests/{42_closure.py => 43_closure.py} | 12 +++++++++++- tests/43_closure_ex.py | 8 -------- 8 files changed, 28 insertions(+), 20 deletions(-) rename tests/{44_decorator.py => 42_decorator.py} (100%) rename tests/{42_closure.py => 43_closure.py} (70%) delete mode 100644 tests/43_closure_ex.py diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index e1256205..5a910b8b 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -373,7 +373,7 @@ int py_dict__len(py_Ref self); bool py_dict__apply(py_Ref self, bool (*f)(py_Ref key, py_Ref val, void* ctx), void* ctx); /************* Others *************/ -int py_replinput(char* buf); +int py_replinput(char* buf, int max_size); /// Python favored string formatting. (just put here, not for users) /// %d: int diff --git a/python/functools.py b/python/functools.py index 1758f966..6596fd76 100644 --- a/python/functools.py +++ b/python/functools.py @@ -1,5 +1,3 @@ -from pkpy import next - class cache: def __init__(self, f): self.f = f @@ -13,9 +11,10 @@ class cache: def reduce(function, sequence, initial=...): it = iter(sequence) if initial is ...: - value = next(it) - if value is StopIteration: - raise TypeError("reduce() of empty iterable with no initial value") + try: + value = next(it) + except StopIteration: + raise TypeError("reduce() of empty sequence with no initial value") else: value = initial for element in it: diff --git a/src/common/_generated.c b/src/common/_generated.c index 9f3fbf64..d5531c60 100644 --- a/src/common/_generated.c +++ b/src/common/_generated.c @@ -10,7 +10,7 @@ const char kPythonLibs_cmath[] = "import math\n\nclass complex:\n def __init_ const char kPythonLibs_collections[] = "from pkpy import _enable_instance_dict\nfrom typing import Generic, TypeVar, Iterable\n\nT = TypeVar('T')\n\ndef Counter(iterable: Iterable[T]):\n a: dict[T, int] = {}\n for x in iterable:\n if x in a:\n a[x] += 1\n else:\n a[x] = 1\n return a\n\n\nclass defaultdict(dict):\n def __init__(self, default_factory, *args):\n super().__init__(*args)\n _enable_instance_dict(self)\n self.default_factory = default_factory\n\n def __missing__(self, key):\n self[key] = self.default_factory()\n return self[key]\n\n def __repr__(self) -> str:\n return f\"defaultdict({self.default_factory}, {super().__repr__()})\"\n\n def copy(self):\n return defaultdict(self.default_factory, self)\n\n\nclass deque(Generic[T]):\n _data: list[T]\n _head: int\n _tail: int\n _capacity: int\n\n def __init__(self, iterable: Iterable[T] = None):\n self._data = [None] * 8 # initial capacity\n self._head = 0\n self._tail = 0\n self._capacity = len(self._data)\n\n if iterable is not None:\n self.extend(iterable)\n\n def __resize_2x(self):\n backup = list(self)\n self._capacity *= 2\n self._head = 0\n self._tail = len(backup)\n self._data.clear()\n self._data.extend(backup)\n self._data.extend([None] * (self._capacity - len(backup)))\n\n def append(self, x: T):\n self._data[self._tail] = x\n self._tail = (self._tail + 1) % self._capacity\n if (self._tail + 1) % self._capacity == self._head:\n self.__resize_2x()\n\n def appendleft(self, x: T):\n self._head = (self._head - 1 + self._capacity) % self._capacity\n self._data[self._head] = x\n if (self._tail + 1) % self._capacity == self._head:\n self.__resize_2x()\n\n def copy(self):\n return deque(self)\n \n def count(self, x: T) -> int:\n n = 0\n for item in self:\n if item == x:\n n += 1\n return n\n \n def extend(self, iterable: Iterable[T]):\n for x in iterable:\n self.append(x)\n\n def extendleft(self, iterable: Iterable[T]):\n for x in iterable:\n self.appendleft(x)\n \n def pop(self) -> T:\n if self._head == self._tail:\n raise IndexError(\"pop from an empty deque\")\n self._tail = (self._tail - 1 + self._capacity) % self._capacity\n return self._data[self._tail]\n \n def popleft(self) -> T:\n if self._head == self._tail:\n raise IndexError(\"pop from an empty deque\")\n x = self._data[self._head]\n self._head = (self._head + 1) % self._capacity\n return x\n \n def clear(self):\n i = self._head\n while i != self._tail:\n self._data[i] = None\n i = (i + 1) % self._capacity\n self._head = 0\n self._tail = 0\n\n def rotate(self, n: int = 1):\n if len(self) == 0:\n return\n if n > 0:\n n = n % len(self)\n for _ in range(n):\n self.appendleft(self.pop())\n elif n < 0:\n n = -n % len(self)\n for _ in range(n):\n self.append(self.popleft())\n\n def __len__(self) -> int:\n return (self._tail - self._head + self._capacity) % self._capacity\n\n def __contains__(self, x: object) -> bool:\n for item in self:\n if item == x:\n return True\n return False\n \n def __iter__(self):\n i = self._head\n while i != self._tail:\n yield self._data[i]\n i = (i + 1) % self._capacity\n\n def __eq__(self, other: object) -> bool:\n if not isinstance(other, deque):\n return False\n if len(self) != len(other):\n return False\n for x, y in zip(self, other):\n if x != y:\n return False\n return True\n \n def __repr__(self) -> str:\n return f\"deque({list(self)!r})\"\n\n"; const char kPythonLibs_colorsys[] = "\"\"\"Conversion functions between RGB and other color systems.\n\nThis modules provides two functions for each color system ABC:\n\n rgb_to_abc(r, g, b) --> a, b, c\n abc_to_rgb(a, b, c) --> r, g, b\n\nAll inputs and outputs are triples of floats in the range [0.0...1.0]\n(with the exception of I and Q, which covers a slightly larger range).\nInputs outside the valid range may cause exceptions or invalid outputs.\n\nSupported color systems:\nRGB: Red, Green, Blue components\nYIQ: Luminance, Chrominance (used by composite video signals)\nHLS: Hue, Luminance, Saturation\nHSV: Hue, Saturation, Value\n\"\"\"\n\n# References:\n# http://en.wikipedia.org/wiki/YIQ\n# http://en.wikipedia.org/wiki/HLS_color_space\n# http://en.wikipedia.org/wiki/HSV_color_space\n\n__all__ = [\"rgb_to_yiq\",\"yiq_to_rgb\",\"rgb_to_hls\",\"hls_to_rgb\",\n \"rgb_to_hsv\",\"hsv_to_rgb\"]\n\n# Some floating point constants\n\nONE_THIRD = 1.0/3.0\nONE_SIXTH = 1.0/6.0\nTWO_THIRD = 2.0/3.0\n\n# YIQ: used by composite video signals (linear combinations of RGB)\n# Y: perceived grey level (0.0 == black, 1.0 == white)\n# I, Q: color components\n#\n# There are a great many versions of the constants used in these formulae.\n# The ones in this library uses constants from the FCC version of NTSC.\n\ndef rgb_to_yiq(r, g, b):\n y = 0.30*r + 0.59*g + 0.11*b\n i = 0.74*(r-y) - 0.27*(b-y)\n q = 0.48*(r-y) + 0.41*(b-y)\n return (y, i, q)\n\ndef yiq_to_rgb(y, i, q):\n # r = y + (0.27*q + 0.41*i) / (0.74*0.41 + 0.27*0.48)\n # b = y + (0.74*q - 0.48*i) / (0.74*0.41 + 0.27*0.48)\n # g = y - (0.30*(r-y) + 0.11*(b-y)) / 0.59\n\n r = y + 0.9468822170900693*i + 0.6235565819861433*q\n g = y - 0.27478764629897834*i - 0.6356910791873801*q\n b = y - 1.1085450346420322*i + 1.7090069284064666*q\n\n if r < 0.0:\n r = 0.0\n if g < 0.0:\n g = 0.0\n if b < 0.0:\n b = 0.0\n if r > 1.0:\n r = 1.0\n if g > 1.0:\n g = 1.0\n if b > 1.0:\n b = 1.0\n return (r, g, b)\n\n\n# HLS: Hue, Luminance, Saturation\n# H: position in the spectrum\n# L: color lightness\n# S: color saturation\n\ndef rgb_to_hls(r, g, b):\n maxc = max(r, g, b)\n minc = min(r, g, b)\n sumc = (maxc+minc)\n rangec = (maxc-minc)\n l = sumc/2.0\n if minc == maxc:\n return 0.0, l, 0.0\n if l <= 0.5:\n s = rangec / sumc\n else:\n s = rangec / (2.0-maxc-minc) # Not always 2.0-sumc: gh-106498.\n rc = (maxc-r) / rangec\n gc = (maxc-g) / rangec\n bc = (maxc-b) / rangec\n if r == maxc:\n h = bc-gc\n elif g == maxc:\n h = 2.0+rc-bc\n else:\n h = 4.0+gc-rc\n # h = (h/6.0) % 1.0\n h = h / 6.0\n h = h - int(h)\n return h, l, s\n\ndef hls_to_rgb(h, l, s):\n if s == 0.0:\n return l, l, l\n if l <= 0.5:\n m2 = l * (1.0+s)\n else:\n m2 = l+s-(l*s)\n m1 = 2.0*l - m2\n return (_v(m1, m2, h+ONE_THIRD), _v(m1, m2, h), _v(m1, m2, h-ONE_THIRD))\n\ndef _v(m1, m2, hue):\n # hue = hue % 1.0\n hue = hue - int(hue)\n if hue < ONE_SIXTH:\n return m1 + (m2-m1)*hue*6.0\n if hue < 0.5:\n return m2\n if hue < TWO_THIRD:\n return m1 + (m2-m1)*(TWO_THIRD-hue)*6.0\n return m1\n\n\n# HSV: Hue, Saturation, Value\n# H: position in the spectrum\n# S: color saturation (\"purity\")\n# V: color brightness\n\ndef rgb_to_hsv(r, g, b):\n maxc = max(r, g, b)\n minc = min(r, g, b)\n rangec = (maxc-minc)\n v = maxc\n if minc == maxc:\n return 0.0, 0.0, v\n s = rangec / maxc\n rc = (maxc-r) / rangec\n gc = (maxc-g) / rangec\n bc = (maxc-b) / rangec\n if r == maxc:\n h = bc-gc\n elif g == maxc:\n h = 2.0+rc-bc\n else:\n h = 4.0+gc-rc\n # h = (h/6.0) % 1.0\n h = h / 6.0\n h = h - int(h)\n return h, s, v\n\ndef hsv_to_rgb(h, s, v):\n if s == 0.0:\n return v, v, v\n i = int(h*6.0) # XXX assume int() truncates!\n f = (h*6.0) - i\n p = v*(1.0 - s)\n q = v*(1.0 - s*f)\n t = v*(1.0 - s*(1.0-f))\n i = i%6\n if i == 0:\n return v, t, p\n if i == 1:\n return q, v, p\n if i == 2:\n return p, v, t\n if i == 3:\n return p, q, v\n if i == 4:\n return t, p, v\n if i == 5:\n return v, p, q\n # Cannot get here"; const char kPythonLibs_datetime[] = "from time import localtime\n\nclass timedelta:\n def __init__(self, days=0, seconds=0):\n self.days = days\n self.seconds = seconds\n\n def __repr__(self):\n return f\"datetime.timedelta(days={self.days}, seconds={self.seconds})\"\n\n def __eq__(self, other: 'timedelta') -> bool:\n if type(other) is not timedelta:\n return NotImplemented\n return (self.days, self.seconds) == (other.days, other.seconds)\n\n def __lt__(self, other: 'timedelta') -> bool:\n if type(other) is not timedelta:\n return NotImplemented\n return (self.days, self.seconds) < (other.days, other.seconds)\n\n def __le__(self, other: 'timedelta') -> bool:\n if type(other) is not timedelta:\n return NotImplemented\n return (self.days, self.seconds) <= (other.days, other.seconds)\n\n def __gt__(self, other: 'timedelta') -> bool:\n if type(other) is not timedelta:\n return NotImplemented\n return (self.days, self.seconds) > (other.days, other.seconds)\n\n def __ge__(self, other: 'timedelta') -> bool:\n if type(other) is not timedelta:\n return NotImplemented\n return (self.days, self.seconds) >= (other.days, other.seconds)\n\n\nclass date:\n def __init__(self, year: int, month: int, day: int):\n self.year = year\n self.month = month\n self.day = day\n\n @staticmethod\n def today():\n t = localtime()\n return date(t.tm_year, t.tm_mon, t.tm_mday)\n\n def __eq__(self, other: 'date') -> bool:\n if type(other) is not date:\n return NotImplemented\n return (self.year, self.month, self.day) == (other.year, other.month, other.day)\n\n def __lt__(self, other: 'date') -> bool:\n if type(other) is not date:\n return NotImplemented\n return (self.year, self.month, self.day) < (other.year, other.month, other.day)\n\n def __le__(self, other: 'date') -> bool:\n if type(other) is not date:\n return NotImplemented\n return (self.year, self.month, self.day) <= (other.year, other.month, other.day)\n\n def __gt__(self, other: 'date') -> bool:\n if type(other) is not date:\n return NotImplemented\n return (self.year, self.month, self.day) > (other.year, other.month, other.day)\n\n def __ge__(self, other: 'date') -> bool:\n if type(other) is not date:\n return NotImplemented\n return (self.year, self.month, self.day) >= (other.year, other.month, other.day)\n\n def __str__(self):\n return f\"{self.year}-{self.month:02}-{self.day:02}\"\n\n def __repr__(self):\n return f\"datetime.date({self.year}, {self.month}, {self.day})\"\n\n\nclass datetime(date):\n def __init__(self, year: int, month: int, day: int, hour: int, minute: int, second: int):\n super().__init__(year, month, day)\n # Validate and set hour, minute, and second\n if not 0 <= hour <= 23:\n raise ValueError(\"Hour must be between 0 and 23\")\n self.hour = hour\n if not 0 <= minute <= 59:\n raise ValueError(\"Minute must be between 0 and 59\")\n self.minute = minute\n if not 0 <= second <= 59:\n raise ValueError(\"Second must be between 0 and 59\")\n self.second = second\n\n def date(self) -> date:\n return date(self.year, self.month, self.day)\n\n @staticmethod\n def now():\n t = localtime()\n tm_sec = t.tm_sec\n if tm_sec == 60:\n tm_sec = 59\n return datetime(t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, tm_sec)\n\n def __str__(self):\n return f\"{self.year}-{self.month:02}-{self.day:02} {self.hour:02}:{self.minute:02}:{self.second:02}\"\n\n def __repr__(self):\n return f\"datetime.datetime({self.year}, {self.month}, {self.day}, {self.hour}, {self.minute}, {self.second})\"\n\n def __eq__(self, other) -> bool:\n if type(other) is not datetime:\n return NotImplemented\n return (self.year, self.month, self.day, self.hour, self.minute, self.second) ==\x5c\n (other.year, other.month, other.day,\n other.hour, other.minute, other.second)\n\n def __lt__(self, other) -> bool:\n if type(other) is not datetime:\n return NotImplemented\n return (self.year, self.month, self.day, self.hour, self.minute, self.second) <\x5c\n (other.year, other.month, other.day,\n other.hour, other.minute, other.second)\n\n def __le__(self, other) -> bool:\n if type(other) is not datetime:\n return NotImplemented\n return (self.year, self.month, self.day, self.hour, self.minute, self.second) <=\x5c\n (other.year, other.month, other.day,\n other.hour, other.minute, other.second)\n\n def __gt__(self, other) -> bool:\n if type(other) is not datetime:\n return NotImplemented\n return (self.year, self.month, self.day, self.hour, self.minute, self.second) >\x5c\n (other.year, other.month, other.day,\n other.hour, other.minute, other.second)\n\n def __ge__(self, other) -> bool:\n if type(other) is not datetime:\n return NotImplemented\n return (self.year, self.month, self.day, self.hour, self.minute, self.second) >=\x5c\n (other.year, other.month, other.day,\n other.hour, other.minute, other.second)\n\n def timestamp(self) -> float:\n raise NotImplementedError\n\n"; -const char kPythonLibs_functools[] = "from pkpy import next\n\nclass cache:\n def __init__(self, f):\n self.f = f\n self.cache = {}\n\n def __call__(self, *args):\n if args not in self.cache:\n self.cache[args] = self.f(*args)\n return self.cache[args]\n \ndef reduce(function, sequence, initial=...):\n it = iter(sequence)\n if initial is ...:\n value = next(it)\n if value is StopIteration:\n raise TypeError(\"reduce() of empty iterable with no initial value\")\n else:\n value = initial\n for element in it:\n value = function(value, element)\n return value\n\nclass partial:\n def __init__(self, f, *args, **kwargs):\n self.f = f\n if not callable(f):\n raise TypeError(\"the first argument must be callable\")\n self.args = args\n self.kwargs = kwargs\n\n def __call__(self, *args, **kwargs):\n kwargs.update(self.kwargs)\n return self.f(*self.args, *args, **kwargs)\n\n"; +const char kPythonLibs_functools[] = "class cache:\n def __init__(self, f):\n self.f = f\n self.cache = {}\n\n def __call__(self, *args):\n if args not in self.cache:\n self.cache[args] = self.f(*args)\n return self.cache[args]\n \ndef reduce(function, sequence, initial=...):\n it = iter(sequence)\n if initial is ...:\n try:\n value = next(it)\n except StopIteration:\n raise TypeError(\"reduce() of empty sequence with no initial value\")\n else:\n value = initial\n for element in it:\n value = function(value, element)\n return value\n\nclass partial:\n def __init__(self, f, *args, **kwargs):\n self.f = f\n if not callable(f):\n raise TypeError(\"the first argument must be callable\")\n self.args = args\n self.kwargs = kwargs\n\n def __call__(self, *args, **kwargs):\n kwargs.update(self.kwargs)\n return self.f(*self.args, *args, **kwargs)\n\n"; const char kPythonLibs_heapq[] = "# Heap queue algorithm (a.k.a. priority queue)\ndef heappush(heap, item):\n \"\"\"Push item onto heap, maintaining the heap invariant.\"\"\"\n heap.append(item)\n _siftdown(heap, 0, len(heap)-1)\n\ndef heappop(heap):\n \"\"\"Pop the smallest item off the heap, maintaining the heap invariant.\"\"\"\n lastelt = heap.pop() # raises appropriate IndexError if heap is empty\n if heap:\n returnitem = heap[0]\n heap[0] = lastelt\n _siftup(heap, 0)\n return returnitem\n return lastelt\n\ndef heapreplace(heap, item):\n \"\"\"Pop and return the current smallest value, and add the new item.\n\n This is more efficient than heappop() followed by heappush(), and can be\n more appropriate when using a fixed-size heap. Note that the value\n returned may be larger than item! That constrains reasonable uses of\n this routine unless written as part of a conditional replacement:\n\n if item > heap[0]:\n item = heapreplace(heap, item)\n \"\"\"\n returnitem = heap[0] # raises appropriate IndexError if heap is empty\n heap[0] = item\n _siftup(heap, 0)\n return returnitem\n\ndef heappushpop(heap, item):\n \"\"\"Fast version of a heappush followed by a heappop.\"\"\"\n if heap and heap[0] < item:\n item, heap[0] = heap[0], item\n _siftup(heap, 0)\n return item\n\ndef heapify(x):\n \"\"\"Transform list into a heap, in-place, in O(len(x)) time.\"\"\"\n n = len(x)\n # Transform bottom-up. The largest index there's any point to looking at\n # is the largest with a child index in-range, so must have 2*i + 1 < n,\n # or i < (n-1)/2. If n is even = 2*j, this is (2*j-1)/2 = j-1/2 so\n # j-1 is the largest, which is n//2 - 1. If n is odd = 2*j+1, this is\n # (2*j+1-1)/2 = j so j-1 is the largest, and that's again n//2-1.\n for i in reversed(range(n//2)):\n _siftup(x, i)\n\n# 'heap' is a heap at all indices >= startpos, except possibly for pos. pos\n# is the index of a leaf with a possibly out-of-order value. Restore the\n# heap invariant.\ndef _siftdown(heap, startpos, pos):\n newitem = heap[pos]\n # Follow the path to the root, moving parents down until finding a place\n # newitem fits.\n while pos > startpos:\n parentpos = (pos - 1) >> 1\n parent = heap[parentpos]\n if newitem < parent:\n heap[pos] = parent\n pos = parentpos\n continue\n break\n heap[pos] = newitem\n\ndef _siftup(heap, pos):\n endpos = len(heap)\n startpos = pos\n newitem = heap[pos]\n # Bubble up the smaller child until hitting a leaf.\n childpos = 2*pos + 1 # leftmost child position\n while childpos < endpos:\n # Set childpos to index of smaller child.\n rightpos = childpos + 1\n if rightpos < endpos and not heap[childpos] < heap[rightpos]:\n childpos = rightpos\n # Move the smaller child up.\n heap[pos] = heap[childpos]\n pos = childpos\n childpos = 2*pos + 1\n # The leaf at pos is empty now. Put newitem there, and bubble it up\n # to its final resting place (by sifting its parents down).\n heap[pos] = newitem\n _siftdown(heap, startpos, pos)"; const char kPythonLibs_itertools[] = "from pkpy import next\n\ndef zip_longest(a, b):\n a = iter(a)\n b = iter(b)\n while True:\n ai = next(a)\n bi = next(b)\n if ai is StopIteration and bi is StopIteration:\n break\n if ai is StopIteration:\n ai = None\n if bi is StopIteration:\n bi = None\n yield ai, bi\n"; const char kPythonLibs_operator[] = "# https://docs.python.org/3/library/operator.html#mapping-operators-to-functions\n\ndef le(a, b): return a <= b\ndef lt(a, b): return a < b\ndef ge(a, b): return a >= b\ndef gt(a, b): return a > b\ndef eq(a, b): return a == b\ndef ne(a, b): return a != b\n\ndef and_(a, b): return a & b\ndef or_(a, b): return a | b\ndef xor(a, b): return a ^ b\ndef invert(a): return ~a\ndef lshift(a, b): return a << b\ndef rshift(a, b): return a >> b\n\ndef is_(a, b): return a is b\ndef is_not(a, b): return a is not b\ndef not_(a): return not a\ndef truth(a): return bool(a)\ndef contains(a, b): return b in a\n\ndef add(a, b): return a + b\ndef sub(a, b): return a - b\ndef mul(a, b): return a * b\ndef truediv(a, b): return a / b\ndef floordiv(a, b): return a // b\ndef mod(a, b): return a % b\ndef pow(a, b): return a ** b\ndef neg(a): return -a\ndef matmul(a, b): return a @ b\n\ndef getitem(a, b): return a[b]\ndef setitem(a, b, c): a[b] = c\ndef delitem(a, b): del a[b]\n\ndef iadd(a, b): a += b; return a\ndef isub(a, b): a -= b; return a\ndef imul(a, b): a *= b; return a\ndef itruediv(a, b): a /= b; return a\ndef ifloordiv(a, b): a //= b; return a\ndef imod(a, b): a %= b; return a\n# def ipow(a, b): a **= b; return a\n# def imatmul(a, b): a @= b; return a\ndef iand(a, b): a &= b; return a\ndef ior(a, b): a |= b; return a\ndef ixor(a, b): a ^= b; return a\ndef ilshift(a, b): a <<= b; return a\ndef irshift(a, b): a >>= b; return a\n"; diff --git a/src/common/sstream.c b/src/common/sstream.c index 7f82afba..8fb6c715 100644 --- a/src/common/sstream.c +++ b/src/common/sstream.c @@ -147,7 +147,7 @@ c11_string* c11_sbuf__submit(c11_sbuf* self) { return retval; } -void c11_sbuf__py_submit(c11_sbuf *self, py_Ref out){ +void c11_sbuf__py_submit(c11_sbuf* self, py_Ref out) { c11_string* res = c11_sbuf__submit(self); py_newstrn(out, res->data, res->size); c11_string__delete(res); @@ -233,7 +233,9 @@ void pk_sprintf(c11_sbuf* ss, const char* fmt, ...) { va_end(args); } -int py_replinput(char* buf) { +int py_replinput(char* buf, int max_size) { + buf[0] = '\0'; + int size = 0; bool multiline = false; printf(">>> "); @@ -252,7 +254,7 @@ int py_replinput(char* buf) { printf("... "); } } else { - if(last == ':' || last == '(' || last == '[' || last == '{') { + if(last == ':' || last == '(' || last == '[' || last == '{' || buf[0] == '@') { printf("... "); multiline = true; } else { @@ -261,6 +263,11 @@ int py_replinput(char* buf) { } } + if(size == max_size - 1) { + buf[size] = '\0'; + return size; + } + buf[size++] = c; } diff --git a/src2/main.c b/src2/main.c index ef8b91a5..c1b05488 100644 --- a/src2/main.c +++ b/src2/main.c @@ -46,7 +46,7 @@ int main(int argc, char** argv) { printf("Type \"exit()\" to exit.\n"); while(true) { - int size = py_replinput(buf); + int size = py_replinput(buf, sizeof(buf)); assert(size < sizeof(buf)); if(size >= 0) { if(!py_exec(buf, "", REPL_MODE, NULL)) py_printexc(); diff --git a/tests/44_decorator.py b/tests/42_decorator.py similarity index 100% rename from tests/44_decorator.py rename to tests/42_decorator.py diff --git a/tests/42_closure.py b/tests/43_closure.py similarity index 70% rename from tests/42_closure.py rename to tests/43_closure.py index b78533a2..40e96ec3 100644 --- a/tests/42_closure.py +++ b/tests/43_closure.py @@ -24,4 +24,14 @@ def f3(x, y): return lambda z: x + y + z a = f3(1, 2) -assert a(3) == 6 \ No newline at end of file +assert a(3) == 6 + +# closure ex +def f(n): + def g(x): + if x==n: + return n + return g(x+1) + return g(0) + +assert f(10) == 10 \ No newline at end of file diff --git a/tests/43_closure_ex.py b/tests/43_closure_ex.py deleted file mode 100644 index e9e3faee..00000000 --- a/tests/43_closure_ex.py +++ /dev/null @@ -1,8 +0,0 @@ -def f(n): - def g(x): - if x==n: - return n - return g(x+1) - return g(0) - -assert f(10) == 10 \ No newline at end of file