Skip to content

Commit 9eb4800

Browse files
committed
Always link scopes + Preserve scoping for invalid numargs
- Always link AST term scopes, ensuring that for example ivariable references have a scope assigned to them. - Preserve scoping behavior for while/for/... functions with an invalid number of arguments. In these cases all arguments within such function will get their own scope, preventing a chain of unexpected SA compile errors on invalid while/for/... usage.
1 parent bdc26f7 commit 9eb4800

File tree

4 files changed

+122
-87
lines changed

4 files changed

+122
-87
lines changed

src/main/java/com/laytonsmith/core/functions/ControlFlow.java

Lines changed: 112 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,10 @@ public Class<? extends CREThrowable>[] thrown() {
193193
@Override
194194
public Scope linkScope(StaticAnalysis analysis, Scope parentScope,
195195
ParseTree ast, Environment env, Set<ConfigCompileException> exceptions) {
196+
197+
// Handle not enough arguments. Link child scopes, but return parent scope.
196198
if(ast.numberOfChildren() < 2) {
199+
super.linkScope(analysis, parentScope, ast, env, exceptions);
197200
return parentScope;
198201
}
199202

@@ -1125,9 +1128,10 @@ public Class<? extends CREThrowable>[] thrown() {
11251128
public Scope linkScope(StaticAnalysis analysis, Scope parentScope,
11261129
ParseTree ast, Environment env, Set<ConfigCompileException> exceptions) {
11271130

1128-
// Fall back to default behavior for invalid usage.
1131+
// Handle invalid number of arguments. Link child scopes, but return parent scope.
11291132
if(ast.numberOfChildren() != 4) {
1130-
return super.linkScope(analysis, parentScope, ast, env, exceptions);
1133+
super.linkScope(analysis, parentScope, ast, env, exceptions);
1134+
return parentScope;
11311135
}
11321136

11331137
// Link child scopes.
@@ -1382,30 +1386,38 @@ public FunctionSignatures getSignatures() {
13821386
@Override
13831387
public Scope linkScope(StaticAnalysis analysis, Scope parentScope,
13841388
ParseTree ast, Environment env, Set<ConfigCompileException> exceptions) {
1385-
if(ast.numberOfChildren() >= (this.runAsFor ? 3 : 4)) {
1386-
ParseTree assign = ast.getChildAt(0);
1387-
ParseTree cond = ast.getChildAt(1);
1388-
ParseTree exp = ast.getChildAt(2);
1389-
ParseTree code = ast.getChildAt(3);
1390-
ParseTree elseCode = (this.runAsFor ? null : ast.getChildAt(4));
1391-
1392-
// Order: assign -> cond -> (code -> exp -> cond)* -> elseCode?.
1393-
Scope assignScope = analysis.linkScope(parentScope, assign, env, exceptions);
1394-
Scope condScope = analysis.linkScope(assignScope, cond, env, exceptions);
1395-
Scope codeParentScope = analysis.createNewScope(condScope);
1396-
Scope codeScope = analysis.linkScope(codeParentScope, code, env, exceptions);
1397-
analysis.linkScope(codeScope, exp, env, exceptions);
1398-
if(elseCode != null) {
1399-
analysis.linkScope(condScope, code, env, exceptions);
1400-
}
14011389

1402-
// Add breakable and continuable declaration in loop code parent scope.
1403-
codeParentScope.addDeclaration(
1404-
new BreakableDeclaration(parentScope, ast.getNodeModifiers(), ast.getTarget()));
1405-
codeParentScope.addDeclaration(
1406-
new ContinuableDeclaration(ast.getNodeModifiers(), ast.getTarget()));
1407-
analysis.setTermScope(ast, codeParentScope);
1390+
// Handle not enough arguments. Link child scopes, but return parent scope.
1391+
if(ast.numberOfChildren() < (this.runAsFor ? 3 : 4)) {
1392+
super.linkScope(analysis, parentScope, ast, env, exceptions);
1393+
return parentScope;
1394+
}
1395+
1396+
// Get AST nodes.
1397+
ParseTree assign = ast.getChildAt(0);
1398+
ParseTree cond = ast.getChildAt(1);
1399+
ParseTree exp = ast.getChildAt(2);
1400+
ParseTree code = ast.getChildAt(3);
1401+
ParseTree elseCode = (this.runAsFor ? null : ast.getChildAt(4));
1402+
1403+
// Order: assign -> cond -> (code -> exp -> cond)* -> elseCode?.
1404+
Scope assignScope = analysis.linkScope(parentScope, assign, env, exceptions);
1405+
Scope condScope = analysis.linkScope(assignScope, cond, env, exceptions);
1406+
Scope codeParentScope = analysis.createNewScope(condScope);
1407+
Scope codeScope = analysis.linkScope(codeParentScope, code, env, exceptions);
1408+
analysis.linkScope(codeScope, exp, env, exceptions);
1409+
if(elseCode != null) {
1410+
analysis.linkScope(condScope, code, env, exceptions);
14081411
}
1412+
1413+
// Add breakable and continuable declaration in loop code parent scope.
1414+
codeParentScope.addDeclaration(
1415+
new BreakableDeclaration(parentScope, ast.getNodeModifiers(), ast.getTarget()));
1416+
codeParentScope.addDeclaration(
1417+
new ContinuableDeclaration(ast.getNodeModifiers(), ast.getTarget()));
1418+
analysis.setTermScope(ast, codeParentScope);
1419+
1420+
// Return parent scope.
14091421
return parentScope;
14101422
}
14111423

@@ -1631,34 +1643,41 @@ public Class<? extends CREThrowable>[] thrown() {
16311643
@Override
16321644
public Scope linkScope(StaticAnalysis analysis, Scope parentScope,
16331645
ParseTree ast, Environment env, Set<ConfigCompileException> exceptions) {
1634-
if(ast.numberOfChildren() >= 3) {
1635-
int ind = 0;
1636-
ParseTree array = ast.getChildAt(ind++);
1637-
ParseTree key = (ast.numberOfChildren() == 4 ? ast.getChildAt(ind++) : null);
1638-
ParseTree val = ast.getChildAt(ind++);
1639-
ParseTree code = ast.getChildAt(ind++);
1640-
1641-
// Order: array -> [key] -> val -> code?.
1642-
Scope arrayScope = analysis.linkScope(parentScope, array, env, exceptions);
1643-
Scope keyParamScope = arrayScope;
1644-
Scope keyValScope = arrayScope;
1645-
if(key != null) {
1646-
Scope[] scopes = analysis.linkParamScope(keyParamScope, keyValScope, key, env, exceptions);
1647-
keyParamScope = scopes[0];
1648-
keyValScope = scopes[1];
1649-
}
1650-
Scope[] scopes = analysis.linkParamScope(keyParamScope, keyValScope, val, env, exceptions);
1651-
Scope valScope = scopes[0]; // paramScope.
1652-
Scope codeParentScope = analysis.createNewScope(valScope);
1653-
analysis.linkScope(codeParentScope, code, env, exceptions);
1654-
1655-
// Add breakable and continuable declaration in loop code parent scope.
1656-
codeParentScope.addDeclaration(
1657-
new BreakableDeclaration(parentScope, ast.getNodeModifiers(), ast.getTarget()));
1658-
codeParentScope.addDeclaration(
1659-
new ContinuableDeclaration(ast.getNodeModifiers(), ast.getTarget()));
1660-
analysis.setTermScope(ast, codeParentScope);
1646+
1647+
// Handle not enough arguments. Link child scopes, but return parent scope.
1648+
if(ast.numberOfChildren() < 3) {
1649+
super.linkScope(analysis, parentScope, ast, env, exceptions);
1650+
return parentScope;
1651+
}
1652+
1653+
int ind = 0;
1654+
ParseTree array = ast.getChildAt(ind++);
1655+
ParseTree key = (ast.numberOfChildren() == 4 ? ast.getChildAt(ind++) : null);
1656+
ParseTree val = ast.getChildAt(ind++);
1657+
ParseTree code = ast.getChildAt(ind++);
1658+
1659+
// Order: array -> [key] -> val -> code?.
1660+
Scope arrayScope = analysis.linkScope(parentScope, array, env, exceptions);
1661+
Scope keyParamScope = arrayScope;
1662+
Scope keyValScope = arrayScope;
1663+
if(key != null) {
1664+
Scope[] scopes = analysis.linkParamScope(keyParamScope, keyValScope, key, env, exceptions);
1665+
keyParamScope = scopes[0];
1666+
keyValScope = scopes[1];
16611667
}
1668+
Scope[] scopes = analysis.linkParamScope(keyParamScope, keyValScope, val, env, exceptions);
1669+
Scope valScope = scopes[0]; // paramScope.
1670+
Scope codeParentScope = analysis.createNewScope(valScope);
1671+
analysis.linkScope(codeParentScope, code, env, exceptions);
1672+
1673+
// Add breakable and continuable declaration in loop code parent scope.
1674+
codeParentScope.addDeclaration(
1675+
new BreakableDeclaration(parentScope, ast.getNodeModifiers(), ast.getTarget()));
1676+
codeParentScope.addDeclaration(
1677+
new ContinuableDeclaration(ast.getNodeModifiers(), ast.getTarget()));
1678+
analysis.setTermScope(ast, codeParentScope);
1679+
1680+
// Return parent scope.
16621681
return parentScope;
16631682
}
16641683

@@ -1929,36 +1948,43 @@ public FunctionSignatures getSignatures() {
19291948
@Override
19301949
public Scope linkScope(StaticAnalysis analysis, Scope parentScope,
19311950
ParseTree ast, Environment env, Set<ConfigCompileException> exceptions) {
1932-
if(ast.numberOfChildren() >= 4) {
1933-
int ind = 0;
1934-
ParseTree array = ast.getChildAt(ind++);
1935-
ParseTree key = (ast.numberOfChildren() == 5 ? ast.getChildAt(ind++) : null);
1936-
ParseTree val = ast.getChildAt(ind++);
1937-
ParseTree code = ast.getChildAt(ind++);
1938-
ParseTree elseCode = ast.getChildAt(ind++);
1939-
1940-
// Order: array -> [key] -> val -> code? | array -> elseCode.
1941-
Scope arrayScope = analysis.linkScope(parentScope, array, env, exceptions);
1942-
Scope keyParamScope = arrayScope;
1943-
Scope keyValScope = arrayScope;
1944-
if(key != null) {
1945-
Scope[] scopes = analysis.linkParamScope(keyParamScope, keyValScope, key, env, exceptions);
1946-
keyParamScope = scopes[0];
1947-
keyValScope = scopes[1];
1948-
}
1949-
Scope[] scopes = analysis.linkParamScope(keyParamScope, keyValScope, val, env, exceptions);
1950-
Scope valScope = scopes[0]; // paramScope.
1951-
Scope codeParentScope = analysis.createNewScope(valScope);
1952-
analysis.linkScope(codeParentScope, code, env, exceptions);
1953-
analysis.linkScope(arrayScope, elseCode, env, exceptions);
1954-
1955-
// Add breakable and continuable declaration in loop code parent scope.
1956-
codeParentScope.addDeclaration(
1957-
new BreakableDeclaration(parentScope, ast.getNodeModifiers(), ast.getTarget()));
1958-
codeParentScope.addDeclaration(
1959-
new ContinuableDeclaration(ast.getNodeModifiers(), ast.getTarget()));
1960-
analysis.setTermScope(ast, codeParentScope);
1951+
1952+
// Handle not enough arguments. Link child scopes, but return parent scope.
1953+
if(ast.numberOfChildren() < 4) {
1954+
super.linkScope(analysis, parentScope, ast, env, exceptions);
1955+
return parentScope;
19611956
}
1957+
1958+
int ind = 0;
1959+
ParseTree array = ast.getChildAt(ind++);
1960+
ParseTree key = (ast.numberOfChildren() == 5 ? ast.getChildAt(ind++) : null);
1961+
ParseTree val = ast.getChildAt(ind++);
1962+
ParseTree code = ast.getChildAt(ind++);
1963+
ParseTree elseCode = ast.getChildAt(ind++);
1964+
1965+
// Order: array -> [key] -> val -> code? | array -> elseCode.
1966+
Scope arrayScope = analysis.linkScope(parentScope, array, env, exceptions);
1967+
Scope keyParamScope = arrayScope;
1968+
Scope keyValScope = arrayScope;
1969+
if(key != null) {
1970+
Scope[] scopes = analysis.linkParamScope(keyParamScope, keyValScope, key, env, exceptions);
1971+
keyParamScope = scopes[0];
1972+
keyValScope = scopes[1];
1973+
}
1974+
Scope[] scopes = analysis.linkParamScope(keyParamScope, keyValScope, val, env, exceptions);
1975+
Scope valScope = scopes[0]; // paramScope.
1976+
Scope codeParentScope = analysis.createNewScope(valScope);
1977+
analysis.linkScope(codeParentScope, code, env, exceptions);
1978+
analysis.linkScope(arrayScope, elseCode, env, exceptions);
1979+
1980+
// Add breakable and continuable declaration in loop code parent scope.
1981+
codeParentScope.addDeclaration(
1982+
new BreakableDeclaration(parentScope, ast.getNodeModifiers(), ast.getTarget()));
1983+
codeParentScope.addDeclaration(
1984+
new ContinuableDeclaration(ast.getNodeModifiers(), ast.getTarget()));
1985+
analysis.setTermScope(ast, codeParentScope);
1986+
1987+
// Return parent scope.
19621988
return parentScope;
19631989
}
19641990

@@ -2105,9 +2131,10 @@ public Mixed exec(Target t, Environment environment, Mixed... args) throws Confi
21052131
public Scope linkScope(StaticAnalysis analysis, Scope parentScope,
21062132
ParseTree ast, Environment env, Set<ConfigCompileException> exceptions) {
21072133

2108-
// Fall back to default behavior for invalid usage.
2134+
// Handle insufficient number of arguments. Link child scopes, but return parent scope.
21092135
if(ast.numberOfChildren() != 2) {
2110-
return super.linkScope(analysis, parentScope, ast, env, exceptions);
2136+
super.linkScope(analysis, parentScope, ast, env, exceptions);
2137+
return parentScope;
21112138
}
21122139

21132140
// Link child scopes.
@@ -2261,9 +2288,10 @@ public Mixed execs(Target t, Environment env, Script parent, ParseTree... nodes)
22612288
public Scope linkScope(StaticAnalysis analysis, Scope parentScope,
22622289
ParseTree ast, Environment env, Set<ConfigCompileException> exceptions) {
22632290

2264-
// Fall back to default behavior for invalid usage.
2291+
// Handle invalid number of arguments. Link child scopes, but return parent scope.
22652292
if(ast.numberOfChildren() != 2) {
2266-
return super.linkScope(analysis, parentScope, ast, env, exceptions);
2293+
super.linkScope(analysis, parentScope, ast, env, exceptions);
2294+
return parentScope;
22672295
}
22682296

22692297
// Link child scopes.

src/main/java/com/laytonsmith/core/functions/DataHandling.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1577,8 +1577,9 @@ public Mixed exec(Target t, Environment env, Mixed... args) throws ConfigRuntime
15771577
public Scope linkScope(StaticAnalysis analysis, Scope parentScope, ParseTree ast,
15781578
Environment env, Set<ConfigCompileException> exceptions) {
15791579

1580-
// Handle not enough arguments.
1580+
// Handle not enough arguments. Link child scopes, but return parent scope.
15811581
if(ast.numberOfChildren() < 2) {
1582+
super.linkScope(analysis, parentScope, ast, env, exceptions);
15821583
return parentScope;
15831584
}
15841585

src/main/java/com/laytonsmith/core/functions/EventBinding.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,9 @@ private CClassType typecheckPrefilterParseTree(
312312
public Scope linkScope(StaticAnalysis analysis, Scope parentScope,
313313
ParseTree ast, Environment env, Set<ConfigCompileException> exceptions) {
314314

315-
// Fully ignore the bind() if it will generate an exception later anyways.
315+
// Handle not enough arguments. Link child scopes, but return parent scope.
316316
if(ast.numberOfChildren() < 5) {
317+
super.linkScope(analysis, parentScope, ast, env, exceptions);
317318
return parentScope;
318319
}
319320

src/main/java/com/laytonsmith/core/functions/Exceptions.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,12 @@ public Scope linkScope(StaticAnalysis analysis, Scope parentScope,
216216
int numArgs = ast.numberOfChildren();
217217
Scope catchParentScope = parentScope;
218218
switch(numArgs) {
219-
default: // Too many arguments, just analyze the first 4, this will cause a compile error later.
219+
default: { // Too many arguments. Analyze the first 4 as usual and handle the rest generically.
220+
Scope scope = parentScope;
221+
for(int i = 4; i < ast.numberOfChildren(); i++) {
222+
scope = analysis.linkScope(scope, ast.getChildAt(i), env, exceptions);
223+
}
224+
}
220225
case 4: { // try(tryCode, exParam, catchCode, exTypes).
221226
ParseTree exTypes = ast.getChildAt(3);
222227
analysis.linkScope(parentScope, exTypes, env, exceptions);

0 commit comments

Comments
 (0)