PageRenderTime 52ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/pypy/module/micronumpy/compile.py

https://bitbucket.org/vanl/pypy
Python | 850 lines | 722 code | 119 blank | 9 comment | 101 complexity | a3404b741a19548e8bbab163edb8fca9 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, AGPL-3.0
  1. """ This is a set of tools for standalone compiling of numpy expressions.
  2. It should not be imported by the module itself
  3. """
  4. import re
  5. from pypy.interpreter import special
  6. from pypy.interpreter.baseobjspace import InternalSpaceCache, W_Root, ObjSpace
  7. from pypy.interpreter.error import OperationError
  8. from rpython.rlib.objectmodel import specialize, instantiate
  9. from rpython.rlib.nonconst import NonConstant
  10. from pypy.module.micronumpy import boxes, ufuncs
  11. from pypy.module.micronumpy.arrayops import where
  12. from pypy.module.micronumpy.ndarray import W_NDimArray
  13. from pypy.module.micronumpy.ctors import array
  14. from pypy.module.micronumpy.descriptor import get_dtype_cache
  15. class BogusBytecode(Exception):
  16. pass
  17. class ArgumentMismatch(Exception):
  18. pass
  19. class ArgumentNotAnArray(Exception):
  20. pass
  21. class WrongFunctionName(Exception):
  22. pass
  23. class TokenizerError(Exception):
  24. pass
  25. class BadToken(Exception):
  26. pass
  27. SINGLE_ARG_FUNCTIONS = ["sum", "prod", "max", "min", "all", "any",
  28. "unegative", "flat", "tostring", "count_nonzero",
  29. "argsort", "cumsum", "logical_xor_reduce"]
  30. TWO_ARG_FUNCTIONS = ["dot", 'take', 'searchsorted']
  31. TWO_ARG_FUNCTIONS_OR_NONE = ['view', 'astype']
  32. THREE_ARG_FUNCTIONS = ['where']
  33. class W_TypeObject(W_Root):
  34. def __init__(self, name):
  35. self.name = name
  36. def lookup(self, name):
  37. return self.getdictvalue(self, name)
  38. def getname(self, space):
  39. return self.name
  40. class FakeSpace(ObjSpace):
  41. w_ValueError = W_TypeObject("ValueError")
  42. w_TypeError = W_TypeObject("TypeError")
  43. w_IndexError = W_TypeObject("IndexError")
  44. w_OverflowError = W_TypeObject("OverflowError")
  45. w_NotImplementedError = W_TypeObject("NotImplementedError")
  46. w_AttributeError = W_TypeObject("AttributeError")
  47. w_None = None
  48. w_bool = W_TypeObject("bool")
  49. w_int = W_TypeObject("int")
  50. w_float = W_TypeObject("float")
  51. w_list = W_TypeObject("list")
  52. w_long = W_TypeObject("long")
  53. w_tuple = W_TypeObject('tuple')
  54. w_slice = W_TypeObject("slice")
  55. w_str = W_TypeObject("str")
  56. w_unicode = W_TypeObject("unicode")
  57. w_complex = W_TypeObject("complex")
  58. w_dict = W_TypeObject("dict")
  59. w_object = W_TypeObject("object")
  60. w_buffer = W_TypeObject("buffer")
  61. def __init__(self):
  62. """NOT_RPYTHON"""
  63. self.fromcache = InternalSpaceCache(self).getorbuild
  64. self.w_Ellipsis = special.Ellipsis()
  65. self.w_NotImplemented = special.NotImplemented()
  66. def _freeze_(self):
  67. return True
  68. def is_none(self, w_obj):
  69. return w_obj is None or w_obj is self.w_None
  70. def issequence_w(self, w_obj):
  71. return isinstance(w_obj, ListObject) or isinstance(w_obj, W_NDimArray)
  72. def len(self, w_obj):
  73. assert isinstance(w_obj, ListObject)
  74. return self.wrap(len(w_obj.items))
  75. def getattr(self, w_obj, w_attr):
  76. assert isinstance(w_attr, StringObject)
  77. return w_obj.getdictvalue(self, w_attr.v)
  78. def isinstance_w(self, w_obj, w_tp):
  79. try:
  80. return w_obj.tp == w_tp
  81. except AttributeError:
  82. return False
  83. def decode_index4(self, w_idx, size):
  84. if isinstance(w_idx, IntObject):
  85. return (self.int_w(w_idx), 0, 0, 1)
  86. else:
  87. assert isinstance(w_idx, SliceObject)
  88. start, stop, step = w_idx.start, w_idx.stop, w_idx.step
  89. if step == 0:
  90. return (0, size, 1, size)
  91. if start < 0:
  92. start += size
  93. if stop < 0:
  94. stop += size + 1
  95. if step < 0:
  96. start, stop = stop, start
  97. start -= 1
  98. stop -= 1
  99. lgt = (stop - start + 1) / step + 1
  100. else:
  101. lgt = (stop - start - 1) / step + 1
  102. return (start, stop, step, lgt)
  103. @specialize.argtype(1)
  104. def wrap(self, obj):
  105. if isinstance(obj, float):
  106. return FloatObject(obj)
  107. elif isinstance(obj, bool):
  108. return BoolObject(obj)
  109. elif isinstance(obj, int):
  110. return IntObject(obj)
  111. elif isinstance(obj, long):
  112. return LongObject(obj)
  113. elif isinstance(obj, W_Root):
  114. return obj
  115. elif isinstance(obj, str):
  116. return StringObject(obj)
  117. raise NotImplementedError
  118. def newlist(self, items):
  119. return ListObject(items)
  120. def newcomplex(self, r, i):
  121. return ComplexObject(r, i)
  122. def getitem(self, obj, index):
  123. assert isinstance(obj, ListObject)
  124. assert isinstance(index, IntObject)
  125. return obj.items[index.intval]
  126. def listview(self, obj, number=-1):
  127. assert isinstance(obj, ListObject)
  128. if number != -1:
  129. assert number == 2
  130. return [obj.items[0], obj.items[1]]
  131. return obj.items
  132. fixedview = listview
  133. def float(self, w_obj):
  134. if isinstance(w_obj, FloatObject):
  135. return w_obj
  136. assert isinstance(w_obj, boxes.W_GenericBox)
  137. return self.float(w_obj.descr_float(self))
  138. def float_w(self, w_obj, allow_conversion=True):
  139. assert isinstance(w_obj, FloatObject)
  140. return w_obj.floatval
  141. def int_w(self, w_obj, allow_conversion=True):
  142. if isinstance(w_obj, IntObject):
  143. return w_obj.intval
  144. elif isinstance(w_obj, FloatObject):
  145. return int(w_obj.floatval)
  146. elif isinstance(w_obj, SliceObject):
  147. raise OperationError(self.w_TypeError, self.wrap("slice."))
  148. raise NotImplementedError
  149. def unpackcomplex(self, w_obj):
  150. if isinstance(w_obj, ComplexObject):
  151. return w_obj.r, w_obj.i
  152. raise NotImplementedError
  153. def index(self, w_obj):
  154. return self.wrap(self.int_w(w_obj))
  155. def str_w(self, w_obj):
  156. if isinstance(w_obj, StringObject):
  157. return w_obj.v
  158. raise NotImplementedError
  159. def int(self, w_obj):
  160. if isinstance(w_obj, IntObject):
  161. return w_obj
  162. assert isinstance(w_obj, boxes.W_GenericBox)
  163. return self.int(w_obj.descr_int(self))
  164. def str(self, w_obj):
  165. if isinstance(w_obj, StringObject):
  166. return w_obj
  167. assert isinstance(w_obj, boxes.W_GenericBox)
  168. return self.str(w_obj.descr_str(self))
  169. def is_true(self, w_obj):
  170. assert isinstance(w_obj, BoolObject)
  171. return bool(w_obj.intval)
  172. def gt(self, w_lhs, w_rhs):
  173. return BoolObject(self.int_w(w_lhs) > self.int_w(w_rhs))
  174. def lt(self, w_lhs, w_rhs):
  175. return BoolObject(self.int_w(w_lhs) < self.int_w(w_rhs))
  176. def is_w(self, w_obj, w_what):
  177. return w_obj is w_what
  178. def eq_w(self, w_obj, w_what):
  179. return w_obj == w_what
  180. def issubtype(self, w_type1, w_type2):
  181. return BoolObject(True)
  182. def type(self, w_obj):
  183. if self.is_none(w_obj):
  184. return self.w_None
  185. try:
  186. return w_obj.tp
  187. except AttributeError:
  188. if isinstance(w_obj, W_NDimArray):
  189. return W_NDimArray
  190. return self.w_None
  191. def lookup(self, w_obj, name):
  192. w_type = self.type(w_obj)
  193. if not self.is_none(w_type):
  194. return w_type.lookup(name)
  195. def gettypefor(self, w_obj):
  196. return W_TypeObject(w_obj.typedef.name)
  197. def call_function(self, tp, w_dtype):
  198. return w_dtype
  199. def call_method(self, w_obj, s, *args):
  200. # XXX even the hacks have hacks
  201. return getattr(w_obj, 'descr_' + s)(self, *args)
  202. @specialize.arg(1)
  203. def interp_w(self, tp, what):
  204. assert isinstance(what, tp)
  205. return what
  206. def allocate_instance(self, klass, w_subtype):
  207. return instantiate(klass)
  208. def newtuple(self, list_w):
  209. return ListObject(list_w)
  210. def newdict(self):
  211. return {}
  212. def setitem(self, dict, item, value):
  213. dict[item] = value
  214. def len_w(self, w_obj):
  215. if isinstance(w_obj, ListObject):
  216. return len(w_obj.items)
  217. # XXX array probably
  218. assert False
  219. def exception_match(self, w_exc_type, w_check_class):
  220. # Good enough for now
  221. raise NotImplementedError
  222. class FloatObject(W_Root):
  223. tp = FakeSpace.w_float
  224. def __init__(self, floatval):
  225. self.floatval = floatval
  226. class BoolObject(W_Root):
  227. tp = FakeSpace.w_bool
  228. def __init__(self, boolval):
  229. self.intval = boolval
  230. class IntObject(W_Root):
  231. tp = FakeSpace.w_int
  232. def __init__(self, intval):
  233. self.intval = intval
  234. class LongObject(W_Root):
  235. tp = FakeSpace.w_long
  236. def __init__(self, intval):
  237. self.intval = intval
  238. class ListObject(W_Root):
  239. tp = FakeSpace.w_list
  240. def __init__(self, items):
  241. self.items = items
  242. class SliceObject(W_Root):
  243. tp = FakeSpace.w_slice
  244. def __init__(self, start, stop, step):
  245. self.start = start
  246. self.stop = stop
  247. self.step = step
  248. class StringObject(W_Root):
  249. tp = FakeSpace.w_str
  250. def __init__(self, v):
  251. self.v = v
  252. class ComplexObject(W_Root):
  253. tp = FakeSpace.w_complex
  254. def __init__(self, r, i):
  255. self.r = r
  256. self.i = i
  257. class InterpreterState(object):
  258. def __init__(self, code):
  259. self.code = code
  260. self.variables = {}
  261. self.results = []
  262. def run(self, space):
  263. self.space = space
  264. for stmt in self.code.statements:
  265. stmt.execute(self)
  266. class Node(object):
  267. def __eq__(self, other):
  268. return (self.__class__ == other.__class__ and
  269. self.__dict__ == other.__dict__)
  270. def __ne__(self, other):
  271. return not self == other
  272. def wrap(self, space):
  273. raise NotImplementedError
  274. def execute(self, interp):
  275. raise NotImplementedError
  276. class Assignment(Node):
  277. def __init__(self, name, expr):
  278. self.name = name
  279. self.expr = expr
  280. def execute(self, interp):
  281. interp.variables[self.name] = self.expr.execute(interp)
  282. def __repr__(self):
  283. return "%r = %r" % (self.name, self.expr)
  284. class ArrayAssignment(Node):
  285. def __init__(self, name, index, expr):
  286. self.name = name
  287. self.index = index
  288. self.expr = expr
  289. def execute(self, interp):
  290. arr = interp.variables[self.name]
  291. w_index = self.index.execute(interp)
  292. # cast to int
  293. if isinstance(w_index, FloatObject):
  294. w_index = IntObject(int(w_index.floatval))
  295. w_val = self.expr.execute(interp)
  296. assert isinstance(arr, W_NDimArray)
  297. arr.descr_setitem(interp.space, w_index, w_val)
  298. def __repr__(self):
  299. return "%s[%r] = %r" % (self.name, self.index, self.expr)
  300. class Variable(Node):
  301. def __init__(self, name):
  302. self.name = name.strip(" ")
  303. def execute(self, interp):
  304. if self.name == 'None':
  305. return None
  306. return interp.variables[self.name]
  307. def __repr__(self):
  308. return 'v(%s)' % self.name
  309. class Operator(Node):
  310. def __init__(self, lhs, name, rhs):
  311. self.name = name
  312. self.lhs = lhs
  313. self.rhs = rhs
  314. def execute(self, interp):
  315. w_lhs = self.lhs.execute(interp)
  316. if isinstance(self.rhs, SliceConstant):
  317. w_rhs = self.rhs.wrap(interp.space)
  318. else:
  319. w_rhs = self.rhs.execute(interp)
  320. if not isinstance(w_lhs, W_NDimArray):
  321. # scalar
  322. dtype = get_dtype_cache(interp.space).w_float64dtype
  323. w_lhs = W_NDimArray.new_scalar(interp.space, dtype, w_lhs)
  324. assert isinstance(w_lhs, W_NDimArray)
  325. if self.name == '+':
  326. w_res = w_lhs.descr_add(interp.space, w_rhs)
  327. elif self.name == '*':
  328. w_res = w_lhs.descr_mul(interp.space, w_rhs)
  329. elif self.name == '-':
  330. w_res = w_lhs.descr_sub(interp.space, w_rhs)
  331. elif self.name == '**':
  332. w_res = w_lhs.descr_pow(interp.space, w_rhs)
  333. elif self.name == '->':
  334. if isinstance(w_rhs, FloatObject):
  335. w_rhs = IntObject(int(w_rhs.floatval))
  336. assert isinstance(w_lhs, W_NDimArray)
  337. w_res = w_lhs.descr_getitem(interp.space, w_rhs)
  338. else:
  339. raise NotImplementedError
  340. if (not isinstance(w_res, W_NDimArray) and
  341. not isinstance(w_res, boxes.W_GenericBox)):
  342. dtype = get_dtype_cache(interp.space).w_float64dtype
  343. w_res = W_NDimArray.new_scalar(interp.space, dtype, w_res)
  344. return w_res
  345. def __repr__(self):
  346. return '(%r %s %r)' % (self.lhs, self.name, self.rhs)
  347. class FloatConstant(Node):
  348. def __init__(self, v):
  349. self.v = float(v)
  350. def __repr__(self):
  351. return "Const(%s)" % self.v
  352. def wrap(self, space):
  353. return space.wrap(self.v)
  354. def execute(self, interp):
  355. return interp.space.wrap(self.v)
  356. class ComplexConstant(Node):
  357. def __init__(self, r, i):
  358. self.r = float(r)
  359. self.i = float(i)
  360. def __repr__(self):
  361. return 'ComplexConst(%s, %s)' % (self.r, self.i)
  362. def wrap(self, space):
  363. return space.newcomplex(self.r, self.i)
  364. def execute(self, interp):
  365. return self.wrap(interp.space)
  366. class RangeConstant(Node):
  367. def __init__(self, v):
  368. self.v = int(v)
  369. def execute(self, interp):
  370. w_list = interp.space.newlist(
  371. [interp.space.wrap(float(i)) for i in range(self.v)]
  372. )
  373. dtype = get_dtype_cache(interp.space).w_float64dtype
  374. return array(interp.space, w_list, w_dtype=dtype, w_order=None)
  375. def __repr__(self):
  376. return 'Range(%s)' % self.v
  377. class Code(Node):
  378. def __init__(self, statements):
  379. self.statements = statements
  380. def __repr__(self):
  381. return "\n".join([repr(i) for i in self.statements])
  382. class ArrayConstant(Node):
  383. def __init__(self, items):
  384. self.items = items
  385. def wrap(self, space):
  386. return space.newlist([item.wrap(space) for item in self.items])
  387. def execute(self, interp):
  388. w_list = self.wrap(interp.space)
  389. return array(interp.space, w_list)
  390. def __repr__(self):
  391. return "[" + ", ".join([repr(item) for item in self.items]) + "]"
  392. class SliceConstant(Node):
  393. def __init__(self, start, stop, step):
  394. self.start = start
  395. self.stop = stop
  396. self.step = step
  397. def wrap(self, space):
  398. return SliceObject(self.start, self.stop, self.step)
  399. def execute(self, interp):
  400. return SliceObject(self.start, self.stop, self.step)
  401. def __repr__(self):
  402. return 'slice(%s,%s,%s)' % (self.start, self.stop, self.step)
  403. class ArrayClass(Node):
  404. def __init__(self):
  405. self.v = W_NDimArray
  406. def execute(self, interp):
  407. return self.v
  408. def __repr__(self):
  409. return '<class W_NDimArray>'
  410. class DtypeClass(Node):
  411. def __init__(self, dt):
  412. self.v = dt
  413. def execute(self, interp):
  414. if self.v == 'int':
  415. dtype = get_dtype_cache(interp.space).w_int64dtype
  416. elif self.v == 'float':
  417. dtype = get_dtype_cache(interp.space).w_float64dtype
  418. else:
  419. raise BadToken('unknown v to dtype "%s"' % self.v)
  420. return dtype
  421. def __repr__(self):
  422. return '<class %s dtype>' % self.v
  423. class Execute(Node):
  424. def __init__(self, expr):
  425. self.expr = expr
  426. def __repr__(self):
  427. return repr(self.expr)
  428. def execute(self, interp):
  429. interp.results.append(self.expr.execute(interp))
  430. class FunctionCall(Node):
  431. def __init__(self, name, args):
  432. self.name = name.strip(" ")
  433. self.args = args
  434. def __repr__(self):
  435. return "%s(%s)" % (self.name, ", ".join([repr(arg)
  436. for arg in self.args]))
  437. def execute(self, interp):
  438. arr = self.args[0].execute(interp)
  439. if not isinstance(arr, W_NDimArray):
  440. raise ArgumentNotAnArray
  441. if self.name in SINGLE_ARG_FUNCTIONS:
  442. if len(self.args) != 1 and self.name != 'sum':
  443. raise ArgumentMismatch
  444. if self.name == "sum":
  445. if len(self.args)>1:
  446. w_res = arr.descr_sum(interp.space,
  447. self.args[1].execute(interp))
  448. else:
  449. w_res = arr.descr_sum(interp.space)
  450. elif self.name == "prod":
  451. w_res = arr.descr_prod(interp.space)
  452. elif self.name == "max":
  453. w_res = arr.descr_max(interp.space)
  454. elif self.name == "min":
  455. w_res = arr.descr_min(interp.space)
  456. elif self.name == "any":
  457. w_res = arr.descr_any(interp.space)
  458. elif self.name == "all":
  459. w_res = arr.descr_all(interp.space)
  460. elif self.name == "cumsum":
  461. w_res = arr.descr_cumsum(interp.space)
  462. elif self.name == "logical_xor_reduce":
  463. logical_xor = ufuncs.get(interp.space).logical_xor
  464. w_res = logical_xor.reduce(interp.space, arr, None)
  465. elif self.name == "unegative":
  466. neg = ufuncs.get(interp.space).negative
  467. w_res = neg.call(interp.space, [arr], None, None, None)
  468. elif self.name == "cos":
  469. cos = ufuncs.get(interp.space).cos
  470. w_res = cos.call(interp.space, [arr], None, None, None)
  471. elif self.name == "flat":
  472. w_res = arr.descr_get_flatiter(interp.space)
  473. elif self.name == "argsort":
  474. w_res = arr.descr_argsort(interp.space)
  475. elif self.name == "tostring":
  476. arr.descr_tostring(interp.space)
  477. w_res = None
  478. else:
  479. assert False # unreachable code
  480. elif self.name in TWO_ARG_FUNCTIONS:
  481. if len(self.args) != 2:
  482. raise ArgumentMismatch
  483. arg = self.args[1].execute(interp)
  484. if not isinstance(arg, W_NDimArray):
  485. raise ArgumentNotAnArray
  486. if self.name == "dot":
  487. w_res = arr.descr_dot(interp.space, arg)
  488. elif self.name == 'take':
  489. w_res = arr.descr_take(interp.space, arg)
  490. elif self.name == "searchsorted":
  491. w_res = arr.descr_searchsorted(interp.space, arg,
  492. interp.space.wrap('left'))
  493. else:
  494. assert False # unreachable code
  495. elif self.name in THREE_ARG_FUNCTIONS:
  496. if len(self.args) != 3:
  497. raise ArgumentMismatch
  498. arg1 = self.args[1].execute(interp)
  499. arg2 = self.args[2].execute(interp)
  500. if not isinstance(arg1, W_NDimArray):
  501. raise ArgumentNotAnArray
  502. if not isinstance(arg2, W_NDimArray):
  503. raise ArgumentNotAnArray
  504. if self.name == "where":
  505. w_res = where(interp.space, arr, arg1, arg2)
  506. else:
  507. assert False
  508. elif self.name in TWO_ARG_FUNCTIONS_OR_NONE:
  509. if len(self.args) != 2:
  510. raise ArgumentMismatch
  511. arg = self.args[1].execute(interp)
  512. if self.name == 'view':
  513. w_res = arr.descr_view(interp.space, arg)
  514. elif self.name == 'astype':
  515. w_res = arr.descr_astype(interp.space, arg)
  516. else:
  517. assert False
  518. else:
  519. raise WrongFunctionName
  520. if isinstance(w_res, W_NDimArray):
  521. return w_res
  522. if isinstance(w_res, FloatObject):
  523. dtype = get_dtype_cache(interp.space).w_float64dtype
  524. elif isinstance(w_res, IntObject):
  525. dtype = get_dtype_cache(interp.space).w_int64dtype
  526. elif isinstance(w_res, BoolObject):
  527. dtype = get_dtype_cache(interp.space).w_booldtype
  528. elif isinstance(w_res, boxes.W_GenericBox):
  529. dtype = w_res.get_dtype(interp.space)
  530. else:
  531. dtype = None
  532. return W_NDimArray.new_scalar(interp.space, dtype, w_res)
  533. _REGEXES = [
  534. ('-?[\d\.]+', 'number'),
  535. ('\[', 'array_left'),
  536. (':', 'colon'),
  537. ('\w+', 'identifier'),
  538. ('\]', 'array_right'),
  539. ('(->)|[\+\-\*\/]+', 'operator'),
  540. ('=', 'assign'),
  541. (',', 'comma'),
  542. ('\|', 'pipe'),
  543. ('\(', 'paren_left'),
  544. ('\)', 'paren_right'),
  545. ]
  546. REGEXES = []
  547. for r, name in _REGEXES:
  548. REGEXES.append((re.compile(r' *(' + r + ')'), name))
  549. del _REGEXES
  550. class Token(object):
  551. def __init__(self, name, v):
  552. self.name = name
  553. self.v = v
  554. def __repr__(self):
  555. return '(%s, %s)' % (self.name, self.v)
  556. empty = Token('', '')
  557. class TokenStack(object):
  558. def __init__(self, tokens):
  559. self.tokens = tokens
  560. self.c = 0
  561. def pop(self):
  562. token = self.tokens[self.c]
  563. self.c += 1
  564. return token
  565. def get(self, i):
  566. if self.c + i >= len(self.tokens):
  567. return empty
  568. return self.tokens[self.c + i]
  569. def remaining(self):
  570. return len(self.tokens) - self.c
  571. def push(self):
  572. self.c -= 1
  573. def __repr__(self):
  574. return repr(self.tokens[self.c:])
  575. class Parser(object):
  576. def tokenize(self, line):
  577. tokens = []
  578. while True:
  579. for r, name in REGEXES:
  580. m = r.match(line)
  581. if m is not None:
  582. g = m.group(0)
  583. tokens.append(Token(name, g))
  584. line = line[len(g):]
  585. if not line:
  586. return TokenStack(tokens)
  587. break
  588. else:
  589. raise TokenizerError(line)
  590. def parse_number_or_slice(self, tokens):
  591. start_tok = tokens.pop()
  592. if start_tok.name == 'colon':
  593. start = 0
  594. else:
  595. if tokens.get(0).name != 'colon':
  596. return FloatConstant(start_tok.v)
  597. start = int(start_tok.v)
  598. tokens.pop()
  599. if not tokens.get(0).name in ['colon', 'number']:
  600. stop = -1
  601. step = 1
  602. else:
  603. next = tokens.pop()
  604. if next.name == 'colon':
  605. stop = -1
  606. step = int(tokens.pop().v)
  607. else:
  608. stop = int(next.v)
  609. if tokens.get(0).name == 'colon':
  610. tokens.pop()
  611. step = int(tokens.pop().v)
  612. else:
  613. step = 1
  614. return SliceConstant(start, stop, step)
  615. def parse_expression(self, tokens, accept_comma=False):
  616. stack = []
  617. while tokens.remaining():
  618. token = tokens.pop()
  619. if token.name == 'identifier':
  620. if tokens.remaining() and tokens.get(0).name == 'paren_left':
  621. stack.append(self.parse_function_call(token.v, tokens))
  622. elif token.v.strip(' ') == 'ndarray':
  623. stack.append(ArrayClass())
  624. elif token.v.strip(' ') == 'int':
  625. stack.append(DtypeClass('int'))
  626. elif token.v.strip(' ') == 'float':
  627. stack.append(DtypeClass('float'))
  628. else:
  629. stack.append(Variable(token.v.strip(' ')))
  630. elif token.name == 'array_left':
  631. stack.append(ArrayConstant(self.parse_array_const(tokens)))
  632. elif token.name == 'operator':
  633. stack.append(Variable(token.v))
  634. elif token.name == 'number' or token.name == 'colon':
  635. tokens.push()
  636. stack.append(self.parse_number_or_slice(tokens))
  637. elif token.name == 'pipe':
  638. stack.append(RangeConstant(tokens.pop().v))
  639. end = tokens.pop()
  640. assert end.name == 'pipe'
  641. elif token.name == 'paren_left':
  642. stack.append(self.parse_complex_constant(tokens))
  643. elif accept_comma and token.name == 'comma':
  644. continue
  645. else:
  646. tokens.push()
  647. break
  648. if accept_comma:
  649. return stack
  650. stack.reverse()
  651. lhs = stack.pop()
  652. while stack:
  653. op = stack.pop()
  654. assert isinstance(op, Variable)
  655. rhs = stack.pop()
  656. lhs = Operator(lhs, op.name, rhs)
  657. return lhs
  658. def parse_function_call(self, name, tokens):
  659. args = []
  660. tokens.pop() # lparen
  661. while tokens.get(0).name != 'paren_right':
  662. args += self.parse_expression(tokens, accept_comma=True)
  663. return FunctionCall(name, args)
  664. def parse_complex_constant(self, tokens):
  665. r = tokens.pop()
  666. assert r.name == 'number'
  667. assert tokens.pop().name == 'comma'
  668. i = tokens.pop()
  669. assert i.name == 'number'
  670. assert tokens.pop().name == 'paren_right'
  671. return ComplexConstant(r.v, i.v)
  672. def parse_array_const(self, tokens):
  673. elems = []
  674. while True:
  675. token = tokens.pop()
  676. if token.name == 'number':
  677. elems.append(FloatConstant(token.v))
  678. elif token.name == 'array_left':
  679. elems.append(ArrayConstant(self.parse_array_const(tokens)))
  680. elif token.name == 'paren_left':
  681. elems.append(self.parse_complex_constant(tokens))
  682. else:
  683. raise BadToken()
  684. token = tokens.pop()
  685. if token.name == 'array_right':
  686. return elems
  687. assert token.name == 'comma'
  688. def parse_statement(self, tokens):
  689. if (tokens.get(0).name == 'identifier' and
  690. tokens.get(1).name == 'assign'):
  691. lhs = tokens.pop().v
  692. tokens.pop()
  693. rhs = self.parse_expression(tokens)
  694. return Assignment(lhs, rhs)
  695. elif (tokens.get(0).name == 'identifier' and
  696. tokens.get(1).name == 'array_left'):
  697. name = tokens.pop().v
  698. tokens.pop()
  699. index = self.parse_expression(tokens)
  700. tokens.pop()
  701. tokens.pop()
  702. return ArrayAssignment(name, index, self.parse_expression(tokens))
  703. return Execute(self.parse_expression(tokens))
  704. def parse(self, code):
  705. statements = []
  706. for line in code.split("\n"):
  707. if '#' in line:
  708. line = line.split('#', 1)[0]
  709. line = line.strip(" ")
  710. if line:
  711. tokens = self.tokenize(line)
  712. statements.append(self.parse_statement(tokens))
  713. return Code(statements)
  714. def numpy_compile(code):
  715. parser = Parser()
  716. return InterpreterState(parser.parse(code))