Skip to content

Commit 69f6baa

Browse files
committed
Don't parse __autoconcat__ to sconcat in strict mode
Parse `__autoconcat__()` to the new `__statements__()` instead of `sconcat()` in strict mode. `__statements__()` takes arguments of any type and returns `void` for typechecking, so compile errors will be generated in cases where `__autoconcat__()` used to insert `sconcat()`s, or in other words, where the user has either forgotten to put some `.` concat, or where the user has made a mistake. This change does not affect non-strict mode, as automatically inserting concats is a feature there. Alias syntax should also remain possible in strict mode, but only when the whole alias is nicely concatenated together by the user. Inserting multiple arguments/statements will cause the code block to be interpreted as a statements block and not as an alias redirect.
1 parent e36e76d commit 69f6baa

File tree

4 files changed

+53
-8
lines changed

4 files changed

+53
-8
lines changed

src/main/java/com/laytonsmith/core/MethodScriptCompiler.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2119,9 +2119,13 @@ private static void rewriteAutoconcats(ParseTree root, Environment env,
21192119
}
21202120
}
21212121
if(root.getData() instanceof CFunction && root.getData().val().equals(__autoconcat__.NAME)) {
2122+
2123+
// In non-strict mode, let __autoconcat__ glue arguments together with sconcat.
2124+
boolean returnSConcat = !root.getFileOptions().isStrict();
2125+
21222126
try {
21232127
ParseTree ret = ((Compiler.__autoconcat__) ((CFunction) root.getData()).getFunction())
2124-
.rewrite(root.getChildren(), true, envs);
2128+
.rewrite(root.getChildren(), returnSConcat, envs);
21252129
root.setData(ret.getData());
21262130
root.setChildren(ret.getChildren());
21272131
} catch (ConfigCompileException ex) {

src/main/java/com/laytonsmith/core/compiler/OptimizerObject.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,11 @@ private void optimize01(ParseTree tree, CompilerEnvironment compilerEnvironment)
4545
= (com.laytonsmith.core.functions.Compiler.__autoconcat__)
4646
FunctionList.getFunction("__autoconcat__", null, Target.UNKNOWN);
4747
if(tree.getData() instanceof CFunction && tree.getData().val().equals("__autoconcat__")) {
48-
ParseTree tempNode = autoconcat.rewrite(tree.getChildren(), true, null);
48+
49+
// In non-strict mode, let __autoconcat__ glue arguments together with sconcat.
50+
boolean returnSConcat = !tree.getFileOptions().isStrict();
51+
52+
ParseTree tempNode = autoconcat.rewrite(tree.getChildren(), returnSConcat, null);
4953
tree.setData(tempNode.getData());
5054
tree.setChildren(tempNode.getChildren());
5155
}

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

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,10 @@ public String docs() {
152152
* this __autoconcat__ node being replaced or in a compile error if the __autoconcat__ cannot be converted to
153153
* an executable AST node. This being a function is merely a convenient way to defer processing until after
154154
* parsing, meaning that it should ALWAYS be rewritten before executing the AST.
155-
*
156-
* @param list
157-
* @param returnSConcat
155+
* @param list - A list containing all {@link ParseTree} children of this __autoconcat__.
156+
* @param returnSConcat - If parsing results in only one child function, then this argument is ignored.
157+
* If {@code true}, the resulting parsed functions will be wrapped into {@link sconcat}.
158+
* If {@code false}, the resulting parsed functions will be wrapped into {@link __statements__}.
158159
* @return The executable AST node, representing the code/tokens in this __autoconcat__.
159160
* @throws ConfigCompileException If this __autoconcat__ cannot be converted to an executable AST node.
160161
*/
@@ -547,14 +548,48 @@ public ParseTree rewrite(List<ParseTree> list, boolean returnSConcat,
547548
if(returnSConcat) {
548549
tree = new ParseTree(new CFunction(sconcat.NAME, t), options);
549550
} else {
550-
tree = new ParseTree(new CFunction(concat.NAME, t), options);
551+
tree = new ParseTree(new CFunction(__statements__.NAME, t), options);
551552
}
552553
tree.setChildren(list);
553554
return tree;
554555
}
555556
}
556557
}
557558

559+
@api
560+
@noprofile
561+
@hide("This is only used internally by the compiler.")
562+
public static class __statements__ extends DummyFunction {
563+
564+
public static final String NAME = "__statements__";
565+
566+
@Override
567+
public String getName() {
568+
return NAME;
569+
}
570+
571+
@Override
572+
public String docs() {
573+
return "void {[...]} Used internally by the compiler. You shouldn't use it.";
574+
}
575+
576+
@Override
577+
public Mixed exec(Target t, Environment env, Mixed... args) throws ConfigRuntimeException {
578+
return CVoid.VOID;
579+
}
580+
581+
@Override
582+
public CClassType getReturnType(Target t, List<CClassType> argTypes,
583+
List<Target> argTargets, Environment env, Set<ConfigCompileException> exceptions) {
584+
return CVoid.TYPE;
585+
}
586+
587+
@Override
588+
public boolean preResolveVariables() {
589+
return false;
590+
}
591+
}
592+
558593
@api
559594
@hide("This is only used for testing unexpected error handling.")
560595
@noboilerplate

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import com.laytonsmith.core.exceptions.CRE.CRERangeException;
4646
import com.laytonsmith.core.exceptions.CRE.CREThrowable;
4747
import com.laytonsmith.core.functions.BasicLogic.and;
48+
import com.laytonsmith.core.functions.Compiler.__statements__;
4849
import com.laytonsmith.core.functions.Compiler.centry;
4950
import com.laytonsmith.core.functions.DataHandling.assign;
5051
import com.laytonsmith.core.functions.Math.dec;
@@ -647,7 +648,8 @@ public ParseTree postParseRewrite(ParseTree ast, Environment env,
647648
List<ParseTree> children = ast.getChildren();
648649
Target t = ast.getTarget();
649650
if(children.size() > 1 && children.get(1).getData() instanceof CFunction
650-
&& new StringHandling.sconcat().getName().equals(children.get(1).getData().val())) {
651+
&& (sconcat.NAME.equals(children.get(1).getData().val())
652+
|| __statements__.NAME.equals(children.get(1).getData().val()))) {
651653
//This is the brace/case/default usage of switch, probably. We need
652654
//to refactor the data into the old switch format.
653655
List<ParseTree> newChildren = new ArrayList<>();
@@ -745,7 +747,7 @@ public ParseTree postParseRewrite(ParseTree ast, Environment env,
745747
newChildren.add(new ParseTree(conditions, children.get(0).getFileOptions()));
746748
}
747749
if(lastCodeBlock.size() > 0) {
748-
ParseTree codeBlock = new ParseTree(new CFunction(new StringHandling.sconcat().getName(), t),
750+
ParseTree codeBlock = new ParseTree(new CFunction(sconcat.NAME, t),
749751
lastCodeBlock.get(0).getFileOptions());
750752
for(ParseTree line : lastCodeBlock) {
751753
codeBlock.addChild(line);

0 commit comments

Comments
 (0)