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.11299 seconds