/// <summary> /// Parses raw lines in to the system. /// </summary> private void parseScriptGroup(List<string> rawLines, string filePath, string fileKey, Logger fileLog) { // split-up the lines in to indatation based blocks. var group = new GroupInfo(filePath, fileKey, fileLog); scriptsLock.EnterWriteLock(); scriptGroups.Add(group); scriptsLock.ExitWriteLock(); var blocks = group.Blocks; int currentLine = 0; string blockKey = null; string[] blockTags = null; string[] blockResponses = null; int blockLine = 0; while (currentLine < rawLines.Count) { string str = rawLines[currentLine]; int indent = 0; fileLog.SetId(currentLine); if (parseCutLine(ref str, ref indent)) // line empty? { if (indent == 0) // indent 0 defines what the key of the upcoming object is. { List<string[]> args; parseBlockStart(str, out blockKey, out args, fileLog); blockTags = null; blockResponses = null; if (args.Count > 0) blockTags = KeyClean(args[0], fileLog); if (args.Count > 1) blockResponses = SanitizeInputReplace(args[1]); blockLine = currentLine; // make sure key is a valid type. var rootKey = KeySplit(blockKey)[0]; if (rootKey != "script" && rootKey != "list" && rootKey != "setup" && rootKey != "personality") { fileLog.Error(string.Format(StringsScripting.Formatted_Error_Invalid_root_type, rootKey), currentLine); break; } ++currentLine; } else if (indent > 0) { if (blockKey == null) { fileLog.Error(StringsScripting.Invalid_Indentation, currentLine); break; } var log = new Logger(fileKey + "." + blockKey); var lines = parseBlock(rawLines, ref currentLine, indent, log); if (lines == null) blocks.Add(new BlockBase(blockKey, null, blockTags, group, log)); else { // Figureout type of script, then add it. var keySplit = KeySplit(blockKey); if (keySplit.Length == 2) { if (keySplit[1] == null || keySplit[1].Length == 0) { fileLog.Warning(StringsScripting.Warning_Empty_sub_key); continue; } var key = fileKey + '.' + keySplit[1]; switch (keySplit[0]) { case "setup": scriptsLock.EnterWriteLock(); try { if (keySplit[1] == "controller") setupController.Add(new Script(this, false, blockKey, lines, blockTags, group, log)); else if (keySplit[1] == "personality") setupPersonality.Add(new Script(this, false, blockKey, lines, blockTags, group, log)); //else //ToDo : Error unknown setup type. } finally { scriptsLock.ExitWriteLock(); } // ToDo : Remove error from strings. //if (blockTags != null && blockTags.Length > 0) // fileLog.Warning(StringsScripting.Setup_has_tags, blockLine); // warn if has responses if (blockResponses != null && blockResponses.Length >= 0) fileLog.Warning(StringsScripting.Setup_has_responses, blockLine); break; case "script": case "list": { var script = new Script(this, keySplit[0] == "list", blockKey, lines, blockTags, group, log); blocks.Add(script); addScript(keySplit[0], fileKey, keySplit[1], script, blockTags, blockResponses); } break; case "personality": { key = keySplit[1]; // does personality already exist? Personality p = null; Variable<Personality> vP = null; if (personalities.TryGetValue(key, out vP)) p = vP.Value; // if not create new. else p = CreatePersonality(key); // run through the script to fill the personalities variables. var script = new Script(this, false, blockKey, lines, null, group, log); var c = new Controller(this, "DUMMY"); c.AddPersonality(p); var sb = new StringBuilder(); validateScript(c, script, null, sb); runThroughScript(c, script, sb); } break; default: fileLog.Error(string.Format(StringsScripting.Formatted_Error_Invalid_root_type, keySplit[0]), blockLine); return; } } else { fileLog.Error(string.Format(StringsScripting.Formatted_Error_Invalid_root_type, keySplit[0]), blockLine); break; } } } } else ++currentLine; } return; }
/// <summary> /// Parses rawLines in to blocks of code recursively based on blockIndent. /// </summary> /// <param name="rawLines"></param> /// <param name="currentLine"></param> /// <param name="blockIndent">Indent level this block is at.</param> /// <returns>Block with lines, or null if zero lines.</returns> private static Line[] parseBlock(List<string> rawLines, ref int currentLine, int blockIndent, Logger log) { // temp list of lines, until we are finished parsing. var lines = new List<Line>(); string lineData; int lineIndent = 0; int indentDifference; // Note: This loop is picky, do NOT edit unilss you understand what is happening. // currentLine should be added to once we are done with the line. while (currentLine < rawLines.Count) { log.SetId(currentLine + 1); // get raw line, cut it and get indent level. lineData = rawLines[currentLine]; if (parseCutLine(ref lineData, ref lineIndent)) { indentDifference = lineIndent - blockIndent; // if indentation difference is negative, then exit the block. if (indentDifference < 0) { break; } // indentation unchanged, so just add the line. else if (indentDifference == 0) { lines.Add(new Line(currentLine + 1, lineData, null)); ++currentLine; } // next level of indentation. Parse as a sub block, then add to last line. else if (indentDifference == +1) { Line[] block = parseBlock(rawLines, ref currentLine, lineIndent, log); if (block == null) // ignore block if empty continue; if (lines.Count == 0) { log.Warning(StringsScripting.Invalid_Indentation); lines.Add(new Line(-1, "", block)); } else { // replace the last line, with the new lines. var tmp = lines[lines.Count - 1]; lines[lines.Count - 1] = new Line(tmp.LineNumber, tmp.Data, block); } } else // invalid indentation. { log.Warning(StringsScripting.Invalid_Indentation); ++currentLine; } } else // line was empty ++currentLine; } if (lines.Count == 0) return null; return lines.ToArray(); }
/// <summary> Parses rawLines as csv for the input replace system </summary> private void parseInputReplace(List<string> rawLines, Logger log) { for (int line = 0; line < rawLines.Count; ++line) { // get line ignore empty var str = rawLines[line]; if (str == null || str.Length == 0 || str.StartsWith("//")) continue; log.SetId(line + 1); // split line, check length. var val = str.Split(','); if (val.Length == 0) continue; if (val.Length < 2) { log.Warning(StringsScripting.InputReplace_Pass_empty); continue; } // get pass and keyward. string keyword = SanitizeInputReplace(val[1]); int pass; if (!int.TryParse(val[0], out pass) || pass < 0) { log.Warning(StringsScripting.InputReplace_Pass_not_a_number); continue; } pass--; // fill list upto pass. while (pass >= inputReplace.Count) { inputReplace.Add(null); } if (inputReplace[pass] == null) inputReplace[pass] = new Dictionary<string, string>(); // split, trim then add to level. var level = inputReplace[pass]; for (int i = 2; i < val.Length; ++i) { var tmp = SanitizeInputReplace(val[i]); if (tmp.Length == 0) continue; if (tmp == keyword) { log.Warning(string.Format(StringsScripting.Formatted_InputReplace_Duplicate_keyword, keyword, val[i])); continue; } level[tmp] = keyword; } } }