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); }
internal DelimiterList(ValueDelimiter delim, List<DelimiterNode> nodes, int indent, string startDelim, string original, IScope scope) { m_delimiter = delim; m_nodes = nodes; m_indent = indent; m_startDelim = startDelim; // if known m_original = original; m_scope = scope; }
static IScope CreateStringScope() { ScopeChain scope = new ScopeChain(); String.Register(scope); ValueDelimiter square = new ValueDelimiter("]", DelimiterType.AsArray); scope.SetValue("[", square); ValueDelimiter str = new ValueDelimiter("'", DelimiterType.AsString); scope.SetValue("'", str); ValueDelimiter curly = new ValueDelimiter("}", DelimiterType.AsArray, new CreateMap()); scope.SetValue("{", curly); return scope; }
static IScope CreateMathScope() { ScopeChain scope = new ScopeChain(); Math.Register(scope); ValueDelimiter square = new ValueDelimiter("]", DelimiterType.AsArray); scope.SetValue("[", square); return scope; }
internal override Value Eval(Value arg, IScope scope) { // extract the delimiter strings string delims = arg.AsString; string start = delims.Substring(0, delims.Length / 2); string end = delims.Substring(delims.Length / 2, delims.Length - delims.Length / 2); // create the delimiter & store it on the current scope ValueDelimiter value = new ValueDelimiter(end, DelimiterType); scope.SetValue(start, value); return value; }
/// <summary>A start delimiter was found without an end delimiter</summary> internal Loki3Exception AddMissingEndDelimiter(ValueDelimiter delim) { m_map[keyMissingEndDelimiter] = delim; return this; }
// simply search for end and stuff everything in the middle into a single token private static bool ParseString(int indent, string[] strs, int iStart, ValueDelimiter thisDelim, List<DelimiterNode> nodes, out int iEnd, out DelimiterList result) { iEnd = -1; bool bExtra = false; for (int i = iStart; i < strs.Length; i++) { string s = strs[i]; if (s == thisDelim.End) { iEnd = i; break; } else if (s.Substring(s.Length - 1, 1) == thisDelim.End) { iEnd = i + 1; bExtra = true; break; } } // no specified end delim means take the remainder of the line if (thisDelim.End == "") iEnd = strs.Length; // if we found end, wrap entire string in a single node if (iEnd != -1) { string subStr = GetSubStr(iStart, iEnd, strs); if (bExtra) { subStr = subStr.Substring(0, subStr.Length - 1); --iEnd; } Token token = new Token(subStr); DelimiterNode node = new DelimiterNodeToken(token); nodes.Add(node); result = new DelimiterList(thisDelim, nodes, indent, strs[iStart - 1], subStr, null); return true; } result = null; return false; }
// 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; }
// ignore everything up to the end delimiter private static bool ParseComment(string[] strs, int iStart, ValueDelimiter thisDelim, out int iEnd, out DelimiterList result) { result = null; for (int i = iStart; i < strs.Length; i++) { if (strs[i] == thisDelim.End) { iEnd = i; return true; } } iEnd = strs.Length; return false; }