private static DelimiterList Do(int indent, string original, string[] strs, int iStart, ValueDelimiter thisDelim, IParseLineDelimiters delims, ILineRequestor requestor, out int iEnd) { List<DelimiterNode> nodes = new List<DelimiterNode>(); DelimiterType type = thisDelim.DelimiterType; if (type == DelimiterType.AsComment) { // ignore everything up to the end delimiter DelimiterList result = null; if (ParseComment(strs, iStart, thisDelim, out iEnd, out result)) return result; } else if (type == DelimiterType.AsString) { // simply search for end and stuff everything in the middle into a single token DelimiterList result = null; if (ParseString(indent, strs, iStart, thisDelim, nodes, out iEnd, out result)) return result; } else // Value, Array && Raw { // handle as individual tokens and nested lists DelimiterList result = null; if (ParseMisc(indent, original, strs, iStart, thisDelim, delims, requestor, nodes, out iEnd, out result)) return result; } // didn't find closing delimiter, TODO request the next line if (thisDelim != ValueDelimiter.Line && thisDelim.End != "") throw new Loki3Exception().AddMissingEndDelimiter(thisDelim); iEnd = strs.Length; string trimmed = original.TrimStart(' ', '\t'); return new DelimiterList(thisDelim, nodes, indent, "", trimmed, null); }
/// <summary> /// Creates delimiter list from string, /// can request lines if missing closing delimiter /// </summary> /// <param name="str">line to parse</param> /// <param name="requestor">used to ask for additional lines if needed, may be null</param> /// <param name="delims">used to ask questions about delimiters</param> internal static DelimiterList Do(string str, IParseLineDelimiters delims, ILineRequestor requestor) { string[] strs = ParseChars.Do(str, delims); int indent = Utility.CountIndent(str); int end; return Do(indent, str, strs, 0, ValueDelimiter.Line, delims, requestor, out end); }
/// <summary>If we haven't already parsed our lines, do so now</summary> private void EnsureParsed(IParseLineDelimiters delims) { if (m_rawLines == null) return; m_parsedLines = new List<DelimiterList>(m_rawLines.Count); foreach (Value v in m_rawLines) { DelimiterList line = null; if (v is ValueString) line = ParseLine.Do(v.AsString, delims); else if (v is ValueRaw) line = (v as ValueRaw).GetValue(); if (line != null) m_parsedLines.Add(line); } m_rawLines = null; }
internal static string[] Do(string s, IParseLineDelimiters delims) { List<string> list = new List<string>(); StringBuilder current = new StringBuilder(); bool atStart = true; bool inWord = false; bool inString = false; char endString = ' '; int maxDelimLen = 0; // find single char string delims //!! fetch from delims List<string> quotes = new List<string>(); Dictionary<string, ValueDelimiter> stringDelims = (delims == null ? null : delims.GetStringDelims()); if (stringDelims != null) { foreach (string key in stringDelims.Keys) { quotes.Add(key); if (key.Length > maxDelimLen) maxDelimLen = key.Length; } } // parse int len = s.Length; for (int i = 0; i < len; i++) { char c = s[i]; if (inString) { if (c == endString) { // end of string if (current.Length > 0) list.Add(current.ToString()); list.Add(c.ToString()); inString = inWord = false; atStart = true; current = new StringBuilder(); } else { current.Append(c); } } else if (s_white.IndexOf(c) == -1) { // non-white if (atStart) { atStart = false; string cAsStr = c.ToString(); if (quotes.Contains(cAsStr)) { // start of string // find the longest starting delim int additional = 0; for (int j = 1; j < maxDelimLen; j++) { if (i + j + 1 > len) break; string substr = s.Substring(i, j + 1); if (quotes.Contains(substr)) { cAsStr = substr; additional = j; } } i += additional; list.Add(cAsStr); //!! should allow multi-char string endDelim = stringDelims[cAsStr].End; endString = (endDelim == null ? '\0' : endDelim[0]); inString = true; continue; } } current.Append(c); inWord = true; } else if (inWord) { // end of word if (current.Length > 1 && current[current.Length - 1] == ',') // remove trailing comma current.Remove(current.Length-1, 1); list.Add(current.ToString()); inWord = false; atStart = true; current = new StringBuilder(); } } if (inWord || inString) list.Add(current.ToString()); return list.ToArray(); }
public DelimiterList GetCurrentLine(IParseLineDelimiters delims) { if (m_current >= m_count) return null; // see if line was already parsed DelimiterList parsedLine = (m_current < m_parsedLines.Count ? m_parsedLines[m_current] : null); if (parsedLine == null) { // if not, parse it now parsedLine = ParseLine.Do(m_lines[m_current], delims); m_parsedLines.Add(parsedLine); } return parsedLine; }
/// <summary> /// Creates delimiter list from string. All delimiters must be closed. /// </summary> /// <param name="str">line to parse</param> /// <param name="delims">used to ask questions about delimiters</param> internal static DelimiterList Do(string str, IParseLineDelimiters delims) { return Do(str, delims, null); }
// handle as individual tokens and nested lists private static bool ParseMisc(int indent, string original, string[] strs, int iStart, ValueDelimiter thisDelim, IParseLineDelimiters delims, ILineRequestor requestor, List<DelimiterNode> nodes, out int iEnd, out DelimiterList result) { result = null; iEnd = strs.Length; for (int i = iStart; i < strs.Length; i++) { string s = strs[i]; // is this the end of current set of delimited tokens? if (s == thisDelim.End) { // end delimiter iEnd = i; string subStr = GetSubStr(iStart, iEnd, strs); result = new DelimiterList(thisDelim, nodes, indent, strs[iStart - 1], subStr, null); return true; } // TODO: rework this so I don't need to check for : (e.g. for :}, when creating a delim) if (s.Substring(s.Length - 1, 1) == thisDelim.End && (s[0] != ':' || s.Length > 2)) { // end delimiter is part of final token iEnd = i + 1; string without = s.Substring(0, s.Length - 1); Token token = new Token(without); DelimiterNode node = new DelimiterNodeToken(token); nodes.Add(node); strs[i] = without; string subStr = GetSubStr(iStart, iEnd, strs); result = new DelimiterList(thisDelim, nodes, indent, strs[iStart - 1], subStr, null); strs[i] = s; --iEnd; return true; } // is it a stand alone starting delimiter? bool bAnyToken = false; ValueDelimiter subDelim = (delims == null ? null : delims.GetDelim(s, out bAnyToken)); string[] strsToUse = strs; bool bExtra = true; if (subDelim == null && !bAnyToken) { // whole thing wasn't a delimiter, function, etc., how about the 1st char? string s1 = s.Substring(0, 1); subDelim = (delims == null ? null : delims.GetDelim(s1, out bAnyToken)); if (subDelim != null) { // copy across array, but break iStart into delim & remainder bExtra = false; strsToUse = new string[strs.Length + 1]; for (int j = 0; j < i; j++) strsToUse[j] = strs[j]; strsToUse[i] = s1; strsToUse[i + 1] = s.Substring(1); for (int j = i + 1; j < strs.Length; j++) strsToUse[j + 1] = strs[j]; } } if (subDelim != null) { // start delimiter int end; DelimiterList sublist = Do(0, original, strsToUse, i + 1, subDelim, delims, requestor, out end); if (sublist != null) { DelimiterNodeList node = new DelimiterNodeList(sublist); nodes.Add(node); } // skip past the sublist i = (bExtra ? end : end - 1); } else { // stand alone token Token token = new Token(s); DelimiterNode node = new DelimiterNodeToken(token); nodes.Add(node); } } return false; }