/// Read expression from string, evaluate it and return the value public object Eval(string expression) { if (expression == null) { return(null); } if (_exprCache == null) { _exprCache = new PrecompiledCache(128); } IOperation ex = _exprCache[expression]; if (ex == null) { using (var sr = new ParsingReader(new StringReader(expression))) { ex = new Parser(TokenSpecialCharacters).Parse(sr); sr.SkipWhiteSpace(); sr.ReadAndThrowIfNot(-1); _exprCache[expression] = ex; } } if (ex == null) { return(null); } return(Eval(ex)); }
/// Evaluate string and return the result of the evaluation, casted to the type T public T Eval <T>(string st) { using (var sr = new ParsingReader(new StringReader(st))) { var o = Eval <T>(sr); sr.SkipWhiteSpaceAndComments(); sr.ReadAndThrowIfNot(-1); return(o); } }
/// Parse stream until the end of the expression, evaluate it, and return result of the evaluation converted to type T public T Eval <T>(ParsingReader sr) { var p = Parser.Parse(sr); if (p == null) { return(Utils.To <T>(null)); } return(Eval <T>(p)); }
/// <summary> /// Load script from string /// </summary> /// <param name="scriptXml">script as XML</param> public void Load(string scriptXml) { Items.Clear(); bool close = true; var r = new ParsingReader(new StringReader(scriptXml)); try { r.SkipWhiteSpace(); if (r.Peek() == '<') { // Get a script file XmlReaderSettings rs = new XmlReaderSettings(); rs.IgnoreWhitespace = false; rs.ValidationType = ValidationType.None; using (XmlReader xr = XmlReader.Create(r, new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Fragment })) { close = false; Load(xr); return; } } if (r.Peek() == '=') { r.Read(); Items.Add(new Eval { Value = r.ReadToEnd() }); return; } Items.Add(new Code { Value = r.ReadToEnd() }); return; } finally { if (close) { r.Close(); } } }
/// Parse command line into the list of arguments. Mimics .NET command line parsing logic where possible public static string[] SplitArgs(string commandLine) { if (commandLine == null) { return(null); } bool quoted = false; List <string> args = new List <string>(); StringBuilder sb = new StringBuilder(); using (var reader = new ParsingReader(new StringReader(commandLine))) { int n; do { n = reader.Read(); if (n == '"') { quoted = true; while (!reader.IsEOF) { var ch = (char)reader.Read(); if (ch == '"') { break; } sb.Append(ch); } } else if (n == -1 || char.IsWhiteSpace((char)n)) { if (sb.Length > 0 || quoted) { args.Add(sb.ToString()); } sb.Length = 0; quoted = false; } else { sb.Append((char)n); } } while (n != -1); } return(args.ToArray()); }
/// True if str is a number public static bool IsNumber(string str) { if (str == null) { throw new ArgumentNullException("str"); } using (var sr = new ParsingReader(str)) { if (sr.ReadNumber() == null) { return(false); } sr.SkipWhiteSpaceAndComments(); if (sr.Peek() != -1) { return(false); } } return(true); }
/// <summary> /// Try to get variable value /// </summary> /// <param name="key">Variable name</param> /// <param name="value">Where to store found variable value</param> /// <returns>true if variable is set</returns> public override bool TryGetValue(string key, out object value) { if (!IsCalculated(key)) { return(base.TryGetValue(key, out value)); } using (var sr = new ParsingReader(key)) { sr.SkipWhiteSpace(); value = sr.ReadNumber(); if (value != null) { sr.SkipWhiteSpace(); sr.ReadAndThrowIfNot(-1); return(true); } } value = EvalMulti(key); return(true); }
/// Parse string to a number. 10 and hex numbers (like 0x222) are allowed. Suffixes like 20.3f are also allowed. public static ValueType ParseNumber(string str) { if (str == null) { throw new ArgumentNullException("str"); } using (var sr = new ParsingReader(str)) { sr.SkipWhiteSpaceAndComments(); ValueType o = sr.ReadNumber(); if (o == null) { throw new ParsingException("Invalid numeric expression at " + sr.ReadLine()); } sr.SkipWhiteSpaceAndComments(); if (sr.Peek() != -1) { throw new ParsingException("Invalid numeric expression, unexpected characters at " + sr.ReadLine()); } return(o); } }
/// Returns null if str is not a number, or its value otherwise public static ValueType TryParseNumber(string stringToParse) { if (stringToParse == null) { return(null); } using (var sr = new ParsingReader(stringToParse)) { sr.SkipWhiteSpaceAndComments(); ValueType o = sr.ReadNumber(); if (o == null) { return(null); } sr.SkipWhiteSpaceAndComments(); if (sr.Peek() != -1) { return(null); } return(o); } }
/// <summary> /// Parse stream and return the expression tree /// </summary> /// <param name="r">Stream</param> /// <returns>Parsed expression or null if no expression is found on stream</returns> public IOperation Parse(ParsingReader r) { List <IOperation> data = new List <IOperation>(); while (!r.IsEOF) { TokenQueue tokenQueue = new TokenQueue(this, r); var ex = parseSingleStatement(tokenQueue, -1); if (ex == null) { break; } if (data.Count > 0) { data.Add(new Operations.OperationPop()); } data.Add(ex); r.SkipWhiteSpaceAndComments(); if (r.Peek() != ';') { break; } do { r.Read(); r.SkipWhiteSpaceAndComments(); } while (r.Peek() == ';'); } if (data.Count == 0) { return(null); } if (data.Count == 1) { return(data[0]); } return(new Operations.OperationExpression(data.ToArray())); }
/// Read multi-expression (like ${a|b|=3+5}) from the string, evaluate it and return the value public object EvalMulti(string multiExpression) { if (multiExpression == null) { return(null); } if (_exprCache == null) { _exprCache = new PrecompiledCache(128); } IOperation o = _exprCache[multiExpression]; if (o == null) { using (var sr = new ParsingReader(new StringReader(multiExpression))) { o = new Parser(TokenSpecialCharacters).ParseMulti(sr); sr.SkipWhiteSpace(); sr.ReadAndThrowIfNot(-1); _exprCache[multiExpression] = o; } } return(Eval(o)); }
/// <summary> /// Try to get variable value /// </summary> /// <param name="key">Variable name</param> /// <param name="value">Where to store found variable value</param> /// <returns>true if variable is set</returns> public override bool TryGetValue(string key, out object value) { if (!IsCalculated(key)) { return(base.TryGetValue(key, out value)); } using (var sr = new ParsingReader(key)) { sr.SkipWhiteSpace(); value = sr.ReadNumber(); if (value != null) { sr.SkipWhiteSpace(); sr.ReadAndThrowIfNot(-1); return(true); } } if (!string.IsNullOrEmpty(key)) { switch (key[0]) { case '%': EnvironmentVariableTarget target = getTarget(ref key); value = Environment.GetEnvironmentVariable(key, target); return(value != null); case '~': value = Find(key.Substring(1), true); return(true); } } value = EvalMulti(key); return(true); }
/// Parse stream until the end of the expression, evaluate it, and return result of the evaluation public object Eval(ParsingReader sr) { return(Eval <object>(sr)); }
public TokenQueue(Parser p, ParsingReader r) { _reader = r; _parser = p; }
private static object convertString(string text, Type pt) { if (pt.IsGenericType && pt.GetGenericTypeDefinition() == typeof(Nullable <>)) { if (String.IsNullOrEmpty(text)) { return(null); } return(convertString(text, pt.GetGenericArguments()[0])); } if (String.IsNullOrEmpty(text)) { if (pt.IsPrimitive || pt.IsEnum || pt == typeof(decimal)) { text = "0"; } } if (pt == typeof(bool)) { int t; if (Int32.TryParse(text, out t)) { return(t != 0); } return(Boolean.Parse(text)); } if (pt == typeof(byte) || pt == typeof(sbyte) || pt == typeof(short) || pt == typeof(ushort) || pt == typeof(int) || pt == typeof(uint) || pt == typeof(long) || pt == typeof(ulong) || pt == typeof(decimal) || pt == typeof(float) || pt == typeof(double)) { object o = ParsingReader.TryParseNumber(text); if (o == null) { throw new InvalidCastException("Cannot cast '" + text + "' to " + pt.FullName); } return(Convert.ChangeType(o, pt)); } if (pt == typeof(char?)) { if (string.IsNullOrEmpty(text)) { return(null); } return(text[0]); } if (pt == typeof(char)) { return(text[0]); } if (pt == typeof(DateTime)) { return(DateTime.Parse(text)); } if (pt == typeof(Guid)) { return(new Guid(text)); } if (pt == typeof(string)) { return(text); } if (pt.IsEnum) { bool hasFlags = CustomAttributeHelper.Has <FlagsAttribute>(pt); bool hasDigits = !string.IsNullOrEmpty(text) && text.IndexOfAny("0123456789".ToCharArray()) != -1; bool isempty = string.IsNullOrEmpty(text); if (isempty || hasFlags || hasDigits) { long val = 0; var names = Enum.GetNames(pt); var dictionary = new Dictionary <string, long>(StringComparer.OrdinalIgnoreCase); var values = Enum.GetValues(pt); for (int i = 0; i < names.Length; ++i) { long vv = (long)Convert.ChangeType(values.GetValue(i), typeof(long)); dictionary[names[i]] = vv; if (isempty && vv == 0) { return(Enum.ToObject(pt, vv)); } } if (isempty) { throw new InvalidCastException(String.Format("Unexpected empty enum value")); } int step = 0; foreach (string str in text.Split(s_enumDelimiters)) { if (String.IsNullOrEmpty(str)) { continue; } step++; if (!hasFlags && step > 1) { throw new InvalidCastException(String.Format("Unexpected enum value {0}", str)); } long v; if (char.IsDigit(str[0])) { val |= ParsingReader.ParseNumber <long>(str); } else if (dictionary.TryGetValue(str, out v)) { val |= v; } else { throw new InvalidCastException(String.Format("Unexpected enum value {0}", str)); } } return(Enum.ToObject(pt, val)); } return(Enum.Parse(pt, text, true)); } throw new InvalidCastException(String.Format("'{0}' cannot be converted to {1}", text, pt.ToString())); }
private IEnumerable <Vars> getTransformedRows(string columnsOverride, string sortOverride, string whereExpression) { bool overrideSort = (sortOverride != null); if (!overrideSort) { sortOverride = Context.TransformStr(SortColumns, Transform); } // ColumnsInfo ci = new ColumnsInfo(); // Load CSV, if present string text = GetTransformedValueStr(); string quote = Context.TransformStr(Quote, Transform); string separator = Context.TransformStr(Separator, Transform); char? quoteChar = string.IsNullOrEmpty(quote) ? (char?)null : quote[0]; bool trim = (Options & RowsetOptions.Trim) != 0; string colNames = Context.TransformStr(Columns, Transform);; // Read additional column names from the first CSV row, if specified ParsingReader csvReader = null; if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(text.Trim())) { csvReader = new ParsingReader(new StringReader(text)); if ((Options & RowsetOptions.Header) == RowsetOptions.Header) { csvReader.SkipWhiteSpace(); colNames = Context.TransformStr(csvReader.ReadLine(), Verbatim ? TransformRules.None : Transform); } } char sep = string.IsNullOrEmpty(separator) ? '\0' : separator[0]; // Add these columns if (!string.IsNullOrEmpty(colNames)) { ci.AddParsed(Context, colNames, quoteChar, sep, trim); } // Add extra columns if (Cols != null) { foreach (var col in Cols) { ColumnInfo cc = new ColumnInfo(); cc.Name = Context.TransformStr(col.Name, col.Transform); cc.Value = Context.TransformStr(col.Value, col.Transform); cc.IsDefault = (col.Default != null); if (cc.IsDefault) { cc.Default = Context.Transform(col.Default, col.Transform); } object t = Context.Transform(col.Type, col.Transform); if (t != null) { if (t is Type) { cc.Type = (Type)t; } else { cc.Type = Context.FindType(t.ToString()); } } ci.Add(cc); } } SortInfos si = new SortInfos(sortOverride, quoteChar, sep, trim); if (!overrideSort && SortCols != null) { foreach (var col in SortCols) { var ss = new SortInfo { Name = Context.TransformStr(col.Name, col.Transform), Sort = col.Sort }; var cmp = Context.Transform(col.Comparer, Transform); if (cmp != null) { object c1 = null; if (cmp is Type) { ss.Comparer = (IComparer)Utils.CreateInstance((Type)cmp); } else if (cmp is string && !string.IsNullOrEmpty((string)cmp)) { string smp = (string)cmp; if (smp.ToUpperInvariant() == "IGNORECASE" || smp.ToUpperInvariant() == "NOCASE" || smp.ToUpperInvariant() == "IC") { ss.Comparer = StringComparer.CurrentCultureIgnoreCase; } else if (Utils.TryGetProperty(null, typeof(StringComparer), smp, null, false, out c1)) { ss.Comparer = (IComparer)c1; } else { ss.Comparer = (IComparer)Utils.CreateInstance(Context.FindType(smp)); } } else { ss.Comparer = (IComparer)cmp; } } si.Add(ss); } } var ret = si.SortAndFilter(Context, columnsOverride, whereExpression, getTransformedRowsInternal(ci, csvReader)); if (columnsOverride == null) { return(ret); } ci = new ColumnsInfo(); ci.AddParsed(Context, columnsOverride, quoteChar, separator[0], trim); return(ci.Process(ret)); }
private IEnumerable <Vars> getTransformedRowsInternal(ColumnsInfo ci, ParsingReader csvReader) { int rowNo = 0; string quote = Context.TransformStr(Quote, Transform); string separator = Context.TransformStr(Separator, Transform); char? quoteChar = string.IsNullOrEmpty(quote) ? (char?)null : quote[0]; bool trim = (Options & RowsetOptions.Trim) != 0; // Read the rest of CSV, if available if (csvReader != null) { // If there are no columns, treat data as the list of strings if (ci.Count == 0) { string s; while ((s = csvReader.ReadLine()) != null) { if ((Options & RowsetOptions.Trim) == RowsetOptions.Trim) { s = s.Trim(); } if (string.IsNullOrEmpty(s) && (Options & RowsetOptions.IgnoreEmpty) == RowsetOptions.IgnoreEmpty) { continue; } Vars r = new Vars(); r[string.Empty] = s; Context.CheckAbort(); yield return(r); } } else { // We have columns, and therefore a complete CSV string[] data; while ((data = Utils.ReadCsvRow(csvReader, quoteChar, separator[0], trim)) != null) { if ((Options & RowsetOptions.IgnoreEmpty) != 0 && (data.Length == 0 || (data.Length == 1 && data[0].Length == 0))) { continue; } rowNo++; if (data.Length > ci.Count) { throw new ScriptRuntimeException(string.Format("{0} columns expected in row #{1}, but {2} found.", ci.Count, rowNo, data.Length)); } Vars r = new Vars(); for (int i = 0; i < Math.Min(ci.Count, data.Length); ++i) { object o = Context.Transform(data[i], Verbatim ? TransformRules.None : Transform); if (i < ci.Count) { r[ci[i].Name] = ci[i].AdjustType(o); } else { r[ci[i].Name] = o; } } ci.ApplyDefaults(r); Context.CheckAbort(); var c = checkWhere(r); if (c == null) { yield break; } if (c.Value) { yield return(r); } } } } // Rowset ID string id = Context.TransformStr(RowsetId, Transform); if (!string.IsNullOrEmpty(id)) { var rs = Context.Find <RowSet>(id, true); foreach (var v in rs.GetData()) { rowNo++; Vars sv1 = null; if (ci.Count == 0) { sv1 = v; } else { sv1 = new Vars(); Context.ExecuteWithVars(() => { foreach (var col in ci) { sv1.Set(col.Name, col.AdjustType(v.GetOrDefault(col.Name, null))); } return(null); }, v, null); } ci.ApplyDefaults(sv1); Context.CheckAbort(); var c = checkWhere(sv1); if (c == null) { yield break; } if (c.Value) { yield return(sv1); } } } // Try XmlDoc id = Context.TransformStr(XmlDocId, Transform); if (!string.IsNullOrEmpty(id)) { XmlDoc doc = Context.Find <XmlDoc>(id, true); foreach (XmlNode n in doc.Nodes(Context.TransformStr(XPath, Transform))) { Vars sv = new Vars(); rowNo++; if (ci.Count > 0) { foreach (var col in ci) { var node = n.SelectSingleNode(col.Value); if (node != null) { sv[col.Name] = col.AdjustType(node.Value); } } } else { foreach (XmlAttribute attr in n.Attributes) { sv[attr.LocalName] = attr.Value; } sv[string.Empty] = n.InnerText; } ci.ApplyDefaults(sv); Context.CheckAbort(); var c = checkWhere(sv); if (c == null) { yield break; } if (c.Value) { yield return(sv); } } } foreach (var row in Rows) { rowNo++; Vars sv = new Vars(); foreach (Var v in row) { var val = (Verbatim) ? v.Value : Context.Transform(v.Value, Transform); sv.Set(v.Name, ci.AdjustType(v.Name, val)); } ci.ApplyDefaults(sv); Context.CheckAbort(); var c = checkWhere(sv); if (c == null) { yield break; } if (c.Value) { yield return(sv); } } }
private object expandVars(TransformRules rules, string s) { string begin; string end; if ((rules & TransformRules.ExpandDual) == TransformRules.ExpandDual) { begin = "${{"; end = "}}"; } else if ((rules & TransformRules.ExpandDualSquare) == TransformRules.ExpandDualSquare) { begin = "[["; end = "]]"; } else if ((rules & TransformRules.ExpandSquare) == TransformRules.ExpandSquare) { begin = "["; end = "]"; } else if ((rules & TransformRules.Expand) == TransformRules.Expand) { begin = "${"; end = "}"; } else { return(s); } if (s.IndexOf(begin, StringComparison.Ordinal) != -1) { StringBuilder sbNew = new StringBuilder(); using (var sr = new ParsingReader(new StringReader(s))) { int ptr = 0; bool first = true; while (!sr.IsEOF) { char ch = (char)sr.Read(); if (ch != begin[ptr]) { sbNew.Append(begin, 0, ptr); sbNew.Append(ch); ptr = 0; first = false; continue; } ptr++; if (ptr < begin.Length) { continue; } if (sr.Peek() == '{' || sr.Peek() == '[') { sbNew.Append(begin); ptr = 0; first = false; continue; } // object sv = EvalMulti(sr); sv = ((rules & TransformRules.ExpandTrimOnly) == TransformRules.ExpandTrimOnly) ? Utils.TransformStr(Utils.To <string>(sv), rules & TransformRules.TrimMask) : sv; sv = ((rules & TransformRules.ExpandReplaceOnly) == TransformRules.ExpandReplaceOnly) ? Utils.TransformStr(Utils.To <string>(sv), rules & TransformRules.ReplaceMask) : sv; // Now read the trailing stuff sr.SkipWhiteSpace(); for (ptr = 0; ptr < end.Length; ++ptr) { sr.ReadAndThrowIfNot(end[ptr]); } if (sr.IsEOF && first) { return(sv); } ptr = 0; first = false; sbNew.Append(Utils.To <string>(sv)); } for (int i = 0; i < ptr; ++i) { sbNew.Append(begin[i]); } } return(sbNew.ToString()); } return(s); }
/// Read multi-expression (like ${a|b|=3+5}) from the stream and evaluate it public object EvalMulti(ParsingReader expressionReader) { return(Eval(new Parser(TokenSpecialCharacters).ParseMulti(expressionReader))); }
/// Parse multi-expression, like ${a|b|=2+3} public IOperation ParseMulti(ParsingReader reader) { Operations.OperationVariableAccess va = new Operations.OperationVariableAccess(); StringBuilder sb = new StringBuilder(); bool orMet = true; int n; while ((n = reader.Peek()) != -1) { var q = (char)n; if (q == '}' || q == ')' || q == ']') { break; } switch (q) { case '|': reader.Read(); va.AddName(sb.ToString()); sb.Length = 0; orMet = true; break; case '\'': case '\"': case '`': orMet = false; if (sb.Length != 0) { reader.ThrowParsingException("Quote must be a first character"); } va.AddValue(reader.ReadQuote()); reader.SkipWhiteSpaceAndComments(); if (reader.Peek() != '}' && reader.Peek() != '|') { reader.ThrowParsingException("Unexpected character '" + (char)reader.Peek() + "'"); } sb.Length = 0; break; case '=': orMet = false; reader.Read(); var v = Parse(reader); if (v != null) { va.AddExpression(v); } else { va.AddValue(null); } break; default: orMet = false; sb.Append(q); reader.Read(); break; } } if (sb.Length > 0 || orMet) { va.AddName(sb.ToString()); } return(va); }