Пример #1
0
    def run_block_test(self, block):
        try:
            lang = block.lang
            code = [block.code]

            if lang.endswith('-repl'):
                lang = lang.rpartition('-')[0]
                code = self.extract_snippets_from_repl(block.code)

            for snippet in code:
                if lang == 'edgeql':
                    ql_parser.parse_block(snippet)
                elif lang == 'sdl':
                    # Strip all the "using extension ..." and comment
                    # lines as they interfere with our module
                    # detection.
                    sdl = re.sub(r'(using\s+extension\s+\w+;)|(#.*?\n)', '',
                                 snippet).strip()

                    # the snippet itself may either contain a module
                    # block or have a fully-qualified top-level name
                    if not sdl or re.match(
                            r'''(?xm)
                                (\bmodule\s+\w+\s*{) |
                                (^.*
                                    (type|annotation|link|property|constraint)
                                    \s+(\w+::\w+)\s+
                                    ({|extending)
                                )
                            ''', sdl):
                        ql_parser.parse_sdl(snippet)
                    else:
                        ql_parser.parse_sdl(f'module default {{ {snippet} }}')
                elif lang == 'edgeql-result':
                    # REPL results
                    pass
                elif lang == 'pseudo-eql':
                    # Skip "pseudo-eql" language as we don't have a
                    # parser for it.
                    pass
                elif lang == 'graphql':
                    graphql_parser.parse(snippet)
                elif lang == 'graphql-schema':
                    # The graphql-schema can be highlighted using graphql
                    # lexer, but it does not have a dedicated parser.
                    pass
                elif lang == 'json':
                    json.loads(snippet)
                elif lang in {
                        'bash', 'powershell', 'c', 'javascript', 'python'
                }:
                    pass
                else:
                    raise LookupError(f'unknown code-lang {lang}')
        except Exception as ex:
            raise AssertionError(
                f'unable to parse {block.lang} code block in '
                f'{block.filename}, around line {block.lineno}') from ex
Пример #2
0
    def run_block_test(self, block):
        try:
            lang = block.lang
            code = [block.code]

            if lang.endswith('-repl'):
                lang = lang.rpartition('-')[0]
                code = self.extract_snippets_from_repl(block.code)

            for snippet in code:
                if lang == 'edgeql':
                    ql_parser.parse_block(snippet)
                elif lang == 'sdl':
                    ql_parser.parse_sdl(snippet)
                elif lang == 'edgeql-result':
                    # REPL results
                    pass
                elif lang == 'pseudo-eql':
                    # Skip "pseudo-eql" language as we don't have a
                    # parser for it.
                    pass
                elif lang == 'graphql':
                    graphql_parser.parse(snippet)
                elif lang == 'graphql-schema':
                    # The graphql-schema can be highlighted using graphql
                    # lexer, but it does not have a dedicated parser.
                    pass
                elif lang == 'json':
                    json.loads(snippet)
                elif lang == 'bash':
                    pass
                else:
                    raise LookupError(f'unknown code-lang {lang}')
        except Exception as ex:
            raise AssertionError(
                f'unable to parse {block.lang} code block in '
                f'{block.filename}, around line {block.lineno}') from ex
Пример #3
0
 def _apply_field_ast(
     self,
     schema: s_schema.Schema,
     context: sd.CommandContext,
     node: qlast.DDLOperation,
     op: sd.AlterObjectProperty,
 ) -> None:
     assert isinstance(node, qlast.CreateExtensionPackage)
     if op.property == 'script':
         node.body = qlast.NestedQLBlock(
             text=op.new_value,
             commands=qlparser.parse_block(op.new_value),
         )
     elif op.property == 'version':
         node.version = qlast.StringConstant(value=str(op.new_value), )
     else:
         super()._apply_field_ast(schema, context, node, op)
