Beispiel #1
0
 def resolve_str(s, mark):
     parts = []
     i = 0
     while i < len(s):
         if s[i] == '\\':
             if i + 1 >= len(s):
                 raise base.Error([mark], f'Incomplete escape')
             if s[i + 1].isdigit():
                 j = i + 1
                 while j < len(s) and s[j].isdigit():
                     j += 1
                 parts.append(chr(int(s[i + 1:j], 8)))
                 i = j
             elif s[i + 1] in _ESCAPE_MAP:
                 parts.append(_ESCAPE_MAP[s[i + 1]])
                 i += 2
             else:
                 raise base.Error([mark], f'Invalid escape {s[i + 1]}')
         else:
             j = i + 1
             while j < len(s) and s[j] != '\\':
                 j += 1
             parts.append(s[i:j])
             i = j
     return ''.join(parts)
Beispiel #2
0
 def get_func_def(scope, name, mark):
     if name not in scope:
         raise base.Error([mark], f'{name} is not defined')
     if not isinstance(scope[name], ast.Function):
         raise base.Error([scope[name].mark, mark],
                          f'{name} is not a function')
     return scope[name]
Beispiel #3
0
    def function_callback(m):
        native = m.value[0]
        rtype = m.value[1]
        name = m.value[2]
        params = m.value[3]
        body_thunk = m.value[4]

        if body_thunk is None:
            body = None
        else:
            scope = Scope(module_scope)
            for param in params:
                scope[param.name] = param
            body = body_thunk(scope)

        if validate:
            if native and body:
                raise base.Error([m.mark],
                                 'Native functions cannot have a body')

            if not native and not body:
                raise base.Error([m.mark],
                                 'Non-native functions must have a body')

        return ast.Function(
            mark=m.mark,
            rtype=rtype,
            name=name,
            params=params,
            body=body,
        )
Beispiel #4
0
 def fcall(mark, f, args):
     if len(f.params) != len(args):
         raise base.Error(
             [f.mark, mark],
             f'Expected {len(f.params)} args but got {len(args)}')
     for param, arg in zip(f.params, args):
         if not types.convertible(arg.type, param.type, global_dict):
             raise base.Error(
                 [param.mark, arg.mark],
                 f'Expected type {param.type} but got {arg.type}')
     return ast.FunctionCall(mark=mark, f=f, args=args)
Beispiel #5
0
 def check_class_name(m):
     name = m.value
     if global_dict is not None:
         if name not in global_dict:
             raise base.Error(
                 [m.mark],
                 f'{repr(name)} is not defined',
             )
         if not isinstance(global_dict[name], ast.Class):
             raise base.Error(
                 [m.mark, global_dict[name].mark],
                 f'{repr(name)} is not a type',
             )
     return name
Beispiel #6
0
    def process_indents_adapter(tokens):
        stack = ['']
        for token in tokens:

            if token.type == 'EOF':
                while len(stack) > 1:
                    stack.pop()
                    yield base.Token(token.mark, 'DEDENT', None)

            if token.type == 'NEWLINE':
                yield base.Token(token.mark, 'NEWLINE', None)
                indent = token.value
                if indent != stack[-1]:
                    if indent.startswith(stack[-1]):
                        yield base.Token(token.mark, 'INDENT', None)
                        stack.append(indent)
                    elif stack[-1].startswith(indent):
                        while (stack[-1] != indent
                               and stack[-1].startswith(indent)):
                            stack.pop()
                            yield base.Token(token.mark, 'DEDENT', None)
                if indent != stack[-1]:
                    raise base.Error([token.mark], 'Invalid indent')
            else:
                yield token
Beispiel #7
0
def _flatten(module_table):
    global_dict = {}
    for module in module_table.values():
        for node in module.vars + module.funcs + module.clss:
            if '_' in node.name:
                raise base.Error(
                    [node.mark],
                    'Global names with underscores are not yet supported')
            global_dict[node.name] = node
    return global_dict
Beispiel #8
0
def _get_all_globals_without_prelude(header: ast.Module, global_dict):
    if header.name not in global_dict['@modules']:
        for imp in header.imports:
            _get_all_globals_without_prelude(load_header(imp.module),
                                             global_dict)
        for node in header.vars + header.funcs + header.clss:
            if node.name in global_dict:
                raise base.Error(
                    [node.mark, global_dict[node.name].mark],
                    f'Duplicate definition of {node.name}',
                )
            global_dict[node.name] = node
        global_dict['@modules'].add(header.name)
    return global_dict
