PageRenderTime 45ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/module/micronumpy/compile.py

https://bitbucket.org/trampgeek/pypy-sandbox-4-pycode
Python | 591 lines | 497 code | 85 blank | 9 comment | 53 complexity | df696a32c6fd7fed8c28368806e61ece MD5 | raw file
  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.module.micronumpy import interp_boxes
  7. from pypy.module.micronumpy.interp_dtype import get_dtype_cache
  8. from pypy.module.micronumpy.interp_numarray import (Scalar, BaseArray,
  9. scalar_w, W_NDimArray, array)
  10. from pypy.module.micronumpy import interp_ufuncs
  11. from pypy.rlib.objectmodel import specialize, instantiate
  12. class BogusBytecode(Exception):
  13. pass
  14. class ArgumentMismatch(Exception):
  15. pass
  16. class ArgumentNotAnArray(Exception):
  17. pass
  18. class WrongFunctionName(Exception):
  19. pass
  20. class TokenizerError(Exception):
  21. pass
  22. class BadToken(Exception):
  23. pass
  24. SINGLE_ARG_FUNCTIONS = ["sum", "prod", "max", "min", "all", "any", "unegative"]
  25. class FakeSpace(object):
  26. w_ValueError = None
  27. w_TypeError = None
  28. w_IndexError = None
  29. w_OverflowError = None
  30. w_None = None
  31. w_bool = "bool"
  32. w_int = "int"
  33. w_float = "float"
  34. w_list = "list"
  35. w_long = "long"
  36. w_tuple = 'tuple'
  37. w_slice = "slice"
  38. def __init__(self):
  39. """NOT_RPYTHON"""
  40. self.fromcache = InternalSpaceCache(self).getorbuild
  41. def issequence_w(self, w_obj):
  42. return isinstance(w_obj, ListObject) or isinstance(w_obj, W_NDimArray)
  43. def isinstance_w(self, w_obj, w_tp):
  44. return w_obj.tp == w_tp
  45. def decode_index4(self, w_idx, size):
  46. if isinstance(w_idx, IntObject):
  47. return (self.int_w(w_idx), 0, 0, 1)
  48. else:
  49. assert isinstance(w_idx, SliceObject)
  50. start, stop, step = w_idx.start, w_idx.stop, w_idx.step
  51. if step == 0:
  52. return (0, size, 1, size)
  53. if start < 0:
  54. start += size
  55. if stop < 0:
  56. stop += size + 1
  57. if step < 0:
  58. lgt = (stop - start + 1) / step + 1
  59. else:
  60. lgt = (stop - start - 1) / step + 1
  61. return (start, stop, step, lgt)
  62. @specialize.argtype(1)
  63. def wrap(self, obj):
  64. if isinstance(obj, float):
  65. return FloatObject(obj)
  66. elif isinstance(obj, bool):
  67. return BoolObject(obj)
  68. elif isinstance(obj, int):
  69. return IntObject(obj)
  70. elif isinstance(obj, W_Root):
  71. return obj
  72. raise NotImplementedError
  73. def newlist(self, items):
  74. return ListObject(items)
  75. def listview(self, obj):
  76. assert isinstance(obj, ListObject)
  77. return obj.items
  78. fixedview = listview
  79. def float(self, w_obj):
  80. if isinstance(w_obj, FloatObject):
  81. return w_obj
  82. assert isinstance(w_obj, interp_boxes.W_GenericBox)
  83. return self.float(w_obj.descr_float(self))
  84. def float_w(self, w_obj):
  85. assert isinstance(w_obj, FloatObject)
  86. return w_obj.floatval
  87. def int_w(self, w_obj):
  88. if isinstance(w_obj, IntObject):
  89. return w_obj.intval
  90. elif isinstance(w_obj, FloatObject):
  91. return int(w_obj.floatval)
  92. raise NotImplementedError
  93. def int(self, w_obj):
  94. if isinstance(w_obj, IntObject):
  95. return w_obj
  96. assert isinstance(w_obj, interp_boxes.W_GenericBox)
  97. return self.int(w_obj.descr_int(self))
  98. def is_true(self, w_obj):
  99. assert isinstance(w_obj, BoolObject)
  100. return w_obj.boolval
  101. def is_w(self, w_obj, w_what):
  102. return w_obj is w_what
  103. def type(self, w_obj):
  104. return w_obj.tp
  105. def gettypefor(self, w_obj):
  106. return None
  107. def call_function(self, tp, w_dtype):
  108. return w_dtype
  109. @specialize.arg(1)
  110. def interp_w(self, tp, what):
  111. assert isinstance(what, tp)
  112. return what
  113. def allocate_instance(self, klass, w_subtype):
  114. return instantiate(klass)
  115. def len_w(self, w_obj):
  116. if isinstance(w_obj, ListObject):
  117. return len(w_obj.items)
  118. # XXX array probably
  119. assert False
  120. def exception_match(self, w_exc_type, w_check_class):
  121. # Good enough for now
  122. raise NotImplementedError
  123. class FloatObject(W_Root):
  124. tp = FakeSpace.w_float
  125. def __init__(self, floatval):
  126. self.floatval = floatval
  127. class BoolObject(W_Root):
  128. tp = FakeSpace.w_bool
  129. def __init__(self, boolval):
  130. self.boolval = boolval
  131. class IntObject(W_Root):
  132. tp = FakeSpace.w_int
  133. def __init__(self, intval):
  134. self.intval = intval
  135. class ListObject(W_Root):
  136. tp = FakeSpace.w_list
  137. def __init__(self, items):
  138. self.items = items
  139. class SliceObject(W_Root):
  140. tp = FakeSpace.w_slice
  141. def __init__(self, start, stop, step):
  142. self.start = start
  143. self.stop = stop
  144. self.step = step
  145. class InterpreterState(object):
  146. def __init__(self, code):
  147. self.code = code
  148. self.variables = {}
  149. self.results = []
  150. def run(self, space):
  151. self.space = space
  152. for stmt in self.code.statements:
  153. stmt.execute(self)
  154. class Node(object):
  155. def __eq__(self, other):
  156. return (self.__class__ == other.__class__ and
  157. self.__dict__ == other.__dict__)
  158. def __ne__(self, other):
  159. return not self == other
  160. def wrap(self, space):
  161. raise NotImplementedError
  162. def execute(self, interp):
  163. raise NotImplementedError
  164. class Assignment(Node):
  165. def __init__(self, name, expr):
  166. self.name = name
  167. self.expr = expr
  168. def execute(self, interp):
  169. interp.variables[self.name] = self.expr.execute(interp)
  170. def __repr__(self):
  171. return "%r = %r" % (self.name, self.expr)
  172. class ArrayAssignment(Node):
  173. def __init__(self, name, index, expr):
  174. self.name = name
  175. self.index = index
  176. self.expr = expr
  177. def execute(self, interp):
  178. arr = interp.variables[self.name]
  179. w_index = self.index.execute(interp)
  180. # cast to int
  181. if isinstance(w_index, FloatObject):
  182. w_index = IntObject(int(w_index.floatval))
  183. w_val = self.expr.execute(interp)
  184. assert isinstance(arr, BaseArray)
  185. arr.descr_setitem(interp.space, w_index, w_val)
  186. def __repr__(self):
  187. return "%s[%r] = %r" % (self.name, self.index, self.expr)
  188. class Variable(Node):
  189. def __init__(self, name):
  190. self.name = name.strip(" ")
  191. def execute(self, interp):
  192. return interp.variables[self.name]
  193. def __repr__(self):
  194. return 'v(%s)' % self.name
  195. class Operator(Node):
  196. def __init__(self, lhs, name, rhs):
  197. self.name = name
  198. self.lhs = lhs
  199. self.rhs = rhs
  200. def execute(self, interp):
  201. w_lhs = self.lhs.execute(interp)
  202. if isinstance(self.rhs, SliceConstant):
  203. w_rhs = self.rhs.wrap(interp.space)
  204. else:
  205. w_rhs = self.rhs.execute(interp)
  206. if not isinstance(w_lhs, BaseArray):
  207. # scalar
  208. dtype = get_dtype_cache(interp.space).w_float64dtype
  209. w_lhs = scalar_w(interp.space, dtype, w_lhs)
  210. assert isinstance(w_lhs, BaseArray)
  211. if self.name == '+':
  212. w_res = w_lhs.descr_add(interp.space, w_rhs)
  213. elif self.name == '*':
  214. w_res = w_lhs.descr_mul(interp.space, w_rhs)
  215. elif self.name == '-':
  216. w_res = w_lhs.descr_sub(interp.space, w_rhs)
  217. elif self.name == '->':
  218. assert not isinstance(w_rhs, Scalar)
  219. if isinstance(w_rhs, FloatObject):
  220. w_rhs = IntObject(int(w_rhs.floatval))
  221. assert isinstance(w_lhs, BaseArray)
  222. w_res = w_lhs.descr_getitem(interp.space, w_rhs)
  223. else:
  224. raise NotImplementedError
  225. if (not isinstance(w_res, BaseArray) and
  226. not isinstance(w_res, interp_boxes.W_GenericBox)):
  227. dtype = get_dtype_cache(interp.space).w_float64dtype
  228. w_res = scalar_w(interp.space, dtype, w_res)
  229. return w_res
  230. def __repr__(self):
  231. return '(%r %s %r)' % (self.lhs, self.name, self.rhs)
  232. class FloatConstant(Node):
  233. def __init__(self, v):
  234. self.v = float(v)
  235. def __repr__(self):
  236. return "Const(%s)" % self.v
  237. def wrap(self, space):
  238. return space.wrap(self.v)
  239. def execute(self, interp):
  240. return interp.space.wrap(self.v)
  241. class RangeConstant(Node):
  242. def __init__(self, v):
  243. self.v = int(v)
  244. def execute(self, interp):
  245. w_list = interp.space.newlist(
  246. [interp.space.wrap(float(i)) for i in range(self.v)]
  247. )
  248. dtype = get_dtype_cache(interp.space).w_float64dtype
  249. return array(interp.space, w_list, w_dtype=dtype, w_order=None)
  250. def __repr__(self):
  251. return 'Range(%s)' % self.v
  252. class Code(Node):
  253. def __init__(self, statements):
  254. self.statements = statements
  255. def __repr__(self):
  256. return "\n".join([repr(i) for i in self.statements])
  257. class ArrayConstant(Node):
  258. def __init__(self, items):
  259. self.items = items
  260. def wrap(self, space):
  261. return space.newlist([item.wrap(space) for item in self.items])
  262. def execute(self, interp):
  263. w_list = self.wrap(interp.space)
  264. dtype = get_dtype_cache(interp.space).w_float64dtype
  265. return array(interp.space, w_list, w_dtype=dtype, w_order=None)
  266. def __repr__(self):
  267. return "[" + ", ".join([repr(item) for item in self.items]) + "]"
  268. class SliceConstant(Node):
  269. def __init__(self, start, stop, step):
  270. # no negative support for now
  271. self.start = start
  272. self.stop = stop
  273. self.step = step
  274. def wrap(self, space):
  275. return SliceObject(self.start, self.stop, self.step)
  276. def execute(self, interp):
  277. return SliceObject(self.start, self.stop, self.step)
  278. def __repr__(self):
  279. return 'slice(%s,%s,%s)' % (self.start, self.stop, self.step)
  280. class Execute(Node):
  281. def __init__(self, expr):
  282. self.expr = expr
  283. def __repr__(self):
  284. return repr(self.expr)
  285. def execute(self, interp):
  286. interp.results.append(self.expr.execute(interp))
  287. class FunctionCall(Node):
  288. def __init__(self, name, args):
  289. self.name = name.strip(" ")
  290. self.args = args
  291. def __repr__(self):
  292. return "%s(%s)" % (self.name, ", ".join([repr(arg)
  293. for arg in self.args]))
  294. def execute(self, interp):
  295. if self.name in SINGLE_ARG_FUNCTIONS:
  296. if len(self.args) != 1:
  297. raise ArgumentMismatch
  298. arr = self.args[0].execute(interp)
  299. if not isinstance(arr, BaseArray):
  300. raise ArgumentNotAnArray
  301. if self.name == "sum":
  302. w_res = arr.descr_sum(interp.space)
  303. elif self.name == "prod":
  304. w_res = arr.descr_prod(interp.space)
  305. elif self.name == "max":
  306. w_res = arr.descr_max(interp.space)
  307. elif self.name == "min":
  308. w_res = arr.descr_min(interp.space)
  309. elif self.name == "any":
  310. w_res = arr.descr_any(interp.space)
  311. elif self.name == "all":
  312. w_res = arr.descr_all(interp.space)
  313. elif self.name == "unegative":
  314. neg = interp_ufuncs.get(interp.space).negative
  315. w_res = neg.call(interp.space, [arr])
  316. else:
  317. assert False # unreachable code
  318. if isinstance(w_res, BaseArray):
  319. return w_res
  320. if isinstance(w_res, FloatObject):
  321. dtype = get_dtype_cache(interp.space).w_float64dtype
  322. elif isinstance(w_res, BoolObject):
  323. dtype = get_dtype_cache(interp.space).w_booldtype
  324. elif isinstance(w_res, interp_boxes.W_GenericBox):
  325. dtype = w_res.get_dtype(interp.space)
  326. else:
  327. dtype = None
  328. return scalar_w(interp.space, dtype, w_res)
  329. else:
  330. raise WrongFunctionName
  331. _REGEXES = [
  332. ('-?[\d\.]+', 'number'),
  333. ('\[', 'array_left'),
  334. (':', 'colon'),
  335. ('\w+', 'identifier'),
  336. ('\]', 'array_right'),
  337. ('(->)|[\+\-\*\/]', 'operator'),
  338. ('=', 'assign'),
  339. (',', 'coma'),
  340. ('\|', 'pipe'),
  341. ('\(', 'paren_left'),
  342. ('\)', 'paren_right'),
  343. ]
  344. REGEXES = []
  345. for r, name in _REGEXES:
  346. REGEXES.append((re.compile(r' *(' + r + ')'), name))
  347. del _REGEXES
  348. class Token(object):
  349. def __init__(self, name, v):
  350. self.name = name
  351. self.v = v
  352. def __repr__(self):
  353. return '(%s, %s)' % (self.name, self.v)
  354. empty = Token('', '')
  355. class TokenStack(object):
  356. def __init__(self, tokens):
  357. self.tokens = tokens
  358. self.c = 0
  359. def pop(self):
  360. token = self.tokens[self.c]
  361. self.c += 1
  362. return token
  363. def get(self, i):
  364. if self.c + i >= len(self.tokens):
  365. return empty
  366. return self.tokens[self.c + i]
  367. def remaining(self):
  368. return len(self.tokens) - self.c
  369. def push(self):
  370. self.c -= 1
  371. def __repr__(self):
  372. return repr(self.tokens[self.c:])
  373. class Parser(object):
  374. def tokenize(self, line):
  375. tokens = []
  376. while True:
  377. for r, name in REGEXES:
  378. m = r.match(line)
  379. if m is not None:
  380. g = m.group(0)
  381. tokens.append(Token(name, g))
  382. line = line[len(g):]
  383. if not line:
  384. return TokenStack(tokens)
  385. break
  386. else:
  387. raise TokenizerError(line)
  388. def parse_number_or_slice(self, tokens):
  389. start_tok = tokens.pop()
  390. if start_tok.name == 'colon':
  391. start = 0
  392. else:
  393. if tokens.get(0).name != 'colon':
  394. return FloatConstant(start_tok.v)
  395. start = int(start_tok.v)
  396. tokens.pop()
  397. if not tokens.get(0).name in ['colon', 'number']:
  398. stop = -1
  399. step = 1
  400. else:
  401. next = tokens.pop()
  402. if next.name == 'colon':
  403. stop = -1
  404. step = int(tokens.pop().v)
  405. else:
  406. stop = int(next.v)
  407. if tokens.get(0).name == 'colon':
  408. tokens.pop()
  409. step = int(tokens.pop().v)
  410. else:
  411. step = 1
  412. return SliceConstant(start, stop, step)
  413. def parse_expression(self, tokens):
  414. stack = []
  415. while tokens.remaining():
  416. token = tokens.pop()
  417. if token.name == 'identifier':
  418. if tokens.remaining() and tokens.get(0).name == 'paren_left':
  419. stack.append(self.parse_function_call(token.v, tokens))
  420. else:
  421. stack.append(Variable(token.v))
  422. elif token.name == 'array_left':
  423. stack.append(ArrayConstant(self.parse_array_const(tokens)))
  424. elif token.name == 'operator':
  425. stack.append(Variable(token.v))
  426. elif token.name == 'number' or token.name == 'colon':
  427. tokens.push()
  428. stack.append(self.parse_number_or_slice(tokens))
  429. elif token.name == 'pipe':
  430. stack.append(RangeConstant(tokens.pop().v))
  431. end = tokens.pop()
  432. assert end.name == 'pipe'
  433. else:
  434. tokens.push()
  435. break
  436. stack.reverse()
  437. lhs = stack.pop()
  438. while stack:
  439. op = stack.pop()
  440. assert isinstance(op, Variable)
  441. rhs = stack.pop()
  442. lhs = Operator(lhs, op.name, rhs)
  443. return lhs
  444. def parse_function_call(self, name, tokens):
  445. args = []
  446. tokens.pop() # lparen
  447. while tokens.get(0).name != 'paren_right':
  448. args.append(self.parse_expression(tokens))
  449. return FunctionCall(name, args)
  450. def parse_array_const(self, tokens):
  451. elems = []
  452. while True:
  453. token = tokens.pop()
  454. if token.name == 'number':
  455. elems.append(FloatConstant(token.v))
  456. elif token.name == 'array_left':
  457. elems.append(ArrayConstant(self.parse_array_const(tokens)))
  458. else:
  459. raise BadToken()
  460. token = tokens.pop()
  461. if token.name == 'array_right':
  462. return elems
  463. assert token.name == 'coma'
  464. def parse_statement(self, tokens):
  465. if (tokens.get(0).name == 'identifier' and
  466. tokens.get(1).name == 'assign'):
  467. lhs = tokens.pop().v
  468. tokens.pop()
  469. rhs = self.parse_expression(tokens)
  470. return Assignment(lhs, rhs)
  471. elif (tokens.get(0).name == 'identifier' and
  472. tokens.get(1).name == 'array_left'):
  473. name = tokens.pop().v
  474. tokens.pop()
  475. index = self.parse_expression(tokens)
  476. tokens.pop()
  477. tokens.pop()
  478. return ArrayAssignment(name, index, self.parse_expression(tokens))
  479. return Execute(self.parse_expression(tokens))
  480. def parse(self, code):
  481. statements = []
  482. for line in code.split("\n"):
  483. if '#' in line:
  484. line = line.split('#', 1)[0]
  485. line = line.strip(" ")
  486. if line:
  487. tokens = self.tokenize(line)
  488. statements.append(self.parse_statement(tokens))
  489. return Code(statements)
  490. def numpy_compile(code):
  491. parser = Parser()
  492. return InterpreterState(parser.parse(code))