Пример #4
0
def compile_func_to_ir(func,
                       schema,
                       *,
                       anchors=None,
                       security_context=None,
                       modaliases=None,
                       implicit_id_in_shapes=False,
                       implicit_tid_in_shapes=False):
    """Compile an EdgeQL function into EdgeDB IR."""

    if debug.flags.edgeql_compile:
        debug.header('EdgeQL Function')
        debug.print(func.get_code(schema))

    trees = ql_parser.parse_block(func.get_code(schema) + ';')
    if len(trees) != 1:
        raise errors.InvalidFunctionDefinitionError(
            'functions can only contain one statement')

    tree = trees[0]
    if modaliases:
        ql_parser.append_module_aliases(tree, modaliases)

    param_anchors, param_aliases = get_param_anchors_for_callable(
        func.get_params(schema), schema)

    if anchors is None:
        anchors = {}

    anchors.update(param_anchors)
    tree.aliases.extend(param_aliases)

    ir = compile_ast_to_ir(
        tree,
        schema,
        anchors=anchors,
        func_params=func.get_params(schema),
        security_context=security_context,
        modaliases=modaliases,
        implicit_id_in_shapes=implicit_id_in_shapes,
        implicit_tid_in_shapes=implicit_tid_in_shapes,
        # the body of a session_only function can contain calls to
        # other session_only functions
        session_mode=func.get_session_only(schema))

    return ir
Пример #5
0
 def _apply_field_ast(
     self,
     schema: s_schema.Schema,
     context: sd.CommandContext,
     node: qlast.DDLOperation,
     op: sd.AlterObjectProperty,
 ) -> None:
     assert isinstance(node, qlast.CreateMigration)
     if op.property == 'script':
         node.script = op.new_value
         node.body = qlast.MigrationBody(commands=tuple(
             qlparser.parse_block(op.new_value)), )
     elif op.property == 'parents':
         if op.new_value and (items := op.new_value.items):
             assert len(items) == 1
             parent = next(iter(items))
             node.parent = s_utils.name_to_ast_ref(parent.get_name(schema))
Пример #6
0
def compile_func_to_ir(func,
                       schema,
                       *,
                       anchors=None,
                       security_context=None,
                       modaliases=None,
                       implicit_id_in_shapes=False,
                       implicit_tid_in_shapes=False):
    """Compile an EdgeQL function into EdgeDB IR."""

    if debug.flags.edgeql_compile:
        debug.header('EdgeQL Function')
        debug.print(func.get_code(schema))

    trees = ql_parser.parse_block(func.get_code(schema) + ';')
    if len(trees) != 1:
        raise errors.InvalidFunctionDefinitionError(
            'functions can only contain one statement')

    tree = trees[0]
    if modaliases:
        ql_parser.append_module_aliases(tree, modaliases)

    param_anchors, param_aliases = get_param_anchors_for_callable(
        func.get_params(schema),
        schema,
        inlined_defaults=func.has_inlined_defaults(schema))

    if anchors is None:
        anchors = {}

    anchors.update(param_anchors)
    tree.aliases.extend(param_aliases)

    ir = compile_ast_to_ir(
        tree,
        schema,
        anchors=anchors,
        func_params=func.get_params(schema),
        security_context=security_context,
        modaliases=modaliases,
        implicit_id_in_shapes=implicit_id_in_shapes,
        implicit_tid_in_shapes=implicit_tid_in_shapes,
        # the body of a session_only function can contain calls to
        # other session_only functions
        session_mode=func.get_session_only(schema))

    return_type = func.get_return_type(schema)
    if (not ir.stype.issubclass(schema, return_type)
            and not ir.stype.implicitly_castable_to(return_type, schema)):
        raise errors.InvalidFunctionDefinitionError(
            f'return type mismatch in function declared to return '
            f'{return_type.get_verbosename(schema)}',
            details=f'Actual return type is '
            f'{ir.stype.get_verbosename(schema)}',
            context=tree.context,
        )

    return_typemod = func.get_return_typemod(schema)
    if (return_typemod is not qltypes.TypeModifier.SET_OF
            and ir.cardinality is qltypes.Cardinality.MANY):
        raise errors.InvalidFunctionDefinitionError(
            f'return cardinality mismatch in function declared to return '
            f'a singleton',
            details=f'Function may return a set with more than one element.',
            context=tree.context,
        )

    return ir