Beispiel #9
0
 def class_callback(m):
     native = m.value[0]
     class_name = m.value[2]
     declared_base = m.value[3]
     field_thunks = m.value[5]
     method_thunks = m.value[6]
     base = (ast.OBJECT if declared_base is None
             and class_name != ast.OBJECT else declared_base)
     scope = Scope(module_scope)
     scope['@class_name'] = class_name
     fields = tuple(ft(scope) for ft in field_thunks)
     methods = tuple(mt(scope) for mt in method_thunks)
     if validate:
         for method in methods:
             if native and method.body:
                 raise base.Error(
                     [m.mark, method.mark],
                     'Native classes cannot have method bodies',
                 )
             if not native and not method.body:
                 raise base.Error(
                     [m.mark, method.mark],
                     'Non-native classes cannot have native methods',
                 )
         if native and fields:
             raise base.Error(
                 [m.mark, fields[0].mark],
                 'Native classes cannot have fields',
             )
     return ast.Class(
         mark=m.mark,
         native=native,
         name=class_name,
         base=base,
         fields=fields,
         methods=methods,
     )
Beispiel #10
0
 def module_callback(m):
     imports = []
     vars = []
     funcs = []
     clss = []
     for kind, node in m.value:
         if kind == 'import':
             imports.append(node)
         elif kind == 'var':
             vars.append(node)
         elif kind == 'func':
             funcs.append(node)
         elif kind == 'cls':
             clss.append(node)
         else:
             raise base.Error([node.mark], f'FUBAR: {kind}: {node}')
     return ast.Module(
         mark=m.mark,
         name=module_name,
         imports=tuple(imports),
         vars=tuple(vars),
         funcs=tuple(funcs),
         clss=tuple(clss),
     )
Beispiel #11
0
 def ensure_global_exists(m):
     name = m.value
     if name not in global_dict:
         raise base.Error([m.mark], f'Name {repr(name)} does not exist')
     return name
Beispiel #12
0
def _make_source_parser(module_name: str, header: ast.Module, global_dict):
    def ensure_global_exists(m):
        name = m.value
        if name not in global_dict:
            raise base.Error([m.mark], f'Name {repr(name)} does not exist')
        return name

    import_map = _make_import_map(
        imports=header.imports,
        module_name=module_name,
    )
    importable_id = _make_importable_id(
        module_name=module_name,
        import_map=import_map,
    ).fatmap(ensure_global_exists)
    exportable_id = _make_exportable_id(
        module_name=module_name,
        import_map=import_map,
    ).fatmap(ensure_global_exists)

    type_ = _make_type_parser(
        importable_id=importable_id,
        global_dict=global_dict,
    )

    module_scope = {
        key: global_dict[val]
        for key, val in _prelude_table.items()
    }
    for imp in header.imports:
        if imp.name in global_dict:
            module_scope[imp.name] = global_dict[imp.name]
        else:
            raise base.Error(
                [imp.mark],
                f'{repr(imp.name)} is not defined',
            )

    def get_func_def(scope, name, mark):
        if name not in scope:
            raise base.Error([mark], f'{name} is not defined')
        if not isinstance(scope[name], ast.Function):
            raise base.Error([scope[name].mark, mark],
                             f'{name} is not a function')
        return scope[name]

    def fcall(mark, f, args):
        if len(f.params) != len(args):
            raise base.Error(
                [f.mark, mark],
                f'Expected {len(f.params)} args but got {len(args)}')
        for param, arg in zip(f.params, args):
            if not types.convertible(arg.type, param.type, global_dict):
                raise base.Error(
                    [param.mark, arg.mark],
                    f'Expected type {param.type} but got {arg.type}')
        return ast.FunctionCall(mark=mark, f=f, args=args)

    # TODO
    expression = Forward(lambda: atom)
    args = All(
        '(',
        expression.join(',').fatmap(
            lambda m: lambda scope: tuple(e(scope) for e in m.value)),
        Any(')').required(),
    ).map(lambda args: args[1])
    atom = Any(
        Any('INT').fatmap(lambda m: lambda scope: ast.IntLiteral(
            mark=m.mark, value=m.value)),
        Any('STR').fatmap(lambda m: lambda scope: ast.StringLiteral(
            mark=m.mark,
            value=m.value,
        )),
        All('ID', args).fatmap(
            lambda m: lambda scope: fcall(
                mark=m.mark,
                f=get_func_def(scope=scope, name=m.value[0], mark=m.mark),
                args=m.value[1](scope),
            ), ),
    )
    statement = Forward(lambda: Any(
        block,
        All('return', expression, ';').fatmap(
            lambda m: lambda scope: ast.Return(
                mark=m.mark,
                expr=m.value[1](scope),
            ), ),
        All(expression, ';').fatmap(lambda m: lambda scope: ast.
                                    ExpressionStatement(
                                        mark=m.mark,
                                        expr=m.value[0](scope),
                                    )),
    ))
    block = (All('{', statement.repeat(),
                 Any('}').required()).fatmap(lambda m: lambda scope: ast.Block(
                     mark=m.mark,
                     stmts=tuple(stmt(scope) for stmt in m.value[1]),
                 )))

    return _make_combined_parser(
        module_name=module_name,
        importable_id=importable_id,
        exportable_id=exportable_id,
        type_=type_,
        expression=expression,
        block=block,
        global_dict=global_dict,
        module_scope=module_scope,
    )
Beispiel #13
0
 def invalid_char_literal(m, mark):
     raise base.Error([mark], 'Multi-character char literal')