def sourceImport(self, id, optional=True): #type: (Text) -> Optional[SourceImport] """ Return "the one and only one" sourceImport for a given metamodel id. If there is no sourceImport then add an issue, unless optional is True in which case None is returned. If there is more than one sourceImport then an issue is added. """ from modelscripts.megamodels import Megamodel metamodel_label = Megamodel.theMetamodel(id=id).label if id not in self._importsByMetamodelId: if optional: return None else: Issue( origin=self.modelSource, level=Levels.Fatal, message= 'No %s model imported.' % metamodel_label ) r=self._importsByMetamodelId[id] if len(r)==1: return r[0] else: Issue( origin=self.modelSource, level=Levels.Fatal, message= 'More than on %s model imported.' % metamodel_label)
def sourceMetamodel(self): #type: (MetamodelDependency) -> Metamodel """ Source metamodel ot ValueError if this metamodel is not registered yet (which should not happen). """ try: from modelscripts.megamodels import Megamodel return Megamodel.theMetamodel(id=self.sourceId) except: raise ValueError( 'No target "%s" metamodel registered from %s' % ( self.sourceId, self.targetId ))
def _matchModelDefinition( lineNo, modelSourceFile, justMatch=False, # prefixRegexp=r' *(--)? *@?', noSymbolChecking=False, recognizeUSEOCLNativeModelDefinition=False): # type: (int, ModelSourceFile, bool, bool, bool) -> Optional[Union[bool,DefinitionStatement]] """ Check if the line is a model definition statement. If justMatch just indicates if the line is recognized. In that case it returns True otherwise None. If not justMatch build an ImportStatement (if possible) Return None if this is not the case. Return a ModelDefinitionStatement if the stmt is valid. Otherwise raise a value error. Definition statements looks like this preliminary usecase model MyModel class model MyModel If 'recognizeUSEOCLNativeModelDefinition' then the line "model <NAME>" is accepted as the model definition in USE OCL files. This is a patch good enough for now for .use file. Later the .use file could be generated and the syntax improved. """ def _parseStandardSyntax(): re_stmt = (r'^ *((?P<modelKind>\w+) +)?' + r'(?P<metamodelLabel>\w+)' + r' +model' + r' +(?P<name>\w+) *$') line = modelSourceFile.realSourceLines[lineNo - 1] m = re.match(re_stmt, line, re.MULTILINE) if m is None: return None else: if m.group('modelKind') == 'import': # because overlapping regexp return None if justMatch: return True else: return { 'modelKind': m.group('modelKind'), 'metamodelLabel': m.group('metamodelLabel'), 'name': m.group('name') } def _parseUSEOCLSyntax(): re_stmt = ('^' + r' *model' + r' +(?P<name>\w+) *$') line = modelSourceFile.realSourceLines[lineNo - 1] m = re.match(re_stmt, line, re.MULTILINE) if m is None: return None if justMatch: return True else: return { 'modelKind': '', 'metamodelLabel': 'class', 'name': m.group('name') } def _parse(): r1 = _parseStandardSyntax() if r1 is not None or not recognizeUSEOCLNativeModelDefinition: return r1 else: # No match so search USEOCL return _parseUSEOCLSyntax() m = _parse() if m in [True, None]: return m else: source_metamodel = modelSourceFile.metamodel # get actual metamodel metamodel_label = m['metamodelLabel'] try: # could raise ValueError from modelscripts.megamodels import Megamodel metamodel = Megamodel.theMetamodel( label=metamodel_label) #type: Metamodel except ValueError as e: LocalizedSourceIssue( sourceFile=modelSourceFile, line=lineNo, level=Levels.Fatal, # could be error with some work message=str(e)) # check model_kind model_kind = ('' if m['modelKind'] is None else m['modelKind']) # noinspection PyUnboundLocalVariable if model_kind not in metamodel.modelKinds: LocalizedSourceIssue( sourceFile=modelSourceFile, line=lineNo, level=Levels.Fatal, # could be error with some work message=( '%s models can\'t be "%s".' ' Choose one of %s.' % (metamodel_label, model_kind, str(metamodel.modelKinds)))) # Check that the metamodel is the expected one # if metamodel != source_metamodel: # LocalizedSourceIssue( # sourceFile=modelSourceFile, # line=lineNo, # level=Levels.Fatal, # could be error with some work # message=( # 'A %s model cannot be defined in a "%s" file.' % ( # metamodel.label, # source_metamodel.extension, # ))) # Check name name = m['name'] if not noSymbolChecking and not (Symbol.is_CamlCase(name)): LocalizedSourceIssue( sourceFile=modelSourceFile, line=lineNo, level=Levels.Error, message=('Invalid model name "%s". It must be in CamlCases.' % (name))) if name.lower() != modelSourceFile.name.lower(): if not recognizeUSEOCLNativeModelDefinition: LocalizedSourceIssue( sourceFile=modelSourceFile, line=lineNo, level=Levels.Error, message=( 'Model must be named %s according to the name of the file' % ( # modelSourceFile.fileName, modelSourceFile.name))) return DefinitionStatement(lineNo=lineNo, sourceFile=modelSourceFile, modelKind=model_kind, metamodel=metamodel, name=name)
def _matchModelImport(lineNo, modelSourceFile, justMatch=False): #Megamodel statements are always extracted from # RAW UNPROCESSED ORIGINAL source file. #type: (int, ModelSourceFile, bool) -> Optional[Union[bool,ImportStatement]] """ Check if the line is an import statement. If justMatch just indicates if the line is recognized. In that case it returns True otherwise None. If not justMatch build an ImportStatement (if possible) Return None if this is not the case. Otherwise return a ModelImportStatement if the import is valid. Otherwise raise a fatal error that go in the issue box. Import statements looks like this import usecase model x.cs import glossary model a/b/../c.gls """ re_stmt = (r'^ *(?P<import>import)' + r' +(?P<metamodelLabel>\w+)' + r' +model' + r' +from' + r' +\'(?P<target>[\w\./\-]+)\' *$') line = modelSourceFile.realSourceLines[lineNo - 1] m = re.match(re_stmt, line, re.MULTILINE) if m is None: return None else: if justMatch: return True else: source_metamodel = modelSourceFile.metamodel # get actual metamodel metamodel_label = m.group('metamodelLabel') try: # could raise ValueError from modelscripts.megamodels import Megamodel metamodel = Megamodel.theMetamodel( label=metamodel_label) #type: Metamodel except ValueError as e: LocalizedSourceIssue( sourceFile=modelSourceFile, line=lineNo, level=Levels.Fatal, # could be error with some work message=str(e)) # Check that metamodel dependency is allowed target_mms = source_metamodel.outMetamodels # noinspection PyUnboundLocalVariable if metamodel not in target_mms: LocalizedSourceIssue( sourceFile=modelSourceFile, line=lineNo, level=Levels.Fatal, # could be error with some work message=('A %s model cannot reference a %s model.' % (source_metamodel.label, metamodel.label))) # Check path literal_target_filename = m.group('target') abs_target_filename = os.path.abspath( os.path.join(modelSourceFile.directory, literal_target_filename)) file_extension = os.path.splitext(abs_target_filename)[1] if file_extension != metamodel.extension: LocalizedSourceIssue( sourceFile=modelSourceFile, line=lineNo, level=Levels.Fatal, # could be error with some work message=('The extension of the file must be "%s".' % (metamodel.extension))) if not os.path.isfile(abs_target_filename): LocalizedSourceIssue( sourceFile=modelSourceFile, line=lineNo, level=Levels.Fatal, # could be error with some work message=('File not found: %s' % literal_target_filename)) return ImportStatement( lineNo=lineNo, sourceFile=modelSourceFile, metamodel=metamodel, absoluteTargetFilename=abs_target_filename, literalTargetFileName=literal_target_filename)
def scriptsIterator(m2id, expectedIssues): metamodel = Megamodel.theMetamodel(id=m2id) res = checkFileIssues(metamodel.extension[1:], [metamodel.extension], expectedIssues)
sys.path.insert(0, modelscribes_home) # sys.path.append("/home/jmfavre/.config/gedit") # sys.path.append("/home/jmfavre/.local/share/gtksourceview-3.0/language-specs") #------------------------------------------------------ import modelscripts from modelscripts.megamodels import Megamodel def source(filename): return Megamodel.loadFile(filename) s = source M = Megamodel gl = Megamodel.theMetamodel(id='gl') cl = Megamodel.theMetamodel(id='cl') us = Megamodel.theMetamodel(id='us') ob = Megamodel.theMetamodel(id='ob') pe = Megamodel.theMetamodel(id='pe') sc = Megamodel.theMetamodel(id='sc') mg = Megamodel.theMetamodel(id='mg') print('ModelScripts Interpreter') print('========================') print("source('foo.cls') to load the file 'foo.cls'") print('quit() to quit this session') print('M to get the megamodel')