Пример #7
0
def compile_func_to_ir(func, schema, *,
                       anchors=None,
                       security_context=None,
                       modaliases=None,
                       implicit_id_in_shapes=False,
                       implicit_tid_in_shapes=False):
    """Compile an EdgeQL function into EdgeDB IR."""

    if debug.flags.edgeql_compile:
        debug.header('EdgeQL Function')
        debug.print(func.get_code(schema))

    trees = ql_parser.parse_block(func.get_code(schema) + ';')
    if len(trees) != 1:
        raise errors.InvalidFunctionDefinitionError(
            'functions can only contain one statement')

    tree = trees[0]
    if modaliases:
        ql_parser.append_module_aliases(tree, modaliases)

    if anchors is None:
        anchors = {}

    anchors['__defaults_mask__'] = irast.Parameter(
        name='__defaults_mask__',
        typeref=irtyputils.type_to_typeref(schema, schema.get('std::bytes')))

    func_params = func.get_params(schema)
    pg_params = s_func.PgParams.from_params(schema, func_params)
    for pi, p in enumerate(pg_params.params):
        p_shortname = p.get_shortname(schema)
        anchors[p_shortname] = irast.Parameter(
            name=p_shortname,
            typeref=irtyputils.type_to_typeref(schema, p.get_type(schema)))

        if p.get_default(schema) is None:
            continue

        tree.aliases.append(
            qlast.AliasedExpr(
                alias=p_shortname,
                expr=qlast.IfElse(
                    condition=qlast.BinOp(
                        left=qlast.FunctionCall(
                            func=('std', 'bytes_get_bit'),
                            args=[
                                qlast.FuncArg(
                                    arg=qlast.Path(steps=[
                                        qlast.ObjectRef(
                                            name='__defaults_mask__')
                                    ])),
                                qlast.FuncArg(
                                    arg=qlast.IntegerConstant(value=str(pi)))
                            ]),
                        right=qlast.IntegerConstant(value='0'),
                        op='='),
                    if_expr=qlast.Path(
                        steps=[qlast.ObjectRef(name=p_shortname)]),
                    else_expr=qlast._Optional(expr=p.get_ql_default(schema)))))

    ir = compile_ast_to_ir(
        tree, schema, anchors=anchors, func=func,
        security_context=security_context, modaliases=modaliases,
        implicit_id_in_shapes=implicit_id_in_shapes,
        implicit_tid_in_shapes=implicit_tid_in_shapes)

    return ir
