def prim_break(compiler, src): if len(src) == 1: return pycode.create('break\nNone') loop_name = context.curr()['LOOP_STACK'][-1] return pycode.create( '%s = $#\nbreak\n%s' % (loop_name, loop_name), compiler.compile(src[1]))
def prim_for(compiler, src): if lisp.Symbol('<-') != src[2]: raise SyntaxError(src[:3]) matcher = src[1] datasource = src[3] body = src[4:] queue_name = pycode.name('for_queue') context.curr().setdefault('FOR_STACK', []).append(queue_name) if type(matcher) is lisp.Symbol: tpl = '%s = []\nfor %s in $#:\n %s.append($#)\n%s' % ( queue_name, matcher.name, queue_name, queue_name) datasource_code = compiler.compile(datasource) if body: body_code = compiler.compile((lisp.Symbol('env'), matcher) + body) else: body_code = pycode.create(matcher.name) output_code = pycode.create(tpl, datasource_code, body_code) else: datasource_code = compiler.compile(datasource) if datasource_code.value == '_': datasource_code = datasource.asname(pycode.name()) for_var = pycode.name('for_var') proc_compiler = proc.Compiler(compiler) matcher_code = proc_compiler.compile(for_var, matcher) tpl = \ '%s = []\n' % (queue_name,) + \ 'for %s in $#:\n' % (for_var,) + \ ' try:\n' + \ ' $#\n' + \ ' except _ME, e:\n' + \ ' continue\n' + \ ' %s.append($#)\n' % (queue_name,) + \ queue_name if body: body_code = compiler.compile((lisp.Symbol('env'), lisp.Symbol(matcher_code.value)) + body) else: body_code = pycode.create(matcher_code.value) output_code = pycode.create(tpl, datasource_code, matcher_code, body_code) context.curr()['FOR_STACK'].pop() return output_code
def compile_test(self, *exprs): proc_var = lisp.env_curr() tpl = 'if not ($#):\n raise _ME()\n%s' % (proc_var,) source = (_S('and'),) + tuple(exprs) test_code = self.compile_lisp(source) return pycode.create( tpl, test_code, shortcut_guards = list(exprs))
def prim_loop(compiler, src): if src[2] != lisp.Symbol("<-"): raise SyntaxError, src[:3] loop_binding = src[1] loop_init = src[3] loop_body = src[4:] loop_name = pycode.name("loop") context.curr().setdefault("LOOP_STACK", []).append(loop_name) tpl = ( "%s = $#\n" % (loop_name,) + "while True:\n" + " try:\n" + " $#\n" + " except _ME:\n" + " break\n" + " $#\n" + " break\n" + loop_name ) output_code = pycode.create( tpl, compiler.compile(loop_init), compiler.compile((lisp.Symbol("="), loop_binding, lisp.Symbol(loop_name))), compiler.compile_block(loop_body, loop_name), ) context.curr()["LOOP_STACK"].pop() return output_code
def prim_proc(compiler, source): proc_name = pycode.name('proc') tpl = 'def %s(%s_in):\n return $#\n%s' % (proc_name, proc_name, proc_name) with context.Context(): proc_compiler = proc.Compiler(compiler) return pycode.create(tpl, proc_compiler.compile(proc_name + '_in', source))
def prim_class(compiler, source): class_name = source[1].name if len(source) > 2 and lisp.getop(source[2]) == ':': extends = [x.name for x in source[2][1:]] block = source[3:] else: extends = ['object'] block = source[2:] tpl = 'class %s(%s):\n' % (class_name, ','.join(extends)) if block: tpl += ' $#\n' + class_name return pycode.create(tpl, compiler.compile_block(block)) else: tpl += ' pass\n' + class_name return pycode.create(tpl)
def prim_loop(compiler, src): if src[2] != lisp.Symbol('<-'): raise SyntaxError, src[:3] loop_binding = src[1] loop_init = src[3] loop_body = src[4:] loop_name = pycode.name('loop') context.curr().setdefault('LOOP_STACK', []).append(loop_name) tpl = \ '%s = $#\n' % (loop_name,) + \ 'while True:\n' + \ ' try:\n' + \ ' $#\n' + \ ' except _ME:\n' + \ ' break\n' + \ ' $#\n' + \ ' break\n' + \ loop_name output_code = pycode.create( tpl, compiler.compile(loop_init), compiler.compile((lisp.Symbol('='), loop_binding, lisp.Symbol(loop_name))), compiler.compile_block(loop_body, loop_name)) context.curr()['LOOP_STACK'].pop() return output_code
def compile_call(compiler, src): subject = src[0] tpl_lines = ['$#'] sum_codes = [compiler.compile(subject)] if len(src) > 1 and src[1] == Symbol('->'): # It's a selector chain op_sects = [] for selector in src[2:]: op_sects.extend(compile_select(compiler, selector)) else: op_sects = compile_call_args(compiler, src[1:]) # Create tpl tmp_name = None for item in op_sects: sect_tpl, sect_codes = item[0], item[1:] if len([x for x in sect_codes if x.is_expr()]) == len(sect_codes): # All section code is expr, save to directly join tpl_lines[-1] += sect_tpl else: if tmp_name is None: tmp_name = pycode.name() tpl_lines[-1] = '%s = %s' % (tmp_name, tpl_lines[-1]) tpl_lines.append(tmp_name + sect_tpl) sum_codes.extend(sect_codes) return pycode.create('\n'.join(tpl_lines), *sum_codes)
def prim_if(compiler, source): chain = _parse_if(source) if_var = pycode.name('if_var') tpl = 'if $#:\n %s = $#\n' % (if_var, ) codes = [ compiler.compile(chain[0][0]), compiler.compile_block(chain[0][1]) ] indent = '' for idx in xrange(1, len(chain)): curr_test, curr_body = chain[idx] if curr_test is None: tpl += indent + 'else:\n' tpl += indent + ' %s = $#\n' % (if_var, ) codes.append(compiler.compile_block(curr_body)) break else: tpl += indent + 'else:\n' tpl += indent + ' if $#:\n' tpl += indent + ' %s = $#\n' % (if_var, ) indent += pycode.TAB codes.extend([ compiler.compile(curr_test), compiler.compile_block(curr_body) ]) tpl += if_var return pycode.create(tpl, *codes)
def prim_for(compiler, src): if lisp.Symbol('<-') != src[2]: raise SyntaxError(src[:3]) matcher = src[1] datasource = src[3] body = src[4:] queue_name = pycode.name('for_queue') context.curr().setdefault('FOR_STACK', []).append(queue_name) if type(matcher) is lisp.Symbol: tpl = '%s = []\nfor %s in $#:\n %s.append($#)\n%s' % ( queue_name, matcher.name, queue_name, queue_name) datasource_code = compiler.compile(datasource) if body: body_code = compiler.compile((lisp.Symbol('env'), matcher) + body) else: body_code = pycode.create(matcher.name) output_code = pycode.create(tpl, datasource_code, body_code) else: datasource_code = compiler.compile(datasource) if datasource_code.value == '_': datasource_code = datasource.asname(pycode.name()) for_var = pycode.name('for_var') proc_compiler = proc.Compiler(compiler) matcher_code = proc_compiler.compile(for_var, matcher) tpl = \ '%s = []\n' % (queue_name,) + \ 'for %s in $#:\n' % (for_var,) + \ ' try:\n' + \ ' $#\n' + \ ' except _ME, e:\n' + \ ' continue\n' + \ ' %s.append($#)\n' % (queue_name,) + \ queue_name if body: body_code = compiler.compile( (lisp.Symbol('env'), lisp.Symbol(matcher_code.value)) + body) else: body_code = pycode.create(matcher_code.value) output_code = pycode.create(tpl, datasource_code, matcher_code, body_code) context.curr()['FOR_STACK'].pop() return output_code
def compile_struct(compiler, data): if type(data) in (tuple, list): elements = map(compiler.compile, data) if type(data) is tuple: tpl = '(' + '$#,' * len(elements) + ')' else: tpl = '[' + '$#,' * len(elements) + ']' return pycode.create(tpl, *elements) elif type(data) is KVStream: element_codes = [ pycode.create( '$#:$#', compiler.compile(x[0]), compiler.compile(x[1])) for x in data] tpl = '{' + '$#,' * len(element_codes) + '}' return pycode.create(tpl, *element_codes) else: return pycode.create('$#', data)
def compile_call(self, proc_src, argument): if type(argument) is not pycode.Code: argument = self.compile_lisp(argument) proc_var = pycode.name('proc_var') return pycode.create( '%s = $#\n$#\n%s' % (proc_var, proc_var), argument, self.compile(proc_var, proc_src))
def prim_infix(compiler, src): op_name = src[0].name if op_name != '-': op_name = op_name.replace('-', ' ') op_name = OP_MAPPING.get(op_name, op_name) tpl = '(' + (') %s (' % (op_name, )).join(['$#'] * (len(src) - 1)) + ')' codes = map(compiler.compile, src[1:]) return pycode.create(tpl, *codes)
def prim_infix(compiler, src): op_name = src[0].name if op_name != '-': op_name = op_name.replace('-', ' ') op_name = OP_MAPPING.get(op_name, op_name) tpl = '(' + (') %s (' % (op_name,)).join(['$#'] * (len(src) - 1)) + ')' codes = map(compiler.compile, src[1:]) return pycode.create(tpl, *codes)
def pattern_ext_not(compiler, element): proc_var = lisp.env_curr() matched_var = pycode.name('switch') tpl = """\ try: $# %s = False except _ME: %s = True if not %s: raise _ME, %s %s""" % (matched_var, matched_var, matched_var, proc_var, proc_var) return pycode.create(tpl, compiler.compile(proc_var, element[1]))
def compile_pattern_element(self, element): proc_var = lisp.env_curr() # '_' is a blank space holder that do nothing if element == _S('_'): return pycode.create(proc_var, shortcut_nop = True) # Name binding bind_to, may_raise = Compiler.get_binding(element) if bind_to is not None: return pycode.create( '%s=%s\n%s' % (bind_to, proc_var, proc_var), shortcut_bind = [bind_to], raise_random = may_raise) opname = lisp.getop(element) # Force equal testing if opname == '\'': return self.compile_equal(element[1]) # Type checking if opname == ':': # NOTE: infact, type checking expression could throw exception return self.compile_test((_S('isinstance'), _S('_'), element[1])) if opname == '?': return self.compile_test(*element[1:]).add_meta(raise_random = True) # Expanded matchings if opname in self.EXTS: return self.EXTS[opname](self, element) # Extractor if type(element) is tuple and len(element) > 0: return self.compile_call( (_S('#'),) + element[1:], (element[0], _S('_'))).add_meta(raise_random = True) # Now all come to the structual matching return self.compile_pattern_struct(element)
def compile(self, proc_var, src): chain = Compiler.construct_chain(src) if not chain: return pycode.create(proc_var) if len(chain) == 1: return self.compile_section(proc_var, chain[0], True) tpl = 'try:\n $#\n' indent = '' for i in xrange(len(chain) - 2): tpl += indent + 'except _ME:\n' tpl += indent + ' try:\n' tpl += indent + ' $#\n' indent += pycode.TAB tpl += indent + 'except _ME:\n' tpl += indent + ' $#\n' tpl += proc_var section_codes = [self.compile_section(proc_var, chain[0], False)] section_codes.extend( [self.compile_section(proc_var, x, False) for x in chain[1:-1]]) section_codes.append(self.compile_section(proc_var, chain[-1], True)) return pycode.create(tpl, *section_codes)
def compile_section(self, proc_var, section, is_last): pattern_part, body_part = section proc_stack = context.curr().setdefault('PROC_STACK', []) lisp.env_push(proc_var) if pattern_part: proc_stack.append('#') pattern_code = self.compile_pattern(pattern_part) if pattern_code.meta.get('raise_random', False) and ( (not is_last) or (len(proc_stack) < 2 or proc_stack[-2] != '#')): # When compiled pattern code may raise random exception # And it's not the last one of matching chain or # The caller is call directely in a LISP environment (not in pattern matching) # It's the pattern matching code's responsibility to catch all exception # and turn it to _ME wrap_tpl = 'try:\n $#\nexcept:\n raise _ME(%s)\n%s' % ( proc_var, proc_var) pattern_code = pycode.create(wrap_tpl, pattern_code) proc_stack.pop() else: pattern_code = pycode.create(proc_var, shortcut_nop=True) if body_part is None: return pattern_code proc_stack.append('=>') body_code = pycode.create(proc_var + ' = $#\n' + proc_var, self.lisp_compiler.compile_block(body_part)) proc_stack.pop() lisp.env_pop() if not is_last: body_tpl = 'try:\n $#\nexcept _ME, e:\n raise _UME(%s)\n%s' % ( proc_var, proc_var) body_code = pycode.create(body_tpl, body_code) return pattern_code + body_code
def compile_pattern_element(self, element): proc_var = lisp.env_curr() # '_' is a blank space holder that do nothing if element == _S('_'): return pycode.create(proc_var, shortcut_nop=True) # Name binding bind_to, may_raise = Compiler.get_binding(element) if bind_to is not None: return pycode.create('%s=%s\n%s' % (bind_to, proc_var, proc_var), shortcut_bind=[bind_to], raise_random=may_raise) opname = lisp.getop(element) # Force equal testing if opname == '\'': return self.compile_equal(element[1]) # Type checking if opname == ':': # NOTE: infact, type checking expression could throw exception return self.compile_test((_S('isinstance'), _S('_'), element[1])) if opname == '?': return self.compile_test(*element[1:]).add_meta(raise_random=True) # Expanded matchings if opname in self.EXTS: return self.EXTS[opname](self, element) # Extractor if type(element) is tuple and len(element) > 0: return self.compile_call( (_S('#'), ) + element[1:], (element[0], _S('_'))).add_meta(raise_random=True) # Now all come to the structual matching return self.compile_pattern_struct(element)
def compile_fn(compiler, fn_name, arglist, body, compile_return=True): if fn_name is None: fn_name = pycode.name('fn') args, kwargs, kwargs_source = _parse_arglist(arglist) kwargs_codes = map(compiler.compile, kwargs_source) arglist_tpl = ','.join(list(args) + [x + '=$#' for x in kwargs]) if compile_return: tpl = 'def %s(%s):\n return $#\n%s' % (fn_name, arglist_tpl, fn_name) else: tpl = 'def %s(%s):\n $#\n%s' % (fn_name, arglist_tpl, fn_name) with context.Context(): body_code = compiler.compile_block(body) return pycode.create(tpl, *(kwargs_codes + [body_code]))
def compile(self, proc_var, src): chain = Compiler.construct_chain(src) if not chain: return pycode.create(proc_var) if len(chain) == 1: return self.compile_section(proc_var, chain[0], True) tpl = 'try:\n $#\n' indent = '' for i in xrange(len(chain) - 2): tpl += indent + 'except _ME:\n' tpl += indent + ' try:\n' tpl += indent + ' $#\n' indent += pycode.TAB tpl += indent + 'except _ME:\n' tpl += indent + ' $#\n' tpl += proc_var section_codes = [self.compile_section(proc_var, chain[0], False)] section_codes.extend([ self.compile_section(proc_var, x, False) for x in chain[1:-1]]) section_codes.append(self.compile_section(proc_var, chain[-1], True)) return pycode.create(tpl, *section_codes)
def compile_fn(compiler, fn_name, arglist, body, compile_return = True): if fn_name is None: fn_name = pycode.name('fn') args, kwargs, kwargs_source = _parse_arglist(arglist) kwargs_codes = map(compiler.compile, kwargs_source) arglist_tpl = ','.join(list(args) + [x + '=$#' for x in kwargs]) if compile_return: tpl = 'def %s(%s):\n return $#\n%s' % (fn_name, arglist_tpl, fn_name) else: tpl = 'def %s(%s):\n $#\n%s' % (fn_name, arglist_tpl, fn_name) with context.Context(): body_code = compiler.compile_block(body) return pycode.create(tpl, *(kwargs_codes + [body_code]))
def compile_section(self, proc_var, section, is_last): pattern_part, body_part = section proc_stack = context.curr().setdefault('PROC_STACK', []) lisp.env_push(proc_var) if pattern_part: proc_stack.append('#') pattern_code = self.compile_pattern(pattern_part) if pattern_code.meta.get('raise_random', False) and ( (not is_last) or (len(proc_stack) < 2 or proc_stack[-2] != '#')): # When compiled pattern code may raise random exception # And it's not the last one of matching chain or # The caller is call directely in a LISP environment (not in pattern matching) # It's the pattern matching code's responsibility to catch all exception # and turn it to _ME wrap_tpl = 'try:\n $#\nexcept:\n raise _ME(%s)\n%s' % (proc_var, proc_var) pattern_code = pycode.create(wrap_tpl, pattern_code) proc_stack.pop() else: pattern_code = pycode.create(proc_var, shortcut_nop = True) if body_part is None: return pattern_code proc_stack.append('=>') body_code = pycode.create( proc_var + ' = $#\n' + proc_var, self.lisp_compiler.compile_block(body_part)) proc_stack.pop() lisp.env_pop() if not is_last: body_tpl = 'try:\n $#\nexcept _ME, e:\n raise _UME(%s)\n%s' % ( proc_var, proc_var) body_code = pycode.create(body_tpl, body_code) return pattern_code + body_code
def pattern_ext_some(compiler, element): proc_var = lisp.env_curr() element_var = pycode.name('pattern_some') matched_var = pycode.name('switch') tpl = \ '%s = False\n' % (matched_var,) + \ 'for %s in %s\n' % (element_var, proc_var) + \ ' try:\n' + \ ' $#\n' + \ ' %s = True\n' % (matched_var,) + \ ' break\n' + \ ' except _ME:\n' + \ ' continue\n' + \ 'if not %s:\n' % (matched_var,) + \ ' raise _ME, %s\n' % (proc_var,) + \ proc_var return pycode.create(tpl, compiler.compile(element_var, element[1]))
def prim_assign(compiler, src): if type(src[1]) is lisp.Symbol: value_code = compiler.compile(src[2]) return pycode.create('%s=$#\n%s' % (src[1].name, src[1].name), value_code) elif is_prop_fetch(src[1]): value_code = compiler.compile(src[2]) if not pycode.Code.is_expr_pure(value_code.value): value_code = value_code.asname(pycode.name()) sym_code = compiler.compile(src[1]) # NOTE: Note that pycode tempalte dosen't work here # Because theres to code is not arguments to one expression stat_lines = (sym_code.stat, value_code.stat, '%s = %s' % (sym_code.value, value_code.value)) stat = '\n'.join([x for x in stat_lines if x]) return pycode.Code(stat, value_code.value) else: pattern_compiler = proc.Compiler(compiler) return pattern_compiler.compile_call(src[1], src[2])
def prim_try(compiler, source): curr_stat = 'try' # Step 1: Parse the list try_block = [] except_blocks = [] finally_block = [] try_var = pycode.name('try') for item in source[1:]: if lisp.getop(item) == 'except': if not type(item[1]) is tuple and len(item[1]) == 2 and ( type(item[1][0]) is lisp.Symbol and type(item[1][1]) is lisp.Symbol): raise SyntaxError, item curr_stat = 'except' (except_blocks.append((item[1][0].name, item[1][1].name, item[2:]))) elif lisp.getop(item) == 'finally': finally_block.extend(item[1:]) else: if curr_stat != 'try': raise SyntaxError, source try_block.append(item) if not except_blocks and not finally_block: raise SyntaxError, source # Try part output_tpl = 'try:\n %s = $#\n' % (try_var,) output_codes = [compiler.compile_block(try_block)] # Except part for type_sym, bind_sym, code in except_blocks: output_tpl += 'except %s, %s:\n %s = $#\n' % ( type_sym, bind_sym, try_var) output_codes.append(compiler.compile_block(code)) if finally_block: output_tpl += 'finally:\n $#\n' output_codes.append(compiler.compile_block(finally_block)) output_tpl += try_var return pycode.create(output_tpl, *output_codes)
def compile_pattern(self, pattern): proc_var = lisp.env_curr() # Combine effect of each pattern element # Count metadata for caller shortcuts = [] is_raise_random = False output = pycode.create(proc_var) for element in pattern: code = self.compile_pattern_element(element) if code.meta.get('shortcut_nop', False): continue output += code is_raise_random = is_raise_random or code.meta.get( 'raise_random', False) if 'shortcut_equal' in code.meta: shortcut = ('equal', code.meta['shortcut_equal']) elif 'shortcut_bind' in code.meta: shortcut = ('bind', code.meta['shortcut_bind']) else: shortcut = (None, None) shortcuts.append(shortcut) if len(shortcuts) == 0: return output.add_meta(shortcut_nop=True) equals = [x[1] for x in shortcuts if x[0] == 'equal'] if len(equals) == len(shortcuts): return output.add_meta(shortcut_equal=equals[0]) binds = [x[1] for x in shortcuts if x[0] == 'bind'] if len(binds) == len(shortcuts): join_binds = [] for item in binds: join_binds.extend(item) return output.add_meta(shortcut_bind=join_binds, raise_random=is_raise_random) return output.add_meta(raise_random=is_raise_random)
def compile_pattern(self, pattern): proc_var = lisp.env_curr() # Combine effect of each pattern element # Count metadata for caller shortcuts = [] is_raise_random = False output = pycode.create(proc_var) for element in pattern: code = self.compile_pattern_element(element) if code.meta.get('shortcut_nop', False): continue output += code is_raise_random = is_raise_random or code.meta.get('raise_random', False) if 'shortcut_equal' in code.meta: shortcut = ('equal', code.meta['shortcut_equal']) elif 'shortcut_bind' in code.meta: shortcut = ('bind', code.meta['shortcut_bind']) else: shortcut = (None, None) shortcuts.append(shortcut) if len(shortcuts) == 0: return output.add_meta(shortcut_nop = True) equals = [x[1] for x in shortcuts if x[0] == 'equal'] if len(equals) == len(shortcuts): return output.add_meta(shortcut_equal = equals[0]) binds = [x[1] for x in shortcuts if x[0] == 'bind'] if len(binds) == len(shortcuts): join_binds = [] for item in binds: join_binds.extend(item) return output.add_meta(shortcut_bind = join_binds, raise_random = is_raise_random) return output.add_meta(raise_random = is_raise_random)
def prim_if(compiler, source): chain = _parse_if(source) if_var = pycode.name('if_var') tpl = 'if $#:\n %s = $#\n' % (if_var,) codes = [compiler.compile(chain[0][0]), compiler.compile_block(chain[0][1])] indent = '' for idx in xrange(1, len(chain)): curr_test, curr_body = chain[idx] if curr_test is None: tpl += indent + 'else:\n' tpl += indent + ' %s = $#\n' % (if_var,) codes.append(compiler.compile_block(curr_body)) break else: tpl += indent + 'else:\n' tpl += indent + ' if $#:\n' tpl += indent + ' %s = $#\n' % (if_var,) indent += pycode.TAB codes.extend([compiler.compile(curr_test), compiler.compile_block(curr_body)]) tpl += if_var return pycode.create(tpl, *codes)
def compile_call(self, proc_src, argument): if type(argument) is not pycode.Code: argument = self.compile_lisp(argument) proc_var = pycode.name('proc_var') return pycode.create('%s = $#\n$#\n%s' % (proc_var, proc_var), argument, self.compile(proc_var, proc_src))
def prim_quote(compiler, src): return pycode.create('$#', src[1])
def compile_pattern_struct(self, source): proc_var = lisp.env_curr() if type(source) is not list or len(source) < 1: return self.compile_equal(source) if len(source) >= 2 and source[-2] == _S('.'): car_part = source[:-2] cdr_part = source[-1] else: car_part = source cdr_part = _S('_') if not car_part: return self.compile(cdr_part) # Compile each element, do special handling with equal and bind shortcuts equal_elements = [] bind_elements = [] custom_elements = [] is_need_wrap = [False] def handle_element_code(idx_expr, src_var, element_code): is_need_wrap[0] = is_need_wrap[0] or \ element_code.meta.get('raise_random', False) if 'shortcut_nop' in element_code.meta: pass elif 'shortcut_equal' in element_code.meta: equal_elements.append((idx_expr, element_code)) elif 'shortcut_bind' in element_code.meta: bind_elements.append((idx_expr, element_code)) else: custom_elements.append((idx_expr, src_var, element_code)) for element_idx in xrange(len(car_part)): idx_expr = '%s[%d]' % ( proc_var, element_idx, ) src_var = '%s_%d' % (proc_var, element_idx) element_code = self.compile(src_var, car_part[element_idx]) handle_element_code(idx_expr, src_var, element_code) # Handle cdr_expr as the same if len(car_part) < len(source): cdr_expr = '%s[%d:]' % ( proc_var, len(car_part), ) src_var = proc_var + '_cdr' cdr_code = self.compile(src_var, cdr_part) handle_element_code(cdr_expr, src_var, cdr_code) # Shortcut: if all element is equal check # Treat as a equal check of whole if len(equal_elements) == len(source): return self.compile_equal(source) code = pycode.create(proc_var).add_meta(shortcut_nop=True) # Compile equal_elemens and length check if equal_elements: fetch_part = '(' + ','.join([x[0] for x in equal_elements]) + ',)' equal_data = tuple(x[1].meta['shortcut_equal'] for x in equal_elements) if len(car_part) == len(source): tpl = 'if len(%s) != %d or $# != $#:\n raise _ME(%s)\n%s' % ( proc_var, len(car_part), proc_var, proc_var) else: tpl = 'if len(%s) < %d or $# != $#:\n raise _ME(%s)\n%s' % ( proc_var, len(car_part), proc_var, proc_var) code += pycode.create(tpl, equal_data, pycode.create(fetch_part)) elif len(car_part) == len(source): code += pycode.create( 'if len(%s) != %d:\n raise _ME(%s)\n%s' % (proc_var, len(car_part), proc_var, proc_var)) else: code += pycode.create( 'if len(%s) < %d:\n raise _ME(%s)\n%s' % (proc_var, len(car_part), proc_var, proc_var)) for bind_idx, bind_code in bind_elements: code += pycode.create('%s=%s\n%s' % ('='.join( bind_code.meta['shortcut_bind']), bind_idx, proc_var)) if custom_elements: for source_idx, src_var, element_code in custom_elements: code += pycode.create('%s = %s\n%s' % (src_var, source_idx, src_var)) code += element_code return code.add_meta(raise_random=is_need_wrap[0])
def compile_test(self, *exprs): proc_var = lisp.env_curr() tpl = 'if not ($#):\n raise _ME()\n%s' % (proc_var, ) source = (_S('and'), ) + tuple(exprs) test_code = self.compile_lisp(source) return pycode.create(tpl, test_code, shortcut_guards=list(exprs))
def prim_global(compiler, src): return pycode.create('global ' + ','.join([x.name for x in src[1:]]) + '\nNone')
def prim_import(compiler, src): if isinstance(src[1], lisp.Symbol): import_expr = src[1].name else: import_expr = str(src[1]) return pycode.create('import %s\nNone' % (import_expr, ))
def prim_emit_many(compiler, src): queue_name = context.curr()['FOR_STACK'][-1] return pycode.create('%s.extend($#)\nNone' % (queue_name,), compiler.compile(src[1]))
def prim_print(compiler, src): return pycode.create('print $#\nNone', compiler.compile(src[1]))
def prim_break(compiler, src): if len(src) == 1: return pycode.create("break\nNone") loop_name = context.curr()["LOOP_STACK"][-1] return pycode.create("%s = $#\nbreak\n%s" % (loop_name, loop_name), compiler.compile(src[1]))
def prim_import(compiler, src): if isinstance(src[1], lisp.Symbol): import_expr = src[1].name else: import_expr = str(src[1]) return pycode.create('import %s\nNone' % (import_expr,))
def compile_pattern_struct(self, source): proc_var = lisp.env_curr() if type(source) is not list or len(source) < 1: return self.compile_equal(source) if len(source) >= 2 and source[-2] == _S('.'): car_part = source[:-2] cdr_part = source[-1] else: car_part = source cdr_part = _S('_') if not car_part: return self.compile(cdr_part) # Compile each element, do special handling with equal and bind shortcuts equal_elements = [] bind_elements = [] custom_elements = [] is_need_wrap = [False] def handle_element_code(idx_expr, src_var, element_code): is_need_wrap[0] = is_need_wrap[0] or \ element_code.meta.get('raise_random', False) if 'shortcut_nop' in element_code.meta: pass elif 'shortcut_equal' in element_code.meta: equal_elements.append((idx_expr, element_code)) elif 'shortcut_bind' in element_code.meta: bind_elements.append((idx_expr, element_code)) else: custom_elements.append((idx_expr, src_var, element_code)) for element_idx in xrange(len(car_part)): idx_expr = '%s[%d]' % (proc_var, element_idx,) src_var = '%s_%d' % (proc_var, element_idx) element_code = self.compile(src_var, car_part[element_idx]) handle_element_code(idx_expr, src_var, element_code) # Handle cdr_expr as the same if len(car_part) < len(source): cdr_expr = '%s[%d:]' % (proc_var, len(car_part),) src_var = proc_var + '_cdr' cdr_code = self.compile(src_var, cdr_part) handle_element_code(cdr_expr, src_var, cdr_code) # Shortcut: if all element is equal check # Treat as a equal check of whole if len(equal_elements) == len(source): return self.compile_equal(source) code = pycode.create(proc_var).add_meta(shortcut_nop = True) # Compile equal_elemens and length check if equal_elements: fetch_part = '(' + ','.join([x[0] for x in equal_elements]) + ',)' equal_data = tuple(x[1].meta['shortcut_equal'] for x in equal_elements) if len(car_part) == len(source): tpl = 'if len(%s) != %d or $# != $#:\n raise _ME(%s)\n%s' % ( proc_var, len(car_part), proc_var, proc_var) else: tpl = 'if len(%s) < %d or $# != $#:\n raise _ME(%s)\n%s' % ( proc_var, len(car_part), proc_var, proc_var) code += pycode.create(tpl, equal_data, pycode.create(fetch_part)) elif len(car_part) == len(source): code += pycode.create('if len(%s) != %d:\n raise _ME(%s)\n%s' % ( proc_var, len(car_part), proc_var, proc_var)) else: code += pycode.create('if len(%s) < %d:\n raise _ME(%s)\n%s' % ( proc_var, len(car_part), proc_var, proc_var)) for bind_idx, bind_code in bind_elements: code += pycode.create('%s=%s\n%s' % ('='.join(bind_code.meta['shortcut_bind']), bind_idx, proc_var)) if custom_elements: for source_idx, src_var, element_code in custom_elements: code += pycode.create('%s = %s\n%s' % (src_var, source_idx, src_var)) code += element_code return code.add_meta(raise_random = is_need_wrap[0])
def prim_prefix(compiler, src): op_name = OP_MAPPING.get(src[0].name, src[0].name.replace('-', ' ')) return pycode.create('%s($#)' % (op_name, ), compiler.compile(src[1]))
def prim_emit_many(compiler, src): queue_name = context.curr()['FOR_STACK'][-1] return pycode.create('%s.extend($#)\nNone' % (queue_name, ), compiler.compile(src[1]))
def pattern_ext_all(compiler, element): proc_var = lisp.env_curr() element_var = pycode.name('pattern_all') tpl = 'for %s in %s:\n $#\n%s' % (element_var, proc_var, proc_var) return pycode.create(tpl, compiler.compile(element_var, element[1]))
def prim_prefix(compiler, src): op_name = OP_MAPPING.get(src[0].name, src[0].name.replace('-', ' ')) return pycode.create('%s($#)' % (op_name,), compiler.compile(src[1]))
def prim_return(compiler, source): return pycode.create('return $#\nNone', compiler.compile(source))
def prim_yield(compiler, source): name = pycode.name('yield') return pycode.create('%s = yield $#\n%s' % (name, name), compiler.compile(source[1]))
def prim_yield(compiler, source): name = pycode.name('yield') return pycode.create( '%s = yield $#\n%s' % (name, name), compiler.compile(source[1]))