fuhrmanator / gift-grammar-peg.js Goto Github PK
View Code? Open in Web Editor NEWDevelopment of PEG grammar to support GIFT (quiz) format
License: MIT License
Development of PEG grammar to support GIFT (quiz) format
License: MIT License
Consider the following input:
[html]Blah\nblah $ 1 \\neq 0 $ {}
On peggyjs.org/online it parses as:
[
{
type: 'Essay',
title: null,
stem: {
format: 'html',
text: 'Blah\\nblah $ 1 \\neq 0 $ '
},
hasEmbeddedAnswers: false,
globalFeedback: null,
id: null,
tags: null
}
]
We can see that the \n
is now escaped, which seems very much like a bug. The current editor tries to replace the \n
with <br/>
, but since the string is actually \\n
(contains a real backslash rather than a newline), the display code breaks the \\neq
string in the katex expression.
Probably we need more tests for these cases, as Moodle allows using \n
in GIFT especially with [html] and [markdown] types.
There is some strange behaiviour in matching questions, e.g.:
Please match the following\:
{
=abc -> ...
=xyz -> , . ,
}
Symbols like .
and ,
lead to errors in the parser, however don't show where the error is (e.g. give line number), as done with other errors. I am not sure if this is "correct". I tried the Moodle Import for the above question and it works correctly.
GIFT isn't so user-friendly, but perhaps it could be helped by autocompletion inside a smart editor? With a grammar this should be feasible. Precedent with PEG.js exists given this answer on stackoverflow: http://stackoverflow.com/a/7857785/1168342
Here's a grammar with a kind of auto-complete: https://github.com/mstefaniuk/Concrete-Freetext/blob/master/grammar/concrete-grammar-template.pegjs
The current parser doesn't parse the title of this description question (exported from Moodle) into the title object (it gets parsed into the stem):
// question: 279223 name: Description Title
::Description Title::[html]Here's a description for the next question.
Title is missing in the grammar for Description.
The following question won't parse (:'s need to be escaped in GIFT).
// multiple choice with multiple good answer (checkbox)
Indicate two people are entombed in Grant's tomb\: {
~%-100%No one
~%50%Grant # yup its good
~%50%Grant's wife
~%-100%Grant's father
}
Despite all the short-answer tests (that appear to pass), this format is producing "MC" type questions. The grammar doesn't define Short Answer anywhere.
According to this reference:
Answers in Short Answer question-type are all prefixed by an equal sign (=),
indicating that they are all correct answers. The answers must not contain a
(~). If there is only one correct Short Answer, it may be written without the
equal sign prefix, as long as it cannot be confused as True-False. For short
answer, feedback is shown only when students input the
corresponding correct answer.
Currently global feedback (Rétroaction générale) don't get parsed (in numerical questions at least).
// question: 229196 name: Test Numerical
::Test Numerical::Whats two plus 4?{#
=%100%6:0#Good job its really 6!
####2+4 \= 6
}
Line 2, column 36: Expected {#... }, {= match1 -> Match1 ...}, {=correct choice ~incorrect choice ... }, or {T} or {F} or {True} or {False} but "{" found.
[
{
"type": "Numerical",
"title": "Test Numerical",
"stem": "Whats two plus 4?",
"hasEmbeddedAnswers": false,
"choices": [
{
"isCorrect": true,
"weight": 100,
"text": {
"type": "range",
"number": 6,
"range": 0
},
"feedback": "Good job its really 6!",
"globalFeedBack": "2+4 = 6"
}
]
}
]
On my side this issues don't need to be fixed. Just wanted to notify you.
{=1..5}
(perhaps not complete list)
See http://nathansuniversity.com/pegs7.html for an explanation, but essentially:
var PEG = require('pegjs');
var assert = require('assert');
var fs = require('fs'); // for loading files
// Read file contents
var data = fs.readFileSync('my.peg', 'utf-8');
// Show the PEG grammar file
console.log(data);
// Create my parser
var parse = PEG.buildParser(data).parse;
// Do a test
assert.deepEqual( parse("(a b c)"), ["a", "b", "c"] );
Explode individual examples from https://github.com/fuhrmanator/GIFT-grammar-PEG.js/blob/master/Moodle%20test%20input%20examples.txt into separate files, and perform assert.deepEqual
on each.
When using a numerical question, having a negative value is considered an error where it shouldn't be.
Here is an example:
import { parse } from "gift-pegjs";
const question = "What is the value of -1? {#-1}."
const quiz = parse(question)
It breaks with this: <!-- -->
::EE_mod_05_T39_P079::[html]<p>¿En qué supuestos podría el Fiscal autorizar a la Policía Judicial la práctica de una diligencia de entrada y registro?</p>{
~[moodle]En ausencia del Juez de Instrucción, titular de la actuaciones, y por razones de urgencia, debidamente acreditadas.
~[moodle]Cuando se trate de delitos de terrorismo.
=[moodle]Nunca.
####<p><span style\="color\: \#ff6600;"><strong>Artículo 5 Estatuto Orgánico del Ministerio Fiscal\:</strong></span></p>\n<p><em><strong>Dos.</strong> Igualmente, y para el esclarecimiento de los hechos denunciados o que aparezcan en los atestados de los que conozca, <span style\="background-color\: \#ffcc99;">puede llevar a cabo u ordenar aquellas diligencias para las que esté legitimado según la <span style\="color\: \#000000;"><a href\="http\://www.formacioncnp.es/base_datos/Penal/lecr.html"><span style\="color\: \#000000; background-color\: \#ffcc99;"><!--<var>LE0000017566_20130224</var>-->Ley de Enjuiciamiento Criminal</span></a></span>, las cuales no podrán suponer la adopción de medidas cautelares o limitativas de derechos. No obstante, podrá ordenar el Fiscal la detención preventiva</span>.</em></p>\n<p> </p>
}
See the embedded tests in https://github.com/totara/moodle/blob/master/question/format/gift/tests/giftformat_test.php
GIFT format supports tags in comments, see https://tracker.moodle.org/browse/MDL-68338
Consider the test file:
GIFT-grammar-PEG.js/tests/questions/symbolsAll.gift
Lines 1 to 3 in 731b922
When imported into Moodle, the text is different from:
That is, the brackets [
and ]
have \
before them in Moodle, implying they don't need escaping. Indeed, removing the \
and re-exporting to GIFT shows they don't take \
at all. This is a bad test file (and the grammar needs to be fixed).
I just installed gift-pegjs in a Electron program and although it works perfectly, I miss being able to locate in which line or question parsing error occurs. I have searched but found no references to error management. Where could I find documentation?
Best regards
Alfonso
// true/false
::Q1:: Es 1+1:=2 {
T}
Moodle will refuse GIFT imports of multiple choice questions if answer weights don't match ones on the list, e.g.:
So, it means that a question like the following will fail to import, because it's not using the precise weights of -33.33333
:
Pick the best answers: {
~%-33%A
~%-33%B
=C
~%-34%D
}
We could add to the grammar options for the Moodle-specific values so as to flag the error before importing.
True or false with feedback for positive and negative answer dont get parse correctly:
Grant is buried in Grant's tomb.{FALSE#wrong answer feedback#right answer feedback}
[
{
"type": "TF",
"title": null,
"stem": "Grant is buried in Grant's tomb.",
"hasEmbeddedAnswers": false,
"isTrue": false,
"feedBack1": "right answer feedback",
"feedBack2": undefined
}
]
[
{
"type": "TF",
"title": null,
"stem": "Grant is buried in Grant's tomb.",
"hasEmbeddedAnswers": false,
"isTrue": false,
"feedBack1": "right answer feedback",
"feedBack2": "wrong answer feedback"
}
]
Since the original PEG.js hasn't been maintained in a while, a new fork of the project called Peggy was created by the community. It appears to be a drop-in replacement, but will require a bit of testing to see whether previous PEG plugins are still compatible with this fork.
The current version of the parser fails to properly load categories when they contains a ":". This is an example of an exported GIFT from Moodle that fails to parse:
$CATEGORY:
$course$ /top/Default for LING-373-2194-B/Set theory: Unit 4
->
// question: 882007 name: iebT26nuevo_P012
::iebT26nuevo_P012::¿Cómo se cambia la orientación de la página en Word 2003 y 2007?\:{
~todas las versiones de Word cambian la orientación de página igual (archivo->diseño de página)
~-archivo->configurar->orientación ó -archivo->configurar->diseño de página
=-archivo-configurar página ó -diseño de página-orientación
}
This GIFT question fails to parse:
::Q6:: What is a number from 1 to 5? {#1..5}
It seems that was never put into the grammar for lack of a test file.
Continued from ethan-ou/vscode-gift#7
New lines should be handled in the GIFT parser so that \n adds a new line and blank lines delimit questions.
Alternative way to parse text, using look-ahead. This might ultimately allow for better syntax errors, as the capturing with "." is more generous.
Here's a prototype that works for T/F.
{
function joinLookAheadCapture(o) {
var s = "";
for (var i = 0; i < o.length; i++) {
s += o[i][1];
}
return s;
}
}
Question = Title? QuestionText Answer
Title "Title"
= TitleStart title:(!TitleEnd .)* TitleEnd { return joinLookAheadCapture(title) }
TitleStart = "::"
TitleEnd = "::"
QuestionText "Text" = answer:(!AnswerStart .)* { return joinLookAheadCapture(answer) }
Answer "Answer"
= AnswerStart answer:AnswerContent AnswerEnd { return answer}
AnswerContent "Answer variants" = AnswerTF
AnswerTF "T/F Answer"
= answer:(TrueAnswer / FalseAnswer ) fb1:FeedbackIncorrectTF? fb2:FeedbackCorrectTF? { return [answer, fb1, fb2]}
TrueAnswer "TRUE" = "TRUE"i
FalseAnswer "FALSE" = "FALSE"i
FeedbackIncorrectTF = FeedbackStart feedback:(!(FeedbackStart / AnswerEnd) .)* { return joinLookAheadCapture(feedback) }
FeedbackCorrectTF = FeedbackStart feedback:(!AnswerEnd .)* { return joinLookAheadCapture(feedback) }
FeedbackStart "Feedback start" = "#"
AnswerStart = "{"
AnswerEnd = "}"
I wanted to open an issue to start discussing how we can transform the parsed JSON back into GIFT text. Doing so would allow things like changing question types (like changing from multiple choice to matching questions in the editor) and even open the possibility of building a standalone editor that exports GIFT as a byproduct.
We're both pretty busy so I'm happy to just leave the idea here and we can work on it async when we've got some time.
Here's an example of the output from https://travis-ci.org/fuhrmanator/GIFT-grammar-PEG.js/jobs/402803321
21 passing (197ms)
3 failing
GIFT parser harness:
parsing GIFT question: ./tests/questions/giftFormatPhpExamples.gift:
AssertionError [ERR_ASSERTION]: Deep equal does not match
"text": "Match the following countries with their corresponding\ncapitals."
"text": "Match the following countries with their corresponding capitals."
at Context. (tests/all-questions-harness.js:34:20)
GIFT parser harness:
parsing GIFT question: ./tests/questions/multiLineFeedback1.gift:
AssertionError [ERR_ASSERTION]: Deep equal does not match
"text": "feedback comment on this wrong answer\non multiple lines"
"text": "feedback comment on this wrong answer on multiple lines"
}
"isCorrect": false
"text": {
"format": "moodle"
--
}
]
"globalFeedback": {
"format": "moodle"
- "text": "Global feedback split\non multiple lines"
+ "text": "Global feedback split on multiple lines"
}
"hasEmbeddedAnswers": false
"stem": {
"format": "moodle"
at Context.<anonymous> (tests/all-questions-harness.js:34:20)
"text": "Japanese characters originally\ncame from what country?"
"text": "Japanese characters originally came from what country?"
"text": "The American holiday of Thanksgiving is\ncelebrated on the _____ Thursday of November."
"text": "The American holiday of Thanksgiving is celebrated on the _____ Thursday of November."
it breacks with ::title\:::stem{
::Al concebido\:::[html]<p>Al concebido\:</p>{
~[moodle]Se le tiene por nacido para todos los efectos que le sean favorables o desfavorables
=[moodle]Se le tiene por nacido para todos los efectos que le sean favorables
~[moodle]El Código Civil no se refiere a este supuesto
####<p><span style\="color\: \#ff0000;"><strong>Artículo 29 Código Civil\:</strong></span></p>\n<p><em>El nacimiento determina la personalidad; pero <span style\="background-color\: \#ffcc99;">el concebido se tiene por nacido para todos los efectos que le sean favorables</span>, siempre que nazca con las condiciones que expresa el artículo siguiente.</em></p>\n<p> </p>
}
It would be handy to publish a parser generated from the grammar on npm. Maybe it could be named simply gift-parser or gift-js maybe a reference to peg.js should be included.
Hello hello. I believe the types aren't working at the moment since they aren't being included in the final NPM package. We'll need to copy them over to the final package for them to work.
It should be easy for us to do this by including the types in the files
section of the package.json
.
Importing the following question into Moodle will result in a short answer question, not a true/false question:
Question {True}
The current parser based on the grammar recognizes it as True/False.
The GIFT format supported by Moodle requires all capitals: {T} {TRUE} {F} {FALSE}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.