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

/pypy/module/micronumpy/compile.py

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