Skip to content
Permalink
Browse files
JEXL-369: let/const disallow any redeclaration of a variable within l…
…exical scope;

added let/const for parameters as well;
refactored badly named internal fields (frame vs scope);
  • Loading branch information
henrib committed May 8, 2022
1 parent 10fc2f1 commit 8549308ac2704b775f4d77fa63bfacdb10f6ee9f
Showing 6 changed files with 261 additions and 183 deletions.
@@ -38,6 +38,7 @@ allow fine-tuning the scripting integration into any project.

New Features in 3.3:
====================
* JEXL-369: Add 'let' and 'const' variable declarations
* JEXL-365: Lambda expressions
* JEXL-363: Allow retrieving captured variables in script
* JEXL-360: Add missing bitshift operators ( >>, >>>, <<)
@@ -58,13 +58,6 @@ public Scope getScope() {
return scope;
}

boolean isLexical(int symbol) {
return scope != null && scope.isLexical(symbol);
}
boolean isConstant(int symbol) {
return scope != null && scope.isConstant(symbol);
}

@Override
public int hashCode() {
return Arrays.deepHashCode(this.stack);
@@ -18,14 +18,13 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
* A script scope, stores the declaration of parameters and local variables as symbols.
* <p>This also acts as the functional scope and variable definition store.
* <p>This also acts as the functional scope and variable definition store.</p>
* @since 3.0
*/
public final class Scope {
@@ -67,32 +66,15 @@ public final class Scope {
* The map of local captured variables to parent scope variables, ie closure.
*/
private Map<Integer, Integer> capturedVariables = null;

/**
* Const symbols.
*/
private LexicalScope constVariables = null;
/**
* Let symbols.
*/
private LexicalScope lexicalVariables = null;

void addLexical(int s) {
if (lexicalVariables == null) {
lexicalVariables = new LexicalScope();
}
lexicalVariables.addSymbol(s);
}

public boolean isLexical(int s) {
return lexicalVariables != null && s >= 0 && lexicalVariables.hasSymbol(s);
}

void addConstant(int s) {
if (constVariables == null) {
constVariables = new LexicalScope();
}
constVariables.addSymbol(s);
}

public boolean isConstant(int s) {
return constVariables != null && s >= 0 && constVariables.hasSymbol(s);
}

/**
* The empty string array.
*/
@@ -170,17 +152,53 @@ private Integer getSymbol(final String name, final boolean capture) {
register = namedVariables.size();
namedVariables.put(name, register);
capturedVariables.put(register, pr);
if (parent.isLexical(pr)) {
this.addLexical(register);
if (parent.isConstant(pr)) {
this.addConstant(register);
}
}
}
}
return register;
}

/**
* Marks a symbol as a lexical, declared through let or const.
* @param s the symbol
* @return true if the symbol was not already present in the lexical set
*/
public boolean addLexical(int s) {
if (lexicalVariables == null) {
lexicalVariables = new LexicalScope();
}
return lexicalVariables.addSymbol(s);
}

/**
* Checks whether a symbol is declared through a let or const.
* @param s the symbol
* @return true if symbol was declared through let or const
*/
public boolean isLexical(int s) {
return lexicalVariables != null && s >= 0 && lexicalVariables.hasSymbol(s);
}

/**
* Marks a symbol as a const.
* @param s the symbol
* @return true if the symbol was not already present in the constant set
*/
public boolean addConstant(int s) {
if (constVariables == null) {
constVariables = new LexicalScope();
}
return constVariables.addSymbol(s);
}

/**
* Checks whether a symbol is declared through a const.
* @param s the symbol
* @return true if symbol was declared through const
*/
public boolean isConstant(int s) {
return constVariables != null && s >= 0 && constVariables.hasSymbol(s);
}

/**
* Checks whether a given symbol is captured.
* @param symbol the symbol number
@@ -240,22 +258,6 @@ public int declareVariable(final String name, boolean lexical, boolean constant)
capturedVariables.put(register, pr);
}
}
if (lexical) {
addLexical(register);
if (constant) {
addConstant(register);
}
}
} else {
// belt and suspenders
if (lexical) {
if (!isLexical(register)) {
throw new IllegalStateException("cant redefine lexical variable");
}
if (constant && !isConstant(register)) {
throw new IllegalStateException("cant redefine const variable");
}
}
}
return register;
}

0 comments on commit 8549308

Please sign in to comment.