private CodeExpression ParseMemberOperator(ParserContext parserContext, CodeExpression primaryExpr, bool assignIsEquality, ValueCheck check) { 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(this.validation.ExpressionInfo(primaryExpr).ExpressionType, this.validation.ThisType, primaryExpr is CodeTypeReferenceExpression, this.validation); return null; } string methodName = (string) token.Value; int startPosition = token.StartPosition; if (parserContext.NextToken().TokenID == TokenID.LParen) { return this.ParseMethodInvoke(parserContext, primaryExpr, methodName, true); } return this.ParseFieldOrProperty(parserContext, primaryExpr, methodName, startPosition, assignIsEquality, check); }
private Type[] ParseGenericTypeArgList(ParserContext parserContext) { System.Diagnostics.Debug.Assert(parserContext.CurrentToken.TokenID == TokenID.Less); List<Type> typeArgs = new List<Type>(); Token token; do { // Eat the opening '<' or ','. token = parserContext.NextToken(); Type type = TryParseTypeSpecifier(parserContext, true); if (type == null) throw new RuleSyntaxException(ErrorNumbers.Error_InvalidTypeArgument, Messages.Parser_InvalidTypeArgument, token.StartPosition); typeArgs.Add(type); } while (parserContext.CurrentToken.TokenID == TokenID.Comma); if (parserContext.CurrentToken.TokenID != TokenID.Greater) throw new RuleSyntaxException(ErrorNumbers.Error_MissingCloseAngleBracket, Messages.Parser_MissingCloseAngleBracket, parserContext.CurrentToken.StartPosition); parserContext.NextToken(); // Eat the '>' return typeArgs.ToArray(); }
// Parse: // array-spec --> type-name // --> type-name array-rank-specifiers // array-rank-specifiers --> [ binary-expression ] // --> [ ] private Type TryParseTypeSpecifierWithOptionalSize(ParserContext parserContext, bool assignIsEquality, out CodeExpression size) { Type type = null; size = null; Token currentToken = parserContext.CurrentToken; type = TryParseTypeName(parserContext, assignIsEquality); // see if size specified if ((type != null) && (parserContext.CurrentToken.TokenID == TokenID.LBracket)) { Token next = parserContext.NextToken(); // skip '[' // get the size, if specified if (next.TokenID != TokenID.RBracket) size = ParseBinaryExpression(parserContext, 0, false, ValueCheck.Read); else size = defaultSize; if (parserContext.CurrentToken.TokenID != TokenID.RBracket) throw new RuleSyntaxException(ErrorNumbers.Error_MissingCloseSquareBracket, Messages.Parser_MissingCloseSquareBracket1, parserContext.CurrentToken.StartPosition); parserContext.NextToken(); // Eat the ']' } return type; }
internal CodeExpression ParseRootTypeIdentifier(ParserContext parserContext, TypeSymbol typeSym, bool assignIsEquality) { string message = null; int typePosition = parserContext.CurrentToken.StartPosition; Token token = parserContext.NextToken(); if (typeSym.GenericArgCount > 0 && token.TokenID != TokenID.Less) { // This is a generic type, but no argument list was provided. message = string.Format(CultureInfo.CurrentCulture, Messages.Parser_MissingTypeArguments, typeSym.Name); throw new RuleSyntaxException(ErrorNumbers.Error_MissingTypeArguments, message, token.StartPosition); } Type type = typeSym.Type; if (token.TokenID == TokenID.Less) { // Start of a generic argument list... the type had better be generic. if (typeSym.GenericArgCount == 0) { message = string.Format(CultureInfo.CurrentCulture, Messages.Parser_NotAGenericType, RuleDecompiler.DecompileType(type)); throw new RuleSyntaxException(ErrorNumbers.Error_NotAGenericType, message, token.StartPosition); } Type[] typeArgs = ParseGenericTypeArgList(parserContext); if (typeArgs.Length != typeSym.GenericArgCount) { message = string.Format(CultureInfo.CurrentCulture, Messages.Parser_BadTypeArgCount, RuleDecompiler.DecompileType(type)); throw new RuleSyntaxException(ErrorNumbers.Error_BadTypeArgCount, message, parserContext.CurrentToken.StartPosition); } // if we are creating generics with design-time types, then the generic needs to be // a wrapped type to create the generic properly, so we look up the generic to get back the wrapper type = Validator.ResolveType(type.AssemblyQualifiedName); type = type.MakeGenericType(typeArgs); } token = parserContext.CurrentToken; if (token.TokenID == TokenID.Dot) { Type nestedType = ParseNestedType(parserContext, type); if (nestedType != null) type = nestedType; } return ParseTypeRef(parserContext, type, typePosition, assignIsEquality); }
private CodeExpression ParseTypeRef(ParserContext parserContext, Type type, int typePosition, bool assignIsEquality) { CodeExpression result = null; if (parserContext.CurrentToken.TokenID == TokenID.LParen) { // A '(' after a typename is only valid if it's an IRuleExpression. if (TypeProvider.IsAssignable(typeof(IRuleExpression), type)) { int lparenPosition = parserContext.CurrentToken.StartPosition; parserContext.NextToken(); // Eat the '(' List<CodeExpression> arguments = ParseArgumentList(parserContext); result = (CodeExpression)ConstructCustomType(type, arguments, lparenPosition); parserContext.exprPositions[result] = lparenPosition; ValidateExpression(parserContext, result, assignIsEquality, ValueCheck.Read); return result; } } CodeTypeReference typeRef = new CodeTypeReference(type); validation.AddTypeReference(typeRef, type); result = new CodeTypeReferenceExpression(typeRef); parserContext.exprPositions[result] = typePosition; ValidateExpression(parserContext, result, assignIsEquality, ValueCheck.Read); return result; }
private CodeExpression ParseConstructorArguments(ParserContext parserContext, Type type, bool assignIsEquality) { System.Diagnostics.Debug.Assert(parserContext.CurrentToken.TokenID == TokenID.LParen); // Start of a constructor parameter list. int lparenPosition = parserContext.CurrentToken.StartPosition; parserContext.NextToken(); if (parserContext.CurrentToken.TokenID == TokenID.EndOfInput && parserContext.provideIntellisense) { parserContext.SetConstructorCompletions(type, Validator.ThisType); return null; } List<CodeExpression> arguments = ParseArgumentList(parserContext); if ((type.IsValueType) && (arguments.Count == 0)) { // this is always allowed } else if (type.IsAbstract) { // this is not allowed string message = string.Format(CultureInfo.CurrentCulture, Messages.UnknownConstructor, RuleDecompiler.DecompileType(type)); throw new RuleSyntaxException(ErrorNumbers.Error_MethodNotExists, message, lparenPosition); } else { // Binding flags include all public & non-public, all instance, and all static. // All are possible candidates for unadorned method references. BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance; if (type.Assembly == validation.ThisType.Assembly) bindingFlags |= BindingFlags.NonPublic; ValidationError error = null; RuleConstructorExpressionInfo constructorInvokeInfo = validation.ResolveConstructor(type, bindingFlags, arguments, out error); if (constructorInvokeInfo == null) throw new RuleSyntaxException(error.ErrorNumber, error.ErrorText, lparenPosition); } CodeExpression postfixExpr = new CodeObjectCreateExpression(type, arguments.ToArray()); parserContext.exprPositions[postfixExpr] = lparenPosition; ValidateExpression(parserContext, postfixExpr, assignIsEquality, ValueCheck.Read); return postfixExpr; }
// Parser: // primary-expr --> ... // --> IDENTIFIER // --> IDENTIFIER method-call-arguments // --> ... internal CodeExpression ParseUnadornedMemberIdentifier(ParserContext parserContext, MemberSymbol symbol, bool assignIsEquality) { // This is an implicit member reference off "this", so add the "this". (Or an implicit // static member reference of the type of "this", so add the type name.) Token token = parserContext.CurrentToken; int namePosition = token.StartPosition; parserContext.NextToken(); // eat the identifier CodeExpression primaryExpr = null; if (parserContext.CurrentToken.TokenID == TokenID.LParen) primaryExpr = ParseUnadornedMethodInvoke(parserContext, symbol.Name, true); else primaryExpr = ParseUnadornedFieldOrProperty(parserContext, symbol.Name, namePosition, assignIsEquality); return primaryExpr; }
// Parse: // assign-statement --> postfix-expression ASSIGN logical-expression // --> postfix-expression private CodeStatement ParseAssignmentStatement(ParserContext parserContext) { CodeStatement result = null; // Parse the postfix-expression CodeExpression postfixExpr = ParsePostfixExpression(parserContext, false, ValueCheck.Read); // See if we need to parse the assignment statement. Token token = parserContext.CurrentToken; if (token.TokenID == TokenID.Assign) { int assignPosition = token.StartPosition; parserContext.NextToken(); // eat the '=' CodeExpression rhsExpr = ParseBinaryExpression(parserContext, 0, true, ValueCheck.Read); result = new CodeAssignStatement(postfixExpr, rhsExpr); parserContext.exprPositions[result] = assignPosition; } else { result = new CodeExpressionStatement(postfixExpr); parserContext.exprPositions[result] = parserContext.exprPositions[postfixExpr]; } ValidateStatement(parserContext, result); return result; }
// Parse: // // binary-expression --> unary-expresssion binary-expression-tail // --> unary-expression // // binary-expression-tail --> binary-operator-precedence unary-expression binary-expression-tail // --> binary-operator-precedence unary-expression // // binary-operator-precedence --> 0:{ || OR } // --> 1:{ && AND } // --> 2:{ | } // --> 3:{ & } // --> 4:{ = == != } // --> 5:{ < > <= >= } // --> 6:{ + - } // --> 7:{ * / % MOD } // // This method is still recursive descent, but parses each precedence group by using the operator precedence // tables defined in this class. private CodeExpression ParseBinaryExpression(ParserContext parserContext, int precedence, bool assignIsEquality, ValueCheck check) { // Must parse at least one left-hand operand. CodeExpression leftResult = (precedence == precedences.Length - 1) ? ParseUnaryExpression(parserContext, assignIsEquality, check) : ParseBinaryExpression(parserContext, precedence + 1, assignIsEquality, check); if (leftResult != null) { for (;;) { Token operatorToken = parserContext.CurrentToken; BinaryPrecedenceDescriptor precedenceDescriptor = precedences[precedence]; BinaryOperationDescriptor operationDescriptor = precedenceDescriptor.FindOperation(operatorToken.TokenID); if (operationDescriptor == null) break; // we're finished; no applicable binary operator token at this precedence level. parserContext.NextToken(); // Parse the right-hand side now. CodeExpression rightResult = (precedence == precedences.Length - 1) ? ParseUnaryExpression(parserContext, true, check) : ParseBinaryExpression(parserContext, precedence + 1, true, check); leftResult = operationDescriptor.CreateBinaryExpression(leftResult, rightResult, operatorToken.StartPosition, this, parserContext, assignIsEquality); } } return leftResult; }
// Parse: // statement-list --> statement statement-list-tail // --> statement // // statement-list-tail --> statement statement-list-tail // --> statement private List<RuleAction> ParseStatements(ParserContext parserContext) { List<RuleAction> statements = new List<RuleAction>(); while (parserContext.CurrentToken.TokenID != TokenID.EndOfInput) { RuleAction statement = ParseStatement(parserContext); if (statement == null) break; statements.Add(statement); // Eat any (optional) semi-colons. They aren't necessary but are comfortable // for a lot of programmers. while (parserContext.CurrentToken.TokenID == TokenID.Semicolon) parserContext.NextToken(); } return statements; }
// 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 CodeExpression ParsePrimaryExpression(ParserContext parserContext, bool assignIsEquality) { CodeExpression expression = null; Token currentToken = parserContext.CurrentToken; switch (currentToken.TokenID) { case TokenID.Identifier: return this.ParseRootIdentifier(parserContext, assignIsEquality); case TokenID.LParen: parserContext.NextToken(); expression = this.ParseBinaryExpression(parserContext, 0, assignIsEquality, ValueCheck.Read); parserContext.exprPositions[expression] = currentToken.StartPosition; if (parserContext.CurrentToken.TokenID != TokenID.RParen) { throw new RuleSyntaxException(0x184, Messages.Parser_MissingRParenInSubexpression, parserContext.CurrentToken.StartPosition); } parserContext.NextToken(); return expression; case TokenID.StringLiteral: case TokenID.CharacterLiteral: case TokenID.IntegerLiteral: case TokenID.DecimalLiteral: case TokenID.FloatLiteral: case TokenID.True: case TokenID.False: case TokenID.Null: parserContext.NextToken(); expression = new CodePrimitiveExpression(currentToken.Value); parserContext.exprPositions[expression] = currentToken.StartPosition; this.ValidateExpression(parserContext, expression, assignIsEquality, ValueCheck.Read); return expression; case TokenID.This: parserContext.NextToken(); expression = new CodeThisReferenceExpression(); parserContext.exprPositions[expression] = currentToken.StartPosition; this.ValidateExpression(parserContext, expression, assignIsEquality, ValueCheck.Read); return expression; case TokenID.TypeName: { parserContext.NextToken(); Type type = (Type) currentToken.Value; CodeTypeReference typeRef = new CodeTypeReference(type); this.validation.AddTypeReference(typeRef, type); expression = new CodeTypeReferenceExpression(typeRef); parserContext.exprPositions[expression] = currentToken.StartPosition; this.ValidateExpression(parserContext, expression, assignIsEquality, ValueCheck.Read); return expression; } case TokenID.New: parserContext.NextToken(); return this.ParseObjectCreation(parserContext, assignIsEquality); case TokenID.EndOfInput: throw new RuleSyntaxException(0x183, Messages.Parser_MissingOperand, currentToken.StartPosition); } throw new RuleSyntaxException(0x187, Messages.Parser_UnknownLiteral, currentToken.StartPosition); }
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 ParseMethodInvoke(ParserContext parserContext, CodeExpression postfixExpr, string methodName, bool assignIsEquality) { int startPosition = parserContext.CurrentToken.StartPosition; parserContext.NextToken(); if ((parserContext.CurrentToken.TokenID == TokenID.EndOfInput) && parserContext.provideIntellisense) { bool includeStatic = postfixExpr is CodeTypeReferenceExpression; parserContext.SetMethodCompletions(this.validation.ExpressionInfo(postfixExpr).ExpressionType, this.validation.ThisType, methodName, includeStatic, !includeStatic, this.validation); return null; } List<CodeExpression> list = this.ParseArgumentList(parserContext); postfixExpr = new CodeMethodInvokeExpression(postfixExpr, methodName, list.ToArray()); parserContext.exprPositions[postfixExpr] = startPosition; this.ValidateExpression(parserContext, postfixExpr, assignIsEquality, ValueCheck.Read); return postfixExpr; }
// Parse: // argument --> direction logical-expression // --> logical-expression // // direction --> IN // --> OUT // --> REF private CodeExpression ParseArgument(ParserContext parserContext, bool assignIsEquality) { CodeExpression argResult = null; Token token = parserContext.CurrentToken; int directionPosition = token.StartPosition; FieldDirection? direction = null; ValueCheck check = ValueCheck.Read; switch (token.TokenID) { case TokenID.In: direction = FieldDirection.In; parserContext.NextToken(); // eat the direction token break; case TokenID.Out: direction = FieldDirection.Out; parserContext.NextToken(); check = ValueCheck.Write; break; case TokenID.Ref: direction = FieldDirection.Ref; parserContext.NextToken(); check = ValueCheck.Read | ValueCheck.Write; break; } argResult = ParseBinaryExpression(parserContext, 0, true, check); if (direction != null) { argResult = new CodeDirectionExpression(direction.Value, argResult); parserContext.exprPositions[argResult] = directionPosition; ValidateExpression(parserContext, argResult, assignIsEquality, ValueCheck.Read); } return argResult; }
// 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: // primary-expression --> ( logical-expression ) // --> IDENTIFIER // --> IDENTIFIER method-call-arguments // --> type-name // --> object-creation-expression // --> array-creation-expression // --> integer-constant // --> decimal-constant // --> float-constant // --> character-constant // --> string-constant // --> NULL // --> THIS // --> TRUE // --> FALSE private CodeExpression ParsePrimaryExpression(ParserContext parserContext, bool assignIsEquality) { CodeExpression primaryExpr = null; Token token = parserContext.CurrentToken; switch (token.TokenID) { case TokenID.LParen: // A parenthesized subexpression parserContext.NextToken(); primaryExpr = ParseBinaryExpression(parserContext, 0, assignIsEquality, ValueCheck.Read); parserContext.exprPositions[primaryExpr] = token.StartPosition; token = parserContext.CurrentToken; if (token.TokenID != TokenID.RParen) throw new RuleSyntaxException(ErrorNumbers.Error_MissingRParenInSubexpression, Messages.Parser_MissingRParenInSubexpression, parserContext.CurrentToken.StartPosition); parserContext.NextToken(); // eat the ')' break; case TokenID.Identifier: primaryExpr = ParseRootIdentifier(parserContext, assignIsEquality); break; case TokenID.This: parserContext.NextToken(); // eat "this" primaryExpr = new CodeThisReferenceExpression(); parserContext.exprPositions[primaryExpr] = token.StartPosition; ValidateExpression(parserContext, primaryExpr, assignIsEquality, ValueCheck.Read); break; case TokenID.TypeName: parserContext.NextToken(); // eat the type name Type type = (Type)token.Value; CodeTypeReference typeRef = new CodeTypeReference(type); validation.AddTypeReference(typeRef, type); primaryExpr = new CodeTypeReferenceExpression(typeRef); parserContext.exprPositions[primaryExpr] = token.StartPosition; ValidateExpression(parserContext, primaryExpr, assignIsEquality, ValueCheck.Read); break; case TokenID.New: parserContext.NextToken(); // eat "new" primaryExpr = ParseObjectCreation(parserContext, assignIsEquality); break; case TokenID.IntegerLiteral: case TokenID.FloatLiteral: case TokenID.DecimalLiteral: case TokenID.CharacterLiteral: case TokenID.StringLiteral: case TokenID.True: case TokenID.False: case TokenID.Null: parserContext.NextToken(); // eat the literal primaryExpr = new CodePrimitiveExpression(token.Value); parserContext.exprPositions[primaryExpr] = token.StartPosition; ValidateExpression(parserContext, primaryExpr, assignIsEquality, ValueCheck.Read); break; case TokenID.EndOfInput: throw new RuleSyntaxException(ErrorNumbers.Error_MissingOperand, Messages.Parser_MissingOperand, token.StartPosition); default: throw new RuleSyntaxException(ErrorNumbers.Error_UnknownLiteral, Messages.Parser_UnknownLiteral, token.StartPosition); } return primaryExpr; }
// Parse: // element-operator --> [ expression-list ] private CodeExpression ParseElementOperator(ParserContext parserContext, CodeExpression primaryExpr, bool assignIsEquality) { System.Diagnostics.Debug.Assert(parserContext.CurrentToken.TokenID == TokenID.LBracket); int lbracketPosition = parserContext.CurrentToken.StartPosition; parserContext.NextToken(); // Consume the '[' List<CodeExpression> indexList = ParseIndexList(parserContext); CodeExpression[] indices = indexList.ToArray(); CodeExpression resultExpr = null; RuleExpressionInfo primaryExprInfo = validation.ExpressionInfo(primaryExpr); if (primaryExprInfo.ExpressionType.IsArray) { // The primary is an array type, so create an array indexer expression. resultExpr = new CodeArrayIndexerExpression(primaryExpr, indices); } else { // The primary isn't an array, so assume it has an indexer property. resultExpr = new CodeIndexerExpression(primaryExpr, indices); } parserContext.exprPositions[resultExpr] = lbracketPosition; ValidateExpression(parserContext, resultExpr, assignIsEquality, ValueCheck.Read); return resultExpr; }
// Parse: // array-initializer --> { variable-initializer-list } // { } // variable-initializer-list --> variable-initializer variable-initializer-list-tail // --> variable-initializer // variable-initializer-list-tail --> , variable-initializer variable-initializer-list-tail // --> , variable-initializer private List<CodeExpression> ParseArrayCreationArguments(ParserContext parserContext) { // if there are no initializers, return null if (parserContext.CurrentToken.TokenID != TokenID.LCurlyBrace) return null; List<CodeExpression> initializers = new List<CodeExpression>(); parserContext.NextToken(); // skip '{' if (parserContext.CurrentToken.TokenID != TokenID.RCurlyBrace) { initializers.Add(ParseInitializer(parserContext, true)); while (parserContext.CurrentToken.TokenID == TokenID.Comma) { parserContext.NextToken(); // eat the comma initializers.Add(ParseInitializer(parserContext, true)); } if (parserContext.CurrentToken.TokenID != TokenID.RCurlyBrace) throw new RuleSyntaxException(ErrorNumbers.Error_MissingRCurlyAfterInitializers, Messages.Parser_MissingRCurlyAfterInitializers, parserContext.CurrentToken.StartPosition); } parserContext.NextToken(); // eat the '}' return initializers; }
// Parse: // expression-list --> logical-expression expression-list-tail // --> logical-expression // // expression-list-tail --> , logical-expression expression-list-tail // --> , logical-expression private List<CodeExpression> ParseIndexList(ParserContext parserContext) { List<CodeExpression> indexList = new List<CodeExpression>(); CodeExpression indexExpr = ParseBinaryExpression(parserContext, 0, true, ValueCheck.Read); //ParseLogicalExpression(); indexList.Add(indexExpr); while (parserContext.CurrentToken.TokenID == TokenID.Comma) { parserContext.NextToken(); // eat the comma indexExpr = ParseBinaryExpression(parserContext, 0, true, ValueCheck.Read); //ParseLogicalExpression(); indexList.Add(indexExpr); } if (parserContext.CurrentToken.TokenID != TokenID.RBracket) throw new RuleSyntaxException(ErrorNumbers.Error_MissingCloseSquareBracket, Messages.Parser_MissingCloseSquareBracket, parserContext.CurrentToken.StartPosition); parserContext.NextToken(); // consume the ']' return indexList; }
// Parse: // namespace-qualified-type-name --> NAMESPACE-NAME namespace-qualifier-tail . TYPE-NAME // --> NAMESPACE-NAME . TYPE-NAME // --> TYPE-NAME // // namespace-qualifier-tail --> . NAMESPACE-NAME namespace-qualifier-tail internal CodeExpression ParseRootNamespaceIdentifier(ParserContext parserContext, NamespaceSymbol nsSym, bool assignIsEquality) { // Loop through all the namespace qualifiers until we find something that's not a namespace. Symbol nestedSym = null; while (nsSym != null) { Token token = parserContext.NextToken(); if (token.TokenID != TokenID.Dot) throw new RuleSyntaxException(ErrorNumbers.Error_MissingDotAfterNamespace, Messages.Parser_MissingDotAfterNamespace, token.StartPosition); token = parserContext.NextToken(); if (token.TokenID != TokenID.Identifier) { if (parserContext.provideIntellisense && token.TokenID == TokenID.EndOfInput) { parserContext.SetNamespaceCompletions(nsSym); return null; } else { throw new RuleSyntaxException(ErrorNumbers.Error_MissingIdentifierAfterDot, Messages.Parser_MissingIdentifierAfterDot, token.StartPosition); } } string name = (string)token.Value; nestedSym = nsSym.FindMember(name); if (nestedSym == null) { string message = string.Format(CultureInfo.CurrentCulture, Messages.Parser_UnknownNamespaceMember, name, nsSym.GetQualifiedName()); throw new RuleSyntaxException(ErrorNumbers.Error_UnknownNamespaceMember, message, token.StartPosition); } nsSym = nestedSym as NamespaceSymbol; } // We are sitting at a type (or overloaded type). return nestedSym.ParseRootIdentifier(this, parserContext, assignIsEquality); }
// Parse: // member-operator --> . IDENTIFIER method-call-arguments // --> . IDENTIFIER // // method-call-arguments --> ( argument-list ) // --> ( ) // // argument-list --> argument argument-list-tail // --> argument // // argument-list-tail --> , argument argument-list-tail // --> , argument private CodeExpression ParseMemberOperator(ParserContext parserContext, CodeExpression primaryExpr, bool assignIsEquality, ValueCheck check) { System.Diagnostics.Debug.Assert(parserContext.CurrentToken.TokenID == TokenID.Dot); Token token = parserContext.NextToken(); // Consume the '.' if (token.TokenID != TokenID.Identifier) { if (parserContext.provideIntellisense && token.TokenID == TokenID.EndOfInput) { parserContext.SetTypeMemberCompletions(validation.ExpressionInfo(primaryExpr).ExpressionType, validation.ThisType, primaryExpr is CodeTypeReferenceExpression, validation); return null; } else { throw new RuleSyntaxException(ErrorNumbers.Error_MissingIdentifierAfterDot, Messages.Parser_MissingIdentifierAfterDot, parserContext.CurrentToken.StartPosition); } } string idName = (string)token.Value; int idPosition = token.StartPosition; CodeExpression postfixExpr = null; if (parserContext.NextToken().TokenID == TokenID.LParen) { postfixExpr = ParseMethodInvoke(parserContext, primaryExpr, idName, true); } else { postfixExpr = ParseFieldOrProperty(parserContext, primaryExpr, idName, idPosition, assignIsEquality, check); } return postfixExpr; }
internal CodeExpression ParseRootOverloadedTypeIdentifier(ParserContext parserContext, List<TypeSymbol> candidateTypeSymbols, bool assignIsEquality) { Token token = parserContext.CurrentToken; string typeName = (string)token.Value; int namePosition = token.StartPosition; // Get the next token after the identifier. token = parserContext.NextToken(); Type type = null; if (token.TokenID == TokenID.Less) { // Choose from the generic candidates. List<Type> candidateTypes = new List<Type>(candidateTypeSymbols.Count); foreach (TypeSymbol typeSym in candidateTypeSymbols) { if (typeSym.GenericArgCount > 0) candidateTypes.Add(typeSym.Type); } type = ParseGenericType(parserContext, candidateTypes, typeName); } else { // See if there's a non-generic candidate. TypeSymbol typeSym = candidateTypeSymbols.Find(delegate(TypeSymbol s) { return s.GenericArgCount == 0; }); if (typeSym == null) { // No argument list was provided, but there's no non-generic overload. string message = string.Format(CultureInfo.CurrentCulture, Messages.Parser_MissingTypeArguments, typeName); throw new RuleSyntaxException(ErrorNumbers.Error_MissingTypeArguments, message, namePosition); } type = typeSym.Type; } if (parserContext.CurrentToken.TokenID == TokenID.Dot) { Type nestedType = ParseNestedType(parserContext, type); if (nestedType != null) type = nestedType; } return ParseTypeRef(parserContext, type, namePosition, assignIsEquality); }
private CodeExpression ParseMethodInvoke(ParserContext parserContext, CodeExpression postfixExpr, string methodName, bool assignIsEquality) { System.Diagnostics.Debug.Assert(parserContext.CurrentToken.TokenID == TokenID.LParen); // Start of a method call parameter list. int lparenPosition = parserContext.CurrentToken.StartPosition; parserContext.NextToken(); if (parserContext.CurrentToken.TokenID == TokenID.EndOfInput && parserContext.provideIntellisense) { bool isStatic = postfixExpr is CodeTypeReferenceExpression; parserContext.SetMethodCompletions(validation.ExpressionInfo(postfixExpr).ExpressionType, validation.ThisType, methodName, isStatic, !isStatic, validation); return null; } List<CodeExpression> arguments = ParseArgumentList(parserContext); postfixExpr = new CodeMethodInvokeExpression(postfixExpr, methodName, arguments.ToArray()); parserContext.exprPositions[postfixExpr] = lparenPosition; ValidateExpression(parserContext, postfixExpr, assignIsEquality, ValueCheck.Read); return postfixExpr; }
// 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; }
private List<CodeExpression> ParseArgumentList(ParserContext parserContext) { List<CodeExpression> argList = new List<CodeExpression>(); if (parserContext.CurrentToken.TokenID != TokenID.RParen) { CodeExpression argResult = ParseArgument(parserContext, true); argList.Add(argResult); while (parserContext.CurrentToken.TokenID == TokenID.Comma) { parserContext.NextToken(); // eat the comma argResult = ParseArgument(parserContext, true); argList.Add(argResult); } if (parserContext.CurrentToken.TokenID != TokenID.RParen) throw new RuleSyntaxException(ErrorNumbers.Error_MissingRParenAfterArgumentList, Messages.Parser_MissingRParenAfterArgumentList, parserContext.CurrentToken.StartPosition); } parserContext.NextToken(); // consume the ')' return argList; }
private Type TryParseTypeName(ParserContext parserContext, bool assignIsEquality) { Type type = null; Token currentToken = parserContext.CurrentToken; if (currentToken.TokenID == TokenID.TypeName) { type = (Type)currentToken.Value; parserContext.NextToken(); // eat the type name } else if (currentToken.TokenID == TokenID.Identifier) { Symbol sym = null; if (globalUniqueSymbols.TryGetValue((string)currentToken.Value, out sym)) { CodeExpression identExpr = sym.ParseRootIdentifier(this, parserContext, assignIsEquality); if (identExpr is CodeTypeReferenceExpression) type = validation.ExpressionInfo(identExpr).ExpressionType; } } return type; }
private CodeExpression ParseUnadornedMethodInvoke(ParserContext parserContext, string methodName, bool assignIsEquality) { System.Diagnostics.Debug.Assert(parserContext.CurrentToken.TokenID == TokenID.LParen); Type thisType = Validator.ThisType; // Start of a method call parameter list. int lparenPosition = parserContext.CurrentToken.StartPosition; parserContext.NextToken(); if (parserContext.CurrentToken.TokenID == TokenID.EndOfInput && parserContext.provideIntellisense) { parserContext.SetMethodCompletions(thisType, thisType, methodName, true, true, validation); return null; } List<CodeExpression> arguments = ParseArgumentList(parserContext); // Binding flags include all public & non-public, all instance, and all static. // All are possible candidates for unadorned method references. BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy | BindingFlags.Instance; ValidationError error = null; RuleMethodInvokeExpressionInfo methodInvokeInfo = validation.ResolveMethod(thisType, methodName, bindingFlags, arguments, out error); if (methodInvokeInfo == null) throw new RuleSyntaxException(error.ErrorNumber, error.ErrorText, lparenPosition); MethodInfo mi = methodInvokeInfo.MethodInfo; CodeExpression primaryExpr = null; if (mi.IsStatic) primaryExpr = new CodeTypeReferenceExpression(thisType); else primaryExpr = new CodeThisReferenceExpression(); CodeExpression postfixExpr = new CodeMethodInvokeExpression(primaryExpr, methodName, arguments.ToArray()); parserContext.exprPositions[postfixExpr] = lparenPosition; ValidateExpression(parserContext, postfixExpr, assignIsEquality, ValueCheck.Read); return postfixExpr; }
// Parse: // rank-specifiers --> rank-specifier rank-specifier-tail // --> rank-specifier // // rank-specifier-tail --> rank-specifier rank-specifier-tail // // rank-specifier --> [ dim-separators ] // --> [ ] // // dim-separators --> , dim-separators-tail // --> , // // dim-separators-tail --> , dim-separators-tail private static Type ParseArrayType(ParserContext parserContext, Type baseType) { Type type = baseType; while (parserContext.CurrentToken.TokenID == TokenID.LBracket) { int rank = 1; while (parserContext.NextToken().TokenID == TokenID.Comma) ++rank; if (parserContext.CurrentToken.TokenID == TokenID.RBracket) parserContext.NextToken(); // Eat the ']' else throw new RuleSyntaxException(ErrorNumbers.Error_MissingCloseSquareBracket, Messages.Parser_MissingCloseSquareBracket, parserContext.CurrentToken.StartPosition); if (rank == 1) type = type.MakeArrayType(); else type = type.MakeArrayType(rank); } return type; }
private List<CodeExpression> ParseIndexList(ParserContext parserContext) { List<CodeExpression> list = new List<CodeExpression>(); CodeExpression item = this.ParseBinaryExpression(parserContext, 0, true, ValueCheck.Read); list.Add(item); while (parserContext.CurrentToken.TokenID == TokenID.Comma) { parserContext.NextToken(); item = this.ParseBinaryExpression(parserContext, 0, true, ValueCheck.Read); list.Add(item); } if (parserContext.CurrentToken.TokenID != TokenID.RBracket) { throw new RuleSyntaxException(410, Messages.Parser_MissingCloseSquareBracket, parserContext.CurrentToken.StartPosition); } parserContext.NextToken(); return list; }