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
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
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)
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
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))
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
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
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
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