protected override IEnumerator Execute(Block block) { CustomEnumerator ctor = CSharp.Interpreter.ValueReturn(block, "LIST", new DataStruct("")); yield return(ctor); DataStruct arg0 = ctor.Data; string type = block.GetFieldValue("TYPE"); string direction = block.GetFieldValue("DIRECTION"); switch (type) { case "NUMERIC": arg0.ListValue.ArraySort(CompareNumeric, direction == "-1"); ReturnData(new DataStruct(arg0.ListValue)); break; case "TEXT": arg0.ListValue.ArraySort(CompareText, direction == "-1"); ReturnData(new DataStruct(arg0.ListValue)); break; case "IGNORE_CASE": arg0.ListValue.ArraySort(CompareImgoreCase, direction == "-1"); ReturnData(new DataStruct(arg0.ListValue)); break; } }
private CodeStruct List_Sort(Block block) { string list = Lua.Generator.ValueToCode(block, "LIST", Lua.ORDER_NONE, "{}"); string direction = block.GetFieldValue("DIRECTION"); string type = block.GetFieldValue("TYPE"); string funcName = Lua.Generator.ProvideFunction("list_sort", "function " + Generator.FUNCTION_NAME_PLACEHOLDER + @"(list, typev, direction) local t = {} for n,v in pairs(list) do table.insert(t, v) end local compareFuncs = { NUMERIC = function(a, b) return (tonumber(tostring(a)) or 0) < (tonumber(tostring(b)) or 0) end, TEXT = function(a, b) return tostring(a) < tostring(b) end, IGNORE_CASE = function(a, b) return string.lower(tostring(a)) < string.lower(tostring(b)) end } local compareTemp = compareFuncs[typev] local compare = compareTemp if direction == -1 then compare = function(a, b) return compareTemp(b, a) end end table.sort(t, compare) return t end"); string code = string.Format(@"{0}({1}, ""{2}"", {3})", funcName, list, type, direction); return(new CodeStruct(code, Lua.ORDER_HIGH)); }
private CodeStruct Text_GetSubstring(Block block) { string text = Lua.Generator.ValueToCode(block, "STRING", Lua.ORDER_NONE, "\'\'"); //get start index string where1 = block.GetFieldValue("WHERE1"); if (string.IsNullOrEmpty(where1)) { where1 = "FROM_START"; } int at1Order = where1 == "FROM_END" ? Lua.ORDER_UNARY : Lua.ORDER_NONE; string at1 = Lua.Generator.ValueToCode(block, "AT1", at1Order, "1"); string start = null; if (where1 == "FIRST") { start = "1"; } else if (where1 == "FROM_START") { start = at1; } else if (where1 == "FROM_END") { start = "-" + at1; } //get end index string where2 = block.GetFieldValue("WHERE2"); if (string.IsNullOrEmpty(where2)) { where2 = "FROM_START"; } int at2Order = where2 == "FROM_END" ? Lua.ORDER_UNARY : Lua.ORDER_NONE; string at2 = Lua.Generator.ValueToCode(block, "AT2", at2Order, "1"); string end = null; if (where2 == "LAST") { end = "-1"; } else if (where2 == "FROM_START") { end = at2; } else if (where2 == "FROM_END") { end = "-" + at2; } string code = string.Format("string.sub({0}, {1}, {2})", text, start, end); return(new CodeStruct(code, Lua.ORDER_HIGH)); }
protected override DataStruct Execute(Block block) { string toggleString = block.GetFieldValue("CHECKBOX"); bool toggleValue = toggleString.Equals("TRUE"); return(new DataStruct(toggleValue)); }
protected override IEnumerator Execute(Block block) { CustomEnumerator ctor = CSharp.Interpreter.ValueReturn(block, "TEXT", new DataStruct("")); yield return(ctor); DataStruct arg0 = ctor.Data; string mode = block.GetFieldValue("MODE"); switch (mode) { case "BOTH": ReturnData(new DataStruct(arg0.StringValue.Trim())); break; case "LEFT": ReturnData(new DataStruct(arg0.StringValue.TrimStart())); break; case "RIGHT": ReturnData(new DataStruct(arg0.StringValue.TrimEnd())); break; } }
protected override IEnumerator Execute(Block block) { string procedureName = block.GetFieldValue("NAME"); Block defBlock = block.Workspace.ProcedureDB.GetDefinitionBlock(procedureName); yield return(CSharp.Interpreter.StatementRun(defBlock, "STACK")); }
protected override DataStruct Execute(Block block) { string value = block.GetFieldValue("NUM"); Number num = new Number(value); return(new DataStruct(num)); }
protected override IEnumerator Execute(Block block) { CustomEnumerator ctor = CSharp.Interpreter.ValueReturn(block, "VALUE", new DataStruct("")); yield return(ctor); DataStruct arg0 = ctor.Data; ctor = CSharp.Interpreter.ValueReturn(block, "FIND", new DataStruct("")); yield return(ctor); DataStruct arg1 = ctor.Data; string end = block.GetFieldValue("END"); switch (end) { case "FIRST": ReturnData(arg0.IsString ? new DataStruct(arg0.StringValue.IndexOf(arg1.StringValue) + 1) : new DataStruct(arg0.ListValue.IndexOf(arg1.Value) + 1)); break; case "LAST": ReturnData(arg0.IsString ? new DataStruct(arg0.StringValue.LastIndexOf(arg1.StringValue) + 1) : new DataStruct(arg0.ListValue.LastIndexOf(arg1.Value) + 1)); break; } }
private string Math_Change(Block block) { string varName = Lua.VariableNames.GetName(block.GetFieldValue("VAR"), Variables.NAME_TYPE); string arg = Lua.Generator.ValueToCode(block, "DELTA", Lua.ORDER_ADDITIVE, "0"); return(string.Format("{0} = {0} + {1}\n", varName, arg)); }
private object Procedure_DefReturn(Block block) { string funcName = Lua.VariableNames.GetName(block.GetFieldValue("NAME"), Define.PROCEDURE_CATEGORY_NAME); string branch = Lua.Generator.StatementToCode(block, "STACK", ""); string returnValue = Lua.Generator.ValueToCode(block, "RETURN", Lua.ORDER_NONE); if (!string.IsNullOrEmpty(returnValue)) { returnValue = " return " + returnValue + "\n"; } StringBuilder argumentSB = new StringBuilder(); List <string> arguments = ProcedureDB.GetProcedureArguments(block); for (int i = 0; i < arguments.Count; i++) { argumentSB.Append(Lua.VariableNames.GetName(arguments[i], Define.VARIABLE_CATEGORY_NAME)); if (i < arguments.Count - 1) { argumentSB.Append(", "); } } string code = string.Format("function {0}({1})\n{2}{3}end\n", funcName, argumentSB.ToString(), branch, returnValue); code = Lua.Generator.Scrub(block, code); // Add % so as not to collide with helper functions in definitions list. Lua.Generator.AddFunction('%' + funcName, code); return(null); }
protected override DataStruct Execute(Block block) { string op = block.GetFieldValue("CONSTANT"); switch (op) { case "PI": return(new DataStruct(System.Math.PI)); case "E": return(new DataStruct(System.Math.E)); case "GOLDEN_RATIO": return(new DataStruct(1 + System.Math.Sqrt(5) / 2.0f)); case "SQRT2": return(new DataStruct(System.Math.Sqrt(2.0f))); case "SQRT1_2": return(new DataStruct(System.Math.Sqrt(1 / 2.0f))); case "INFINITY": return(new DataStruct(float.PositiveInfinity)); } return(DataStruct.Undefined); }
private string Control_For(Block block) { string variable0 = CSharp.VariableNames.GetName(block.GetFieldValue("VAR"), Variables.NAME_TYPE); string from = CSharp.Generator.ValueToCode(block, "FROM", CSharp.ORDER_NONE, "0"); string to = CSharp.Generator.ValueToCode(block, "TO", CSharp.ORDER_NONE, "0"); string increment = CSharp.Generator.ValueToCode(block, "BY", CSharp.ORDER_NONE, "1"); string branch = CSharp.Generator.StatementToCode(block, "DO", ""); branch = CSharp.Generator.AddLoopTrap(branch, block.ID); string incValue; float fromValue, toValue, incrementVar; if (float.TryParse(from, out fromValue) && float.TryParse(to, out toValue) && float.TryParse(increment, out incrementVar)) { bool up = fromValue <= toValue; float step = Math.Abs(incrementVar); incValue = up ? "+= " + step : "-= " + step; string code = string.Format("for (float {0} = {1}, {0} {2} {3}, {0} {4})\n{{\n {5}\n}}\n", variable0, from, up ? "<=" : ">=", to, incValue, branch); return(code); } else { throw new Exception("input value \"FROM\" \"TO\" \"BY\" of block controls_for must be a number type."); } }
private string Variables_Set(Block block) { var arg = Lua.Generator.ValueToCode(block, "VALUE", Lua.ORDER_NONE, "0"); var varName = Lua.VariableNames.GetName(block.GetFieldValue("VAR"), Define.VARIABLE_CATEGORY_NAME); return(varName + " = " + arg + "\n"); }
private CodeStruct Math_Constant(Block block) { string op = block.GetFieldValue("CONSTANT"); switch (op) { case "PI": return(new CodeStruct("math.pi", Lua.ORDER_HIGH)); case "E": return(new CodeStruct("math.exp(1)", Lua.ORDER_HIGH)); case "GOLDEN_RATIO": return(new CodeStruct("(1 + math.sqrt(5)) / 2", Lua.ORDER_MULTIPLICATIVE)); case "SQRT2": return(new CodeStruct("math.sqrt(2)", Lua.ORDER_HIGH)); case "SQRT1_2": return(new CodeStruct("math.sqrt(1 / 2)", Lua.ORDER_HIGH)); case "INFINITY": return(new CodeStruct("math.huge", Lua.ORDER_HIGH)); } return(CodeStruct.Empty); }
private string List_RemoveIndex(Block block) { string where = block.GetFieldValue("WHERE"); if (string.IsNullOrEmpty(where)) { where = "FROM_START"; } string list = Lua.Generator.ValueToCode(block, "VALUE", Lua.ORDER_HIGH, "{}"); Regex regex = new Regex(@"^\w+$"); // If `list` would be evaluated more than once (which is the case for LAST, // FROM_END, and RANDOM) and is non-trivial, make sure to access it only once. if ((where == "LAST" || where == "FROM_END" || where == "RANDOM") && !regex.IsMatch(list)) { // `list` is an expression, so we may not evaluate it more than once. // We can use multiple statements. int atOrder = (where == "FROM_END") ? Lua.ORDER_ADDITIVE : Lua.ORDER_NONE; string at = Lua.Generator.ValueToCode(block, "AT", atOrder, "1"); string listVar = Lua.VariableNames.GetDistinctName("tmp_list"); at = GetListIndexStr(listVar, where, at); string code = string.Format("{0} = {1}\ntable.remove({0}, {2})\n", listVar, list, at); return(code); } else { // Either `list` is a simple variable, or we only need to refer to `list` once. string at = Lua.Generator.ValueToCode(block, "AT", Lua.ORDER_NONE, "1"); at = GetListIndexStr(list, where, at); string code = "table.remove(" + list + ", " + at + ")"; return(code + "\n"); } }
protected override IEnumerator Execute(Block block) { ResetFlowState(); StartLoop(); int repeats = int.Parse(block.GetFieldValue("TIMES")); for (int i = 0; i < repeats; i++) { yield return(CSharp.Interpreter.StatementRun(block, "DO")); //reset flow control if (NeedBreak) { break; } if (NeedContinue) { ResetFlowState(); } if (CheckInfiniteLoop()) { break; } } }
protected override IEnumerator Execute(Block block) { Debug.Log(">>>>>> block wait_time start: " + Time.time); CustomEnumerator ctor = CSharp.Interpreter.ValueReturn(block, "TIME", new DataStruct(0)); yield return(ctor); DataStruct time = ctor.Data; string unit = block.GetFieldValue("UNIT"); switch (unit) { case "MILLISECOND": yield return(new WaitForSeconds(time.NumberValue.Value * 0.001f)); break; case "SECONDS": yield return(new WaitForSeconds(time.NumberValue.Value)); break; case "MINUTES": yield return(new WaitForSeconds(time.NumberValue.Value * 60f)); break; case "TOOHIGH": Debug.Log("wait time too long"); break; } Debug.Log(">>>>>> block wait_time end: " + Time.time); }
private CodeStruct Logic_Boolean(Block block) { // Boolean values true and false. string code = block.GetFieldValue("BOOL").Equals("TRUE") ? "true" : "false"; return(new CodeStruct(code, CSharp.ORDER_ATOMIC)); }
private CodeStruct Logic_Operation(Block block) { // Operations 'and', 'or'. bool isAnd = block.GetFieldValue("OP").Equals("AND"); string op = isAnd ? "&&" : "||"; int order = isAnd ? CSharp.ORDER_LOGICAL_AND : CSharp.ORDER_LOGICAL_OR; string argument0 = CSharp.Generator.ValueToCode(block, "A", order); string argument1 = CSharp.Generator.ValueToCode(block, "B", order); if (string.IsNullOrEmpty(argument0) && string.IsNullOrEmpty(argument1)) { argument0 = "false"; argument1 = "false"; } else { //Single missing arguments have no effect on the return value. string defaultArgument = isAnd ? "true" : "false"; if (string.IsNullOrEmpty(argument0)) { argument0 = defaultArgument; } if (string.IsNullOrEmpty(argument1)) { argument1 = defaultArgument; } } string code = argument0 + " " + op + " " + argument1; return(new CodeStruct(code, order)); }
protected override IEnumerator Execute(Block block) { CustomEnumerator ctor = CSharp.Interpreter.ValueReturn(block, "NUM", new DataStruct(0)); yield return(ctor); DataStruct arg0 = ctor.Data; string op = block.GetFieldValue("OP"); switch (op) { case "ROUND": ReturnData(new DataStruct(System.Math.Round(arg0.NumberValue.Value))); break; case "ROUNDUP": ReturnData(new DataStruct(System.Math.Ceiling(arg0.NumberValue.Value))); break; case "ROUNDDOWN": ReturnData(new DataStruct(System.Math.Floor(arg0.NumberValue.Value))); break; } }
private CodeStruct Math_Arithmetic(Block block) { Dictionary <string, KeyValuePair <string, int> > operators = new Dictionary <string, KeyValuePair <string, int> > { { "ADD", new KeyValuePair <string, int>(" + ", CSharp.ORDER_ADDITIVE) }, { "MINUS", new KeyValuePair <string, int>(" - ", CSharp.ORDER_ADDITIVE) }, { "MULTIPLY", new KeyValuePair <string, int>(" * ", CSharp.ORDER_MULTIPLICATIVE) }, { "DIVIDE", new KeyValuePair <string, int>(" / ", CSharp.ORDER_MULTIPLICATIVE) }, { "POWER", new KeyValuePair <string, int>(null, CSharp.ORDER_COMMA) }, }; var pair = operators[block.GetFieldValue("OP")]; string op = pair.Key; int order = pair.Value; string arg0 = CSharp.Generator.ValueToCode(block, "A", order, "0"); string arg1 = CSharp.Generator.ValueToCode(block, "B", order, "0"); string code; if (op == null) { //Power in c# requires a special case since it has no operator. code = string.Format("System.Math.Pow({0}, {1})", arg0, arg1); return(new CodeStruct(code, CSharp.ORDER_EXPRESSION)); } code = arg0 + op + arg1; return(new CodeStruct(code, order)); }
protected override IEnumerator Execute(Block block) { string op = block.GetFieldValue("OP"); CustomEnumerator ctor = CSharp.Interpreter.ValueReturn(block, "A", new DataStruct(false)); yield return(ctor); DataStruct argument0 = ctor.Data; ctor = CSharp.Interpreter.ValueReturn(block, "B", new DataStruct(false)); yield return(ctor); DataStruct argument1 = ctor.Data; if (argument0.Type != argument1.Type || argument0.Type != Define.EDataType.Boolean) { throw new Exception("arguments of block logic_operation should be the same BOOLEAN type"); } DataStruct returnData = new DataStruct(false); switch (op) { case "AND": returnData.BooleanValue = argument0.BooleanValue && argument1.BooleanValue; break; case "OR": returnData.BooleanValue = argument0.BooleanValue || argument1.BooleanValue; break; } ReturnData(returnData); }
private CodeStruct List_IndexOf(Block block) { string list = Lua.Generator.ValueToCode(block, "VALUE", Lua.ORDER_UNARY, "{}"); string item = Lua.Generator.ValueToCode(block, "FIND", Lua.ORDER_NONE, "\'\'"); string funcName; if (block.GetFieldValue("END").Equals("FIRST")) { funcName = Lua.Generator.ProvideFunction("first_index", "function " + Generator.FUNCTION_NAME_PLACEHOLDER + @"(t, elem) for k, v in ipairs(t) do if v == elem then return k end end return 0 end"); } else { funcName = Lua.Generator.ProvideFunction("last_index", "function " + Generator.FUNCTION_NAME_PLACEHOLDER + @"(t, elem) for i = #t, 1, -1 do if t[i] == elem then return i end end return 0 end"); } string code = string.Format("{0}({1}, {2})", funcName, list, item); return(new CodeStruct(code, Lua.ORDER_HIGH)); }
protected override IEnumerator Execute(Block block) { ResetFlowState(); CustomEnumerator ctor = CSharp.Interpreter.ValueReturn(block, "LIST"); yield return(ctor); DataStruct arg0 = ctor.Data; if (arg0.IsUndefined) { arg0 = new DataStruct(new ArrayList()); } if (!arg0.IsList) { throw new Exception("input value \"LIST\" of block controls_forEach must be LIST type"); } string variable0 = CSharp.VariableNames.GetName(block.GetFieldValue("VAR"), Variables.NAME_TYPE); foreach (var e in arg0.ListValue) { DataStruct data; if (e is bool) { data = new DataStruct((bool)e); } else if (e is float) { data = new DataStruct(new Number((float)e)); } else if (e is string) { data = new DataStruct((string)e); } else if (e is ArrayList) { data = new DataStruct((ArrayList)e); } else { throw new Exception("LIST element is undefined type."); } CSharp.VariableDatas.SetData(variable0, data); yield return(CSharp.Interpreter.StatementRun(block, "DO")); //reset flow control if (NeedBreak) { break; } if (NeedContinue) { ResetFlowState(); } } }
private CodeStruct Text_CharAt(Block block) { // Get letter at index. string where = block.GetFieldValue("WHERE"); if (string.IsNullOrEmpty(where)) { where = "FROM_START"; } int atOrder = where == "FROM_END" ? Lua.ORDER_UNARY : Lua.ORDER_NONE; string at = Lua.Generator.ValueToCode(block, "AT", atOrder, "1"); string text = Lua.Generator.ValueToCode(block, "VALUE", Lua.ORDER_NONE, "\'\'"); StringBuilder code = new StringBuilder(); if (where == "RANDOM") { string funcName = Lua.Generator.ProvideFunction("text_random_letter", "function " + Generator.FUNCTION_NAME_PLACEHOLDER + @"(str) local index = math.random(string.len(str)) return string.sub(str, index, index) end"); code.Append(funcName + "(" + text + ")"); } else { string start = null; if (where == "FIRST") { start = "1"; } else if (where == "LAST") { start = "-1"; } else if (where == "FROM_START") { start = at; } else if (where == "FROM_END") { start = "-" + at; } Regex regex = new Regex(@"^-?\w*$"); if (regex.IsMatch(start)) { code.Append(string.Format("string.sub({0}, {1}, {1})", text, start)); } else { string funcName = Lua.Generator.ProvideFunction("text_char_at", "function " + Generator.FUNCTION_NAME_PLACEHOLDER + @"(str, index) return string.sub(str, index, index) end"); code.Append(string.Format("{0}({1}, {2})", funcName, text, start)); } } return(new CodeStruct(code.ToString(), Lua.ORDER_HIGH)); }
private CodeStruct Math_Number(Block block) { string code = block.GetFieldValue("NUM"); float num = float.Parse(code); int order = num < 0 ? Lua.ORDER_UNARY : Lua.ORDER_ATOMIC; return(new CodeStruct(code, order)); }
protected override IEnumerator Execute(Block block) { string varName = CSharp.VariableNames.GetName(block.GetFieldValue("VAR"), Define.VARIABLE_CATEGORY_NAME); CustomEnumerator ctor = CSharp.Interpreter.ValueReturn(block, "VALUE"); yield return(ctor); CSharp.VariableDatas.SetData(varName, ctor.Data); }
private string Control_Repeat(Block block) { int repeats = int.Parse(block.GetFieldValue("TIMES")); string branch = CSharp.Generator.StatementToCode(block, "DO", ""); string loopVar = CSharp.VariableNames.GetDistinctName("count"); string code = string.Format("for (int {0} = 0; {0} < {1}; ++{0})\n{{\n {2}\n}}\n", loopVar, repeats, branch); return(code); }
private CodeStruct Math_Single(Block block) { string op = block.GetFieldValue("OP"); string code; string arg; if (op == "NEG") { // Negation is a special case given its different operator precedence. arg = Lua.Generator.ValueToCode(block, "NUM", Lua.ORDER_UNARY, "0"); return(new CodeStruct("-" + arg, Lua.ORDER_UNARY)); } if (op == "SIN" || op == "COS" || op == "TAN") { arg = Lua.Generator.ValueToCode(block, "NUM", Lua.ORDER_MULTIPLICATIVE, "0"); } else { arg = Lua.Generator.ValueToCode(block, "NUM", Lua.ORDER_NONE, "0"); } switch (op) { case "ABS": code = string.Format("math.abs({0})", arg); break; case "ROOT": code = string.Format("math.sqrt({0})", arg); break; case "LN": code = string.Format("math.log({0})", arg); break; case "LOG10": code = string.Format("math.log10({0})", arg); break; case "EXP": code = string.Format("math.exp({0})", arg); break; case "POW10": code = string.Format("math.pow(10, {0})", arg); break; case "ROUND": code = string.Format("math.floor({0}, .5)", arg); break; case "ROUNDUP": code = string.Format("math.ceil({0})", arg); break; case "ROUNDDOWN": code = string.Format("math.floor({0})", arg); break; case "SIN": code = string.Format("math.sin(math.rad({0}))", arg); break; case "COS": code = string.Format("math.cos(math.rad({0}))", arg); break; case "TAN": code = string.Format("math.tan(math.rad({0}))", arg); break; case "ASIN": code = string.Format("math.deg(math.asin({0}))", arg); break; case "ACOS": code = string.Format("math.deg(math.acos({0}))", arg); break; case "ATAN": code = string.Format("math.deg(math.atan({0}))", arg); break; default: throw new Exception("Unknown math operator: " + op); } return(new CodeStruct(code, Lua.ORDER_HIGH)); }
private string Control_FlowStatement(Block block) { switch (block.GetFieldValue("FLOW")) { case "BREAK": return("break\n"); case "CONTINUE": return("goto continue\n"); } throw new Exception("Unknown flow statement."); }