def _caller_split(tp): proto, scope_id = tp.split(':', maxsplit=1) if proto == 'instance_call': fname, ret = scope_id.split(':', maxsplit=1) if ' ' in ret: ret, desc = ret.split(' ', maxsplit=1) if '**' in desc: argtypes, kwtypes = desc.split('**') argtypes = argtypes.strip().split(' ') kwtypes = kwtypes.strip().split(' ') else: argtypes = desc.strip().split(' ') kwtypes = None else: argtypes = None kwtypes = None elif proto == 'f' and scope_id in interpreter.LIB.generators: fname = 'f_' + scope_id_to_name(scope_id) ret = 'generator:' + scope_id argtypes = None kwtypes = None elif proto == 'f': fname = 'f_' + scope_id_to_name(scope_id) ret = interpreter.LIB.types[scope_id][''] argtypes = interpreter.LIB.args_cast[scope_id] kwtypes = None elif proto == 'module_call': fname, ret = scope_id.split(':', maxsplit=1) argtypes = None kwtypes = None else: assert False, proto return fname, ret, argtypes, kwtypes
def func(phrases, j, state): s = phrases[j] _id = s.tree.phrase_id if not Scope.can_create(_id): return skip_segment(phrases, j) if _id in interpreter.LIB.generators: return gen_block(phrases, j, state, _id) scope = Scope(_id, state.scope) ret = definer.typestr(interpreter.LIB.types[_id]['']) args = interpreter.LIB.func_args[_id] scope_name = scope_id_to_name(_id) alst = [definer.typestr(scope.find(arg)) + ' ' + w(arg) for arg in args] asep = ', ' if args else '' astr = 'struct thread *thread' + asep + ', '.join(alst) state.print(ret, ' f_', scope_name, '(', astr, ')') state.print('{') inner = State(scope, state.n_tabs) inner.shift(1) put_vars(inner, _id, '', args) inner.shift(-1) j = segment(phrases, j + 1, inner) inner.shift(1) inner.flush_cleanup() inner.shift(-1) state.print('}') return j
def maker(state, scope_id): scope = Scope.create_from_type('class:' + scope_id) name = scope_id_to_name(scope_id) init = definer.init_id(scope_id) state.print(f'static void unmake_', name, '(struct thread *thread, struct o_', name, ' *self)') state.msg_shift('{', 1) free_vars(state, scope_id + '[instance]', 'self->') state.print('free(self);') state.msg_shift('}', -1) if not init: state.print(f'struct o_{name}* f_', name, '(struct thread *thread)') state.msg_shift('{', 1) state.print(f'struct o_{name}* obj = NEW(o_{name});') state.print(f'obj->obj.free = (delete)unmake_{name};') zero_vars(state, scope_id + '[instance]', 'obj->') state.msg_shift('}', -1) return args = interpreter.LIB.func_args[init] init_name = scope_id_to_name(init) init_scope = Scope(init, scope) alst = [definer.typestr(init_scope.find(arg)) + ' ' + w(arg) for arg in args] asep = ', ' if len(args) > 1 else '' astr = 'struct thread *thread' + asep + ', '.join(alst[1:]) state.print(f'struct o_{name}* f_', name, '(', astr, ')') state.msg_shift('{', 1) state.print(f'struct o_{name}* obj = NEW(o_{name});') state.print(f'obj->obj.free = (delete)unmake_{name};') zero_vars(state, scope_id + '[instance]', 'obj->') wargs = ', '.join(w(arg) for arg in args[1:]) state.print(f'f_{init_name}(thread, obj', asep, wargs, ');') state.print(f'return obj;') state.msg_shift('}', -1)
def obj(phrases, i, state): s = phrases[i] _id = s.tree.phrase_id state.print('// class ', definer.Nest.name(_id)) scope = Scope(_id, state.scope) state = State(scope, state.n_tabs) name = scope_id_to_name(_id) state.print('void static_init_', name, '(struct thread *thread)') state.print('{') segment(phrases, i + 1, state) state.print('}') maker(state, _id)
def union_cast(s, tp): s = '(' + s + ').' if tp in ('str:', 'utf8:'): return s + tp[:-1] if tp == 'str:1': return s + 'ch' if tp.startswith('instance:'): scope_id = tp[len('instance:'):-len('[instance]')] name = scope_id_to_name(scope_id) return '((struct ' + name + ')' + s + 'obj)' if tp.startswith('c:size_t'): return s + 'i' if tp.startswith('c:ssize_t'): return s + 'si' if tp.startswith('c:double'): return s + 'lf' assert False, tp
def export_modules(names): for name in names: types = interpreter.LIB.types[name] Out.print('struct module_', name, ' module_', name, ' = {', sep='') fields = [] for _name, tp in types.items(): if tp.startswith('module:'): continue if _name.startswith('@') or _name.startswith('(cast)'): continue if tp.startswith('f:'): f_name = scope_id_to_name(definer.tp_to_scope_id(tp)) fields.append((_name, ' f_' + f_name)) for _name, f in fields[:-1]: Out.print('\t', f, ',', ' // ', _name, sep='') _name, f = fields[-1] Out.print('\t', f, ' // ', _name, sep='') Out.print('};', sep='')
def gen_block(phrases, j, state, _id): scope = Scope(_id, state.scope, prefix='self->', stateless=True) ret = definer.typestr(interpreter.LIB.types[_id]['']) args = interpreter.LIB.func_args[_id] if args: astr = ', ' + ', '.join(definer.typestr(interpreter.LIB.types[_id][a]) + ' ' + w(a) for a in args) else: astr = '' scope_name = scope_id_to_name(_id) comment_name = definer.Nest.comment_name(_id) state.print('/* free generator: ', comment_name, ' */') state.print('void free_', scope_name, f'(struct thread *thread, struct g_{scope_name} *it)') state.print('{') state.shift(1) gen_free(state, _id, args, 'it->') state.print('free(it);') state.shift(-1) state.print('}') state.print('/* init generator: ', comment_name, ' */') state.print('struct g_', scope_name, ' *f_', scope_name, f'(struct thread *thread', astr, ')') state.print('{') state.shift(1) state.print(f'struct g_{scope_name} *it = NEW(g_{scope_name});') gen_init(state, _id, args, 'it->') state.print('it->obj.free = (delete)free_', scope_name, ';') state.print('return it;') state.shift(-1) state.print('}') state.print('/* generator: ', comment_name, ' */') state.print(f'bool loop_{scope_name}(struct thread *thread, struct g_{scope_name} *self)') state.print('{') inner_state = State(scope, state.n_tabs + 1) j = gen_loop(inner_state, 'self->', phrases, j) state.print('}') return j
def segment(phrases, j, state): level = -1 j = j - 1 state.shift(1) while j + 1 < len(phrases): j += 1 s = phrases[j] log('//', s.debug) if level < 0: level = s.level elif level > s.level: j -= 1 break if s.name == 'unit': #j = func(phrases, j, level, state) j = skip_segment(phrases, j, state) continue if s.name == 'class': #j = obj(phrases, j, level, state) _id = s.tree.phrase_id name = scope_id_to_name(_id) state.print('static_init_', name, '(thread);') j = skip_segment(phrases, j, state) continue if s.name == 'import': state.print('/* IMPORT NOT IMPLEMNTED; */') continue state.print('// ', s.debug) if s.name == 'return': if s.tree is None: state.flush_cleanup() state.print('return;') continue state.print('/* begin return block */ {') Temps.push(state) if s.tree.name == 'name': ret = val(s.tree, state) Temps.pop() state.print('/* end return block */ }') if is_ref(ret.tp): state.print('INC_STACK(', ret.value, ');') state.flush_cleanup() state.print('return ', ret.value, ';') continue expr = val(s.tree, state) if not is_ref(expr.tp) and not expr.dependency: Temps.pop() state.print('/* end return block */ }') state.flush_cleanup() state.print('return ', expr.value, ';') continue state.print(definer.typestrt(expr.tp), f' return_value = ({expr.final()});') if is_ref(expr.tp): ref_op(state, expr.tp, 'INC_STACK', 'return_value') Temps.pop() state.flush_cleanup() state.print('return return_value;') state.print('/* end return value calc block */ }') elif s.name == 'yield': assert s.tree is not None state.print('/* begin calc yielded */ {') Temps.push(state) v = val(s.tree, state) state.print('self->value = ', v.final(), ';') if not v.is_new and is_ref(v.tp): ref_op(state, v.tp, 'INC_STACK', 'self->value') Temps.pop() state.print('/* end calc yielded */ }') state.print('self->jump = ', state.yield_count, ';') state.print('return true;') state.insert_case('case', ' ', state.yield_count) state.yield_count += 1 elif s.name == 'raise': state.print('RAISE_NOT_IMPLEMENTED;') elif s.name == 'break': state.print('break;') elif s.name == 'continue': state.print('continue;') elif s.name == 'pass': state.print('{}') elif s.name == 'assert': state.print('/* assert begin */ {') Temps.push(state) if s.tree.name == 'list': cond = val(s.tree.inner[0], state) mess = val(s.tree.inner[1], state) state.print(f'if (!({cond.value})) ', '{') state.shift(1) state.print('rt_print_str(thread, "BUG (assert failed)! %s\\n", ', mess.final(), ', true);') state.print('EXIT();') state.shift(-1) state.print('}') else: cond = val(s.tree, state) state.print(f'if (!({cond.value})) ', '{ fprintf(stderr, "BUG (assert failed)!\\n"); EXIT(); }') Temps.pop() state.print('/* assert end */ }') elif s.name == 'for': i_name = s.tree.inner[0] tp = interpreter.LIB.types[state.scope.scope_id][interpreter.anonymous(s.tree.phrase_id)] state.print('/* begin loop */ {') Temps.push(state) if tp.startswith('generator:'): _id = tp[len('generator:'):] gen = val(s.tree.inner[2], state) ret = interpreter.LIB.types[_id][''] name = 'it' if not state.scope.stateless else definer.anonymous(s.tree.phrase_id) scope_name = scope_id_to_name(_id) state.print('struct g_', scope_name, ' *', name, ' = ', gen.final(), ';') state.print('while (loop_', scope_name, f'(thread, {name})', ') {') state.shift(1) ret = interpreter.LIB.types[_id][''] _assign(i_name, Expr(f'({name}->value)', ret), '=', state) if is_ref(ret): ref_op(state, ret, 'DEC_STACK', f'({name}->value)') state.shift(-1) j = segment(phrases, j + 1, state) state.print('}') state.print(f'DEC_HEAP({name});') elif tp.startswith('constructor:') and not state.scope.stateless: _id = tp[len('constructor:'):] scope_name = scope_id_to_name(_id) #if args.depend(): # state.print('const bool expr = ', args.dependency(), ', true;') state.print('struct ' + scope_name + ' it;') it = Expr('&it', tp) args = args_from_tree(s.tree.inner[2].inner[1], state) args.prepend(it) state.print('for (', call(tp, '__init__', args).value, ';', call(tp, '__notdone__', arguments(it)).value, ';', call(tp, '__promote__', arguments(it)).value, ')', '{') state.shift(1) _assign(i_name, call(tp, '__current__', arguments(it)), '=', state) state.shift(-1) j = segment(phrases, j + 1, state) state.print('}') else: assert False, tp Temps.pop() state.print('/* end loop */ }') elif s.name == 'while': state.print('/* begin while block */ {') Temps.push(state) expr = val(s.tree, state) state.print(f'while ({cond_with_temps(expr)}) ', '{') j = segment(phrases, j + 1, state) state.print('}') Temps.pop() state.print('/* end while block */ }') elif s.name == 'if': state.print('/* begin if block */ {') Temps.push(state) expr = val(s.tree, state) state.print(f'if ({cond_with_temps(expr)}) ', '{') j = segment(phrases, j + 1, state) state.print('}') j = elses(phrases, j, level, state) Temps.pop() state.print('/* end if block */ }') elif s.name == 'expr' and s.tree.name == 'assignment': state.print('/* begin assignment block */ {') Temps.push(state) assert s.tree.inner[1].content != 'in' _assign(s.tree.inner[0], val(s.tree.inner[2], state), s.tree.inner[1].content, state) Temps.pop() state.print('/* end assign block */ }') elif s.name == 'cast': if s.tree.name == 'list': names = [name.content for name in s.tree.inner] else: names = [s.tree.content] state.scope.push_cast(s.tree.phrase_id, names) j = segment(phrases, j + 1, state) state.scope.pop_cast() else: assert s.name == 'expr' state.print('/* begin expr block */ {') Temps.push(state) expr = val(s.tree, state) if is_ref(expr.tp): tmp = Temps.new(expr.tp, True) state.print(tmp, ' = ', expr.final(), ';') else: state.print('const bool expression = (', expr.final(), ', true);') Temps.pop() state.print('/* end expr block */ }') state.shift(-1) return j
def val(tree, scope, temps): if tree.name == 'binary' or tree.name == 'compare': left = val(tree.inner[0], scope, temps) right = val(tree.inner[2], scope, temps) sign = tree.inner[1].content if (left.tp.startswith('c:') and right.tp.startswith('c:')) or (left.tp == right.tp == 'str:1'): if sign == 'and': sign = '&&' elif sign == 'or': sign = '||' if sign in '+-/*%&^|': tp = left.tp else: tp = 'c:bool' return Expr(f'({left.final()}) {sign} ({right.final()})', tp, is_new=True) if sign == 'is in' or sign == 'is not in': temp = left left = right right = temp OP = { 'and': '__and__', 'or': '__or__', '+': '__plus__', '-': '__minus__', '/': '__div__', '*': '__mult__', '%': '__mod__', '&': '__band__', '|': '__bor__', '^': '__bxor__', 'is in': '__isin__', 'is not in': '!__isin__', '==': '__eq__', '!=': '__neq__' } return _call(left.tp, OP[sign], Arguments(temps, left, right)) if tree.name == 'assignment': sign = tree.inner[1].content assert sign != 'in' assert ltree.name == 'name' left = val(tree.inner[0], scope, temps) right = val(tree.inner[2], scope, temps) if not left.tp.startswith('c:'): raise NotImplementedError( 'Expression assignment of non native types') assert left.tp == right.tp return Expr(f'{left.value}', right.tp, dependency=[f'{left.value} {sign} ({right.final})']) if tree.name == 'name': full, tp = scope.find_full(tree.content) return Expr(full, tp) if tree.name == 'digit': return Expr(str(float(tree.content)), 'c:double') if tree.name == 'string': #s = interpreter.escape(tree.content[1:-1]) s = tree.content[1:-1] unescaped = interpreter.escape(s) if len(unescaped) == 1: return Expr('(unsigned char)\'' + s.replace('\'', '\\\'') + '\'', 'str:1') name = Strings.append(s) return Expr(f'&{name}', 'str:') if tree.name == 'attr': owner = val(tree.inner[0], scope, temps) t, props = owner.tp.split(':', maxsplit=1) if t == 'builtin': inner = BuiltinScope(owner.value) elif t == 'instance': inner = Scope(props, None) elif t == 'module' and props in ('sys', ): inner = BuiltinScope(props) elif t == 'module': inner = Scope(props, None) elif t == 'list': inner = BuiltinScope('list', props) elif t == 'str': inner = BuiltinScope('str', props) elif t == 'dict': inner = BuiltinScope('dict', props) else: assert False, owner.tp right = attr_right(tree.inner[2], scope, inner, temps) assert not right.dependency if right.tp.startswith('namespace:'): owner.tp = right.tp + owner.tp return owner owner = temps.absorb(owner) return Expr(f'({owner.final()})->{right.value}', right.tp) if tree.name == 'call': argvals = argvalues(tree.inner[1], scope, temps) if tree.inner[0].name == 'attr' and tree.inner[0].inner[ -1].name == 'name': owner = val(tree.inner[0].inner[0], scope, temps) attr = tree.inner[0].inner[-1].content args = Arguments(temps, *argvals) if not owner.tp.startswith('builtin:') and not owner.tp.startswith( 'module:'): args.prepend(owner) return _call(owner.tp, attr, args) f = val(tree.inner[0], scope, temps) method, name = f.tp.split(':', maxsplit=1) if method == 'print_hack': n = Expr(str(len(argvals)), 'c:size_t') types = ['c:size_t'] + (['str:'] * len(argvals)) return _call('builtin:', 'print_strings', Arguments(temps, n, *argvals).cast(types)) if method == 'interface_call': assert len(argvals) == 1 owner = argvals[0] return _call(owner.tp, name, Arguments(temps, owner)) fname = scope_id_to_name(name) if method == 'f' and name in interpreter.LIB.generators: tp = 'generator:' + name args = Arguments(temps, *argvals) return Expr(f'f_{fname}({args.final()})', tp, is_new=True) if method == 'class': tp = 'instance:' + name + '[instance]' scope = module_scope(tp) if scope.can_find('__init__'): init_type = scope.find('__init__') init_args = interpreter.LIB.args_cast[ init_type[len('f:'):]][1:] argstr = Arguments(temps, *argvals).cast(init_args).final() return Expr(f'f_{fname}({argstr})', tp, is_new=True) else: assert not args return Expr(f'NEW(o_{fname})', tp, is_new=True) if method == 'f': argstr = Arguments(temps, *argvals).final() ret = interpreter.LIB.types[name][''] return Expr(f'f_{fname}({argstr})', ret, is_new=True) assert False, method elif tree.name == 'index': mem = val(tree.inner[0], scope, temps) ind = tree.inner[1].inner[0] return index(mem, ind, scope, temps) if tree.name == 'list': exprs = [val(v, scope, temps) for v in tree.inner] types = [ex.tp for ex in exprs] tup = temps.add_tuple(types) tp = 'struct ' + tup.replace(':', '_') sval = ', '.join(val.final() for val in exprs) return Expr(f'(({tp})' + '{' + sval + '})', tup, components=exprs) elif tree.name == '()': if len(tree.inner) == 0: raise NotImplementedError('empty tuples not implemented') if len(tree.inner) == 1: return val(tree.inner[0], scope, temps) else: raise NotImplementedError('adhoc generators not implemented') if tree.name == '[]': elements = builtin.Types.types['list_items:' + tree.phrase_id] tp = definer.typestr(elements) if len(tree.inner) == 0: ut = f'{union_type(elements)}' return Expr(f'new_list(thread, NULL, 0, {ut})', 'list:' + tp, is_new=True) raise NotImplementedError("list & list comprehension not implemented") if tree.name == '{}': if 'set_elements:' + tree.phrase_id in builtin.Types.types: tp_elements = builtin.Types.types['set_elements:' + tree.phrase_id] tp = 'set:' + definer.typestr(tp_elements) if tree.inner[0].name != 'list': nosep = [tree.inner[0]] else: nosep = [t for t in tree.inner[0].inner if t.name != 'sign'] flat = [val(item, scope, temps) for item in nosep] values = _union_array(flat) ut = f'{union_type(tp_elements)}' return Expr(f'new_set(thread, {values}, {len(flat)}, {ut})', tp, is_new=True) if len(tree.inner) > 1: raise NotImplementedError('dict comprehension implemented') keys = builtin.Types.types['dict_keys:' + tree.phrase_id] values = builtin.Types.types['dict_values:' + tree.phrase_id] tp_keys = definer.typestr(keys) tp_values = definer.typestr(values) tp = 'dict:' + tp_keys + ':' + tp_values ut = f'{union_type(keys)}, {union_type(values)}' if len(tree.inner) == 0: return Expr(f'new_dict(thread, NULL, NULL, 0, {ut})', tp, is_new=True) if tree.inner[0].name != 'list': assert len(tree.inner[0].inner) == 1 nosep = [t for t in tree.inner[0].inner if t.name != 'sign'] ukeys = _union_array( val(tree.inner[0], scope, temps) for tree in nosep) uvals = _union_array( val(tree.inner[2], scope, temps) for tree in nosep) return Expr(f'new_dict(thread, {ukeys}, {uvals}, {len(nosep)}, {ut})', tp, is_new=True) if tree.name == 'range': raise NotImplementedError('range not implemented') if tree.name == 'keyword': if tree.content == 'True': return Expr('true', 'c:bool') if tree.content == 'False': return Expr('false', 'c:bool') if tree.content == 'None': return Expr('NULL', 'c:void*') assert False, tree.content if tree.name == 'unary': expr = val(tree.inner[1], scope, temps) sign = tree.inner[0].content if sign == 'not': sign = '!' return Expr(f'{sign}({expr.value})', expr.tp, is_new=True) assert False, tree.name