def __init__( self, namespace: Namespace, name: LocatableString, target_type: LocatableString, statements: BasicBlock, comment: LocatableString, ): TypeDefinitionStatement.__init__(self, namespace, str(name)) self.name = str(name) if "-" in self.name: inmanta_warnings.warn(HyphenDeprecationWarning(name)) self.block = statements self.entity = target_type self.comment = None if comment is not None: self.comment = str(comment) self.location = name.get_location() self.type = Implementation(str(self.name), self.block, self.namespace, str(target_type), self.comment) self.type.location = name.get_location() self.anchors = [TypeReferenceAnchor(namespace, target_type)] self.anchors.extend(statements.get_anchors())
def __init__( self, entity_name: LocatableString, implementations: List[LocatableString], select: ExpressionStatement, inherit: bool = False, comment: LocatableString = None, ) -> None: DefinitionStatement.__init__(self) self.entity = entity_name self.entity_location = entity_name.get_location() self.implementations = implementations self.anchors = [ TypeReferenceAnchor(x.namespace, x) for x in implementations ] self.anchors.append( TypeReferenceAnchor(entity_name.namespace, entity_name)) self.anchors.extend(select.get_anchors()) self.location = entity_name.get_location() if inherit and (not isinstance(select, Literal) or select.value is not True): raise RuntimeException( self, "Conditional implementation with parents not allowed") self.select = select self.inherit: bool = inherit if comment is not None: self.comment = str(comment) else: self.comment = None
def __init__( self, namespace: Namespace, lname: LocatableString, comment: Optional[LocatableString], parents: List[LocatableString], attributes: List[DefineAttribute], ) -> None: name = str(lname) TypeDefinitionStatement.__init__(self, namespace, name) if "-" in name: inmanta_warnings.warn(HyphenDeprecationWarning(lname)) self.anchors = [TypeReferenceAnchor(namespace, x) for x in parents] self.name = name self.attributes = attributes if comment is not None: self.comment = str(comment) else: self.comment = None self.parents = parents if len(self.parents) == 0 and not (self.name == "Entity" and self.namespace.name == "std"): dummy_location: Range = Range("__internal__", 1, 1, 1, 1) self.parents.append(LocatableString("std::Entity", dummy_location, -1, namespace)) self.type = Entity(self.name, namespace, self.comment) self.type.location = lname.location
def __init__( self, namespace: Namespace, name: LocatableString, basetype: LocatableString, expression: ExpressionStatement ) -> None: TypeDefinitionStatement.__init__(self, namespace, str(name)) self.set_location(name.get_location()) self.basetype = basetype self.anchors.append(TypeReferenceAnchor(namespace, basetype)) self.anchors.extend(expression.get_anchors()) self.set_expression(expression) self.type = ConstraintType(self.namespace, str(name)) self.type.location = name.get_location() self.comment = None if self.name in TYPES: inmanta_warnings.warn(CompilerRuntimeWarning(self, "Trying to override a built-in type: %s" % self.name)) if "-" in self.name: inmanta_warnings.warn(HyphenDeprecationWarning(name))
def get_string_ast_node(string_ast: LocatableString, mls: bool) -> Union[Literal, StringFormat]: matches: List[re.Match[str]] = list( format_regex_compiled.finditer(str(string_ast))) if len(matches) == 0: return Literal(str(string_ast)) start_lnr = string_ast.location.lnr start_char_pos = string_ast.location.start_char whole_string = str(string_ast) mls_offset: int = 3 if mls else 1 # len(""") or len(') or len(") def char_count_to_lnr_char(position: int) -> Tuple[int, int]: # convert in-string position to lnr/charcount before = whole_string[0:position] lines = before.count("\n") if lines == 0: return start_lnr, start_char_pos + position + mls_offset else: return start_lnr + lines, position - before.rindex("\n") locatable_matches: List[Tuple[str, LocatableString]] = [] for match in matches: start_line, start_char = char_count_to_lnr_char(match.start(2)) end_line, end_char = char_count_to_lnr_char(match.end(2)) range: Range = Range(string_ast.location.file, start_line, start_char, end_line, end_char) locatable_string = LocatableString(match[2], range, string_ast.lexpos, string_ast.namespace) locatable_matches.append((match[1], locatable_string)) return create_string_format(string_ast, locatable_matches)
def __init__(self, namespace: Namespace, name: LocatableString, class_ctor: Constructor): TypeDefinitionStatement.__init__(self, namespace, str(name)) self.type = Default(namespace, self.name) self.ctor = class_ctor self.comment = None self.type.location = name.get_location() self.anchors.extend(class_ctor.get_anchors())
def __init__(self, variable: ExpressionStatement, loop_var: LocatableString, module: BasicBlock) -> None: super().__init__() self.base = variable self.loop_var = str(loop_var) self.loop_var_loc = loop_var.get_location() self.module = module self.anchors.extend(module.get_anchors()) self.anchors.extend(variable.get_anchors())
def __init__(self, namespace: Namespace, name: LocatableString, class_ctor: Constructor): TypeDefinitionStatement.__init__(self, namespace, str(name)) self.type = Default(namespace, self.name) self.ctor = class_ctor self.comment = None self.type.location = name.get_location() self.anchors.extend(class_ctor.get_anchors()) if "-" in self.name: inmanta_warnings.warn(HyphenDeprecationWarning(name))
def create_string_format( format_string: LocatableString, variables: List[Tuple[str, LocatableString]]) -> StringFormat: """ Create a string interpolation statement. This function assumes that the variables of a match are on the same line. :param format_string: the LocatableString as it was received by get_string_ast_node() :param variables: A list of tuples where each tuple is a combination of a string and LocatableString The string is the match containing the {{}} (ex: {{a.b}}) and the LocatableString is composed of just the variables and the range for those variables. (ex. LocatableString("a.b", range(a.b), lexpos, namespace)) """ assert namespace _vars = [] for match, var in variables: var_name: str = str(var) var_parts: List[str] = var_name.split(".") start_char = var.location.start_char end_char = start_char + len(var_parts[0]) range: Range = Range(var.location.file, var.location.lnr, start_char, var.location.lnr, end_char) ref_locatable_string = LocatableString(var_parts[0], range, var.lexpos, var.namespace) ref = Reference(ref_locatable_string) ref.namespace = namespace if len(var_parts) > 1: attribute_offsets: Iterator[int] = accumulate( var_parts[1:], lambda acc, part: acc + len(part) + 1, initial=end_char + 1) for attr, char_offset in zip(var_parts[1:], attribute_offsets): range_attr: Range = Range(var.location.file, var.location.lnr, char_offset, var.location.lnr, char_offset + len(attr)) attr_locatable_string: LocatableString = LocatableString( attr, range_attr, var.lexpos, var.namespace) ref = AttributeReference(ref, attr_locatable_string) ref.location = range_attr ref.namespace = namespace _vars.append((ref, match)) else: _vars.append((ref, match)) return StringFormat(str(format_string), _vars)
def merge_lnr_to_string(p: YaccProduction, starttoken: int = 1, endtoken: int = 2) -> None: assert namespace v = p[0] et = p[endtoken] st = p[starttoken] expanded_range: Range = expand_range( st.location, et.location) if isinstance( st, LocatableString) else et.location p[0] = LocatableString(v, expanded_range, p.lexpos(endtoken), namespace)
def t_RSTRING(t: lex.LexToken) -> lex.LexToken: # noqa: N802 r"r(\"([^\\\"\n]|\\.)*\")|r(\'([^\\\'\n]|\\.)*\')" t.value = t.value[2:-1] lexer = t.lexer end = lexer.lexpos - lexer.linestart + 1 (s, e) = lexer.lexmatch.span() start = end - (e - s) t.value = LocatableString( t.value, Range(lexer.inmfile, lexer.lineno, start, lexer.lineno, end), lexer.lexpos, lexer.namespace) return t
def p_class_ref_err_dot(p: YaccProduction) -> None: "class_ref : var_ref '.' CID" var: Union[LocatableString, Reference] = p[1] var_str: LocatableString = var if isinstance( var, LocatableString) else var.locatable_name cid: LocatableString = p[3] assert namespace full_string: LocatableString = LocatableString( "%s.%s" % (var_str, cid), expand_range(var_str.location, cid.location), var_str.lexpos, namespace, ) raise InvalidNamespaceAccess(full_string)
def t_STRING(t: lex.LexToken) -> lex.LexToken: # noqa: N802 r"(\"([^\\\"]|\\.)*\")|(\'([^\\\']|\\.)*\')" t.value = bytes(t.value[1:-1], "utf-8").decode("unicode_escape") lexer = t.lexer end = lexer.lexpos - lexer.linestart + 1 (s, e) = lexer.lexmatch.span() start = end - (e - s) t.value = LocatableString( t.value, Range(lexer.inmfile, lexer.lineno, start, lexer.lineno, end), lexer.lexpos, lexer.namespace) return t
def t_ID(t: lex.LexToken) -> lex.LexToken: # noqa: N802 r"[a-zA-Z_][a-zA-Z_0-9-]*" t.type = reserved.get(t.value, "ID") # Check for reserved words if t.value[0].isupper(): t.type = "CID" lexer = t.lexer end = lexer.lexpos - lexer.linestart + 1 (s, e) = lexer.lexmatch.span() start = end - (e - s) t.value = LocatableString( t.value, Range(lexer.inmfile, lexer.lineno, start, lexer.lineno, end), lexer.lexpos, lexer.namespace) return t
def to_type(self, arg_type: Optional[object], resolver: Namespace) -> Optional[inmanta_type.Type]: """ Convert a string representation of a type to a type """ if arg_type is None: return None if not isinstance(arg_type, str): raise CompilerException( "bad annotation in plugin %s::%s, expected str but got %s (%s)" % (self.ns, self.__class__.__function_name__, type(arg_type), arg_type)) if arg_type == "any": return None if arg_type == "expression": return None # quickfix issue #1774 allowed_element_type: inmanta_type.Type = inmanta_type.Type() if arg_type == "list": return inmanta_type.TypedList(allowed_element_type) if arg_type == "dict": return inmanta_type.TypedDict(allowed_element_type) plugin_line: Range = Range(self.location.file, self.location.lnr, 1, self.location.lnr + 1, 1) locatable_type: LocatableString = LocatableString( arg_type, plugin_line, 0, None) # stack of transformations to be applied to the base inmanta_type.Type # transformations will be applied right to left transformation_stack: List[Callable[[inmanta_type.Type], inmanta_type.Type]] = [] if locatable_type.value.endswith("?"): locatable_type.value = locatable_type.value[0:-1] transformation_stack.append(inmanta_type.NullableType) if locatable_type.value.endswith("[]"): locatable_type.value = locatable_type.value[0:-2] transformation_stack.append(inmanta_type.TypedList) return reduce(lambda acc, transform: transform(acc), reversed(transformation_stack), resolver.get_type(locatable_type))
def __init__(self, instance: Reference, attribute: LocatableString) -> None: range: Range = Range( instance.locatable_name.location.file, instance.locatable_name.lnr, instance.locatable_name.start, attribute.elnr, attribute.end, ) reference: LocatableString = LocatableString( "%s.%s" % (instance.full_name, attribute), range, instance.locatable_name.lexpos, instance.namespace ) Reference.__init__(self, reference) self.attribute = attribute # a reference to the instance self.instance = instance
def t_begin_mls(t: lex.LexToken) -> lex.LexToken: r'["]{3}' t.lexer.begin("mls") t.type = "MLS" lexer = t.lexer end = lexer.lexpos - lexer.linestart + 1 (s, e) = lexer.lexmatch.span() start = end - (e - s) t.value = LocatableString( "", Range(lexer.inmfile, lexer.lineno, start, lexer.lineno, end), lexer.lexpos, lexer.namespace) return t
def add_attribute(self, lname: LocatableString, value: ExpressionStatement) -> None: """ Add an attribute to this constructor call """ name = str(lname) if name not in self.__attributes: self.__attributes[name] = value self.anchors.append( AttributeReferenceAnchor(lname.get_location(), lname.namespace, self.class_type, name)) self.anchors.extend(value.get_anchors()) else: raise RuntimeException( self, "The attribute %s in the constructor call of %s is already set." % (name, self.class_type))
def t_mls_end(t: lex.LexToken) -> lex.LexToken: r'.*["]{3}' t.lexer.begin("INITIAL") t.type = "MLS_END" value = t.value[:-3] lexer = t.lexer end = lexer.lexpos - lexer.linestart + 1 (s, e) = lexer.lexmatch.span() start = end - (e - s) t.value = LocatableString( value, Range(lexer.inmfile, lexer.lineno, start, lexer.lineno, end), lexer.lexpos, lexer.namespace) return t
def t_MLS(t: lex.LexToken) -> lex.LexToken: r'"{3,5}([\s\S]*?)"{3,5}' value = t.value[3:-3] lexer = t.lexer match = lexer.lexmatch[0] lines = match.split("\n") start_line = lexer.lineno end_line = lexer.lineno + len(lines) - 1 t.lexer.lineno = end_line (s, e) = lexer.lexmatch.span() start = lexer.lexpos - lexer.linestart - (e - s) + 1 end = len(lines[-1]) + 1 t.value = LocatableString( value, Range(lexer.inmfile, start_line, start, end_line, end), lexer.lexpos, lexer.namespace) return t
def merge_lnr_to_string(p: YaccProduction, starttoken: int = 1, endtoken: int = 2) -> None: v = p[0] et = p[endtoken] endline = et.elnr endchar = et.end st = p[starttoken] if isinstance(st, LocatableString): startline = st.lnr startchar = st.start else: startline = et.lnr startchar = et.start p[0] = LocatableString(v, Range(file, startline, startchar, endline, endchar), endchar, namespace)
def compile(self) -> Tuple[List["Statement"], List["BasicBlock"]]: """ This method will parse and prepare everything to start evaluation the configuration specification. This method will: - load all modules using Project.get().get_complete_ast() - add all plugins - create std::Entity """ project = module.Project.get() self.__root_ns = project.get_root_namespace() project.load() statements, blocks = project.get_complete_ast() # load plugins for name, cls in PluginMeta.get_functions().items(): mod_ns = cls.__module__.split(".") if mod_ns[0] != const.PLUGINS_PACKAGE: raise Exception( "All plugin modules should be loaded in the %s package not in %s" % (const.PLUGINS_PACKAGE, cls.__module__) ) mod_ns = mod_ns[1:] ns: Optional[Namespace] = self.__root_ns for part in mod_ns: if ns is None: break ns = ns.get_child(part) if ns is None: raise Exception("Unable to find namespace for plugin module %s" % (cls.__module__)) name = name.split("::")[-1] statement = PluginStatement(ns, name, cls) statements.append(statement) # add the entity type (hack?) ns = self.__root_ns.get_child_or_create("std") nullrange = Range("internal", 1, 0, 0, 0) entity = DefineEntity( ns, LocatableString("Entity", nullrange, 0, ns), LocatableString("The entity all other entities inherit from.", nullrange, 0, ns), [], [], ) str_std_entity = LocatableString("std::Entity", nullrange, 0, ns) requires_rel = DefineRelation( (str_std_entity, LocatableString("requires", nullrange, 0, ns), (0, None)), (str_std_entity, LocatableString("provides", nullrange, 0, ns), (0, None)), ) requires_rel.namespace = self.__root_ns.get_ns_from_string("std") statements.append(entity) statements.append(requires_rel) return (statements, blocks)