Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redundant assignment elimination may transform the variable beyond its scope #152

Open
starsJuly opened this issue Jun 1, 2024 · 0 comments

Comments

@starsJuly
Copy link

When trying to write the Dodge the Creeps (Godot 2d demo) with GDLisp, the GDLisp compiler outputs the script error :

GDLisp v1.0.0
Running under Godot
3.5.3.stable.official.6c814135b
Compiling .\main.lisp ...
SCRIPT ERROR: Parse Error: The identifier "direction" isn't declared in the current scope.
          at: GDScript::reload (C:/Users/yzxl/AppData/Local/Temp/__gdlisp_fileDt1rg.gd:38)

The same parsed error can be caused by the simple statement :

(let ((x 0))
      (set x (+ x 1)))

The statement will be transformed by the GDLisp compiler, and output some GDScript statements as below:

func test():
    var x = x + 1
    return x

After a several attempts, I think that the redundant assignment elimination leads to the variable beyond its scope.
See the src\optimize\gdscript\redundant_assignment_elimination.rs. :)

  // ...
  pub fn run_on_stmts(&self, stmts: &[Stmt]) -> Result<Vec<Stmt>, GDError> {
    // Look for something to eliminate. If we find it, do the
    // elimination and call the function again. If not, we're done.
    for (index, stmt1) in stmts.iter().enumerate() {
      if let Some(AssignmentStmt { assign_type, var_name: name, expr: expr1 }) = self.match_first_assign(stmt1) {
        if !constant::expr_has_side_effects(expr1) {
          // Found a match. Keep going.
          for jndex in index+1..stmts.len() {
            let stmt2 = &stmts[jndex];
            if let Some(expr2) = self.match_second_assign(name, stmt2) {
              // Redundant assignment; cull
              let new_stmt = self.rebuild_assignment(assign_type.ensure_eq(), name, expr2);
              let mut new_stmts = stmts.to_vec();
              new_stmts.splice(index..=jndex, vec!(new_stmt).into_iter());
              return self.run_on_stmts(&new_stmts);
            } else if constant::stmt_has_side_effects(stmt2) {
              // If it's stateful, then we can't do anything
              break;
            }
          }
        }
      }
    }
  //...

When the first assignment type is VarDecl and the second assignment type is AssignType::Assignment(op::AssignOp::Eq), the expression of the second statement will be moved as the new VarDecl statement expression. The expression may contains any number of references of the variable (with the same name).

When inserting some stateful statements, or replacing the second assignment with other compound assignments, the script error will disappear. For example,

(let ((x 0))
      (print "hello world")
      (set x (+ x 1)))

Of course, they not trigger the redundant assignment elimination. :)

Environment Info.
Windows
Godot 3.5.3.stable.official.6c814135b
GDLisp v1.0.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant