/// <summary> /// Handler of general containers. /// Moving upward from deepest container. /// /// $(name) or $(name:project) or $([MSBuild]::MakeRelative($(path1), ...):project) .. /// https://msdn.microsoft.com/en-us/library/vstudio/dd633440%28v=vs.120%29.aspx /// </summary> /// <param name="data"></param> /// <param name="sh"></param> /// <param name="limit">Limitation to containers. Aborts if reached</param> /// <exception cref="LimitException"></exception> /// <returns></returns> protected string containerIn(string data, StringHandler sh, uint limit) { Regex con = RPattern.ContainerInCompiled; int maxRep = 1; // rule of depth, e.g.: $(p1 = $(Platform))$(p2 = $(p1))$(p2) //TODO: it's slowest but fully compatible with classic rules with minimal programming.. so, improve performance references.Clear(); uint step = 0; do { if (step++ > limit) { sh.flush(); throw new LimitException("Restriction of supported containers '{0}' reached. Aborted.", limit); } data = con.Replace(data, delegate(Match m) { string raw = m.Groups[1].Value; Log.Trace("containerIn: raw - `{0}`", raw); return(evaluate(prepare(sh.recovery(raw)))); }, maxRep); // protect before new checking data = sh.protectEscContainer(sh.protectMixedQuotes(data)); } while(con.IsMatch(data)); return(data); }
/// <summary> /// Entry point to evaluating MSBuild data. /// </summary> /// <param name="data">mixed data</param> /// <returns>All evaluated values for data</returns> public virtual string parse(string data) { if (String.IsNullOrEmpty(data)) { return(String.Empty); // convert to not null value } if (String.IsNullOrWhiteSpace(data)) { return(data); // save all white-space characters } StringHandler sh = new StringHandler(); lock (_lock) { return(hquotes( sh.recovery( containerIn( sh.protectEscContainer( sh.protectMixedQuotes(data) ), sh, CONTAINERS_LIMIT ) ) )); } }
/// <param name="data">mixed data</param> /// <returns>prepared and evaluated data</returns> public override string parse(string data) { var hString = new StringHandler(); Match m = CRule.Match(hString.protectMixedQuotes(data.Trim())); if(!m.Success) { throw new SyntaxIncorrectException("Failed ConditionComponent - '{0}'", data); } string condition = hString.recovery(m.Groups[1].Value); string bodyIfTrue = hString.recovery(m.Groups[2].Value); string bodyIfFalse = (m.Groups[3].Success)? hString.recovery(m.Groups[3].Value) : Value.Empty; return parse(condition, bodyIfTrue, bodyIfFalse); }
/// <summary> /// Handler of general containers. /// Moving upward from deepest container. /// /// $(name) or $(name:project) or $([MSBuild]::MakeRelative($(path1), ...):project) .. /// https://msdn.microsoft.com/en-us/library/vstudio/dd633440%28v=vs.120%29.aspx /// </summary> /// <param name="data"></param> /// <param name="sh"></param> /// <param name="limit">Limitation to containers. Aborts if reached</param> /// <exception cref="LimitException"></exception> /// <returns></returns> protected string containerIn(string data, StringHandler sh, uint limit) { Regex con = new Regex(RPattern.ContainerIn, RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled); int maxRep = 1; // rule of depth, e.g.: $(p1 = $(Platform))$(p2 = $(p1))$(p2) //TODO: it's slowest but fully compatible with classic rules with minimal programming.. so, improve performance uint step = 0; do { if(step++ > limit) { throw new LimitException("Restriction of supported containers '{0}' reached. Aborted.", limit); } data = con.Replace(data, delegate(Match m) { string raw = m.Groups[1].Value; Log.Trace("containerIn: raw - '{0}'", raw); return evaluate(prepare(sh.recovery(raw))); }, maxRep); // protect before new checking data = sh.protectEscContainer(sh.protectSingleQuotes(data)); } while(con.IsMatch(data)); return data; }
/// <summary> /// Entry point to evaluating MSBuild data. /// </summary> /// <param name="data">mixed data</param> /// <returns>All evaluated values for data</returns> public virtual string parse(string data) { if(String.IsNullOrEmpty(data)) { return String.Empty; // convert to not null value } if(String.IsNullOrWhiteSpace(data)) { return data; // save all white-space characters } StringHandler sh = new StringHandler(); lock(_lock) { return sh.recovery( containerIn( sh.protectEscContainer( sh.protectSingleQuotes(data) ), sh, CONTAINERS_LIMIT ) ); } }
/// <summary> /// Gets right operand as a Level object. /// </summary> /// <param name="data">raw data</param> /// <param name="handler">Handler of string if used.</param> /// <returns></returns> protected ILevel getRightOperand(string data, StringHandler handler = null) { if(String.IsNullOrWhiteSpace(data)) { return new Level() { Type = LevelType.RightOperandEmpty }; } Match m = Regex.Match(data, @"^\s*(=|:)(.*)$", RegexOptions.Singleline); if(!m.Success) { throw new SyntaxIncorrectException("PM - getRightOperand: incorrect data '{0}'", data); } string type = m.Groups[1].Value; string raw = m.Groups[2].Value; string ldata = (handler == null)? raw : handler.recovery(raw); if(type == ":") { return new Level() { Type = LevelType.RightOperandColon, Data = eval(EvalType.RightOperandColon, ldata) }; } return new Level() { Type = LevelType.RightOperandStd, Data = eval(EvalType.RightOperandStd, ldata) }; }
/// <summary> /// Extracts all arguments from line. /// </summary> /// <param name="data">Raw line with user arguments.</param> /// <param name="splitter">A character that delimits arguments.</param> /// <returns>List of parsed arguments or null value if data is empty.</returns> /// <exception cref="SyntaxIncorrectException">If incorrect arguments line.</exception> protected Argument[] extractArgs(string data, char splitter = ',') { if(String.IsNullOrWhiteSpace(data)) { return new Argument[0]; } StringHandler h = new StringHandler(); string[] raw = h.protectArguments(data).Split(splitter); Argument[] ret = new Argument[raw.Length]; for(int i = 0; i < raw.Length; ++i) { string arg = h.recovery(raw[i]).Trim(); if(arg.Length < 1 && splitter == ',') { // std: p1, p2, p3 throw new SyntaxIncorrectException("PM - extractArgs: incorrect arguments line '{0}'", data); } ret[i] = detectArgument(arg); } return ret; }
/// <summary> /// Entry point of analyser. /// </summary> /// <param name="data">mixed data</param> protected void detect(string data) { Log.Trace("PM-detect: entered with '{0}'", data); StringHandler h = new StringHandler(); data = h.protectMixedQuotes(data); Match m = Rcon.Match(data); if(!m.Success) { Levels.Add(getRightOperand(data, h)); return; } string method = (m.Groups[1].Success)? m.Groups[1].Value : null; string arguments = (m.Groups[2].Success)? m.Groups[2].Value : null; string property = (m.Groups[3].Success)? m.Groups[3].Value : null; string operation = m.Groups[4].Value; Log.Trace("PM-detect: found '{0}', '{1}', '{2}', '{3}'", property, method, arguments, operation); if(property != null) { Levels.Add(new Level() { Type = LevelType.Property, Data = property, }); } else { Levels.Add(new Level() { Type = LevelType.Method, Data = method, Args = extractArgs(h.recovery(arguments)), }); } detect(h.recovery(operation)); }