Skip to content
Snippets Groups Projects
Commit 2afd66f8 authored by Chris Sangwin's avatar Chris Sangwin
Browse files

WIP: failed to make must sense of the error trapping.

parent 6de45ebd
No related branches found
No related tags found
No related merge requests found
......@@ -148,11 +148,7 @@ echo html_writer::tag('form',
if ($string) {
echo $OUTPUT->heading(stack_string('questionvariablevalues'), 3);
echo html_writer::start_tag('div', array('class' => 'questionvariables'));
// Display only the values of the question variables.
foreach ($kvss->get_session() as $var) {
$variables .= $var->get_evaluationform() . "\n";
}
echo html_writer::tag('pre', $variables);
echo html_writer::tag('pre', $kvss->get_keyval_representation());
echo html_writer::end_tag('div');
}
......
......@@ -921,12 +921,8 @@ class qtype_stack_question extends question_graded_automatically_with_countback
* effects in Maxima, e.g. orderless. If you use these values you may not get
* the same results as if you recreate the whole session from $this->questionvariables.
*/
public function get_question_var_values() {
$vars = array();
foreach ($this->session->get_all_keys() as $key) {
$vars[$key] = $this->session->get_value_key($key);
}
return $vars;
public function get_question_session_keyval_representation() {
return $this->session->get_keyval_representation();
}
/**
......
......@@ -150,12 +150,8 @@ echo html_writer::tag('pre', $question->questionvariables);
echo html_writer::end_tag('div');
echo $OUTPUT->heading(stack_string('questionvariablevalues'), 3);
$qvv = '';
foreach ($question->get_question_var_values() as $key => $value) {
$qvv .= s($key) . ':' . s($value) .";\n";
}
echo html_writer::start_tag('div', array('class' => 'questionvariables'));
echo html_writer::tag('pre', $qvv);
echo html_writer::tag('pre', $question->get_question_session_keyval_representation());
echo html_writer::end_tag('div');
// Display the question text.
......
......@@ -450,11 +450,7 @@ echo html_writer::tag('p', stack_ouput_castext($question->get_question_summary()
// Display the question variables.
echo $OUTPUT->heading(stack_string('questionvariablevalues'), 3);
echo html_writer::start_tag('div', array('class' => 'questionvariables'));
$displayqvs = '';
foreach ($question->get_question_var_values() as $key => $value) {
$displayqvs .= s($key) . ' : ' . s($value). ";\n";
}
echo html_writer::tag('pre', $displayqvs);
echo html_writer::tag('pre', $question->get_question_session_keyval_representation());
echo html_writer::end_tag('div');
// Display a representation of the PRT for offline use.
......
......@@ -125,21 +125,20 @@ class stack_answertest_general_cas extends stack_anstest {
$this->options->set_option('simplify', $this->simp);
}
$op = $this->atoption;
$cascommands = array();
// The prefix equality should be the identity function in the context of answer tests.
// The conversion "stackeq(x):=x" is now done at the ast level.
$sa = stack_ast_container::make_from_teacher_source('STACKSA:' . $this->sanskey, '', new stack_cas_security());
$ta = stack_ast_container::make_from_teacher_source('STACKTA:' . $this->tanskey, '', new stack_cas_security());
$sa = clone $this->sanskey;
$sa->set_key('STACKSA');
$ta = clone $this->tanskey;
$sa->set_key('STACKTA');
$ops = stack_ast_container::make_from_teacher_source('STACKOP:true', '', new stack_cas_security());
$result = stack_ast_container::make_from_teacher_source("result:{$this->casfunction}(STACKSA,STACKTA)", '',
new stack_cas_security());
if (!(!$this->processcasoptions || trim($op) === '')) {
$ops = stack_ast_container::make_from_teacher_source('STACKOP:' . $op, '', new stack_cas_security());
$res = stack_ast_container::make_from_teacher_source("result:{$this->casfunction}(STACKSA,STACKTA,STACKOP)", '',
$op = $this->atoption->get_inputform();
if (!(!$this->processcasoptions || trim($op === ''))) {
$ops = clone $this->atoption;
$ops->set_key('STACKOP');
$result = stack_ast_container::make_from_teacher_source("result:{$this->casfunction}(STACKSA,STACKTA,STACKOP)", '',
new stack_cas_security());
}
$session = new stack_cas_session2(array($sa, $ta, $ops, $result), $this->options, 0);
if ($session->get_valid()) {
$session->instantiate();
......
......@@ -93,8 +93,6 @@ class stack_ast_container extends stack_ast_container_silent implements cas_late
}
}
public function get_evaluationform(): string {
// The common_ast_container provides means of dealing with validation context.
if ($this->validationcontext === null) {
......@@ -144,7 +142,6 @@ class stack_ast_container extends stack_ast_container_silent implements cas_late
return $this->validationcontext['vname'] . ':' . $vcmd;
}
// This returns the fully filttered AST as it should be inputted were
// it inputted perfectly.
public function get_inputform(bool $keyless=false): string {
......@@ -183,8 +180,6 @@ class stack_ast_container extends stack_ast_container_silent implements cas_late
return $this->latex;
}
// If we "CAS validate" this string, then we need to set various options.
// If the teacher's answer is null then we use typeless validation, otherwise we check type.
public function set_cas_validation_context($vname, $lowestterms, $tans, $validationmethod, $simp) {
......@@ -207,7 +202,6 @@ class stack_ast_container extends stack_ast_container_silent implements cas_late
return $this->validationcontext;
}
public function get_value() {
if (null === $this->evaluated) {
throw new stack_exception('stack_ast_container: tried to get the value form of an unevaluated casstring.');
......@@ -265,6 +259,28 @@ class stack_ast_container extends stack_ast_container_silent implements cas_late
$this->feedback = $val;
}
/*
* We sometimes need to modify the ast to set a particular key.
*/
public function set_key($key) {
$root = $this->ast;
if ($root instanceof MP_Root) {
$root = $root->items[0];
}
if ($root instanceof MP_Statement) {
$root = $root->statement;
}
if ($root instanceof MP_Operation && $root->op === ':' &&
$root->lhs instanceof MP_Identifier) {
$root->lhs->value = $key;
}
// Otherwise set a key.
$ast = $this->ast;
$ast = new MP_Operation(':', new MP_Identifier($key), $ast);
$this->ast = $ast;
}
/**
* Replace the ast, with a human readable value, so we can test equality cleanly and dump values.
*/
......
......@@ -334,7 +334,7 @@ class stack_ast_container_silent implements cas_evaluatable {
/**
* This function decodes the error generated by Maxima into meaningful notes.
* */
public function decode_maxima_errors($error) {
public function decode_maxima_errors(string $error) {
$searchstrings = array('DivisionZero', 'CommaError', 'Illegal_floats', 'Lowest_Terms', 'SA_not_matrix',
'SA_not_list', 'SA_not_equation', 'SA_not_inequality', 'SA_not_set', 'SA_not_expression',
'Units_SA_excess_units', 'Units_SA_no_units', 'Units_SA_only_units', 'Units_SA_bad_units',
......
......@@ -130,7 +130,10 @@ class stack_cas_session2 {
return true;
}
public function get_by_key(string $key): cas_evaluatable {
/*
* TODO: set return value of : ?cas_evaluatable
*/
public function get_by_key(string $key) {
// Searches from the statements the last one with a given key.
// This is a concession for backwards compatibility and should not be used.
$found = null;
......@@ -272,11 +275,11 @@ class stack_cas_session2 {
$command .= ',print("<STACK-OUTPUT-ENDS")';
$command .= ')$';
// Send it to cas.
// Send it to CAS.
$connection = stack_connection_helper::make();
$results = $connection->json_compute($command);
// Lets collect what we got.
// Let's collect what we got.
$asts = array();
$latex = array();
$ersbystatement = array();
......@@ -342,6 +345,22 @@ class stack_cas_session2 {
return $this->instantiated;
}
/*
* This representation is only used in debugging questions, and for
* offline (sandbox) testing. We need to provide teachers with something
* they can type into Maxima.
*/
public function get_keyval_representation(): string {
$keyvals = '';
foreach ($this->statements as $statement) {
$val = trim($statement->get_evaluationform());
if ($val) {
$keyvals .= $val . ";\n";
}
}
return trim($keyvals);
}
public function get_debuginfo() {
// TODO...
return '';
......
......@@ -18,7 +18,7 @@ defined('MOODLE_INTERNAL') || die();
require_once(__DIR__ . '/filter.interface.php');
/**
* AST filter that marks everything that has been fiexd by fixing
* AST filter that marks everything that has been fixed by fixing
* spaces as invalid.
*/
class stack_ast_filter_990_no_fixing_spaces implements stack_cas_astfilter_exclusion {
......@@ -37,7 +37,7 @@ class stack_ast_filter_990_no_fixing_spaces implements stack_cas_astfilter_exclu
$ast->callbackRecurse($check, false);
// Now that those have been checked and invalidated. Lets write custom errors.
// Now that those have been checked and invalidated. Let's write custom errors.
if ($spaces === true) {
$missingstring = $ast->toString(
array('fixspaces_as_red_spaces' => true, 'qmchar' => true, 'inputform' => true));
......@@ -53,8 +53,7 @@ class stack_ast_filter_990_no_fixing_spaces implements stack_cas_astfilter_exclu
}
public function conflicts_with(string $otherfiltername): bool {
if ($otherfiltername === '999_strict' ||
$otherfiltername === '991_no_fixing_stars') {
if ($otherfiltername === '999_strict') {
return true;
}
return false;
......
......@@ -18,7 +18,7 @@ defined('MOODLE_INTERNAL') || die();
require_once(__DIR__ . '/filter.interface.php');
/**
* AST filter that marks everything that has been fiexd by inserting
* AST filter that marks everything that has been fixed by inserting
* stars as invalid.
*/
class stack_ast_filter_991_no_fixing_stars implements stack_cas_astfilter_exclusion {
......@@ -36,7 +36,7 @@ class stack_ast_filter_991_no_fixing_stars implements stack_cas_astfilter_exclus
$ast->callbackRecurse($check, false);
// Now that those have been checked and invalidated. Lets write custom errors.
// Now that those have been checked and invalidated. Let's write custom errors.
if ($stars === true) {
$missingstring = $ast->toString(array('insertstars_as_red' => true, 'qmchar' => true, 'inputform' => true));
if ($ast instanceof MP_Root) {
......@@ -53,8 +53,7 @@ class stack_ast_filter_991_no_fixing_stars implements stack_cas_astfilter_exclus
}
public function conflicts_with(string $otherfiltername): bool {
if ($otherfiltername === '999_strict' ||
$otherfiltername === '991_no_fixing_spaces') {
if ($otherfiltername === '999_strict') {
return true;
}
return false;
......
......@@ -286,7 +286,7 @@ class stack_equiv_input extends stack_input {
if ('' != $cs->get_errors() || '' == $cs->get_value()) {
$valid = false;
$errors[$index] = ' '.stack_maxima_translate($cs->get_errors());
$display .= '<td>' . stack_maxima_format_casstring($cs->get_raw_casstring()) . '</td>';
$display .= '<td>' . stack_maxima_format_casstring($cs->get_inputform()) . '</td>';
$display .= '<td>' . stack_maxima_translate($errors[$index]) . '</td></tr>';
} else {
$display .= '<td>\(\displaystyle ' . $cs->get_display() . ' \)</td>';
......@@ -336,7 +336,7 @@ class stack_equiv_input extends stack_input {
if (array_key_exists(0, $tcontents)) {
$ta = $tcontents[0];
if (array_key_exists(0, $caslines)) {
$sa = $caslines[0]->get_raw_casstring();
$sa = $caslines[0]->get_inputform();
$fl = new stack_cas_casstring('firstline:second(ATEqualComAss('.$sa.','.$ta.'))');
}
}
......
......@@ -175,7 +175,7 @@ class stack_textarea_input extends stack_input {
if ('' != $cs->get_errors() || '' == $cs->get_value()) {
$valid = false;
$errors[$index] = ' ' . stack_maxima_translate($cs->get_errors());
$display .= '<td>' . stack_maxima_format_casstring($cs->get_raw_casstring()) . '</td>';
$display .= '<td>' . stack_maxima_format_casstring($cs->get_inputform()) . '</td>';
$display .= '<td>' . stack_maxima_translate($errors[$index]). '</td></tr>';
} else {
$display .= '<td>\(\displaystyle ' . $cs->get_display() . ' \)</td>';
......
......@@ -311,8 +311,8 @@ class stack_potentialresponse_node {
$ct = new stack_cas_text($this->branches[0]['feedback'] . $this->branches[1]['feedback']);
$requiredcasstrings = $ct->get_all_raw_casstrings();
$requiredcasstrings[] = $this->sans->get_raw_casstring();
$requiredcasstrings[] = $this->tans->get_raw_casstring();
$requiredcasstrings[] = $this->sans->get_inputform();
$requiredcasstrings[] = $this->tans->get_inputform();
if ($this->process_atoptions() && trim($this->atoptions) != '') {
$requiredcasstrings[] = $this->atoptions;
......@@ -352,7 +352,7 @@ class stack_potentialresponse_node {
if ($this->process_atoptions() && trim($this->atoptions) != '') {
$cs = stack_ast_container::make_from_teacher_source('PRATOPT:' . $this->atoptions,
'', new stack_cas_security());
$variables[] = $atopts;
$variables[] = $cs;
}
return $variables;
......@@ -388,7 +388,7 @@ class stack_potentialresponse_node {
$ncasoptions = $this->atoptions;
}
$at = new stack_ans_test_controller($this->answertest,
$this->sans->get_raw_casstring(), $this->tans->get_raw_casstring(), null, $ncasoptions);
$this->sans->get_inputform(), $this->tans->get_inputform(), null, $ncasoptions);
return $at->get_trace(false);
}
}
......@@ -112,11 +112,11 @@ class stack_question_test {
*/
public static function compute_response(qtype_stack_question $question, $inputs) {
// If the question has simp:false, then the local options should reflect this.
// In this case, test constructors (question authors) will need to explicitly simplify their test case constructions.
// In this case, question authors will need to explicitly simplify their test case constructions.
$localoptions = clone $question->options;
// Start with the question variables (note that order matters here).
$cascontext = new stack_cas_session(null, $localoptions, $question->seed);
$cascontext = new stack_cas_session2(array(), $localoptions, $question->seed);
$question->add_question_vars_to_session($cascontext);
// Turn off simplification - we *always* need test cases to be unsimplified, even if the question option is true.
......@@ -133,12 +133,13 @@ class stack_question_test {
}
}
}
$cascontext->add_vars($vars);
$cascontext->add_statements($vars);
$cascontext->instantiate();
$response = array();
foreach ($inputs as $name => $notused) {
$computedinput = $cascontext->get_value_key('testresponse_' . $name, true);
$var = $cascontext->get_by_key('testresponse_' . $name, true);
$computedinput = $var->get_value();
// In the case we start with an invalid input, and hence don't send it to the CAS.
// We want the response to constitute the raw invalid input.
// This permits invalid expressions in the inputs, and to compute with valid expressions.
......@@ -146,7 +147,7 @@ class stack_question_test {
$computedinput = $inputs[$name];
} else {
// 4.3. means the logic_nouns_sort is done through parse trees.
$computedinput = $cascontext->get_ast_key('testresponse_' . $name)->toString(array('nounify' => false));
$computedinput = $cascontext->get_by_key('testresponse_' . $name)->get_dispvalue();
}
if (array_key_exists($name, $question->inputs)) {
// Remove things like apostrophies in test case inputs so we don't create an invalid student input.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment