On this page ...

Using the Context

Now that we’ve established how to determine basic runtime values, we can continue with the heavy work: connecting all elements. This is where the context plays its role.

Evaluation of a Step

We’re working bottom-up, so the next concept to implement is Step.
Each step has a fromPage and a series of answers to the questions on that page, as shown below.

Image 'examples/Interpreter/TestB.png' seems to be missing
Figure 1. The steps in a test

What we need to do is:

  1. Compare the given answers for each question on the fromPage with the correct answers, and determine the number of correct answers.
  2. Based on the answers, find the grade from the fromPage.
  3. Using the grade, consult the page flow to find the page to switch to.
  4. Return that page as the runtime value for this step.

Let’s look at the implementation step by step.

Number of Correct Answers

// EducationInterpreter/src/custom/interpreter/EducationInterpreter.ts#L113-L126

// Put the page for this step in the context
const newCtx = new InterpreterContext(ctx)

// Find the nr of correct answers and add it to the context
let nrOfCorrectAnswers = 0
for (const answer of node.answerSeries) {
    const actualAnswer = main.evaluate(answer.value, newCtx)
    // Store the actual answer with the question.
    newCtx.set(answer.$question, actualAnswer)
    const expectedAnswer = main.evaluate(answer.$question.correctAnswer, newCtx)
    if (actualAnswer.equals(expectedAnswer)) {
        nrOfCorrectAnswers++
    }
}

Contexts can be nested. We create a new context with the parent ctx
(new InterpreterContext(ctx)). For every answer we evaluate the given value and store it in the context (newCtx.set(...)). Recall from evalQuestionReference that we retrieve a given answer by looking it up in the context:

// EducationInterpreter/src/custom/interpreter/EducationInterpreter.ts#L190-L190

const givenAnswer = ctx.find(question)

During the loop we also count correct answers, which we’ll store in the context.

The Grade

Now we have enough information to determine the grade of the fromPage:

// EducationInterpreter/src/custom/interpreter/EducationInterpreter.ts#L128-L129


// Find the grade for the given answers

We use the context that contains NR_OF_CORRECT_ANSWERS, because page evaluation may depend on it.

The Page to Present to the Pupil

In the model, the page flow is defined in a Flow model unit.
To decide which page to show next (given the current grade), the current flow must be available. A Step node doesn’t know which flow to use, so we carry it in the context under the name CURRENT_FLOW (the overall test evaluation stores this value).

From the flow we obtain the rule for the current page, then the transition for the computed grade:

// EducationInterpreter/src/custom/interpreter/EducationInterpreter.ts#L131-L147


//  Find rule for current page
const currentFlow = ctx.find("CURRENT_FLOW") as RtFlow
if (isNullOrUndefined(currentFlow)) {
    return new RtError(`No flow found for page ${currentPage.name}`)
}

const pageRule: FlowRule = currentFlow.flow.rules.find((rule) => rule.$page === currentPage)
if (isNullOrUndefined(pageRule)) {
    return new RtError(`No rules found for page ${currentPage.name} in ${currentFlow.flow.name}`)
}

// Find the page to which the application should switch based on the calculated grade,
// and return it as the result of evaluating this step
const transition = pageRule.transitions.find((trans) => trans.$condition === (grade as RtGrade).grade)
if (isNullOrUndefined(transition)) {
    return new RtError(`No transition found for grade ${grade.grade} on page ${currentPage.name} in ${currentFlow.flow.name}`)

All that’s left is to return the found page:

// EducationInterpreter/src/custom/interpreter/EducationInterpreter.ts#L150-L150

return new RtPage(transition.$toPage)
© 2018 - 2025 Freon contributors - Freon is open source under the MIT License.