use of com.laytonsmith.core.constructs.Variable in project CommandHelper by EngineHub.
the class MethodScriptCompiler method execute.
/**
* Executes a pre-compiled MethodScript, given the specified Script environment, but also provides a method to set
* the constants in the script.
*
* @param root
* @param env
* @param done
* @param script
* @param vars
* @return
*/
public static Construct execute(ParseTree root, Environment env, MethodScriptComplete done, Script script, List<Variable> vars) {
if (root == null) {
return CVoid.VOID;
}
if (script == null) {
script = new Script(null, null, env.getEnv(GlobalEnv.class).GetLabel(), new FileOptions(new HashMap<>()));
}
if (vars != null) {
Map<String, Variable> varMap = new HashMap<>();
for (Variable v : vars) {
varMap.put(v.getVariableName(), v);
}
for (Construct tempNode : root.getAllData()) {
if (tempNode instanceof Variable) {
Variable vv = varMap.get(((Variable) tempNode).getVariableName());
if (vv != null) {
((Variable) tempNode).setVal(vv.getDefault());
} else {
// The variable is unset. I'm not quite sure what cases would cause this
((Variable) tempNode).setVal("");
}
}
}
}
StringBuilder b = new StringBuilder();
Construct returnable = null;
for (ParseTree gg : root.getChildren()) {
Construct retc = script.eval(gg, env);
if (root.numberOfChildren() == 1) {
returnable = retc;
}
String ret = retc instanceof CNull ? "null" : retc.val();
if (ret != null && !ret.trim().isEmpty()) {
b.append(ret).append(" ");
}
}
if (done != null) {
done.done(b.toString().trim());
}
if (returnable != null) {
return returnable;
}
return Static.resolveConstruct(b.toString().trim(), Target.UNKNOWN);
}
use of com.laytonsmith.core.constructs.Variable in project CommandHelper by EngineHub.
the class Script method checkAmbiguous.
public void checkAmbiguous(List<Script> scripts) throws ConfigCompileException {
List<Construct> thisCommand = this.cleft;
for (Script script : scripts) {
List<Construct> thatCommand = script.cleft;
if (thatCommand == null) {
// It hasn't been compiled yet.
return;
}
if (this.cleft == script.cleft) {
// Of course this command is going to match its own signature.
continue;
}
matchScope: {
for (int k = 0; k < thisCommand.size(); k++) {
Construct c1 = thisCommand.get(k);
if (k < thatCommand.size()) {
Construct c2 = thatCommand.get(k);
// the same argument position.
if (c1.getCType() == c2.getCType() && (c1.getCType() == ConstructType.STRING || c1.getCType() == ConstructType.COMMAND)) {
if (c1.nval() != c2.nval() && (c1.nval() == null || !c1.nval().equals(c2.nval()))) {
break matchScope;
}
}
} else {
// after the last Construct in thatCommand.
if (!(c1 instanceof Variable) || (c1 instanceof Variable && !((Variable) c1).isOptional())) {
break matchScope;
} else {
// There is no need to loop over later Constructs, the commands are ambigous.
break;
}
}
}
if (thatCommand.size() > thisCommand.size()) {
// thisCommand is shorter than thatCommand.
// Commands are not ambigous if thatCommand contains a non-variable or a non-optional variable
// after the last Construct in thisCommand.
Construct c2 = thatCommand.get(thisCommand.size());
if (!(c2 instanceof Variable) || (c2 instanceof Variable && !((Variable) c2).isOptional())) {
break matchScope;
}
}
// The signature of thisCommand and thatCommand are ambigous. Throw a compile exception.
String commandThis = "";
for (Construct c : thisCommand) {
commandThis += c.val() + " ";
}
String commandThat = "";
for (Construct c : thatCommand) {
commandThat += c.val() + " ";
}
script.compilerError = true;
this.compilerError = true;
throw new ConfigCompileException("The command " + commandThis.trim() + " is ambiguous because it " + "matches the signature of " + commandThat.trim() + " defined at " + thatCommand.get(0).getTarget(), thisCommand.get(0).getTarget());
}
}
}
use of com.laytonsmith.core.constructs.Variable in project CommandHelper by EngineHub.
the class Script method compileLeft.
private boolean compileLeft() {
cleft = new ArrayList<>();
if (label != null && label.startsWith("!")) {
if (label.length() > 1) {
label = label.substring(1);
}
nolog = true;
}
for (int i = 0; i < left.size(); i++) {
Token t = left.get(i);
if (t.value.startsWith("/")) {
cleft.add(new Command(t.val(), t.target));
} else if (t.type == Token.TType.VARIABLE) {
cleft.add(new Variable(t.val(), null, t.target));
} else if (t.type.equals(TType.FINAL_VAR)) {
Variable v = new Variable(t.val(), null, t.target);
v.setFinal(true);
cleft.add(v);
} else if (t.type.equals(TType.LSQUARE_BRACKET)) {
if (i + 2 < left.size() && left.get(i + 2).type.equals(TType.OPT_VAR_ASSIGN)) {
Variable v = new Variable(left.get(i + 1).val(), left.get(i + 3).val(), t.target);
v.setOptional(true);
if (left.get(i + 1).type.equals(TType.FINAL_VAR)) {
v.setFinal(true);
}
cleft.add(v);
i += 4;
} else {
t = left.get(i + 1);
Variable v = new Variable(t.val(), null, t.target);
v.setOptional(true);
if (t.val().equals("$")) {
v.setFinal(true);
}
cleft.add(v);
i += 2;
}
} else {
cleft.add(new CString(t.val(), t.getTarget()));
}
}
return true;
}
use of com.laytonsmith.core.constructs.Variable in project CommandHelper by EngineHub.
the class Script method verifyLeft.
private boolean verifyLeft() throws ConfigCompileException {
boolean inside_opt_var = false;
boolean after_no_def_opt_var = false;
String lastVar = null;
// Go through our token list and readjust non-spaced symbols. Any time we combine a symbol,
// the token becomes a string
List<Token> tempLeft = new ArrayList<>();
for (int i = 0; i < left.size(); i++) {
Token t = left.get(i);
if (i == 0 && t.type == TType.NEWLINE) {
continue;
}
if (t.type.isSymbol() && left.size() - 1 > i && left.get(i + 1).type != TType.WHITESPACE) {
StringBuilder b = new StringBuilder();
b.append(t.value);
i++;
Token m = left.get(i);
while (m.type.isSymbol() && m.type != TType.WHITESPACE) {
b.append(m.value);
i++;
m = left.get(i);
}
if (m.type != TType.WHITESPACE && m.type != TType.LABEL) {
b.append(m.value);
}
t = new Token(TType.STRING, b.toString(), t.target);
if (m.type == TType.LABEL) {
tempLeft.add(t);
tempLeft.add(m);
continue;
}
}
// Go ahead and toString the other symbols too
if (t.type.isSymbol()) {
t = new Token(TType.STRING, t.value, t.target);
}
if (t.type != TType.WHITESPACE) {
tempLeft.add(t);
}
}
// Look through and concatenate all tokens before the label, if such exists.
boolean hasLabel = false;
for (Token aTempLeft : tempLeft) {
if (aTempLeft.type == TType.LABEL) {
hasLabel = true;
break;
}
}
if (hasLabel) {
StringBuilder b = new StringBuilder();
int count = 0;
while (tempLeft.get(count).type != TType.LABEL) {
b.append(tempLeft.get(count).val());
count++;
}
tempLeft.set(0, new Token(TType.STRING, b.toString(), Target.UNKNOWN));
for (int i = 0; i < count - 1; i++) {
tempLeft.remove(1);
}
}
left = tempLeft;
for (int j = 0; j < left.size(); j++) {
Token t = left.get(j);
// Token prev_token = j - 2 >= 0?c.tokens.get(j - 2):new Token(TType.UNKNOWN, "", t.line_num);
Token last_token = j - 1 >= 0 ? left.get(j - 1) : new Token(TType.UNKNOWN, "", t.getTarget());
Token next_token = j + 1 < left.size() ? left.get(j + 1) : new Token(TType.UNKNOWN, "", t.getTarget());
Token after_token = j + 2 < left.size() ? left.get(j + 2) : new Token(TType.UNKNOWN, "", t.getTarget());
if (j == 0) {
if (next_token.type == TType.LABEL) {
this.label = t.val();
j--;
left.remove(0);
left.remove(0);
continue;
}
}
if (t.type == TType.LABEL) {
continue;
}
if (t.type.equals(TType.FINAL_VAR) && left.size() - j >= 5) {
throw new ConfigCompileException("FINAL_VAR must be the last argument in the alias", t.target);
}
if (t.type.equals(TType.VARIABLE) || t.type.equals(TType.FINAL_VAR)) {
Variable v = new Variable(t.val(), null, t.target);
lastVar = t.val();
v.setOptional(last_token.type.equals(TType.LSQUARE_BRACKET));
left_vars.put(t.val(), v);
if (v.isOptional()) {
after_no_def_opt_var = true;
} else {
v.setDefault("");
}
}
// We're looking for a command up front
if (j == 0 && !t.value.startsWith("/")) {
if (!(next_token.type == TType.LABEL && after_token.type == TType.COMMAND)) {
throw new ConfigCompileException("Expected command (/command) at start of alias." + " Instead, found " + t.type + " (" + t.val() + ")", t.target);
}
}
if (last_token.type.equals(TType.LSQUARE_BRACKET)) {
inside_opt_var = true;
if (!(t.type.equals(TType.FINAL_VAR) || t.type.equals(TType.VARIABLE))) {
throw new ConfigCompileException("Unexpected " + t.type.toString() + " (" + t.val() + "), was expecting" + " a $variable", t.target);
}
}
if (after_no_def_opt_var && !inside_opt_var) {
if (t.type.equals(TType.VARIABLE) || t.type.equals(TType.FINAL_VAR)) {
throw new ConfigCompileException("You cannot have anything other than optional arguments after your" + " first optional argument.", t.target);
}
}
if (!t.type.equals(TType.LSQUARE_BRACKET) && !t.type.equals(TType.OPT_VAR_ASSIGN) && !t.type.equals(TType.RSQUARE_BRACKET) && !t.type.equals(TType.VARIABLE) && !t.type.equals(TType.LIT) && !t.type.equals(TType.COMMAND) && !t.type.equals(TType.FINAL_VAR)) {
if (j - 1 > 0 && !(/*t.type.equals(TType.STRING) &&*/
left.get(j - 1).type.equals(TType.OPT_VAR_ASSIGN))) {
throw new ConfigCompileException("Unexpected " + t.type + " (" + t.val() + ")", t.target);
}
}
if (last_token.type.equals(TType.COMMAND)) {
if (!(t.type.equals(TType.VARIABLE) || t.type.equals(TType.LSQUARE_BRACKET) || t.type.equals(TType.FINAL_VAR) || t.type.equals(TType.LIT) || t.type.equals(TType.STRING))) {
throw new ConfigCompileException("Unexpected " + t.type + " (" + t.val() + ") after command", t.target);
}
}
if (inside_opt_var && t.type.equals(TType.OPT_VAR_ASSIGN)) {
if (!(next_token.type.isAtomicLit() && after_token.type.equals(TType.RSQUARE_BRACKET) || (next_token.type.equals(TType.RSQUARE_BRACKET)))) {
throw new ConfigCompileException("Unexpected token in optional variable", t.target);
} else if (next_token.type.isAtomicLit()) {
left_vars.get(lastVar).setDefault(next_token.val());
}
}
if (t.type.equals(TType.RSQUARE_BRACKET)) {
if (!inside_opt_var) {
throw new ConfigCompileException("Unexpected " + t.type.toString(), t.target);
}
inside_opt_var = false;
}
}
return true;
}
Aggregations