Quellcode durchsuchen

added outports to the language

Simon Van Mierlo vor 8 Jahren
Ursprung
Commit
6a9b8e9cf5

+ 7 - 0
textualnotations/sccd_asg_mapper.py

@@ -322,6 +322,13 @@ class SCCD_ASG_Mapper(object):
 							'name': ('nameattr.string','String')
 						}
 					},
+			'outport': {'name': 'OutPort',
+						'type': 'Class',
+						'body':
+						{
+							'name': ('nameattr.string','String')
+						}
+					},
 			'transition': { 'name': 'Transition',
 						'type': 'Class',
 						'body':

+ 4 - 2
textualnotations/sccd_grammar.g

@@ -2,9 +2,10 @@ start: sccd;
 
 sccd: diagram INDENT (top)? element+ (bottom)? DEDENT;
 
-@element: (inport | class);
+@element: (inport | outport | class);
 
 inport: INPORT LPAR nameattr RPAR NEWLINE;
+outport: OUTPORT LPAR nameattr RPAR NEWLINE;
 
 nameattr: NAMEATTR ASSIGN string;
 defaultattr: DEFAULTATTR ASSIGN boolean;
@@ -17,7 +18,7 @@ classdefattrs: classdefattr (COMMA classdefattr)*;
 
 classdefattr: nameattr | defaultattr;
 
-@classelement: inport | association | inheritance | aggregation | composition |
+@classelement: inport | outport | association | inheritance | aggregation | composition |
 				attribute | constructor | destructor | method | statemachine;
 
 aggregation: AGGREGATION LPAR aggregattrs RPAR NEWLINE;
@@ -797,6 +798,7 @@ CLASS: 'Class';
 TOP: 'Top';
 BOTTOM: 'Bottom';
 INPORT: 'Inport';
+OUTPORT: 'Outport';
 
 NAMEATTR: 'name';
 DEFAULTATTR: 'default';

+ 40 - 0
textualnotations/sccd_modelverse_sources/sccd_metamodel.mtn

@@ -128,6 +128,9 @@ package protected.formalisms:
         Class:
             name = 'InPort'
 
+        Class:
+            name = 'OutPort'
+
         Class:
             name = 'AbsState'
             is_abstract = True
@@ -719,6 +722,38 @@ package protected.formalisms:
                 name = 'name'
                 type = String
 
+        Association:
+            name = 'class_outport'
+
+            from_port = 'from_class'
+            from_class = Class
+
+            to_min = 0
+            to_max = *
+            to_port = 'to_outport'
+            to_class = OutPort
+
+            id_field = 'class_outport.name'
+            Attribute:
+                name = 'name'
+                type = String
+
+        Association:
+            name = 'transition_outport'
+
+            from_port = 'from_transition'
+            from_class = Transition
+
+            to_min = 0
+            to_max = 1
+            to_port = 'to_outport'
+            to_class = OutPort
+
+            id_field = 'transition_outport.name'
+            Attribute:
+                name = 'name'
+                type = String
+
         Association:
             name = 'transition_actionblock'
 
@@ -1370,6 +1405,11 @@ package protected.formalisms:
             from_class = InPort
             to_class = Named
 
+        Inheritance:
+            name = 'OutPort_i_Named'
+            from_class = OutPort
+            to_class = Named
+
         Inheritance:
             name = 'AbsState_i_ID'
             from_class = AbsState

+ 61 - 0
textualnotations/sccd_modelverse_sources/sccd_metamodel.py

@@ -486,6 +486,13 @@ class Gen():
 			StringValue('Class.is_abstract'): BooleanValue(False),
 			StringValue('Class.name'): StringValue('InPort')})
 		}))
+		cl = self.mvk.create(MappingValue({
+			CreateConstants.TYPE_KEY: LocationValue('protected.formalisms.SimpleClassDiagrams.Class'),
+			CreateConstants.LOCATION_KEY: LocationValue('protected.formalisms.SCCD'),
+			CreateConstants.ATTRS_KEY: MappingValue({
+			StringValue('Class.is_abstract'): BooleanValue(False),
+			StringValue('Class.name'): StringValue('OutPort')})
+		}))
 		cl = self.mvk.create(MappingValue({
 			CreateConstants.TYPE_KEY: LocationValue('protected.formalisms.SimpleClassDiagrams.Class'),
 			CreateConstants.LOCATION_KEY: LocationValue('protected.formalisms.SCCD'),
@@ -1394,6 +1401,14 @@ class Gen():
 			StringValue('from_class'): LocationValue('protected.formalisms.SCCD.InPort'),
 			StringValue('to_class'): LocationValue('protected.formalisms.SCCD.Named')})
 		}))
+		cl = self.mvk.create(MappingValue({
+			CreateConstants.TYPE_KEY: LocationValue('protected.formalisms.SimpleClassDiagrams.Inheritance'),
+			CreateConstants.LOCATION_KEY: LocationValue('protected.formalisms.SCCD'),
+			CreateConstants.ATTRS_KEY: MappingValue({
+			StringValue('Inheritance.name'): StringValue('OutPort_i_Named'),
+			StringValue('from_class'): LocationValue('protected.formalisms.SCCD.OutPort'),
+			StringValue('to_class'): LocationValue('protected.formalisms.SCCD.Named')})
+		}))
 		cl = self.mvk.create(MappingValue({
 			CreateConstants.TYPE_KEY: LocationValue('protected.formalisms.SimpleClassDiagrams.Inheritance'),
 			CreateConstants.LOCATION_KEY: LocationValue('protected.formalisms.SCCD'),
@@ -1589,6 +1604,29 @@ class Gen():
 			StringValue('Attribute.name'): StringValue('name'),
 			StringValue('Attribute.type'): StringType()})
 		}))
