Merge pull request #1404 from woodsb02/mono-route
[mono.git] / mcs / class / Microsoft.Build / Microsoft.Build.Internal / ExpressionParserManual.cs
index 83d4e9b15655ef9d13bfa1de904a655736672342..73bac64445e11fa5b98bf225bc1d56867c3fb7c8 100644 (file)
@@ -30,7 +30,7 @@ using System.Collections.Generic;
 using System.Linq;
 using Microsoft.Build.Exceptions;
 
-namespace Microsoft.Build.Internal
+namespace Microsoft.Build.Internal.Expressions
 {
        class ExpressionParserManual
        {
@@ -58,13 +58,15 @@ namespace Microsoft.Build.Internal
 
                        var ret = new ExpressionList ();
                        while (start < end) {
+                               int bak = start;
                                ret.Add (ParseSingle (ref start, end));
-                               SkipSpaces (ref start);
+                               if (bak == start)
+                                       throw new Exception ("Parser failed to progress token position: " + source);
                        }
                        return ret;
                }
                
-               static readonly char [] token_starters = "$@%(),".ToCharArray ();
+               static readonly char [] token_starters = "$@%(),'\"".ToCharArray ();
                
                Expression ParseSingle (ref int start, int end)
                {
@@ -98,7 +100,23 @@ namespace Microsoft.Build.Internal
                                        ret = EvaluateItemExpression (start, last);
                                start = last + 1;
                                return ret;
-                               
+                       
+                       case '\'':
+                       case '"':
+                               var quoteChar = source [start];
+                               start++;
+                               last = FindMatchingCloseQuote (quoteChar, start, end);
+                               if (last < 0) {
+                                       if (validation_type == ExpressionValidationType.StrictBoolean)
+                                               throw new InvalidProjectFileException (string.Format ("expression did not have matching ')' since index {0} in \"{1}\"", start, source));
+                                       else {
+                                               start--;
+                                               goto default; // treat as raw literal to the section end
+                                       }
+                               }
+                               ret = new QuotedExpression () { QuoteChar = quoteChar, Contents = Parse (start, last) };
+                               start = last + 1;
+                               return ret;
                        // Below (until default) are important only for Condition evaluation
                        case '(':
                                if (validation_type == ExpressionValidationType.LaxString)
@@ -122,7 +140,7 @@ namespace Microsoft.Build.Internal
                                int idx = source.IndexOfAny (token_starters, start + 1);
                                string name = idx < 0 ? source.Substring (start, end - start) : source.Substring (start, idx - start);
                                var val = new NameToken () { Name = name };
-                               ret = new StringLiteral () { Value = val };
+                               ret = new RawStringLiteral () { Value = val };
                                if (idx >= 0)
                                        start = idx;
                                else
@@ -131,7 +149,7 @@ namespace Microsoft.Build.Internal
                                return ret;
                        }
                }
-               
+
                int FindMatchingCloseParen (int start, int end)
                {
                        int n = 0;
@@ -145,7 +163,21 @@ namespace Microsoft.Build.Internal
                        }
                        return -1; // invalid
                }
-               
+
+               int FindMatchingCloseQuote (char quote, int start, int end)
+               {
+                       int n = 0;
+                       for (int i = start; i < end; i++) {
+                               if (i < end + 1 && source [i] == '\\' && (source [i + 1] == quote || source [i + 1] == '\\'))
+                                       n += 2;
+                               else if (source [i] == quote) {
+                                       if (n-- == 0)
+                                               return i;
+                               }
+                       }
+                       return -1; // invalid
+               }
+
                static readonly string spaces = " \t\r\n";
                
                void SkipSpaces (ref int start)
@@ -163,6 +195,7 @@ namespace Microsoft.Build.Internal
                                // property access without member specification
                                int parenAt = source.IndexOf ('(', start, end - start);
                                string name = parenAt < 0 ? source.Substring (start, end - start) : source.Substring (start, parenAt - start);
+                               name = name.Trim ();
                                var access = new PropertyAccess () {
                                        Name = new NameToken () { Name = name },
                                        TargetType = PropertyTargetType.Object
@@ -178,6 +211,7 @@ namespace Microsoft.Build.Internal
                                int mstart = dotAt + 1;
                                int parenAt = source.IndexOf ('(', mstart, end - mstart);
                                string name = parenAt < 0 ? source.Substring (mstart, end - mstart) : source.Substring (mstart, parenAt - mstart);
+                               name = name.Trim ();
                                var access = new PropertyAccess () {
                                        Name = new NameToken () { Name = name },
                                        TargetType = PropertyTargetType.Object,
@@ -193,10 +227,11 @@ namespace Microsoft.Build.Internal
                                string type = source.Substring (start, colonsAt - start);
                                if (type.Length < 2 || type [0] != '[' || type [type.Length - 1] != ']')
                                        throw new InvalidProjectFileException (string.Format ("Static function call misses appropriate type name surrounded by '[' and ']' at {0} in \"{1}\"", start, source));
-                               type = type.Substring (1, type.Length - 2);
+                               type = type.Substring (1, type.Length - 2).Trim ();
                                start = colonsAt + 2;
                                int parenAt = source.IndexOf ('(', start, end - start);
                                string member = parenAt < 0 ? source.Substring (start, end - start) : source.Substring (start, parenAt - start);
+                               member = member.Trim ();
                                if (member.Length == 0)
                                        throw new InvalidProjectFileException ("Static member name is missing");
                                var access = new PropertyAccess () {
@@ -225,6 +260,7 @@ namespace Microsoft.Build.Internal
                                        if (source [start] != ',')
                                                throw new InvalidProjectFileException (string.Format ("invalid function call arguments specification. ',' is expected, got '{0}'", source [start]));
                                        start++;
+                                       SkipSpaces (ref start);
                                }
                                args.Add (ParseSingle (ref start, end));
                        } while (true);
@@ -241,7 +277,7 @@ namespace Microsoft.Build.Internal
                                return new ItemAccessExpression () {
                                        Application = new ItemApplication () {
                                                Name = new NameToken () { Name = name },
-                                               Expressions = Parse (idx, end - idx)
+                                               Expressions = Parse (idx + 2, end)
                                                }
                                        };
                        } else {
@@ -250,13 +286,18 @@ namespace Microsoft.Build.Internal
                                        Application = new ItemApplication () { Name = new NameToken () { Name = name } }
                                        };
                        }
-                       
-                       throw new NotImplementedException ();
                }
                
                MetadataAccessExpression EvaluateMetadataExpression (int start, int end)
                {
-                       throw new NotImplementedException ();
+                       int idx = source.IndexOf ('.', start, end - start);
+                       string item = idx < 0 ? null : source.Substring (start, idx - start);
+                       string meta = idx < 0 ? source.Substring (start, end - start) : source.Substring (idx + 1, end - idx - 1);
+                       var access = new MetadataAccess () {
+                                       ItemType = item == null ? null : new NameToken () { Column = start, Name = item },
+                                       Metadata = new NameToken () { Column = idx < 0 ? start : idx + 1, Name = meta }
+                                       };
+                       return new MetadataAccessExpression () { Access = access };
                }
        }
 }