Skip to main content
aboutsummaryrefslogblamecommitdiffstats
blob: 4c534995c463136abdb03e47fe87d584bef36335 (plain) (tree)
1
2
3

                                        
                                                                                                    




































                                                          
                                              





                                            

                                                     







                                                                                  
                                                                       







                                                                 
                                             




















































                                                                                           
                                             






                                               
                                              














































                                                                                                                               
                                                   






                                
                                                 











































                                                                                 
                                                       





                                       
                                    





                                       
                                                    













                                                                 
                                           
                                    
                                         




























                                                               
                                                                  



                                               
                                                                          

































                                                       
                                        






                                 
                                            







                                    
                                    

















                                                                                                                          



                                
                                         

         



                                
                                         

         






                                         



                                
                                         





                                
                                         





                                
                                         





                                
                                         





                                
                                         





                                 
                                         





                                
                                         





                                
                                         





                                
                                         





                                
                                         







                                    
                                    







                                     
                                    







                                     
                                    















                                         
                                    















                                         
                                    






                                    
                                    

         




                                    
                                    

         




                                    
                                    






                                    
                                    






                                    
                                    








                                          
                                    






                                          
                                    

























































































                                                                         



                                                                           















































                                                                                                        
-- @authors		Frédéric Jouault
-- @date		2007/07/25
-- @description	This ACG code generator generates .asm files that run on the ATL VM from ACG models.
acg ACG startsWith ACG {

	function Node::suffix() =
		if self.mode.oclIsUndefined() then
			''
		else
			'_' + self.mode
		endif;

	function AnalyzeStat::suffix() =
		if self.mode.oclIsUndefined() then
			''
		else
			'_' + self.mode
		endif;

	asm ACG
			name self.metamodel + 'Compiler' {
		field 'asmEmitter' : 'J'
		field 'col' : 'J'
		field 'fileName' : 'S'

		operation
				context 'A'
				name 'main' {
			param 'WriteTo' : 'S'

			getasm
			load 'WriteTo'
			set 'fileName'

			getasm
			push 'OclParametrizedType'
			push '#native'
			new
			dup
			push 'Collection'
			pcall 'J.setName(S):V'
			dup
			push 'OclSimpleType'
			push '#native'
			new
			dup
			push 'OclAny'
			pcall 'J.setName(S):V'
			pcall 'J.setElementType(J):V'
			set 'col'
			
			foreach(a in self.elements->select(e | e isa Attribute)) {
				push a.context
				push self.metamodel
				findme
				push a.name
				push '__init' + a.name
				pcall 'J.registerHelperAttribute(SS):V'
			}

			push self.startsWith
			push self.metamodel 
			findme
			call 'MMOF!Classifier;.allInstances():QJ'
			call 'QJ.asSequence():QJ'
			call 'QJ.first():J'
			pcall 'J.process():V'
		}

		operation
				context 'J'
				name 'process' {
			push 'Error: could not find matching node for '
			load 'self'
			call 'J.oclType():J'
			get 'name'
			call 'S.+(S):S'
			push ' at '
			call 'S.+(S):S'
			load 'self'
			get 'location'
			call 'S.+(S):S'
			push 'BEGIN'
			call 'J.debug(S):J'
		}

		analyze self.elements
	}

	Function {
		operation
				context 'M' + self.acg.metamodel + '!' + self.context + ';'
				name self.name {
			foreach(p in self.parameters) {
				param p.name : 'J'
			}
			analyze self.body
		}
	}
	
	Attribute {
		operation
				context 'M' + self.acg.metamodel + '!' + self.context + ';'
				name '__init' + self.name {
			analyze self.body
		}
	}
-- @begin Nodes
	ASMNode {
		operation
				context 'M' + self.acg.metamodel + '!' + self.element + ';'
				name 'process' + self.suffix() {
			getasm
			dup
			push 'ASMEmitter'
			push '#native'
			new
			set 'asmEmitter'
			get 'asmEmitter'
			analyze self.name
			pcall 'J.newASM(S):V'

			analyze self.statements

			getasm
			get 'asmEmitter'
			getasm
			get 'fileName'
			pcall 'J.dumpASM(S):V'
		}
	}

	-- For the first node with the same element we generate the process operation that handles all of them.
	Node {
		let nodesWithSameContext = self.acg.nodes()->select(e | e.element = self.element and e.mode = self.mode) {
			if(nodesWithSameContext.indexOf(self) = 1) {
				operation
						context 'M' + self.acg.metamodel + '!' + self.element + ';'
						name 'process' + self.suffix() {

					analyze self mode head

					foreach(n in nodesWithSameContext->select(e | not e.guard.oclIsUndefined())) {
						analyze n.guard
						call 'B.not():B'
						if thn
							analyze n.statements
							goto end
					    thn(n):
					}
					let unguarded = nodesWithSameContext->select(e | e.guard.oclIsUndefined()).first() {
						if(not unguarded.oclIsUndefined()) {
							analyze unguarded.statements
						} else {
							push 'Error: could not find matching node for ' + self.element + ' at '
							load 'self'
							get 'location'
							call 'S.+(S):S'
							push 'BEGIN'
							call 'J.debug(S):J'
						}
					}

					
				    end:
					analyze self mode tail
				}
			}
		}
	}

	CodeNode mode head {
		getasm
		get 'asmEmitter'
		load 'self'
		get 'location'
		pcall 'J.beginLineNumberEntry(S):V'
	}

	CodeNode mode tail {
		getasm
		get 'asmEmitter'
		load 'self'
		get 'location'
		pcall 'J.endLineNumberEntry(S):V'
	}

	SimpleNode mode head {}

	SimpleNode mode tail {}
-- @end Nodes

-- @begin Statements
-- @begin CompoundStats
	function ACG::nodes() = self.elements->select(e | e isa Node);

	code ForEachStat {
		analyze self.collection
		variable self named 'forEach' {
			load self
			iterate
				variable self.iterator named self.iterator.name {
					analyze self.statements
				}
			enditerate
		}
	}

	function Statement::forEach() =
		if self.refImmediateComposite() isa ForEachStat then
			self.refImmediateComposite()
		else
			self.refImmediateComposite().forEach()
		endif;

	code OnceStat {
		enditerate
		analyze self.statements
		load self.forEach()
		iterate
		store self.forEach().iterator
	}

	code VariableStat {
		getasm
		get 'asmEmitter'
		analyze self.definition
		get '__xmiID__'
		analyze self.name
		pcall 'J.beginLocalVariableEntry(SS):V'

		getasm
		get 'asmEmitter'
		push 'store'
		analyze self.definition
		get '__xmiID__'
		pcall 'J.emit(SS):V'
		analyze self.statements

		getasm
		get 'asmEmitter'
		analyze self.definition
		get '__xmiID__'
		pcall 'J.endLocalVariableEntry(S):V'
	}

	code LetStat {
		analyze self.value
		variable self.variable named self.variable.name {
			analyze self.statements
		}
	}

	code OperationStat {
		getasm
		get 'asmEmitter'
		dup
		analyze self.name
		pcall 'J.addOperation(S):V'
		analyze self.context
		pcall 'J.setContext(S):V'

		analyze self.statements
	}

	code ConditionalStat | self.elseStatements.size() = 0 {
		analyze self.condition
		call 'B.not():B'
		if thn
			analyze self.statements
	    thn:
	}

	code ConditionalStat {
		analyze self.condition
		if thn
			analyze self.elseStatements
			goto eoi
	    thn:
			analyze self.statements
	    eoi:
	}

	code AnalyzeStat {
		analyze self.target
		dup
		getasm
		get 'col'
		call 'J.oclIsKindOf(J):B'
		if thn
			pcall 'J.process' + self.suffix() + '():V'
			analyze self.statements
			goto eoi
	    thn:
			iterate
				pcall 'J.process' + self.suffix() + '():V'
				analyze self.statements
			enditerate
	    eoi:
	}
-- @end CompoundStats

	code ReportStat {
		push 'Problem'
		push 'Problem'
		new
		
		dup
		push 'EnumLiteral'
		push '#native'
		new
		dup
		push self.severity.toString()
		set 'name'
		set 'severity'
		
		dup
		analyze self.message
		set 'description'
		
		load 'self'
		get 'location'
		set 'location'
	}

	code FieldStat {
		getasm
		get 'asmEmitter'
		analyze self.name
		analyze self.type
		pcall 'J.addField(SS):V'
	}

	code ParamStat {
		getasm
		get 'asmEmitter'
		analyze self.name
		analyze self.type
		pcall 'J.addParameter(SS):V'
	}

-- @begin EmitStats
	code LabelStat {
		getasm
		get 'asmEmitter'
		push 'label'
		analyze self mode id
		pcall 'J.emit(SS):V'
	}

	-- TODO: there is a problem here, when a label is in a loop, because the same "location" may be used
	-- several times.
	-- Cannot be a CodeNode because there is already a line number entry for it (in default mode, see above)
	LabelStat mode id {
		load 'self'
		get 'location'
		push self.location	-- __xmiID__ does not work, sometimes there are several with same value!!!
		call 'S.+(S):S'
		if(not self.id.oclIsUndefined()) {
			analyze self.id
			get '__xmiID__'
			call 'S.+(S):S'
		}
					-- what is important is that it is unique, name cannot be guarranteed to be unique
	}

	code NewinStat {
		getasm
		get 'asmEmitter'
		push 'newin'
		pcall 'J.emitSimple(S):V'
	}

	code NewStat {
		getasm
		get 'asmEmitter'
		push 'new'
		pcall 'J.emitSimple(S):V'
	}

	code DeleteStat {
		getasm
		get 'asmEmitter'
		push 'delete'
		pcall 'J.emitSimple(S):V'
	}

	code DupStat {
		getasm
		get 'asmEmitter'
		push 'dup'
		pcall 'J.emitSimple(S):V'
	}

	code DupX1Stat {
		getasm
		get 'asmEmitter'
		push 'dup_x1'
		pcall 'J.emitSimple(S):V'
	}

	code PopStat {
		getasm
		get 'asmEmitter'
		push 'pop'
		pcall 'J.emitSimple(S):V'
	}

	code SwapStat {
		getasm
		get 'asmEmitter'
		push 'swap'
		pcall 'J.emitSimple(S):V'
	}

	code IterateStat {
		getasm
		get 'asmEmitter'
		push 'iterate'
		pcall 'J.emitSimple(S):V'
	}

	code EndIterateStat {
		getasm
		get 'asmEmitter'
		push 'enditerate'
		pcall 'J.emitSimple(S):V'
	}

	code GetAsmStat {
		getasm
		get 'asmEmitter'
		push 'getasm'
		pcall 'J.emitSimple(S):V'
	}

	code FindMEStat {
		getasm
		get 'asmEmitter'
		push 'findme'
		pcall 'J.emitSimple(S):V'
	}

	code PushTStat {
		getasm
		get 'asmEmitter'
		push 'pusht'
		pcall 'J.emitSimple(S):V'
	}

	code PushFStat {
		getasm
		get 'asmEmitter'
		push 'pushf'
		pcall 'J.emitSimple(S):V'
	}

-- @begin EmitWithOperandStats
	code PushStat {
		getasm
		get 'asmEmitter'
		push 'push'
		analyze self.operand
		pcall 'J.emit(SS):V'
	}

	code PushIStat {
		getasm
		get 'asmEmitter'
		push 'pushi'
		analyze self.operand
		call 'J.toString():S'
		pcall 'J.emit(SS):V'
	}

	code PushDStat {
		getasm
		get 'asmEmitter'
		push 'pushd'
		analyze self.operand
		call 'J.toString():S'
		pcall 'J.emit(SS):V'
	}

	code LoadStat {
		getasm
		get 'asmEmitter'
		push 'load'

		analyze self.operand
		dup
		push 'String'
		push '#native'
		findme
		call 'J.oclIsKindOf(J):B'
		if thn
		get '__xmiID__'
	    thn:
		pcall 'J.emit(SS):V'
	}

	code StoreStat {
		getasm
		get 'asmEmitter'
		push 'store'

		analyze self.operand
		dup
		push 'String'
		push '#native'
		findme
		call 'J.oclIsKindOf(J):B'
		if thn
		get '__xmiID__'
	    thn:
		pcall 'J.emit(SS):V'
	}

	code CallStat {
		getasm
		get 'asmEmitter'
		push 'call'
		analyze self.operand
		pcall 'J.emit(SS):V'
	}

	code PCallStat {
		getasm
		get 'asmEmitter'
		push 'pcall'
		analyze self.operand
		pcall 'J.emit(SS):V'
	}

	code SuperCallStat {
		getasm
		get 'asmEmitter'
		push 'supercall'
		analyze self.operand
		pcall 'J.emit(SS):V'
	}

	code GetStat {
		getasm
		get 'asmEmitter'
		push 'get'
		analyze self.operand
		pcall 'J.emit(SS):V'
	}

	code SetStat {
		getasm
		get 'asmEmitter'
		push 'set'
		analyze self.operand
		pcall 'J.emit(SS):V'
	}
-- @end EmitWithOperandStats

-- @begin EmitWithLabelRefStats
	code IfStat {
		getasm
		get 'asmEmitter'
		push 'if'
		analyze self.label mode id
		pcall 'J.emit(SS):V'
	}

	code GotoStat {
		getasm
		get 'asmEmitter'
		push 'goto'
		analyze self.label mode id
		pcall 'J.emit(SS):V'
	}
-- @end EmitWithLabelRefStats
-- @end EmitStats
-- @end Statements

-- @begin Expressions
	code VariableExp | self.variable isa Parameter {
		load self.variable.name
	}

	code VariableExp {
		load self.variable
	}

	code SelfExp {
		load 'self'
	}

	code LastExp {	-- TODO: handle nested foreach
		load 'last'
	}

	code IfExp {
		analyze self.condition
		if thn
			analyze self.elseExp
			goto eoi
	    thn:
			analyze self.thenExp
	    eoi:
	}

	function LocatedElement::getACG() =
		if self.refImmediateComposite() isa ACG then
			self.refImmediateComposite()
		else
			self.refImmediateComposite().getACG()
		endif;

	code IsAExp {
		analyze self.source
		push self.type
		push self.getACG().metamodel
		findme
		call 'J.oclIsKindOf(J):B'
	}

	code LetExp {
		analyze self.value
		variable self.variable named self.variable.name {
			analyze self.in
		}
	}

-- @begin ProperyCallExps
	code NavigationExp {
		analyze self.source
		get self.name
	}

	code IteratorExp | self.name = 'collect' {
		push 'Sequence'
		push '#native'
		new
		analyze self.source
		iterate
			variable self.iterator named self.iterator.name {
				analyze self.body
				call 'CJ.including(J):CJ'
			}
		enditerate
	}

	code IteratorExp | self.name = 'select' {
		push 'Sequence'
		push '#native'
		new
		analyze self.source
		iterate
			variable self.iterator named self.iterator.name {
				analyze self.body
				call 'B.not():B'
				if thn
					load self.iterator
					call 'CJ.including(J):CJ'
			    thn:
			}
		enditerate
	}

	code IteratorExp {
		report error 'iterator \'' + self.name + '\' not supported'
	}
	
	code OperationCallExp {
		analyze self.source
		analyze self.arguments
		call 'J.' + self.name + '(' + self.arguments->collect(e | 'J').prepend('').sum() + '):J'
	}
-- @end ProperyCallExps

-- @begin LiteralExps

	code OclUndefinedExp {
		push 'Sequence'
		push '#native'
		new
		call 'QJ.first():J'
	}

-- @begin CollectionExps
	code SequenceExp {
		push 'Sequence'
		push '#native'
		new
		analyze self.elements {
			call 'CJ.including(J):CJ'
		}
	}
-- @end CollectionExps

-- @begin Primitive LiteralExps
	code BooleanExp | self.value {
		pusht
	}

	code BooleanExp | not self.value {
		pushf
	}

	code IntegerExp {
		pushi self.value
	}

	code StringExp {
		push self.value
	}
-- @end Primitive LiteralExps
-- @end LiteralExps
-- @end Expressions
}

Back to the top