2
// <copyright see="prj:///doc/copyright.txt"/>
3
// <license see="prj:///doc/license.txt"/>
4
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
5
// <version>$Revision: 4740 $</version>
8
using ICSharpCode.OldNRefactory.Visitors;
10
using System.Collections.Generic;
11
using System.Diagnostics;
13
using ICSharpCode.OldNRefactory.Ast;
15
namespace ICSharpCode.OldNRefactory.Parser.CSharp
17
internal sealed partial class Parser : AbstractParser
21
public Parser(ILexer lexer) : base(lexer)
23
this.lexer = (Lexer)lexer;
24
// due to anonymous methods, we always need a compilation unit, so
25
// create it in the constructor
26
compilationUnit = new CompilationUnit();
29
StringBuilder qualidentBuilder = new StringBuilder();
32
[System.Diagnostics.DebuggerStepThrough]
39
[System.Diagnostics.DebuggerStepThrough]
41
return lexer.LookAhead;
45
public void Error(string s)
47
if (errDist >= MinErrDist) {
48
this.Errors.Error(la.line, la.col, s);
53
public override void Parse()
56
compilationUnit.AcceptVisitor(new SetParentVisitor(), null);
59
public override TypeReference ParseTypeReference ()
67
public override Expression ParseExpression()
70
Location startLocation = la.Location;
73
// SEMICOLON HACK : without a trailing semicolon, parsing expressions does not work correctly
74
if (la.kind == Tokens.Semicolon) lexer.NextToken();
76
expr.StartLocation = startLocation;
77
expr.EndLocation = t.EndLocation;
78
expr.AcceptVisitor(new SetParentVisitor(), null);
84
public override BlockStatement ParseBlock()
87
compilationUnit = new CompilationUnit();
89
BlockStatement blockStmt = new BlockStatement();
90
blockStmt.StartLocation = la.Location;
91
compilationUnit.BlockStart(blockStmt);
93
while (la.kind != Tokens.EOF) {
97
// did not advance lexer position, we cannot parse this as a statement block
102
compilationUnit.BlockEnd();
103
blockStmt.EndLocation = t.EndLocation;
105
blockStmt.AcceptVisitor(new SetParentVisitor(), null);
109
public override List<INode> ParseTypeMembers()
112
compilationUnit = new CompilationUnit();
114
TypeDeclaration newType = new TypeDeclaration(Modifiers.None, null);
115
compilationUnit.BlockStart(newType);
117
compilationUnit.BlockEnd();
119
newType.AcceptVisitor(new SetParentVisitor(), null);
120
return newType.Children;
126
if (la.kind != Tokens.OpenParenthesis) {
129
bool isPossibleExpression = true;
132
Token pt = lexer.Peek();
134
if (!IsTypeNameOrKWForTypeCast(ref pt, ref isPossibleExpression)) {
139
if (pt.kind != Tokens.CloseParenthesis) {
142
if (isPossibleExpression) {
145
return Tokens.CastFollower[pt.kind];
147
// not possibly an expression: don't check cast follower
152
/* !!! Proceeds from current peek position !!! */
153
bool IsTypeKWForTypeCast(ref Token pt)
155
if (Tokens.TypeKW[pt.kind]) {
157
return IsPointerOrDims(ref pt) && SkipQuestionMark(ref pt);
158
} else if (pt.kind == Tokens.Void) {
160
return IsPointerOrDims(ref pt);
165
/* !!! Proceeds from current peek position !!! */
166
bool IsTypeNameOrKWForTypeCast(ref Token pt, ref bool isPossibleExpression)
168
if (Tokens.TypeKW[pt.kind] || pt.kind == Tokens.Void) {
169
isPossibleExpression = false;
170
return IsTypeKWForTypeCast(ref pt);
172
return IsTypeNameForTypeCast(ref pt, ref isPossibleExpression);
176
bool IsTypeNameOrKWForTypeCast(ref Token pt)
179
return IsTypeNameOrKWForTypeCast(ref pt, ref tmp);
182
// TypeName = ident [ "::" ident ] { ["<" TypeNameOrKW { "," TypeNameOrKW } ">" ] "." ident } ["?"] PointerOrDims
183
/* !!! Proceeds from current peek position !!! */
184
bool IsTypeNameForTypeCast(ref Token pt, ref bool isPossibleExpression)
187
if (!IsIdentifierToken(pt)) {
192
if (pt.kind == Tokens.DoubleColon) {
194
if (!IsIdentifierToken(pt)) {
199
// { ["<" TypeNameOrKW { "," TypeNameOrKW } ">" ] "." ident }
201
if (pt.kind == Tokens.LessThan) {
204
if (!IsTypeNameOrKWForTypeCast(ref pt)) {
207
} while (pt.kind == Tokens.Comma);
208
if (pt.kind != Tokens.GreaterThan) {
213
if (pt.kind != Tokens.Dot)
216
if (pt.kind != Tokens.Identifier) {
222
if (pt.kind == Tokens.Question) {
225
if (pt.kind == Tokens.Times || pt.kind == Tokens.OpenSquareBracket) {
226
isPossibleExpression = false;
227
return IsPointerOrDims(ref pt);
233
// Gets if the token is a possible token for an expression start
234
// Is used to determine if "a is Type ? token" a the start of a ternary
235
// expression or a type test for Nullable<Type>
236
bool IsPossibleExpressionStart(int token)
238
return Tokens.CastFollower[token] || Tokens.UnaryOp[token];
241
// ( { [TypeNameOrKWForTypeCast] ident "," } )
242
bool IsLambdaExpression()
244
if (la.kind != Tokens.OpenParenthesis) {
249
while (pt.kind != Tokens.CloseParenthesis) {
250
if (pt.kind == Tokens.Out || pt.kind == Tokens.Ref) {
253
if (!IsTypeNameOrKWForTypeCast(ref pt)) {
256
if (IsIdentifierToken(pt)) {
257
// make ident optional: if implicitly typed lambda arguments are used, IsTypeNameForTypeCast
258
// has already accepted the identifier
261
if (pt.kind == Tokens.CloseParenthesis) {
264
// require comma between parameters:
265
if (pt.kind == Tokens.Comma) {
272
return pt.kind == Tokens.LambdaArrow;
275
/* Checks whether the next sequences of tokens is a qualident *
276
* and returns the qualident string */
277
/* !!! Proceeds from current peek position !!! */
278
bool IsQualident(ref Token pt, out string qualident)
280
if (IsIdentifierToken(pt)) {
281
qualidentBuilder.Length = 0; qualidentBuilder.Append(pt.val);
283
while (pt.kind == Tokens.Dot || pt.kind == Tokens.DoubleColon) {
285
if (!IsIdentifierToken(pt)) {
286
qualident = String.Empty;
289
qualidentBuilder.Append('.');
290
qualidentBuilder.Append(pt.val);
293
qualident = qualidentBuilder.ToString();
296
qualident = String.Empty;
300
/* Skips generic type extensions */
301
/* !!! Proceeds from current peek position !!! */
303
/* skip: { "*" | "[" { "," } "]" } */
304
/* !!! Proceeds from current peek position !!! */
305
bool IsPointerOrDims (ref Token pt)
308
if (pt.kind == Tokens.OpenSquareBracket) {
310
while (pt.kind == Tokens.Comma);
311
if (pt.kind != Tokens.CloseSquareBracket) return false;
312
} else if (pt.kind != Tokens.Times) break;
318
/* Return the n-th token after the current lookahead token */
340
/*-----------------------------------------------------------------*
341
* Resolver routines to resolve LL(1) conflicts: * *
342
* These resolution routine return a boolean value that indicates *
343
* whether the alternative at hand shall be choosen or not. *
344
* They are used in IF ( ... ) expressions. *
345
*-----------------------------------------------------------------*/
347
/* True, if ident is followed by "=" */
350
return IsIdentifierToken(la) && Peek(1).kind == Tokens.Assign;
353
bool IdentAndDoubleColon ()
355
return IsIdentifierToken(la) && Peek(1).kind == Tokens.DoubleColon;
358
bool IsAssignment () { return IdentAndAsgn(); }
360
/* True, if ident is followed by ",", "=", "[" or ";" */
362
int peek = Peek(1).kind;
363
return IsIdentifierToken(la) &&
364
(peek == Tokens.Comma || peek == Tokens.Assign || peek == Tokens.Semicolon || peek == Tokens.OpenSquareBracket);
367
/* True, if the comma is not a trailing one, *
368
* like the last one in: a, b, c, */
369
bool NotFinalComma () {
370
int peek = Peek(1).kind;
371
return la.kind == Tokens.Comma &&
372
peek != Tokens.CloseCurlyBrace && peek != Tokens.CloseSquareBracket;
375
/* True, if "void" is followed by "*" */
376
bool NotVoidPointer () {
377
return la.kind == Tokens.Void && Peek(1).kind != Tokens.Times;
380
/* True, if "checked" or "unchecked" are followed by "{" */
381
bool UnCheckedAndLBrace () {
382
return la.kind == Tokens.Checked || la.kind == Tokens.Unchecked &&
383
Peek(1).kind == Tokens.OpenCurlyBrace;
386
/* True, if "." is followed by an ident */
387
bool DotAndIdent () {
388
return la.kind == Tokens.Dot && IsIdentifierToken(Peek(1));
391
/* True, if ident is followed by ":" */
392
bool IdentAndColon () {
393
return IsIdentifierToken(la) && Peek(1).kind == Tokens.Colon;
396
bool IsLabel () { return IdentAndColon(); }
398
/* True, if ident is followed by "(" */
399
bool IdentAndLPar () {
400
return IsIdentifierToken(la) && Peek(1).kind == Tokens.OpenParenthesis;
403
/* True, if "catch" is followed by "(" */
404
bool CatchAndLPar () {
405
return la.kind == Tokens.Catch && Peek(1).kind == Tokens.OpenParenthesis;
407
bool IsTypedCatch () { return CatchAndLPar(); }
409
/* True, if "[" is followed by the ident "assembly" */
410
bool IsGlobalAttrTarget () {
412
return la.kind == Tokens.OpenSquareBracket &&
413
IsIdentifierToken(pt) && (pt.val == "assembly" || pt.val == "module");
416
/* True, if "[" is followed by "," or "]" */
417
bool LBrackAndCommaOrRBrack () {
418
int peek = Peek(1).kind;
419
return la.kind == Tokens.OpenSquareBracket &&
420
(peek == Tokens.Comma || peek == Tokens.CloseSquareBracket);
423
/* True, if "[" is followed by "," or "]" */
424
/* or if the current token is "*" */
425
bool TimesOrLBrackAndCommaOrRBrack () {
426
return la.kind == Tokens.Times || LBrackAndCommaOrRBrack();
428
bool IsPointerOrDims () { return TimesOrLBrackAndCommaOrRBrack(); }
429
bool IsPointer () { return la.kind == Tokens.Times; }
432
bool SkipGeneric(ref Token pt)
434
if (pt.kind == Tokens.LessThan) {
437
if (!IsTypeNameOrKWForTypeCast(ref pt)) return false;
438
} while (pt.kind == Tokens.Comma);
439
if (pt.kind != Tokens.GreaterThan) return false;
444
bool SkipQuestionMark(ref Token pt)
446
if (pt.kind == Tokens.Question) {
452
/* True, if lookahead is a primitive type keyword, or */
453
/* if it is a type declaration followed by an ident */
454
bool IsLocalVarDecl ()
456
if (IsYieldStatement ()) {
460
if ((Tokens.TypeKW[la.kind] && Peek (1).kind != Tokens.Dot) || la.kind == Tokens.Void) {
466
bool result = IsTypeNameOrKWForTypeCast (ref pt) && IsIdentifierToken (pt);
467
if (Peek (1).kind == Tokens.Question) {
468
if (Peek (2).kind == Tokens.OpenSquareBracket) // array case: T?[,]
470
result &= Peek (2).kind == Tokens.Identifier;
471
result &= Peek (3).kind == Tokens.Semicolon || Peek (3).kind == Tokens.Comma || Peek (3).kind == Tokens.Assign;
476
/* True if lookahead is a type argument list (<...>) followed by
477
* one of "( ) ] } : ; , . ? == !=" */
478
bool IsGenericInSimpleNameOrMemberAccess()
481
if (t.kind != Tokens.LessThan) return false;
483
return SkipGeneric(ref t) && Tokens.GenericFollower[t.kind];
486
bool IsExplicitInterfaceImplementation()
491
if (pt.kind == Tokens.Dot || pt.kind == Tokens.DoubleColon)
493
if (pt.kind == Tokens.LessThan) {
494
if (SkipGeneric(ref pt))
495
return pt.kind == Tokens.Dot;
500
/* True, if lookahead ident is "yield" and than follows a break or return */
501
bool IsYieldStatement () {
502
return la.kind == Tokens.Yield && (Peek(1).kind == Tokens.Return || Peek(1).kind == Tokens.Break);
505
/* True, if lookahead is a local attribute target specifier, *
506
* i.e. one of "event", "return", "field", "method", *
507
* "module", "param", "property", or "type" */
508
bool IsLocalAttrTarget () {
512
return (cur == Tokens.Event || cur == Tokens.Return ||
513
(Tokens.IdentifierTokens[cur] &&
514
(val == "field" || val == "method" || val == "module" ||
515
val == "param" || val == "property" || val == "type"))) &&
516
Peek(1).kind == Tokens.Colon;
521
Token next = Peek(1);
522
// TODO : Add col test (seems not to work, lexer bug...) : && la.col == next.col - 1
523
return (la.kind == Tokens.GreaterThan && next.kind == Tokens.GreaterThan);
526
bool IsGenericExpression(Expression expr)
528
if (expr is IdentifierExpression)
529
return ((IdentifierExpression)expr).TypeArguments.Count > 0;
530
else if (expr is MemberReferenceExpression)
531
return ((MemberReferenceExpression)expr).TypeArguments.Count > 0;
536
bool ShouldConvertTargetExpressionToTypeReference(Expression targetExpr)
538
if (targetExpr is IdentifierExpression)
539
return ((IdentifierExpression)targetExpr).TypeArguments.Count > 0;
540
else if (targetExpr is MemberReferenceExpression)
541
return ((MemberReferenceExpression)targetExpr).TypeArguments.Count > 0;
546
TypeReference GetTypeReferenceFromExpression(Expression expr)
548
if (expr is TypeReferenceExpression)
549
return (expr as TypeReferenceExpression).TypeReference;
551
IdentifierExpression ident = expr as IdentifierExpression;
553
return new TypeReference(ident.Identifier, ident.TypeArguments);
556
MemberReferenceExpression member = expr as MemberReferenceExpression;
557
if (member != null) {
558
TypeReference targetType = GetTypeReferenceFromExpression(member.TargetObject);
559
if (targetType != null) {
560
if (targetType.GenericTypes.Count == 0 && targetType.IsArrayType == false) {
561
TypeReference tr = new TypeReference(targetType.Type + "." + member.MemberName, member.TypeArguments);
562
tr.IsGlobal = targetType.IsGlobal;
565
return new InnerClassTypeReference(targetType, member.MemberName, member.TypeArguments);
572
bool IsMostNegativeIntegerWithoutTypeSuffix()
575
if (token.kind == Tokens.Literal) {
576
return token.val == "2147483648" || token.val == "9223372036854775808";
582
bool LastExpressionIsUnaryMinus(System.Collections.ArrayList expressions)
584
if (expressions.Count == 0) return false;
585
UnaryOperatorExpression uoe = expressions[expressions.Count - 1] as UnaryOperatorExpression;
587
return uoe.Op == UnaryOperatorType.Minus;
593
bool StartOfQueryExpression()
595
if (la.kind == Tokens.From) {
597
if (IsIdentifierToken(p) || Tokens.TypeKW[p.kind])
603
static bool IsIdentifierToken(Token tk)
605
return Tokens.IdentifierTokens[tk.kind];
609
/// Adds a child item to a collection stored in the parent node.
610
/// Also set's the item's parent to <paramref name="parent"/>.
611
/// Does nothing if item is null.
613
static void SafeAdd<T>(INode parent, List<T> list, T item) where T : class, INode
615
Debug.Assert(parent != null);
616
Debug.Assert((parent is INullable) ? !(parent as INullable).IsNull : true);
619
item.Parent = parent;
623
internal static string GetReflectionNameForOperator(OverloadableOperatorType op)
626
case OverloadableOperatorType.None:
628
case OverloadableOperatorType.Add:
629
return "op_Addition";
630
case OverloadableOperatorType.BitNot:
631
return "op_OnesComplement";
632
case OverloadableOperatorType.BitwiseAnd:
633
return "op_BitwiseAnd";
634
case OverloadableOperatorType.BitwiseOr:
635
return "op_BitwiseOr";
636
case OverloadableOperatorType.Concat:
637
case OverloadableOperatorType.CType:
639
case OverloadableOperatorType.Decrement:
640
return "op_Decrement";
641
case OverloadableOperatorType.Divide:
642
return "op_Division";
643
case OverloadableOperatorType.DivideInteger:
645
case OverloadableOperatorType.Equality:
646
return "op_Equality";
647
case OverloadableOperatorType.ExclusiveOr:
648
return "op_ExclusiveOr";
649
case OverloadableOperatorType.GreaterThan:
650
return "op_GreaterThan";
651
case OverloadableOperatorType.GreaterThanOrEqual:
652
return "op_GreaterThanOrEqual";
653
case OverloadableOperatorType.Increment:
654
return "op_Increment";
655
case OverloadableOperatorType.InEquality:
656
return "op_Inequality";
657
case OverloadableOperatorType.IsFalse:
659
case OverloadableOperatorType.IsTrue:
661
case OverloadableOperatorType.LessThan:
662
return "op_LessThan";
663
case OverloadableOperatorType.LessThanOrEqual:
664
return "op_LessThanOrEqual";
665
case OverloadableOperatorType.Like:
667
case OverloadableOperatorType.Modulus:
669
case OverloadableOperatorType.Multiply:
670
return "op_Multiply";
671
case OverloadableOperatorType.Not:
672
return "op_LogicalNot";
673
case OverloadableOperatorType.Power:
675
case OverloadableOperatorType.ShiftLeft:
676
return "op_LeftShift";
677
case OverloadableOperatorType.ShiftRight:
678
return "op_RightShift";
679
case OverloadableOperatorType.Subtract:
680
return "op_Subtraction";
681
case OverloadableOperatorType.UnaryMinus:
682
return "op_UnaryNegation";
683
case OverloadableOperatorType.UnaryPlus:
684
return "op_UnaryPlus";
686
throw new NotSupportedException("opeartor type:" + op);