예제 #1
0
파일: expressions.py 프로젝트: yrapop01/hut
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
예제 #2
0
파일: compiler.py 프로젝트: yrapop01/hut
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
예제 #3
0
파일: compiler.py 프로젝트: yrapop01/hut
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)
예제 #4
0
파일: compiler.py 프로젝트: yrapop01/hut
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)
예제 #5
0
파일: expressions.py 프로젝트: yrapop01/hut
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
예제 #6
0
파일: compiler.py 프로젝트: yrapop01/hut
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='')
예제 #7
0
파일: compiler.py 프로젝트: yrapop01/hut
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
예제 #8
0
파일: compiler.py 프로젝트: yrapop01/hut
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
예제 #9
0
파일: expressions.py 프로젝트: yrapop01/hut
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