Пример #8
0
    def run_block_test(self, block):
        try:
            lang = block.lang

            if lang.endswith('-repl'):
                lang = lang.rpartition('-')[0]
                code = self.extract_snippets_from_repl(block.code)
            elif lang.endswith('-diff'):
                # In the diff block we need to truncate "-"/"+" at the
                # beginning of each line. We will make two copies of
                # the code as the before and after version. Both will
                # be validated.
                before = []
                after = []
                for line in block.code.split('\n'):

                    if line == "":
                        continue

                    first = line.strip()[0]
                    if first == '-':
                        before.append(line[1:])
                    elif first == '+':
                        after.append(line[1:])
                    else:
                        before.append(line[1:])
                        after.append(line[1:])

                code = ['\n'.join(before), '\n'.join(after)]
                # truncate the "-diff" from the language
                lang = lang[:-5]
            else:
                code = [block.code]

            for snippet in code:
                if lang == 'edgeql':
                    ql_parser.parse_block(snippet)
                elif lang == 'sdl':
                    # Strip all the "using extension ..." and comment
                    # lines as they interfere with our module
                    # detection.
                    sdl = re.sub(r'(using\s+extension\s+\w+;)|(#.*?\n)', '',
                                 snippet).strip()

                    # the snippet itself may either contain a module
                    # block or have a fully-qualified top-level name
                    if not sdl or re.match(
                            r'''(?xm)
                                (\bmodule\s+\w+\s*{) |
                                (^.*
                                    (type|annotation|link|property|constraint)
                                    \s+(\w+::\w+)\s+
                                    ({|extending)
                                )
                            ''', sdl):
                        ql_parser.parse_sdl(snippet)
                    else:
                        ql_parser.parse_sdl(f'module default {{ {snippet} }}')
                elif lang == 'edgeql-result':
                    # REPL results
                    pass
                elif lang == 'pseudo-eql':
                    # Skip "pseudo-eql" language as we don't have a
                    # parser for it.
                    pass
                elif lang == 'graphql':
                    graphql_parser.parse(snippet)
                elif lang == 'graphql-schema':
                    # The graphql-schema can be highlighted using graphql
                    # lexer, but it does not have a dedicated parser.
                    pass
                elif lang == 'json':
                    json.loads(snippet)
                elif lang in {
                        'bash', 'powershell', 'shell', 'c', 'javascript',
                        'python', 'typescript', 'go', 'yaml'
                }:
                    pass
                elif lang[-5:] == '-diff':
                    pass
                else:
                    raise LookupError(f'unknown code-lang {lang}')
        except Exception as ex:
            raise AssertionError(
                f'unable to parse {block.lang} code block in '
                f'{block.filename}, around line {block.lineno}') from ex
Пример #9
0
def compile_func_to_ir(
    func: s_func.Function,
    schema: s_schema.Schema,
) -> irast.Statement:
    """Compile an EdgeQL function into EdgeDB IR.

    Args:
        func:
            A function object.

        schema:
            A schema instance where the function is defined.

    Returns:
        An instance of :class:`ir.ast.Statement` representing the
        function body.
    """
    if debug.flags.edgeql_compile:
        debug.header('EdgeQL Function')
        debug.print(func.get_code(schema))

    code = func.get_code(schema)
    assert code is not None
    trees = ql_parser.parse_block(code + ';')
    if len(trees) != 1:
        raise errors.InvalidFunctionDefinitionError(
            'functions can only contain one statement')

    tree = trees[0]

    param_anchors, param_aliases = get_param_anchors_for_callable(
        func.get_params(schema),
        schema,
        inlined_defaults=func.has_inlined_defaults(schema))

    tree.aliases.extend(param_aliases)

    ir = compile_ast_to_ir(
        tree,
        schema,
        anchors=param_anchors,  # type: ignore
        # (typing#273)
        func_params=func.get_params(schema),
        # the body of a session_only function can contain calls to
        # other session_only functions
        session_mode=func.get_session_only(schema),
    )

    assert isinstance(ir, irast.Statement)

    return_type = func.get_return_type(schema)
    if (not ir.stype.issubclass(schema, return_type)
            and not ir.stype.implicitly_castable_to(return_type, schema)):
        raise errors.InvalidFunctionDefinitionError(
            f'return type mismatch in function declared to return '
            f'{return_type.get_verbosename(schema)}',
            details=f'Actual return type is '
            f'{ir.stype.get_verbosename(schema)}',
            context=tree.context,
        )

    return_typemod = func.get_return_typemod(schema)
    if (return_typemod is not qltypes.TypeModifier.SET_OF
            and ir.cardinality is qltypes.Cardinality.MANY):
        raise errors.InvalidFunctionDefinitionError(
            f'return cardinality mismatch in function declared to return '
            f'a singleton',
            details=f'Function may return a set with more than one element.',
            context=tree.context,
        )

    return ir