2

I'm using the eval function to evaluate an abstract list pattern against a list and it keeps coming up with an Undeclared Variable error. Below is included a small reproducible example.

module PuzzleScript::Test::Engine::EvalExample

import util::Eval;
import IO;

data Animal = dog() | cat();

void main(){    
    bool boolean = [*_, cat(), *_] := [dog(), cat()];
    if (boolean) println("True 1");
    
    println("[*_, cat(), *_] := [dog(), cat()];");
    Result[bool] re = eval(#bool, "[*_, cat(), *_] := [dog(), cat()];");
    if (re.val) println("True 2");

}

Which generates the following error

Rascal Version: 0.18.2, see |release-notes://0.18.2|
rascal>import PuzzleScript::Test::Engine::EvalExample;
ok
rascal>main()
True 1
[*_, cat(), *_] := [dog(), cat()];
|std:///util/Eval.rsc|(622,1030,<23,0>,<60,95>): StaticError(
  "Undeclared variable: dog\nAdvice: |http://tutor.rascal-mpl.org/Errors/Static/UndeclaredVariable/UndeclaredVariable.html|",
  |eval:///?command=[*_,%2520cat(),%2520*_]%20:=%20[dog(),%2520cat()];|(20,3,<1,20>,<1,23>))
        at $evalinstance$0(|main://$evalinstance$0|)
        at *** somewhere ***(|std:///util/Eval.rsc|(622,1030,<23,0>,<60,95>))
        at eval(|project://AutomatedPuzzleScript/src/PuzzleScript/Test/Engine/EvalExample.rsc|(288,36,<13,31>,<13,67>))
        at $root$(|prompt:///|(0,47,<1,0>,<1,47>)ok
rascal>

As far as I understand, the error happens when it tries to evaluate the dog constructor on the right side of the pattern. I'm looking for a solution that would allow me to make the environment available to the eval function without having to re-import everything in the eval. The reason I'm doing it this way is that I haven't found a way to dynamically generate abstract patterns, if there's a way I'd be glad to hear about it since it is the root of my current issue.

1 Answers1

1
  • eval is not an often used function in Rascal; do you really need to dynamically create patterns?
  • there is the node pattern: (str name)() which in this case would match any constructor with no arguments
  • the real answer is that if you do import the right modules in the call to eval those modules will be cached by the interpreter which is used by the eval function
  • so that would not be slow
  • however, module reloading is not well-supported and you might have to restart the shell to get a fresh version into the eval evaluator.
Jurgen Vinju
  • 6,393
  • 1
  • 15
  • 26
  • I'm re-implementing a simple game engine that uses "rules" to rewrite part of a 2d level. Since I'm storing levels as a 3d matrix (row, columns and collision layers) I thought list matching would be the best for this, hence the need to be able to generate patterns. For example, `[ RIGHT Player | Crate ]` becomes `[_*, moving_object("player", "right"), object("crate"), *_]` I will try the other solutions you proposed, as they sound like they would fit, and report back. Thanks for your help as always. – Clement Julia Sep 01 '21 at 14:09
  • 1
    Alright, keep us posted! Love that you are doing this. – Jurgen Vinju Sep 02 '21 at 15:30
  • In the end, I decided with importing the right modules before the call, caching everything I needed. I still need to optimise a few others things so I'm not completely sure of the impact on performance but it works very well. Thanks for the solution! – Clement Julia Sep 13 '21 at 09:02