// Parse nested types. private Type ParseNestedType(ParserContext parserContext, Type currentType) { System.Diagnostics.Debug.Assert(parserContext.CurrentToken.TokenID == TokenID.Dot); Type nestedType = null; while (parserContext.CurrentToken.TokenID == TokenID.Dot) { // Save the state of the scanner. Since we can't tell if we're parsing a nested // type or a member, we'll need to backtrack if we go too far. int savedTokenState = parserContext.SaveCurrentToken(); Token token = parserContext.NextToken(); if (token.TokenID != TokenID.Identifier) { if (parserContext.provideIntellisense && token.TokenID == TokenID.EndOfInput) { parserContext.SetTypeMemberCompletions(currentType, validation.ThisType, true, validation); return null; } else { throw new RuleSyntaxException(ErrorNumbers.Error_MissingIdentifierAfterDot, Messages.Parser_MissingIdentifierAfterDot, parserContext.CurrentToken.StartPosition); } } string name = (string)token.Value; BindingFlags bindingFlags = BindingFlags.Public; if (currentType.Assembly == validation.ThisType.Assembly) bindingFlags |= BindingFlags.NonPublic; if (parserContext.NextToken().TokenID == TokenID.Less) { // Might be a generic type. List<Type> candidateGenericTypes = new List<Type>(); Type[] nestedTypes = currentType.GetNestedTypes(bindingFlags); string prefix = name + "`"; for (int i = 0; i < nestedTypes.Length; ++i) { Type candidateType = nestedTypes[i]; if (candidateType.Name.StartsWith(prefix, StringComparison.Ordinal)) candidateGenericTypes.Add(candidateType); } if (candidateGenericTypes.Count == 0) { // It wasn't a generic type. Reset the scanner to the saved state. parserContext.RestoreCurrentToken(savedTokenState); // Also reset the deepenst nested type. nestedType = currentType; break; } nestedType = ParseGenericType(parserContext, candidateGenericTypes, name); currentType = nestedType; } else { // Might be a non-generic type. MemberInfo[] mi = currentType.GetMember(name, bindingFlags); if (mi == null || mi.Length != 1 || (mi[0].MemberType != MemberTypes.NestedType && mi[0].MemberType != MemberTypes.TypeInfo)) { // We went too far, reset the state. parserContext.RestoreCurrentToken(savedTokenState); // Also reset the deepest nested type. nestedType = currentType; break; } nestedType = (Type)mi[0]; if (currentType.IsGenericType && nestedType.IsGenericTypeDefinition) { // The outer type was generic (and bound), but the nested type is not. We have // to re-bind the generic arguments. nestedType = nestedType.MakeGenericType(currentType.GetGenericArguments()); } currentType = nestedType; } } return nestedType; }
// Parse: // unary-expression --> unary-operator unary-expression // --> postfix-expression private CodeExpression ParseUnaryExpression(ParserContext parserContext, bool assignIsEquality, ValueCheck check) { Token currentToken = parserContext.CurrentToken; CodeExpression unaryResult = null; if (currentToken.TokenID == TokenID.Not) { int notPosition = currentToken.StartPosition; parserContext.NextToken(); unaryResult = ParseUnaryExpression(parserContext, true, check); // This becomes "subExpr == false" unaryResult = new CodeBinaryOperatorExpression(unaryResult, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false)); parserContext.exprPositions[unaryResult] = notPosition; ValidateExpression(parserContext, unaryResult, assignIsEquality, check); } else if (currentToken.TokenID == TokenID.Minus) { int negativePosition = currentToken.StartPosition; parserContext.NextToken(); unaryResult = ParseUnaryExpression(parserContext, true, check); // This becomes "0 - subExpr" unaryResult = new CodeBinaryOperatorExpression(new CodePrimitiveExpression(0), CodeBinaryOperatorType.Subtract, unaryResult); parserContext.exprPositions[unaryResult] = negativePosition; ValidateExpression(parserContext, unaryResult, assignIsEquality, check); } else if (currentToken.TokenID == TokenID.LParen) { int lparenPosition = currentToken.StartPosition; // Save the state. This may actually be a parenthesized subexpression. int savedTokenState = parserContext.SaveCurrentToken(); currentToken = parserContext.NextToken(); // Eat the '(' Type type = TryParseTypeSpecifier(parserContext, assignIsEquality); if (type == null || parserContext.CurrentToken.TokenID != TokenID.RParen) { // It wasn't a cast. // In some cases it may have looked like a cast up to a point, such as: // // (MyType.MyMember // // but "MyMember" is a static field, property, or enum. // Reset the scanner state, and re-parse as a postfix-expr parserContext.RestoreCurrentToken(savedTokenState); unaryResult = ParsePostfixExpression(parserContext, assignIsEquality, check); } else { // It is a cast. It must have a balancing ')'. if (parserContext.CurrentToken.TokenID != TokenID.RParen) throw new RuleSyntaxException(ErrorNumbers.Error_MissingRParenInSubexpression, Messages.Parser_MissingRParenInSubexpression, parserContext.CurrentToken.StartPosition); parserContext.NextToken(); unaryResult = ParseUnaryExpression(parserContext, true, check); CodeTypeReference typeRef = new CodeTypeReference(type); validation.AddTypeReference(typeRef, type); unaryResult = new CodeCastExpression(typeRef, unaryResult); parserContext.exprPositions[unaryResult] = lparenPosition; ValidateExpression(parserContext, unaryResult, assignIsEquality, check); } } else { unaryResult = ParsePostfixExpression(parserContext, assignIsEquality, check); } return unaryResult; }
// Parse: // statement --> assign-statement // --> update-statement // --> HALT // // update-statement --> UPDATE ( "path" ) // --> UPDATE ( postfix-expr ) private RuleAction ParseStatement(ParserContext parserContext) { RuleAction action = null; Token statementToken = parserContext.CurrentToken; if (statementToken.TokenID == TokenID.Halt) { parserContext.NextToken(); // eat the "halt" action = new RuleHaltAction(); parserContext.exprPositions[action] = statementToken.StartPosition; ValidateAction(parserContext, action); } else if (statementToken.TokenID == TokenID.Update) { string message; parserContext.NextToken(); // eat the "update" if (parserContext.CurrentToken.TokenID != TokenID.LParen) { message = string.Format(CultureInfo.CurrentCulture, Messages.Parser_MissingLparenAfterCommand, "UPDATE"); throw new RuleSyntaxException(ErrorNumbers.Error_MissingLparenAfterCommand, message, parserContext.CurrentToken.StartPosition); } parserContext.NextToken(); // Eat the "(" string pathString = null; Token updateArgToken = parserContext.CurrentToken; if (updateArgToken.TokenID == TokenID.StringLiteral) { // Treat UPDATE("foo/bar") as a literal path. pathString = (string)updateArgToken.Value; parserContext.NextToken(); // Eat the path string. } else { CodeExpression pathExpr = ParsePostfixExpression(parserContext, true, ValueCheck.Read); RuleAnalysis analysis = new RuleAnalysis(validation, true); RuleExpressionWalker.AnalyzeUsage(analysis, pathExpr, false, true, null); ICollection<string> paths = analysis.GetSymbols(); if (paths.Count == 0 || paths.Count > 1) { // The expression did not modify anything, or it modified more than one. throw new RuleSyntaxException(ErrorNumbers.Error_InvalidUpdateExpression, Messages.Parser_InvalidUpdateExpression, updateArgToken.StartPosition); } else { IEnumerator<string> enumerator = paths.GetEnumerator(); enumerator.MoveNext(); pathString = enumerator.Current; } } if (parserContext.CurrentToken.TokenID != TokenID.RParen) throw new RuleSyntaxException(ErrorNumbers.Error_MissingRParenAfterArgumentList, Messages.Parser_MissingRParenAfterArgumentList, parserContext.CurrentToken.StartPosition); parserContext.NextToken(); // Eat the ")" action = new RuleUpdateAction((string)pathString); parserContext.exprPositions[action] = statementToken.StartPosition; ValidateAction(parserContext, action); } else { // Try to parse a custom RuleAction. int savedTokenState = parserContext.SaveCurrentToken(); Type type = TryParseTypeSpecifier(parserContext, false); if (type != null && parserContext.CurrentToken.TokenID == TokenID.LParen && TypeProvider.IsAssignable(typeof(RuleAction), type)) { // The statement started with a "type (", and the type derived from RuleAction. // This is a custom rule action. int lparenPosition = parserContext.CurrentToken.StartPosition; parserContext.NextToken(); // Eat the '(' List<CodeExpression> arguments = ParseArgumentList(parserContext); action = (RuleAction)ConstructCustomType(type, arguments, lparenPosition); parserContext.exprPositions[action] = statementToken.StartPosition; ValidateAction(parserContext, action); } else { // It wasn't a custom action. // In some cases it may have looked like one up to a point, such as: // // MyType.MyMember( // // but "MyMember" is a static method. // Reset the scanner state, and re-parse as an assignment. parserContext.RestoreCurrentToken(savedTokenState); CodeStatement statement = ParseAssignmentStatement(parserContext); if (statement != null) { // Create a rule statement action around it. No need to validate it, as // the underlying CodeDom statement has been validated already. action = new RuleStatementAction(statement); } } } return action; }
private Type ParseNestedType(ParserContext parserContext, Type currentType) { Type type = null; while (parserContext.CurrentToken.TokenID == TokenID.Dot) { int tokenValue = parserContext.SaveCurrentToken(); Token token = parserContext.NextToken(); if (token.TokenID != TokenID.Identifier) { if (!parserContext.provideIntellisense || (token.TokenID != TokenID.EndOfInput)) { throw new RuleSyntaxException(0x185, Messages.Parser_MissingIdentifierAfterDot, parserContext.CurrentToken.StartPosition); } parserContext.SetTypeMemberCompletions(currentType, this.validation.ThisType, true, this.validation); return null; } string typeName = (string) token.Value; BindingFlags @public = BindingFlags.Public; if (currentType.Assembly == this.validation.ThisType.Assembly) { @public |= BindingFlags.NonPublic; } if (parserContext.NextToken().TokenID == TokenID.Less) { List<Type> candidateGenericTypes = new List<Type>(); Type[] nestedTypes = currentType.GetNestedTypes(@public); string str2 = typeName + "`"; for (int i = 0; i < nestedTypes.Length; i++) { Type item = nestedTypes[i]; if (item.Name.StartsWith(str2, StringComparison.Ordinal)) { candidateGenericTypes.Add(item); } } if (candidateGenericTypes.Count == 0) { parserContext.RestoreCurrentToken(tokenValue); return currentType; } type = this.ParseGenericType(parserContext, candidateGenericTypes, typeName); currentType = type; } else { MemberInfo[] member = currentType.GetMember(typeName, @public); if (((member == null) || (member.Length != 1)) || ((member[0].MemberType != MemberTypes.NestedType) && (member[0].MemberType != MemberTypes.TypeInfo))) { parserContext.RestoreCurrentToken(tokenValue); return currentType; } type = (Type) member[0]; if (currentType.IsGenericType && type.IsGenericTypeDefinition) { type = type.MakeGenericType(currentType.GetGenericArguments()); } currentType = type; } } return type; }
private CodeExpression ParseUnaryExpression(ParserContext parserContext, bool assignIsEquality, ValueCheck check) { Token currentToken = parserContext.CurrentToken; CodeExpression expression = null; if (currentToken.TokenID == TokenID.Not) { int startPosition = currentToken.StartPosition; parserContext.NextToken(); expression = new CodeBinaryOperatorExpression(this.ParseUnaryExpression(parserContext, true, check), CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false)); parserContext.exprPositions[expression] = startPosition; this.ValidateExpression(parserContext, expression, assignIsEquality, check); return expression; } if (currentToken.TokenID == TokenID.Minus) { int num2 = currentToken.StartPosition; parserContext.NextToken(); expression = this.ParseUnaryExpression(parserContext, true, check); expression = new CodeBinaryOperatorExpression(new CodePrimitiveExpression(0), CodeBinaryOperatorType.Subtract, expression); parserContext.exprPositions[expression] = num2; this.ValidateExpression(parserContext, expression, assignIsEquality, check); return expression; } if (currentToken.TokenID == TokenID.LParen) { int num3 = currentToken.StartPosition; int tokenValue = parserContext.SaveCurrentToken(); currentToken = parserContext.NextToken(); Type type = this.TryParseTypeSpecifier(parserContext, assignIsEquality); if ((type == null) || (parserContext.CurrentToken.TokenID != TokenID.RParen)) { parserContext.RestoreCurrentToken(tokenValue); return this.ParsePostfixExpression(parserContext, assignIsEquality, check); } if (parserContext.CurrentToken.TokenID != TokenID.RParen) { throw new RuleSyntaxException(0x184, Messages.Parser_MissingRParenInSubexpression, parserContext.CurrentToken.StartPosition); } parserContext.NextToken(); expression = this.ParseUnaryExpression(parserContext, true, check); CodeTypeReference typeRef = new CodeTypeReference(type); this.validation.AddTypeReference(typeRef, type); expression = new CodeCastExpression(typeRef, expression); parserContext.exprPositions[expression] = num3; this.ValidateExpression(parserContext, expression, assignIsEquality, check); return expression; } return this.ParsePostfixExpression(parserContext, assignIsEquality, check); }
private RuleAction ParseStatement(ParserContext parserContext) { RuleAction action = null; Token currentToken = parserContext.CurrentToken; if (currentToken.TokenID == TokenID.Halt) { parserContext.NextToken(); action = new RuleHaltAction(); parserContext.exprPositions[action] = currentToken.StartPosition; this.ValidateAction(parserContext, action); return action; } if (currentToken.TokenID == TokenID.Update) { parserContext.NextToken(); if (parserContext.CurrentToken.TokenID != TokenID.LParen) { string message = string.Format(CultureInfo.CurrentCulture, Messages.Parser_MissingLparenAfterCommand, new object[] { "UPDATE" }); throw new RuleSyntaxException(0x180, message, parserContext.CurrentToken.StartPosition); } parserContext.NextToken(); string path = null; Token token2 = parserContext.CurrentToken; if (token2.TokenID == TokenID.StringLiteral) { path = (string) token2.Value; parserContext.NextToken(); } else { CodeExpression expression = this.ParsePostfixExpression(parserContext, true, ValueCheck.Read); RuleAnalysis analysis = new RuleAnalysis(this.validation, true); RuleExpressionWalker.AnalyzeUsage(analysis, expression, false, true, null); ICollection<string> symbols = analysis.GetSymbols(); if ((symbols.Count == 0) || (symbols.Count > 1)) { throw new RuleSyntaxException(0x181, Messages.Parser_InvalidUpdateExpression, token2.StartPosition); } IEnumerator<string> enumerator = symbols.GetEnumerator(); enumerator.MoveNext(); path = enumerator.Current; } if (parserContext.CurrentToken.TokenID != TokenID.RParen) { throw new RuleSyntaxException(0x182, Messages.Parser_MissingRParenAfterArgumentList, parserContext.CurrentToken.StartPosition); } parserContext.NextToken(); action = new RuleUpdateAction(path); parserContext.exprPositions[action] = currentToken.StartPosition; this.ValidateAction(parserContext, action); return action; } int tokenValue = parserContext.SaveCurrentToken(); Type fromType = this.TryParseTypeSpecifier(parserContext, false); if (((fromType != null) && (parserContext.CurrentToken.TokenID == TokenID.LParen)) && TypeProvider.IsAssignable(typeof(RuleAction), fromType)) { int startPosition = parserContext.CurrentToken.StartPosition; parserContext.NextToken(); List<CodeExpression> arguments = this.ParseArgumentList(parserContext); action = (RuleAction) this.ConstructCustomType(fromType, arguments, startPosition); parserContext.exprPositions[action] = currentToken.StartPosition; this.ValidateAction(parserContext, action); return action; } parserContext.RestoreCurrentToken(tokenValue); CodeStatement codeDomStatement = this.ParseAssignmentStatement(parserContext); if (codeDomStatement != null) { action = new RuleStatementAction(codeDomStatement); } return action; }