| How to validate through all objects [message #1804307] | 
Fri, 22 March 2019 03:29   | 
 
Eclipse User  | 
 | 
 | 
   | 
 
Hi everyone! I just started learning Xtext and Xtend so please have patience with me :) 
 
I have written a following grammar: 
 
Model:
	'Program' name=ID ';'
	'START' 
		model+=(Student | Course | Enroll)* 
	'FINISH'
;
Student: 
	'Student' name=ID 
	// personal info
	'(' firstName=STRING lastName=STRING 'born' 'in' ageOfBirth=INT ')' 
	// student faculty - only fixed choices
	'studies' faculty=('Informatics' | 'Computing' | 'Electrotehnics') ';' 
; 
Course:
	'Course' name=ID '(' 'ECTS' ects=INT ')' (students+=[Student])?  ';'  
;
Enroll:
	'Enroll' students+=[Student](',' students+=[Student])* 'to' course=[Course] ';'
;
 
 
and I use the following validation to prevent duplicates: 
 
	@Check
	def checkDuplicateCourseEnrollement(Enroll enroll) {
		val names = newHashSet;
		for(i : enroll.students)
			if(!names.add(i.name))
				error("Duplicate entry: " + "\'" + i.name + "\'!",   
					MyDslPackage.Literals.ENROLL__STUDENTS, enroll.students.lastIndexOf(i));			
	}
} 
 
The problem is that my validation only works in this case: 
 
Enroll John, Mark, Mark to Mathematics; // duplicate 'Mark'  
 
but the following does not report an error: 
 
Enroll John to English;
Enroll John, Mark to English;  // I would like to have error here since John is already enrolled to English course
  
 
Help would be appreciated!
 |  
 |  
  | 
 | 
 | 
| Re: How to validate through all objects [message #1805189 is a reply to message #1804307] | 
Tue, 09 April 2019 10:43    | 
 
Eclipse User  | 
 | 
 | 
   | 
 
Hi! 
 
I would like to ask for help regarding code generator for the grammar I already posted. 
 
For generator, I wrote this method: 
 
		override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) {
        fsa.generateFile("generator.txt", '''
            «FOR student : resource.allContents.filter(Student).toIterable»
            Student «student.name»("«student.firstName»", "«student.lastName»", «student.ageOfBirth», "«student.faculty»");
            «ENDFOR»
            «FOR course : resource.allContents.filter(Course).toIterable»
            Course «course.name»(«course.ects»«FOR student : course.students», «student.name»«ENDFOR»);
            «ENDFOR»
        ''')
	} 
For the following application 
 
Program StudentDSL_Test; 
START 
	Course English (ECTS 6);  
	Student John ("John" "Johnston" born in 2000) studies Computing;
	Course Mathematics (ECTS 0) enroll John; 
	Student Mark ("Mark" "Markston" born in 2002) studies Informatics;
FINISH
 
it will generate: 
 
Student John("John", "Johnston", 2000, "Computing");
Student Mark("Mark", "Markston", 2002, "Informatics");
Course English(6);
Course Mathematics(0, John);
 
The result is as expected; first Student code is generated and then Course code. BUT, how do I rewrite my generator example to respect the order of created objects? In the DSL example above, I would like to have the following generated code: 
 
Course English(6);
Student John("John", "Johnston", 2000, "Computing");
Course Mathematics(0, John);
Student Mark("Mark", "Markston", 2002, "Informatics"); 
I suspect I need to iterate through StudentDSL, but don't know how..
[Updated on: Tue, 09 April 2019 10:46] by Moderator  
 |  
 |  
  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
| Re: How to validate through all objects [message #1805203 is a reply to message #1805201] | 
Tue, 09 April 2019 15:33    | 
 
Eclipse User  | 
 | 
 | 
   | 
 
Please let me revise: 
 
Grammar: 
StudentDSL:
	'Program' name=ID ';'
	'START' 
		studentDSL+=(Student | Course | Enroll)* 
	'FINISH'
;
Student: 
	'Student' name=ID 
	// personal info
	'(' firstName=STRING lastName=STRING 'born' 'in' ageOfBirth=INT ')' 
	// student faculty - only fixed choices
	'studies' faculty=('Informatics' | 'Computing' | 'Electrotehnics') ';' 
; 
Course:
	'Course' name=ID
	// how many ECTS? 
	'(' 'ECTS' ects=INT ')'
	// enroll students (optional)  
	('enroll' students+=[Student](',' students+=[Student])*)?  
	';'  
;
Enroll:
	'Enroll' students+=[Student](',' students+=[Student])* 'to' course=[Course] ';'
; 
 
This is the test DSL application: 
 
Program StudentDSL_Test; 
START 
	Student John ("John" "Johnston" born in 2000) studies Computing;
	Course English (ECTS 6);  
	Student Mark ("Mark" "Markston" born in 2002) studies Informatics;
	Course Mathematics (ECTS 0) enroll John; 
	Enroll John, Mark to Mathematics; 
FINISH
 
 
And this is what I am trying to get with the code generator: 
 
    Student John("John", "Johnston", 2000, "Computing");
    Course English(6);
    Student Mark("Mark", "Markston", 2002, "Informatics");
    Course Mathematics(0, John);
    Mathematics.Enroll(John, Mark);
 
 
I appreciate your time & help :) Please let me know if you need me to clarify anything else. 
[Updated on: Tue, 09 April 2019 15:34] by Moderator  
 |  
 |  
  | 
 | 
 | 
 | 
 | 
 | 
| Re: How to validate through all objects [message #1805212 is a reply to message #1805209] | 
Tue, 09 April 2019 16:29   | 
 
Eclipse User  | 
 | 
 | 
   | 
 
Did it! 
 
	override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) {
		val root = resource.contents.get(0) as StudentDSL;
		fsa.generateFile("program_cpp.txt", '''
		«FOR item : root.studentDSL»
		«IF item instanceof Student»
		Student «item.name»("«item.firstName»", "«item.lastName»",«item.ageOfBirth»);
		«ELSEIF item instanceof Course»
		Course «item.name»(«item.ects»);
		«ELSEIF item instanceof Enroll»
		«item.course.name».Enroll(«FOR stud : item.students SEPARATOR ', '»«stud.name »«ENDFOR»);
		«ELSE»
		Unrecognized type: «item.eClass.name»
		«ENDIF»
		«ENDFOR»            
        ''')
	} 
 |  
 |  
  | 
Powered by 
FUDForum. Page generated in 0.52306 seconds