+		cl = self.mvk.create(MappingValue({
+			CreateConstants.TYPE_KEY: LocationValue('protected.formalisms.SimpleClassDiagrams.Association'),
+			CreateConstants.LOCATION_KEY: LocationValue('protected.formalisms.SCCD'),
+			CreateConstants.ATTRS_KEY: MappingValue({
+			StringValue('Association.to_max'): IntegerValue(1),
+			StringValue('Association.from_max'): InfiniteValue('inf'),
+			StringValue('Association.from_port'): StringValue('from_transition'),
+			StringValue('Association.to_min'): IntegerValue(0),
+			StringValue('Class.name'): StringValue('transition_outport'),
+			StringValue('Association.to_port'): StringValue('to_outport'),
+			StringValue('Class.is_abstract'): BooleanValue(False),
+			StringValue('Association.from_min'): IntegerValue(0),
+			StringValue('Class.id_field'): StringValue('transition_outport.name'),
+			StringValue('from_class'): LocationValue('protected.formalisms.SCCD.Transition'),
+			StringValue('to_class'): LocationValue('protected.formalisms.SCCD.OutPort')})
+		}))
+		cl = self.mvk.create(MappingValue({
+			CreateConstants.TYPE_KEY: LocationValue('protected.formalisms.SimpleClassDiagrams.Attribute'),
+			CreateConstants.LOCATION_KEY: LocationValue('protected.formalisms.SCCD.transition_outport'),
+			CreateConstants.ATTRS_KEY: MappingValue({
+			StringValue('Attribute.name'): StringValue('name'),
+			StringValue('Attribute.type'): StringType()})
+		}))
 		cl = self.mvk.create(MappingValue({
 			CreateConstants.TYPE_KEY: LocationValue('protected.formalisms.SimpleClassDiagrams.Inheritance'),
 			CreateConstants.LOCATION_KEY: LocationValue('protected.formalisms.SCCD'),
@@ -2545,6 +2583,29 @@ class Gen():
 			StringValue('Attribute.name'): StringValue('name'),
 			StringValue('Attribute.type'): StringType()})
 		}))
