// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#if NET_2_0
-
using System;
using System.Collections;
+using System.Collections.Generic;
using System.Text;
namespace Microsoft.Build.BuildEngine {
internal class ConditionParser {
- ConditionTokenizer tokenizer = new ConditionTokenizer ();
+ ConditionTokenizer tokenizer;
+ string conditionStr;
- private ConditionParser (string condition)
+ ConditionParser (string condition)
{
+ tokenizer = new ConditionTokenizer ();
tokenizer.Tokenize (condition);
+ conditionStr = condition;
}
+ public static bool ParseAndEvaluate (string condition, Project context)
+ {
+ if (String.IsNullOrEmpty (condition))
+ return true;
+
+ try {
+ ConditionExpression ce = ParseCondition (condition);
+
+ if (!ce.CanEvaluateToBool (context))
+ throw new InvalidProjectFileException (String.Format ("Can not evaluate \"{0}\" to bool.", condition));
+
+ return ce.BoolEvaluate (context);
+ } catch (ExpressionParseException epe) {
+ throw new InvalidProjectFileException (
+ String.Format ("Unable to parse condition \"{0}\" : {1}", condition, epe.Message),
+ epe);
+ } catch (ExpressionEvaluationException epe) {
+ throw new InvalidProjectFileException (
+ String.Format ("Unable to evaluate condition \"{0}\" : {1}", condition, epe.Message),
+ epe);
+ }
+ }
+
public static ConditionExpression ParseCondition (string condition)
{
ConditionParser parser = new ConditionParser (condition);
ConditionExpression e = parser.ParseExpression ();
if (!parser.tokenizer.IsEOF ())
- throw new ExpressionParseException (String.Format ("Unexpected token: {0}", parser.tokenizer.Token.Value));
+ throw new ExpressionParseException (String.Format ("Unexpected token found, {0}, in condition \"{1}\"", parser.tokenizer.Token, condition));
return e;
}
- private ConditionExpression ParseExpression ()
+ ConditionExpression ParseExpression ()
{
return ParseBooleanExpression ();
}
- private ConditionExpression ParseBooleanExpression ()
+ ConditionExpression ParseBooleanExpression ()
{
return ParseBooleanAnd ();
}
+
+ public static string And (string a, string b)
+ {
+ return a + " and " + b;
+ }
- private ConditionExpression ParseBooleanAnd ()
+ ConditionExpression ParseBooleanAnd ()
{
ConditionExpression e = ParseBooleanOr ();
while (tokenizer.IsToken (TokenType.And)) {
tokenizer.GetNextToken ();
- e = new ConditionAndExpression ((ConditionExpression) e, (ConditionExpression) ParseBooleanOr ());
+ e = new ConditionAndExpression (e, ParseBooleanOr ());
}
return e;
}
- private ConditionExpression ParseBooleanOr ()
+ ConditionExpression ParseBooleanOr ()
{
ConditionExpression e = ParseRelationalExpression ();
while (tokenizer.IsToken (TokenType.Or)) {
tokenizer.GetNextToken ();
- e = new ConditionOrExpression ((ConditionExpression) e, (ConditionExpression) ParseRelationalExpression ());
+ e = new ConditionOrExpression (e, ParseRelationalExpression ());
}
return e;
}
- private ConditionExpression ParseRelationalExpression ()
+ ConditionExpression ParseRelationalExpression ()
{
ConditionExpression e = ParseFactorExpression ();
+
Token opToken;
RelationOperator op;
default:
throw new ExpressionParseException (String.Format ("Wrong relation operator {0}", opToken.Value));
}
-
- e = new ConditionRelationalExpression ((ConditionExpression) e, ParseFactorExpression (), op);
+
+ e = new ConditionRelationalExpression (e, ParseFactorExpression (), op);
}
return e;
}
- // FIXME: parse sub expression in parens, parse TokenType.Not, parse functions
- private ConditionExpression ParseFactorExpression ()
+ ConditionExpression ParseFactorExpression ()
{
+ ConditionExpression e;
Token token = tokenizer.Token;
tokenizer.GetNextToken ();
+
+ if (token.Type == TokenType.LeftParen) {
+ e = ParseExpression ();
+ tokenizer.Expect (TokenType.RightParen);
+ } else if (token.Type == TokenType.String && tokenizer.Token.Type == TokenType.LeftParen) {
+ e = ParseFunctionExpression (token.Value);
+ } else if (token.Type == TokenType.String) {
+ e = new ConditionFactorExpression (token);
+ } else if (token.Type == TokenType.Number) {
+ e = new ConditionFactorExpression (token);
+ } else if (token.Type == TokenType.Item || token.Type == TokenType.Property
+ || token.Type == TokenType.Metadata) {
+ e = ParseReferenceExpression (token.Value);
+ } else if (token.Type == TokenType.Not) {
+ e = ParseNotExpression ();
+ } else
+ throw new ExpressionParseException (String.Format ("Unexpected token {0}, while parsing condition \"{1}\"", token, conditionStr));
- if (token.Type != TokenType.String && token.Type != TokenType.Number)
- throw new ExpressionParseException (String.Format ("Unexpected token type {0}.", token.Type));
+ return e;
+ }
+
+ ConditionExpression ParseNotExpression ()
+ {
+ return new ConditionNotExpression (ParseFactorExpression ());
+ }
+
+ ConditionExpression ParseFunctionExpression (string function_name)
+ {
+ return new ConditionFunctionExpression (function_name, ParseFunctionArguments ());
+ }
+
+ List <ConditionFactorExpression> ParseFunctionArguments ()
+ {
+ List <ConditionFactorExpression> list = new List <ConditionFactorExpression> ();
+ ConditionFactorExpression e;
+
+ while (true) {
+ tokenizer.GetNextToken ();
+ if (tokenizer.Token.Type == TokenType.RightParen) {
+ tokenizer.GetNextToken ();
+ break;
+ }
+ if (tokenizer.Token.Type == TokenType.Comma)
+ continue;
+
+ tokenizer.Putback (tokenizer.Token);
+ e = (ConditionFactorExpression) ParseFactorExpression ();
+ list.Add (e);
+ }
- return new ConditionFactorExpression (token);
+ return list;
+ }
+
+ //@prefix: @ or $
+ ConditionExpression ParseReferenceExpression (string prefix)
+ {
+ StringBuilder sb = new StringBuilder ();
+
+ string ref_type = prefix [0] == '$' ? "a property" : "an item list";
+ int token_pos = tokenizer.Token.Position;
+ IsAtToken (TokenType.LeftParen, String.Format (
+ "Expected {0} at position {1} in condition \"{2}\". Missing opening parantheses after the '{3}'.",
+ ref_type, token_pos, conditionStr, prefix));
+ tokenizer.GetNextToken ();
+
+ sb.AppendFormat ("{0}({1}", prefix, tokenizer.Token.Value);
+
+ tokenizer.GetNextToken ();
+ if (prefix == "@" && tokenizer.Token.Type == TokenType.Transform) {
+ tokenizer.GetNextToken ();
+ sb.AppendFormat ("->'{0}'", tokenizer.Token.Value);
+
+ tokenizer.GetNextToken ();
+ if (tokenizer.Token.Type == TokenType.Comma) {
+ tokenizer.GetNextToken ();
+ sb.AppendFormat (", '{0}'", tokenizer.Token.Value);
+ tokenizer.GetNextToken ();
+ }
+ }
+
+ IsAtToken (TokenType.RightParen, String.Format (
+ "Expected {0} at position {1} in condition \"{2}\". Missing closing parantheses'.",
+ ref_type, token_pos, conditionStr, prefix));
+ tokenizer.GetNextToken ();
+
+ sb.Append (")");
+
+ //FIXME: HACKY!
+ return new ConditionFactorExpression (new Token (sb.ToString (), TokenType.String, token_pos));
+ }
+
+ // used to check current token type
+ void IsAtToken (TokenType type, string error_msg)
+ {
+ if (tokenizer.Token.Type != type) {
+ if (!String.IsNullOrEmpty (error_msg))
+ throw new ExpressionParseException (error_msg);
+
+ if (tokenizer.Token.Type == TokenType.EOF)
+ throw new ExpressionParseException (String.Format (
+ "Expected a \"{0}\" but the condition ended abruptly, while parsing condition \"{1}\"",
+ Token.TypeAsString (type), conditionStr));
+
+ throw new ExpressionParseException (String.Format (
+ "Expected \"{0}\" token, but got {1}, while parsing \"{2}\"",
+ Token.TypeAsString (type), tokenizer.Token, conditionStr));
+ }
}
}
}
-
-#endif