Skip to content
Permalink
Browse files

Add switch_ic, an ignore-case version of switch

  • Loading branch information...
LadyCailin committed Sep 5, 2019
1 parent 621c79b commit 257909e826faeff9c908bed8356f9a0126d0c2ce
@@ -0,0 +1,27 @@
package com.laytonsmith.core.compiler.keywords;

import com.laytonsmith.PureUtilities.Version;
import com.laytonsmith.core.MSVersion;
import com.laytonsmith.core.compiler.Keyword;

/**
*
*/
@Keyword.keyword("switch_ic")
public class SwitchIcKeyword extends SimpleBlockKeywordFunction {
@Override
protected Integer[] getFunctionArgumentCount() {
return new Integer[]{1};
}

@Override
public String docs() {
return "Defines a switch_ic block, which is a more efficient, but narrower version of an if/else if/else"
+ " chain doing case insensitive comparisons.";
}

@Override
public Version since() {
return MSVersion.V3_3_4;
}
}
@@ -2,6 +2,7 @@

import com.laytonsmith.PureUtilities.TermColors;
import com.laytonsmith.PureUtilities.Common.StreamUtils;
import com.laytonsmith.PureUtilities.Version;
import com.laytonsmith.annotations.api;
import com.laytonsmith.annotations.breakable;
import com.laytonsmith.annotations.core;
@@ -22,13 +23,15 @@
import com.laytonsmith.core.compiler.VariableScope;
import com.laytonsmith.core.compiler.keywords.InKeyword;
import com.laytonsmith.core.constructs.CArray;
import com.laytonsmith.core.constructs.CClassType;
import com.laytonsmith.core.constructs.CFunction;
import com.laytonsmith.core.constructs.CIdentifier;
import com.laytonsmith.core.constructs.CInt;
import com.laytonsmith.core.constructs.CKeyword;
import com.laytonsmith.core.constructs.CLabel;
import com.laytonsmith.core.constructs.CNull;
import com.laytonsmith.core.constructs.CSlice;
import com.laytonsmith.core.constructs.CString;
import com.laytonsmith.core.constructs.CVoid;
import com.laytonsmith.core.constructs.Construct;
import com.laytonsmith.core.constructs.IVariable;
@@ -416,7 +419,7 @@ public boolean preResolveVariables() {
}

@Override
public MSVersion since() {
public Version since() {
return MSVersion.V3_3_0;
}

@@ -827,6 +830,69 @@ public ParseTree optimizeDynamic(Target t, Environment env,
}
}

@api
public static class switch_ic extends _switch implements Optimizable, BranchStatement, VariableScope {

@Override
public Mixed exec(Target t, Environment environment, Mixed... args) throws ConfigRuntimeException {
throw new Error();
}

@Override
public String getName() {
return "switch_ic";
}

@Override
public String docs() {
return "mixed {value, [equals, code]..., [defaultCode]} Provides a case insensitive switch statement, for"
+ " switching over strings. This works by compiler transformations, transforming this into a normal"
+ " switch statement, with each case lowercased, and the input to the switch wrapped in to_lower."
+ " The case statements must be strings, however, which is the main difference between this method"
+ " and the normal switch statement. The lowercasing is done with the system's default locale.";
}

@Override
public Version since() {
return MSVersion.V3_3_4;
}

@Override
public ParseTree optimizeDynamic(Target t, Environment env,
Set<Class<? extends Environment.EnvironmentImpl>> envs, List<ParseTree> children,
FileOptions fileOptions) throws ConfigCompileException, ConfigRuntimeException {
// Allow the normal switch optimization to run, which does the heavy lifting of getting the code into the
// functional format, which becomes easier for us to parse.
ParseTree switchTree = super.optimizeDynamic(t, env, envs, children, fileOptions);
// Replace the 0th child with to_lower(child)
ParseTree condition = children.get(0);
if(!CFunction.IsFunction(condition, StringHandling.to_lower.class)) {
// Don't re-add it if it's already there
ParseTree to_lower = new ParseTree(new CFunction(new StringHandling.to_lower().getName(), t),
fileOptions);
to_lower.addChild(condition);
children.set(0, to_lower);
}
// Now loop through the children, looking for the case statements. Also ensure each is a string.
for(int i = 1; i < children.size(); i += 2) {
ParseTree cseArray = children.get(i);
CArray newData = new CArray(cseArray.getTarget());
for(Mixed cse : ((CArray) cseArray.getData()).asList()) {
if(cse instanceof CString) {
CString data = (CString) cse;
newData.push(new CString(data.val().toLowerCase(), data.getTarget()), data.getTarget());
} else {
throw new ConfigCompileException(getName() + " can only accept strings in case statements.",
cse.getTarget());
}
}
cseArray.setData(newData);
}
return switchTree;
}

}

@api
@noboilerplate
@breakable
@@ -422,4 +422,10 @@ public void testDandOptimization() throws Exception {
public void testCommentBlock() throws Exception {
assertEquals(2, MethodScriptCompiler.lex("/*/ still a comment -()*/", null, new File("OptimizationTest"), true, true).size());
}

@Test
public void testSwitchIc() throws Exception {
assertEquals("switch_ic(to_lower(dyn('AsDf')),array('asdf'),msg('hello'),array('fdsa'),msg('nope'))",
optimize("switch_ic(dyn('AsDf')) { case 'aSdF': msg('hello'); case 'fdsa': msg('nope'); }"));
}
}

0 comments on commit 257909e

Please sign in to comment.
You can’t perform that action at this time.