+		cl = self.mvk.create(MappingValue({
+			CreateConstants.TYPE_KEY: LocationValue('protected.formalisms.SimpleClassDiagrams.Association'),
+			CreateConstants.LOCATION_KEY: LocationValue('protected.formalisms.SCCD'),
+			CreateConstants.ATTRS_KEY: MappingValue({
+			StringValue('Association.to_max'): InfiniteValue('inf'),
+			StringValue('Association.from_max'): InfiniteValue('inf'),
+			StringValue('Association.from_port'): StringValue('from_class'),
+			StringValue('Association.to_min'): IntegerValue(0),
+			StringValue('Class.name'): StringValue('class_outport'),
+			StringValue('Association.to_port'): StringValue('to_outport'),
+			StringValue('Class.is_abstract'): BooleanValue(False),
+			StringValue('Association.from_min'): IntegerValue(0),
+			StringValue('Class.id_field'): StringValue('class_outport.name'),
+			StringValue('from_class'): LocationValue('protected.formalisms.SCCD.Class'),
+			StringValue('to_class'): LocationValue('protected.formalisms.SCCD.OutPort')})
+		}))
+		cl = self.mvk.create(MappingValue({
+			CreateConstants.TYPE_KEY: LocationValue('protected.formalisms.SimpleClassDiagrams.Attribute'),
+			CreateConstants.LOCATION_KEY: LocationValue('protected.formalisms.SCCD.class_outport'),
+			CreateConstants.ATTRS_KEY: MappingValue({
+			StringValue('Attribute.name'): StringValue('name'),
+			StringValue('Attribute.type'): StringType()})
+		}))
 		cl = self.mvk.create(MappingValue({
 			CreateConstants.TYPE_KEY: LocationValue('protected.formalisms.SimpleClassDiagrams.Association'),
 			CreateConstants.LOCATION_KEY: LocationValue('protected.formalisms.SCCD'),

+ 381 - 381
textualnotations/sccd_to_xml.py

@@ -5,10 +5,10 @@ import re
 
 from mvk.impl.python.constants import CreateConstants, UpdateConstants
 from mvk.impl.python.datatype import TypeFactory, Type, IntegerType, StringType, \
-	BooleanType, FloatType
+    BooleanType, FloatType
 from mvk.impl.python.datavalue import MappingValue, \
-	LocationValue, StringValue, FloatValue, \
-	IntegerValue, BooleanValue, InfiniteValue, Iterator, AnyValue
+    LocationValue, StringValue, FloatValue, \
+    IntegerValue, BooleanValue, InfiniteValue, Iterator, AnyValue
 
 from mvk.impl.python.object import ClabjectReference, Clabject
 
@@ -21,389 +21,389 @@ from shell import Shell
 DEBUG = False
 
 def debug_print(_str_):
-	if(DEBUG is False):
-		return
-	print('>>> debug: ' + _str_)
+    if(DEBUG is False):
+        return
+    print('>>> debug: ' + _str_)
 
 
 class SCCD_to_XML(object):
-	def __init__(self, rules, modelverse=None):
-
-		self.modelpackage = ''
-		self.modelname = ''
-		self.modelitem = None
-		self.rules = rules
-		self.outputStream = ''
-		self.reset_indentation()
-		
-#		if(modelverse is None): # load default...
-#			self.mvk = MvK()
-#			gmm = GenSCCD()
-#			gmm.mvk = self.mvk
-#			gmm.instance()
-#			gbb = GenBBals()
-#			gbb.mvk = gmm.mvk
-#			gbb.instance()
-#		else:
-		self.mvk = modelverse
-		self.reservedwords = ['@newline', '@indent', '@dedent']
-
-	def reset_indentation(self):
-		self.indentation = 0
-		self.lastnewline = False
-
-	def increase_indentation(self):
-		self.indentation = self.indentation + 1
-
-	def decrease_indentation(self):
-		self.indentation = self.indentation - 1
-
-	def getidentstring(self):
-		ntabs = self.indentation
-		outstring = ''
-		while ntabs > 0:
-			outstring = outstring + '\t'
-			ntabs = ntabs - 1
-		return outstring
-
-	## override this to emmit to other outputs
-	def emmitCode(self, string, tabs=False):
-		string = string.replace('\[','{')
-		string = string.replace('\]','}')
-
-		if tabs is True or self.lastnewline is True:
-			self.write(self.getidentstring() + string)
-		else:
-			self.write(string)
-		self.lastnewline = False
-
-	def newline(self):
-		self.write('\n')
-		self.lastnewline = True
-
-	def write(self, string):
-		self.outputStream += string
-
-	def compile(self, location='MyFormalisms.BouncingBalls'):
-		modelrule = None
-		for key in self.rules:
-			if(self.rules[key]['type'] == 'Model'):
-				modelrule = {'key': key, 'body': self.rules[key]}
-
-		if modelrule == None:
-			raise Exception('Error: no model rule defined')
-
-		rl = self.mvk.read(LocationValue(location))
-		if(not rl.is_success()):
-			raise Exception('Error: Invalid location: ' + location)
-
-		item = rl.get_item()
-		typename = str(item.typed_by().get_location())
-		debug_print(typename)
-		self.modelpackage = modelrule['body']['package']
-		self.modelname = modelrule['body']['name']
-		self.modelitem = item
-		expectedtype = self.modelpackage + '.' + modelrule['body']['name']
-		if(typename != expectedtype):
-			raise Exception('Model at specified location is not an ' + expectedtype + ' model!')
-
-		if(self.isEnabled(modelrule, item)):
-			self.evaluateRule(modelrule, item)
-
-	def processReserved(self, elem):
-		if(elem == '@newline'):
-			self.newline()
-		elif(elem == '@indent'):
-			self.increase_indentation()
-		elif(elem == '@dedent'):
-			self.decrease_indentation()
-
-	def evaluateRule(self, rule, item):
-		debug_print('evaluateRule: ' + str(rule))
-		debug_print('evaluateRule: ' + str(item))
-		pattern = rule['body']['pattern']
-		for elem in pattern:
-			if(elem.startswith('@')):
-				if(elem in self.reservedwords):
-					self.processReserved(elem)
-				elif(elem[1:] == '@'):
-					continue ## just ignore mute attributes
-				elif(self.isAttributeIn(elem[1:], item)):
-					self.processAttributeIn(elem[1:], item)
-				elif(elem[1:] in self.rules):
-					self.evaluateIn(elem[1:], item)
-				else:
-					raise Exception(elem + ' not found!')
-			elif(elem.startswith('\@')):
-				self.emmitCode(elem[2:])
-			else:
-				self.emmitCode(elem)
-
-	def evaluateRuleOnSet(self, rule, item, list):
-		#debug_print('evaluateRuleOnSet: ' + str(rule))
-		#debug_print('evaluateRuleOnSet: ' + str(item))
-		pattern = rule['body']['pattern']
-		for elem in pattern:
-			if(elem.startswith('@')):
-				if(elem in self.reservedwords):
-					self.processReserved(elem)
-				elif(elem[1:] == '@'):
-					continue ## just ignore mute attributes
-				elif(self.isAttributeIn(elem[1:], item)):
-					self.processAttributeIn(elem[1:], item)
-				elif(elem[1:] in self.rules):
-					for itemlist in list:
-						self.evaluateIn(elem[1:], itemlist)
-				else:
-					raise Exception(elem + ' not found!')
-			elif(elem.startswith('\@')):
-				self.emmitCode(elem[2:])
-			else:
-				self.emmitCode(elem)
-
-	def evaluateIn(self, rulename, item):
-		#debug_print('evaluateIn: ' + str(rulename))
-		#debug_print('evaluateIn: ' + str(item))
-
-		rule = {'key': rulename, 'body': self.rules[rulename]}
-
-		if(not self.isEnabledIn(rulename, item)):
-			return
-
-		if(rule['body']['type'] == 'Class'):
-			if(isinstance(item, mvk.interfaces.object.Clabject)):
-				self.evaluateRule(rule, item)
-			else:
-				iterator = Iterator(self.modelitem.get_elements().keys())
-				while(iterator.has_next()):
-					itemin = iterator.next()
-					value = self.modelitem.get_elements()[itemin]
-					#debug_print('item.get_elements()[itemin]: ' + str(value))
-					if(not isinstance(value, mvk.interfaces.object.Association)):
-						typename = str(value.typed_by().get_location())
-						if((self.modelpackage + '.' + rule['body']['name']) == typename):
-							self.evaluateRule(rule, value)
-		elif(rule['body']['type'] == 'Association'):
-			#debug_print('Association?')
-			iterator = Iterator(item.out_associations.keys())
-			alist = []
-			while(iterator.has_next()):
-				itemin = iterator.next()
-				relvalue = item.out_associations[itemin]
-				#debug_print('item.out_associations[itemin]: ' + str(relvalue))
-				typename = str(relvalue.typed_by().get_location())
-				#debug_print('typename: ' + typename)
-				expectedtypename = self.modelpackage + '.' + rule['body']['name']
-				if(expectedtypename == typename):
-					#debug_print('expectedtypename: ' + expectedtypename)
-					alist.append(relvalue.get_to_multiplicity().get_node())
-			self.evaluateRuleOnSet(rule, item, alist)
-		else:
-			self.evaluateRule(rule, item)
-
-
-	def processAttributeIn(self, elem, item):
-		debug_print('processAttributeIn: ' + elem)
-
-		reverse = False
-		if(elem.startswith('-')):
-			elem = elem[1:]
-			reverse = True
-
-		if(elem.startswith('(')):
-			splitres = re.split('\).', elem[1:])
-			if(len(splitres) == 2):
-				item = self.resolveNavItem(splitres[0], reverse, item)
-				debug_print('setting new item: ' + str(item))
-				self.processAttributeIn(splitres[1], item)
-				return
-			else:
-				raise Exception('Internal Syntax error on: ' + elem)
-
-		value = item.get_attribute(StringValue(elem)).get_value()
-		if(isinstance(value,AnyValue)):
-			return
-		self.emmitCode(str(value))
-
-	def isEnabledIn(self, rulename, item):
-		#debug_print('isEnabledIn: ' + str(rulename))
-		#debug_print('isEnabledIn: ' + str(item))
-
-		rule = {'key': rulename, 'body': self.rules[rulename]}
-
-		if(rule['body']['type'] == 'Class'):
-			#debug_print('isEnabledIn: ' + str(rule['body']['name']))
-
-			if(isinstance(item, mvk.interfaces.object.Clabject)):
-				if(self.isEnabled(rule, item)):
-					return True
-			else:
-				iterator = Iterator(item.get_elements().keys())
-				while(iterator.has_next()):
-					itemin = iterator.next()
-					value = item.get_elements()[itemin]
-					if(not isinstance(value, mvk.interfaces.object.Association)):
-						typename = str(value.typed_by().get_location())
-						if((self.modelpackage + '.' + rule['body']['name']) == typename):
-							if(self.isEnabled(rule, value)):
-								return True
-		elif(rule['body']['type'] == 'Association'):
-			#debug_print('isEnabledIn: ' + str(rule['body']['target']))
-			iterator = Iterator(item.out_associations.keys())
-			while(iterator.has_next()):
-				itemin = iterator.next()
-				relvalue = item.out_associations[itemin]
-				typename = str(relvalue.typed_by().get_location())
-				#debug_print('typename: ' + typename)
-				expectedtypename = self.modelpackage + '.' + rule['body']['name']
-				#debug_print('expectedtypename: ' + expectedtypename)
-				if(expectedtypename == typename):
-					if(self.isEnabled(rule, relvalue.get_to_multiplicity().get_node())):
-						return True
-		elif(rule['body']['type'] == 'Attribute'):
-			return self.isEnabled(rule, item)
-
-		return False
-
-	def hasExpectedType(self, expectedtype, elem):
-		item = elem.typed_by()
-		lastname = re.compile('\w+').findall(str(item.get_location())).pop()
-		if(self.modelname + '.' + lastname == expectedtype):
-			return True
-
-		iterator = Iterator(item.get_all_super_classes())
-		while(iterator.has_next()):
-			itemin = iterator.next()
-			lastname = re.compile('\w+').findall(str(itemin.get_location())).pop()
-			if(self.modelname + '.' + lastname == expectedtype):
-				return True
-
-		return False
-
-	def isEnabled(self, rule, item):
-		debug_print('isEnabled rule: ' + str(rule))
-		debug_print('isEnabled item: ' + str(item.typed_by().get_location()))
-
-		if(rule['body']['type'] == 'Class'):
-			if(not self.hasExpectedType(rule['body']['name'], item)):
-				return False
-
-		pattern = rule['body']['pattern']
-		nonterminalFound = False
-		for elem in pattern:
-			if(elem.startswith('@')):
-				if(elem in self.reservedwords):
-					continue
-				if(elem[1:] == '@'):
-					return True
-				elif(self.isAttributeIn(elem[1:], item)):
-					nonterminalFound = True
-					if(self.hasValue(elem[1:], item)):
-						return True
-				elif(elem[1:] in self.rules):
-					nonterminalFound = True
-					if(self.isEnabledIn(elem[1:], item)):
-						return True
-			else:
-				continue
-
-		return not nonterminalFound
-
-	def resolveNavItem(self, navexpr, reverse, item):
-		debug_print('resolveNavItem: ' + navexpr)
-		if(isinstance(item, mvk.interfaces.object.Association)):
-			return item
-		if(isinstance(item, mvk.interfaces.object.Clabject)):
-			if(reverse):
-				iterator = Iterator(item.get_in_associations())
-			else:
-				iterator = Iterator(item.get_out_associations())
-
-			debug_print('here!!!!')
-
-			while(iterator.has_next()):
-				association = iterator.next()
-				name = str(association.get_name())
-				typename = str(association.typed_by().get_location())
-				debug_print('name: ' + name)
-				debug_print('typename: ' + typename)
-				if(typename.endswith(navexpr)):
-					if(reverse):
-						return association.get_from_multiplicity().get_node()
-					else:
-						return association.get_to_multiplicity().get_node()
-		raise Exception('Type not found: ' + navexpr)
-
-	def isAttributeIn(self, elem, item):
-		debug_print('isAttributeIn: ' + elem)
-		debug_print('isAttributeIn item: ' + str(item))
-
-		reverse = False
-		if(elem.startswith('-')):
-			elem = elem[1:]
-			reverse = True
-
-		if(elem.startswith('(')):
-			splitres = re.split('\).', elem[1:])
-			if(len(splitres) == 2):
-				item = self.resolveNavItem(splitres[0], reverse, item)
-				debug_print('setting new item: ' + str(item))
-				isattribute = self.isAttributeIn(splitres[1], item)
-				debug_print('was found? ' + str(isattribute))
-				return isattribute
-			else:
-				raise Exception('Internal Syntax error on: ' + elem)
-
-		iterator  = Iterator(item.get_attributes())
-
-		while(iterator.has_next()):
-			attribute = iterator.next()
-			name = str(attribute.get_name())
-			if(elem == name):
-				return True
-
-	def hasValue(self, elem, item):
-		debug_print('hasValue: ' + elem + ' in ' + str(item))
-
-		reverse = False
-		if(elem.startswith('-')):
-			elem = elem[1:]
-			reverse = True
-
-		if(elem.startswith('(')):
-			splitres = re.split('\).', elem[1:])
-			if(len(splitres) == 2):
-				item = self.resolveNavItem(splitres[0], reverse, item)
-				debug_print('setting new item: ' + str(item))
-				hasValue = self.hasValue(splitres[1], item)
-				debug_print('has value? ' + str(hasValue))
-				return hasValue
-			else:
-				raise Exception('Internal Syntax error on: ' + elem)
-
-
-		value = item.get_attribute(StringValue(elem)).get_value()
-		if(isinstance(value,AnyValue)):
-			return False
-		#debug_print('has indeed a value! on: ' + elem + str(value))
-		return True
-
-	def outputTo(self, output='console'):
-		if(output == 'console'):
-			print(self.outputStream)
-		else:
-			fo = open(output, 'a')
-			fo.write(self.outputStream)
-			fo.close()
+    def __init__(self, rules, modelverse=None):
+        
+        self.modelpackage = ''
+        self.modelname = ''
+        self.modelitem = None
+        self.rules = rules
+        self.outputStream = ''
+        self.reset_indentation()
+        
+#        if(modelverse is None): # load default...
+#            self.mvk = MvK()
+#            gmm = GenSCCD()
+#            gmm.mvk = self.mvk
+#            gmm.instance()
+#            gbb = GenBBals()
+#            gbb.mvk = gmm.mvk
+#            gbb.instance()
+#        else:
+        self.mvk = modelverse
+        self.reservedwords = ['@newline', '@indent', '@dedent']
+
+    def reset_indentation(self):
+        self.indentation = 0
+        self.lastnewline = False
+
+    def increase_indentation(self):
+        self.indentation = self.indentation + 1
+
+    def decrease_indentation(self):
+        self.indentation = self.indentation - 1
+
+    def getidentstring(self):
+        ntabs = self.indentation
+        outstring = ''
+        while ntabs > 0:
+            outstring = outstring + '\t'
+            ntabs = ntabs - 1
+        return outstring
+
+    ## override this to emmit to other outputs
+    def emmitCode(self, string, tabs=False):
+        string = string.replace('\[','{')
+        string = string.replace('\]','}')
+
+        if tabs is True or self.lastnewline is True:
+            self.write(self.getidentstring() + string)
+        else:
+            self.write(string)
+        self.lastnewline = False
+
+    def newline(self):
+        self.write('\n')
+        self.lastnewline = True
+
+    def write(self, string):
+        self.outputStream += string
+
+    def compile(self, location='MyFormalisms.BouncingBalls'):
+        modelrule = None
+        for key in self.rules:
+            if(self.rules[key]['type'] == 'Model'):
+                modelrule = {'key': key, 'body': self.rules[key]}
+
+        if modelrule == None:
+            raise Exception('Error: no model rule defined')
+
+        rl = self.mvk.read(LocationValue(location))
+        if(not rl.is_success()):
+            raise Exception('Error: Invalid location: ' + location)
+
+        item = rl.get_item()
+        typename = str(item.typed_by().get_location())
+        debug_print(typename)
+        self.modelpackage = modelrule['body']['package']
+        self.modelname = modelrule['body']['name']
+        self.modelitem = item
+        expectedtype = self.modelpackage + '.' + modelrule['body']['name']
+        if(typename != expectedtype):
+            raise Exception('Model at specified location is not an ' + expectedtype + ' model!')
+
+        if(self.isEnabled(modelrule, item)):
+            self.evaluateRule(modelrule, item)
+
+    def processReserved(self, elem):
+        if(elem == '@newline'):
+            self.newline()
+        elif(elem == '@indent'):
+            self.increase_indentation()
+        elif(elem == '@dedent'):
+            self.decrease_indentation()
+
+    def evaluateRule(self, rule, item):
+        debug_print('evaluateRule: ' + str(rule))
+        debug_print('evaluateRule: ' + str(item))
+        pattern = rule['body']['pattern']
+        for elem in pattern:
+            if(elem.startswith('@')):
+                if(elem in self.reservedwords):
+                    self.processReserved(elem)
+                elif(elem[1:] == '@'):
+                    continue ## just ignore mute attributes
+                elif(self.isAttributeIn(elem[1:], item)):
+                    self.processAttributeIn(elem[1:], item)
+                elif(elem[1:] in self.rules):
+                    self.evaluateIn(elem[1:], item)
+                else:
+                    raise Exception(elem + ' not found!')
+            elif(elem.startswith('\@')):
+                self.emmitCode(elem[2:])
+            else:
+                self.emmitCode(elem)
+
+    def evaluateRuleOnSet(self, rule, item, list):
+        #debug_print('evaluateRuleOnSet: ' + str(rule))
+        #debug_print('evaluateRuleOnSet: ' + str(item))
+        pattern = rule['body']['pattern']
+        for elem in pattern:
+            if(elem.startswith('@')):
+                if(elem in self.reservedwords):
+                    self.processReserved(elem)
+                elif(elem[1:] == '@'):
+                    continue ## just ignore mute attributes
+                elif(self.isAttributeIn(elem[1:], item)):
+                    self.processAttributeIn(elem[1:], item)
+                elif(elem[1:] in self.rules):
+                    for itemlist in list:
+                        self.evaluateIn(elem[1:], itemlist)
+                else:
+                    raise Exception(elem + ' not found!')
+            elif(elem.startswith('\@')):
+                self.emmitCode(elem[2:])
+            else:
+                self.emmitCode(elem)
+
+    def evaluateIn(self, rulename, item):
+        #debug_print('evaluateIn: ' + str(rulename))
+        #debug_print('evaluateIn: ' + str(item))
+
+        rule = {'key': rulename, 'body': self.rules[rulename]}
+
+        if(not self.isEnabledIn(rulename, item)):
+            return
+
+        if(rule['body']['type'] == 'Class'):
+            if(isinstance(item, mvk.interfaces.object.Clabject)):
+                self.evaluateRule(rule, item)
+            else:
+                iterator = Iterator(self.modelitem.get_elements().keys())
+                while(iterator.has_next()):
+                    itemin = iterator.next()
+                    value = self.modelitem.get_elements()[itemin]
+                    #debug_print('item.get_elements()[itemin]: ' + str(value))
+                    if(not isinstance(value, mvk.interfaces.object.Association)):
+                        typename = str(value.typed_by().get_location())
+                        if((self.modelpackage + '.' + rule['body']['name']) == typename):
+                            self.evaluateRule(rule, value)
+        elif(rule['body']['type'] == 'Association'):
+            #debug_print('Association?')
+            iterator = Iterator(item.out_associations.keys())
+            alist = []
+            while(iterator.has_next()):
+                itemin = iterator.next()
+                relvalue = item.out_associations[itemin]
+                #debug_print('item.out_associations[itemin]: ' + str(relvalue))
+                typename = str(relvalue.typed_by().get_location())
+                #debug_print('typename: ' + typename)
+                expectedtypename = self.modelpackage + '.' + rule['body']['name']
+                if(expectedtypename == typename):
+                    #debug_print('expectedtypename: ' + expectedtypename)
+                    alist.append(relvalue.get_to_multiplicity().get_node())
+            self.evaluateRuleOnSet(rule, item, alist)
+        else:
+            self.evaluateRule(rule, item)
+
+
+    def processAttributeIn(self, elem, item):
+        debug_print('processAttributeIn: ' + elem)
+
+        reverse = False
+        if(elem.startswith('-')):
+            elem = elem[1:]
+            reverse = True
+
+        if(elem.startswith('(')):
+            splitres = re.split('\).', elem[1:])
+            if(len(splitres) == 2):
+                item = self.resolveNavItem(splitres[0], reverse, item)
+                debug_print('setting new item: ' + str(item))
+                self.processAttributeIn(splitres[1], item)
+                return
+            else:
+                raise Exception('Internal Syntax error on: ' + elem)
+
+        value = item.get_attribute(StringValue(elem)).get_value()
+        if(isinstance(value,AnyValue)):
+            return
+        self.emmitCode(str(value))
+
+    def isEnabledIn(self, rulename, item):
+        #debug_print('isEnabledIn: ' + str(rulename))
+        #debug_print('isEnabledIn: ' + str(item))
+
+        rule = {'key': rulename, 'body': self.rules[rulename]}
+
+        if(rule['body']['type'] == 'Class'):
+            #debug_print('isEnabledIn: ' + str(rule['body']['name']))
+
+            if(isinstance(item, mvk.interfaces.object.Clabject)):
+                if(self.isEnabled(rule, item)):
+                    return True
+            else:
+                iterator = Iterator(item.get_elements().keys())
+                while(iterator.has_next()):
+                    itemin = iterator.next()
+                    value = item.get_elements()[itemin]
+                    if(not isinstance(value, mvk.interfaces.object.Association)):
+                        typename = str(value.typed_by().get_location())
+                        if((self.modelpackage + '.' + rule['body']['name']) == typename):
+                            if(self.isEnabled(rule, value)):
+                                return True
+        elif(rule['body']['type'] == 'Association'):
+            #debug_print('isEnabledIn: ' + str(rule['body']['target']))
+            iterator = Iterator(item.out_associations.keys())
+            while(iterator.has_next()):
+                itemin = iterator.next()
+                relvalue = item.out_associations[itemin]
+                typename = str(relvalue.typed_by().get_location())
+                #debug_print('typename: ' + typename)
+                expectedtypename = self.modelpackage + '.' + rule['body']['name']
+                #debug_print('expectedtypename: ' + expectedtypename)
+                if(expectedtypename == typename):
+                    if(self.isEnabled(rule, relvalue.get_to_multiplicity().get_node())):
+                        return True
+        elif(rule['body']['type'] == 'Attribute'):
+            return self.isEnabled(rule, item)
+
+        return False
+
+    def hasExpectedType(self, expectedtype, elem):
+        item = elem.typed_by()
+        lastname = re.compile('\w+').findall(str(item.get_location())).pop()
+        if(self.modelname + '.' + lastname == expectedtype):
+            return True
+
+        iterator = Iterator(item.get_all_super_classes())
+        while(iterator.has_next()):
+            itemin = iterator.next()
+            lastname = re.compile('\w+').findall(str(itemin.get_location())).pop()
+            if(self.modelname + '.' + lastname == expectedtype):
+                return True
+
+        return False
+
+    def isEnabled(self, rule, item):
+        debug_print('isEnabled rule: ' + str(rule))
+        debug_print('isEnabled item: ' + str(item.typed_by().get_location()))
+
+        if(rule['body']['type'] == 'Class'):
+            if(not self.hasExpectedType(rule['body']['name'], item)):
+                return False
+
+        pattern = rule['body']['pattern']
+        nonterminalFound = False
+        for elem in pattern:
+            if(elem.startswith('@')):
+                if(elem in self.reservedwords):
+                    continue
+                if(elem[1:] == '@'):
+                    return True
+                elif(self.isAttributeIn(elem[1:], item)):
+                    nonterminalFound = True
+                    if(self.hasValue(elem[1:], item)):
+                        return True
+                elif(elem[1:] in self.rules):
+                    nonterminalFound = True
+                    if(self.isEnabledIn(elem[1:], item)):
+                        return True
+            else:
+                continue
+
+        return not nonterminalFound
+
+    def resolveNavItem(self, navexpr, reverse, item):
+        debug_print('resolveNavItem: ' + navexpr)
+        if(isinstance(item, mvk.interfaces.object.Association)):
+            return item
+        if(isinstance(item, mvk.interfaces.object.Clabject)):
+            if(reverse):
+                iterator = Iterator(item.get_in_associations())
+            else:
+                iterator = Iterator(item.get_out_associations())
+
+            debug_print('here!!!!')
+
+            while(iterator.has_next()):
+                association = iterator.next()
+                name = str(association.get_name())
+                typename = str(association.typed_by().get_location())
+                debug_print('name: ' + name)
+                debug_print('typename: ' + typename)
+                if(typename.endswith(navexpr)):
+                    if(reverse):
+                        return association.get_from_multiplicity().get_node()
+                    else:
+                        return association.get_to_multiplicity().get_node()
+        raise Exception('Type not found: ' + navexpr)
+
+    def isAttributeIn(self, elem, item):
+        debug_print('isAttributeIn: ' + elem)
+        debug_print('isAttributeIn item: ' + str(item))
+
+        reverse = False
+        if(elem.startswith('-')):
+            elem = elem[1:]
+            reverse = True
+
+        if(elem.startswith('(')):
+            splitres = re.split('\).', elem[1:])
+            if(len(splitres) == 2):
+                item = self.resolveNavItem(splitres[0], reverse, item)
+                debug_print('setting new item: ' + str(item))
+                isattribute = self.isAttributeIn(splitres[1], item)
+                debug_print('was found? ' + str(isattribute))
+                return isattribute
+            else:
+                raise Exception('Internal Syntax error on: ' + elem)
+
+        iterator  = Iterator(item.get_attributes())
+
+        while(iterator.has_next()):
+            attribute = iterator.next()
+            name = str(attribute.get_name())
+            if(elem == name):
+                return True
+
+    def hasValue(self, elem, item):
+        debug_print('hasValue: ' + elem + ' in ' + str(item))
+
+        reverse = False
+        if(elem.startswith('-')):
+            elem = elem[1:]
+            reverse = True
+
+        if(elem.startswith('(')):
+            splitres = re.split('\).', elem[1:])
+            if(len(splitres) == 2):
+                item = self.resolveNavItem(splitres[0], reverse, item)
+                debug_print('setting new item: ' + str(item))
+                hasValue = self.hasValue(splitres[1], item)
+                debug_print('has value? ' + str(hasValue))
+                return hasValue
+            else:
+                raise Exception('Internal Syntax error on: ' + elem)
+
+
+        value = item.get_attribute(StringValue(elem)).get_value()
+        if(isinstance(value,AnyValue)):
+            return False
+        #debug_print('has indeed a value! on: ' + elem + str(value))
+        return True
+
+    def outputTo(self, output='console'):
+        if(output == 'console'):
+            print(self.outputStream)
+        else:
+            fo = open(output, 'a')
+            fo.write(self.outputStream)
+            fo.close()
 
 if __name__ == '__main__':
-	pass
-	#compiler = SCCD_to_XML(XMLRules().rules)
+    pass
+    #compiler = SCCD_to_XML(XMLRules().rules)
 
-	#compiler.compile()
-	#compiler.outputTo()
+    #compiler.compile()
+    #compiler.outputTo()
 
-	#shell = Shell()
-	#shell.mvk = compiler.mvk
-	#shell.setupCommandLine()
+    #shell = Shell()
+    #shell.mvk = compiler.mvk
+    #shell.setupCommandLine()
 

+ 6 - 0
textualnotations/sccd_to_xml_JS.py

@@ -12,6 +12,7 @@ class XML2JavaScriptRules(object):
 							'@indent',
 								'@SCCDdescription',
 								'@SCCDInPort',
+								'@SCCDOutPort',
 								'@SCCDTop',
 								'@SCCDClass',
 								'@SCCDBottom',
@@ -33,6 +34,11 @@ class XML2JavaScriptRules(object):
 				'name': 'SCCD.InPort',
 				'pattern': ['<inport name="', '@Named.name','"/>', '@newline']
 			},
+			'SCCDOutPort': {
+				'type': 'Class',
+				'name': 'SCCD.OutPort',
+				'pattern': ['<outport name="', '@Named.name','"/>', '@newline']
+			},
 			'SCCDTop': {
 				'type': 'Class',
 				'name': 'SCCD.Top',

+ 6 - 0
textualnotations/sccd_to_xml_PY.py

@@ -12,6 +12,7 @@ class XML2PythonRules(object):
 							'@indent',
 								'@SCCDdescription',
 								'@SCCDInPort',
+								'@SCCDOutPort',
 								'@SCCDTop',
 								'@SCCDClass',
 								'@SCCDBottom',
@@ -33,6 +34,11 @@ class XML2PythonRules(object):
 				'name': 'SCCD.InPort',
 				'pattern': ['<inport name="', '@Named.name','"/>', '@newline']
 			},
+			'SCCDOutPort': {
+				'type': 'Class',
+				'name': 'SCCD.OutPort',
+				'pattern': ['<outport name="', '@Named.name','"/>', '@newline']
+			},
 			'SCCDTop': {
 				'type': 'Class',
 				'name': 'SCCD.Top',

+ 133 - 133
textualnotations/sccdtnc.py

@@ -23,147 +23,147 @@ from mvk_loader import MvKLoader
 from sccd_to_xml import SCCD_to_XML
 
 def generate(input_file, output_file, target_language, platform):
-	sccd = xmlToSccd(input_file)
+    sccd = xmlToSccd(input_file)
 
-	if not target_language:
-		if sccd.language:
-			target_language = sccd.language
-		else:
-			target_language = "python" # default
-	elif sccd.language and target_language != sccd.language:
-		Logger.showError("Diagram specifies target language as \"" + sccd.language + "\", but language option of compiler has been set to \"" + target_language + "\". No output has been generated.")
-		return
+    if not target_language:
+        if sccd.language:
+            target_language = sccd.language
+        else:
+            target_language = "python" # default
+    elif sccd.language and target_language != sccd.language:
+        Logger.showError("Diagram specifies target language as \"" + sccd.language + "\", but language option of compiler has been set to \"" + target_language + "\". No output has been generated.")
+        return
 
-	if target_language == "python" and not output_file.endswith(".py") :
-		output_file += ".py"
-	elif target_language == "javascript" and not output_file.endswith(".js") :
-		output_file += ".js"
+    if target_language == "python" and not output_file.endswith(".py") :
+        output_file += ".py"
+    elif target_language == "javascript" and not output_file.endswith(".js") :
+        output_file += ".js"
 
-	generic = sccdToGeneric(sccd, platform)
-	genericToTarget(generic, target_language, output_file)
+    generic = sccdToGeneric(sccd, platform)
+    genericToTarget(generic, target_language, output_file)
 
 def xmlToSccd(xml_file):
-	cd = ClassDiagram(xml_file) # create AST
-	cd.accept(SuperClassLinker())
-	#SuperClassLinker().visit(cd) # visitor linking super classs references
-	StateLinker().visit(cd) # visitor fixing state references
-	PathCalculator().visit(cd) # visitor calculating paths
-	return cd
-	
+    cd = ClassDiagram(xml_file) # create AST
+    cd.accept(SuperClassLinker())
+    #SuperClassLinker().visit(cd) # visitor linking super classs references
+    StateLinker().visit(cd) # visitor fixing state references
+    PathCalculator().visit(cd) # visitor calculating paths
+    return cd
+    
 def sccdToGeneric(sccd, platform):
-	succesfull_generation = False
-	generator = GenericGenerator(platform)
-	sccd.accept(generator)
-	generic = generator.get()
-	Logger.showInfo("Classes <" + ", ".join(sccd.class_names) + "> have been converted to generic language constructs.")
-	return generic
+    succesfull_generation = False
+    generator = GenericGenerator(platform)
+    sccd.accept(generator)
+    generic = generator.get()
+    Logger.showInfo("Classes <" + ", ".join(sccd.class_names) + "> have been converted to generic language constructs.")
+    return generic
 
 def genericToTarget(generic, target_language, output_file):
-	try:
-		f = FileWriter(output_file)
-		if target_language == "javascript":
-			writer = JavascriptWriter(f)
-		elif target_language == "python":
-			writer = PythonWriter(f)
-		else:
-			raise Exception("Language not supported")
-		generic.accept(writer)
-		Logger.showInfo("Generic language constructs have been converted to target language constructs and have been written to file '" + output_file + "'.")
-	finally:
-		f.close()
+    try:
+        f = FileWriter(output_file)
+        if target_language == "javascript":
+            writer = JavascriptWriter(f)
+        elif target_language == "python":
+            writer = PythonWriter(f)
+        else:
+            raise Exception("Language not supported")
+        generic.accept(writer)
+        Logger.showInfo("Generic language constructs have been converted to target language constructs and have been written to file '" + output_file + "'.")
+    finally:
+        f.close()
 def main():
-	mapper = SCCD_ASG_Mapper()
-
-	parser = argparse.ArgumentParser()
-	parser.add_argument('input', help='The path to the XML file to be compiled.')
-	parser.add_argument('-o', '--output', type=str, help='The path to the generated code. Defaults to the same name as the input file but with matching extension.')
-	parser.add_argument('-v', '--verbose', type=int, help='2 = all output; 1 = only warnings and errors; 0 = only errors; -1 = no output.  Defaults to 2.', default = 2)
-	parser.add_argument('-p', '--platform', type=str, help="Let the compiled code run on top of threads, gameloop or eventloop. The default is eventloop.")
-	parser.add_argument('-l', '--language', type=str, help='Target language, either "javascript" or "python". Defaults to the latter.')
-	parser.add_argument('-m', '--mvklocation', type=str, help='Location in the Modelverse. After compilation the modelverse shell is opened.')
-	parser.add_argument('-justxml', dest='justxml', action='store_true')
-	parser.set_defaults(justxml=False)
-
-
-	args = vars(parser.parse_args())
-	
-	#Set verbose
-	if args['verbose'] is not None:
-		if args['verbose'] in [-1, 0,1,2] :
-			Logger.verbose = args['verbose']
-		else :
-			Logger.showError("Invalid verbose argument.")
-	else :
-		Logger.verbose = 2
-
-	#Set source file
-	source = args['input'].lower()
-	if not source.endswith(".sccd") :
-		Logger.showError("Input file not valid.")
-		return
-
-	#Set target language
-	if args['language'] :
-		target_language = args['language']
-	else :
-		target_language = ""
-
-	#Set output file
-	if args['output'] :
-		output = args['output']
-	else:
-		output = os.path.splitext(os.path.split(source)[1])[0]
-		
-	#Set platform	
-	if args['platform'] :
-		args['platform'] = args['platform'].lower()
-		if args['platform'] == "threads" :
-			platform = Platforms.Threads
-		elif args['platform'] == "gameloop" :
-			platform = Platforms.GameLoop
-		elif args['platform'] == "eventloop" :
-			platform = Platforms.EventLoop
-		else :
-			Logger.showError("Invalid platform.")
-			return		  
-	else :
-		platform = Platforms.Threads
-
-	if args['mvklocation'] :
-		mvklocation = args['mvklocation']
-		modelverseshell = True
-	else:
-		mvklocation = 'temporaryLocation'
-		modelverseshell = False
-
-	if args['justxml']:
-		try :
-			generate(output+'.xml', output, target_language, platform)
-		except CompilerException as exception :
-			Logger.showError(str(exception));
-		return
-
-	context = MvKLoader(mapper.rules, mapper.metamodel_location, mapper.metamodel_path, mvklocation).load(source)
-	if(target_language == "javascript"):
-		compiler = SCCD_to_XML(XML2JavaScriptRules().rules, context.mvk)
-	else:
-		compiler = SCCD_to_XML(XML2PythonRules().rules, context.mvk)
-	compiler.compile(context.target+'.'+context.modelname)
-
-	if os.path.exists(output+'.xml'):
-		os.remove(output+'.xml')
-	compiler.outputTo(output+'.xml')
-
-	#Compile
-	try :
-		generate(output+'.xml', output, target_language, platform)
-	except CompilerException as exception :
-		Logger.showError(str(exception));
-
-	if(modelverseshell):
-		shell = Shell()
-		shell.mvk = context.mvk
-		shell.setupCommandLine()
+    mapper = SCCD_ASG_Mapper()
+
+    parser = argparse.ArgumentParser()
+    parser.add_argument('input', help='The path to the XML file to be compiled.')
+    parser.add_argument('-o', '--output', type=str, help='The path to the generated code. Defaults to the same name as the input file but with matching extension.')
+    parser.add_argument('-v', '--verbose', type=int, help='2 = all output; 1 = only warnings and errors; 0 = only errors; -1 = no output.  Defaults to 2.', default = 2)
+    parser.add_argument('-p', '--platform', type=str, help="Let the compiled code run on top of threads, gameloop or eventloop. The default is eventloop.")
+    parser.add_argument('-l', '--language', type=str, help='Target language, either "javascript" or "python". Defaults to the latter.')
+    parser.add_argument('-m', '--mvklocation', type=str, help='Location in the Modelverse. After compilation the modelverse shell is opened.')
+    parser.add_argument('-justxml', dest='justxml', action='store_true')
+    parser.set_defaults(justxml=False)
+
+
+    args = vars(parser.parse_args())
+    
+    #Set verbose
+    if args['verbose'] is not None:
+        if args['verbose'] in [-1, 0,1,2] :
+            Logger.verbose = args['verbose']
+        else :
+            Logger.showError("Invalid verbose argument.")
+    else :
+        Logger.verbose = 2
+
+    #Set source file
+    source = args['input'].lower()
+    if not source.endswith(".sccd") :
+        Logger.showError("Input file not valid.")
+        return
+
+    #Set target language
+    if args['language'] :
+        target_language = args['language']
+    else :
+        target_language = ""
+
+    #Set output file
+    if args['output'] :
+        output = args['output']
+    else:
+        output = os.path.splitext(os.path.split(source)[1])[0]
+        
+    #Set platform    
+    if args['platform'] :
+        args['platform'] = args['platform'].lower()
+        if args['platform'] == "threads" :
+            platform = Platforms.Threads
+        elif args['platform'] == "gameloop" :
+            platform = Platforms.GameLoop
+        elif args['platform'] == "eventloop" :
+            platform = Platforms.EventLoop
+        else :
+            Logger.showError("Invalid platform.")
+            return          
+    else :
+        platform = Platforms.Threads
+
+    if args['mvklocation'] :
+        mvklocation = args['mvklocation']
+        modelverseshell = True
+    else:
+        mvklocation = 'temporaryLocation'
+        modelverseshell = False
+
+    if args['justxml']:
+        try :
+            generate(output+'.xml', output, target_language, platform)
+        except CompilerException as exception :
+            Logger.showError(str(exception));
+        return
+
+    context = MvKLoader(mapper.rules, mapper.metamodel_location, mapper.metamodel_path, mvklocation).load(source)
+    if(target_language == "javascript"):
+        compiler = SCCD_to_XML(XML2JavaScriptRules().rules, context.mvk)
+    else:
+        compiler = SCCD_to_XML(XML2PythonRules().rules, context.mvk)
+    compiler.compile(context.target+'.'+context.modelname)
+
+    if os.path.exists(output+'.xml'):
+        os.remove(output+'.xml')
+    compiler.outputTo(output+'.xml')
+
+    #Compile
+    try :
+        generate(output+'.xml', output, target_language, platform)
+    except CompilerException as exception :
+        Logger.showError(str(exception));
+
+    if(modelverseshell):
+        shell = Shell()
+        shell.mvk = context.mvk
+        shell.setupCommandLine()
 
 if __name__ == "__main__":
-	main()
+    main()