2 using System.Collections.Generic;
4 using Microsoft.Build.Exceptions;
6 namespace Microsoft.Build.Internal
8 class ExpressionParserManual
10 public ExpressionParserManual (string source, ExpressionValidationType validationType)
13 validation_type = validationType;
17 ExpressionValidationType validation_type;
19 public ExpressionList Parse ()
21 return Parse (0, source.Length);
24 static readonly char [] token_starters = "$@%('\"".ToCharArray ();
26 ExpressionList Parse (int start, int end)
28 if (string.IsNullOrWhiteSpace (source))
29 return new ExpressionList ();
31 var head = new List<Expression> ();
32 var tail = new List<Expression> ();
34 char token = source [start];
39 if (start == end || start + 1 == source.Length || source [start + 1] != '(') {
40 if (validation_type == ExpressionValidationType.StrictBoolean)
41 throw new InvalidProjectFileException (string.Format ("missing '(' after '{0}' at {1} in \"{2}\"", source [start], start, source));
43 goto default; // treat as raw literal to the section end
46 int last = source.LastIndexOf (')', end - 1, end - start - 1);
48 if (validation_type == ExpressionValidationType.StrictBoolean)
49 throw new InvalidProjectFileException (string.Format ("expression did not have matching ')' since index {0} in \"{1}\"", start, source));
53 goto default; // treat as raw literal to the section end
58 head.Add (EvaluatePropertyExpression (start, last));
59 else if (token == '%')
60 head.Add (EvaluateMetadataExpression (start, last));
62 head.Add (EvaluateItemExpression (start, last));
66 // Below (until default) are important only for Condition evaluation
68 if (validation_type == ExpressionValidationType.LaxString)
71 last = source.LastIndexOf (')', end - 1, end - start);
73 throw new InvalidProjectFileException (string.Format ("expression did not have matching ')' since index {0} in \"{1}\"", start, source));
74 var contents = Parse (start, last).ToArray ();
75 if (contents.Length > 1)
76 throw new InvalidProjectFileException (string.Format ("unexpected continuous expression within (){0} in \"{1}\"", contents [1].Column > 0 ? " at " + contents [1].Column : null, source));
77 head.Add (contents.First ());
81 int idx = source.IndexOfAny (token_starters, start + 1);
82 string name = idx < 0 ? source.Substring (start, end - start) : source.Substring (start, idx - start);
83 var val = new NameToken () { Name = name };
84 var literal = new RawStringLiteral () { Value = val };
85 head.Add (new StringLiteralExpression () { Contents = new ExpressionList () { literal } });
93 SkipSpaces (ref start);
95 var ret = new ExpressionList ();
96 foreach (var e in head.Concat (((IEnumerable<Expression>) tail).Reverse ()))
101 static readonly string spaces = " \t\r\n";
103 void SkipSpaces (ref int start)
105 while (start < source.Length && spaces.Contains (source [start]))
109 PropertyAccessExpression EvaluatePropertyExpression (int start, int end)
112 int idx = source.LastIndexOf ('.', start);
114 string name = (idx > 0) ? source.Substring (idx, end - idx) : source.Substring (start, end);
115 return new PropertyAccessExpression () {
116 Access = new PropertyAccess () {
117 Name = new NameToken () { Name = name },
118 TargetType = PropertyTargetType.Object,
119 Target = idx < 0 ? null : Parse (start, idx).FirstOrDefault ()
123 // static type access
124 idx = source.IndexOf ("::", start, StringComparison.Ordinal);
126 throw new NotImplementedException ();
128 string type = source.Substring (start, idx - start);
129 if (type.Length < 2 || type [0] != '[' || type [type.Length - 1] != ']')
130 throw new InvalidProjectFileException (string.Format ("Static function call misses appropriate type name surrounded by '[' and ']' at {0} in \"{1}\"", start, source));
131 int start2 = idx + 2;
132 int idx2 = source.IndexOf ('(', idx + 2, end - start2);
134 // access to static property
135 string member = source.Substring (start2, end - start2);
137 // access to static method
138 string member = source.Substring (start2, idx2 - start2);
141 // property access without member specification
142 return new PropertyAccessExpression () {
143 Access = new PropertyAccess () {
144 Name = new NameToken () { Name = source.Substring (start, end - start) },
145 TargetType = PropertyTargetType.Object
152 ItemAccessExpression EvaluateItemExpression (int start, int end)
154 // using property as context and evaluate
155 int idx = source.IndexOf ("->", start, StringComparison.Ordinal);
157 string name = source.Substring (start, idx - start);
158 return new ItemAccessExpression () {
159 Application = new ItemApplication () {
160 Name = new NameToken () { Name = name },
161 Expressions = Parse (idx, end - idx)
165 string name = source.Substring (start, end - start);
166 return new ItemAccessExpression () {
167 Application = new ItemApplication () { Name = new NameToken () { Name = name } }
171 throw new NotImplementedException ();
174 MetadataAccessExpression EvaluateMetadataExpression (int start, int end)
176 throw new NotImplementedException ();