CSharpParser.cs :  » Development » devAdvantage » AnticipatingMinds » Genesis » CodeParser » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Development » devAdvantage 
devAdvantage » AnticipatingMinds » Genesis » CodeParser » CSharpParser.cs
using System;
using System.IO;
using System.Text;
using System.Threading;
using AnticipatingMinds.Genesis.CodeDOM;
using AnticipatingMinds.Genesis.CodeDOM.Utilities;
using System.Diagnostics;
using System.CodeDom.Compiler;
using System.Collections;
using AnticipatingMinds.Genesis.CodeParser;
using TAnticipatingMinds.Genesis.CodeParser.CSharpInternals.CSharpTokenType;
using AnticipatingMinds.Genesis.CodeParser.CSharpInternals;
using AnticipatingMinds.PlatformServices.Globalization;

namespace AnticipatingMinds.Genesis.CodeParser{
  /// <summary>
  /// Summary description for CSharpParser.
  /// </summary>
  [System.Security.Permissions.StrongNameIdentityPermissionAttribute(System.Security.Permissions.SecurityAction.LinkDemand,
     PublicKey=
     "00240000048000009400000006020000002400005253413100040000010001009D309779C258129573FC313836474C75C4CE9F4" +
     "107524FA0B9A6DB2E52754459C5A8946E4CBD5B98ACDB2413C5AFD38C1DF00C9A946713E867237B47F9D9CC473D4A853EACBEAB" + 
     "799EC0A271B468D4B6D52301A414A7772F05FEBD2BA7D0A2835F0D45E401C3C37F9E7B991D29F07DA88E20BB3839A34A2739AB6" + 
     "56B5204C8BC")]
  public class CSharpParser : AnticipatingMinds.Genesis.CodeParser.CodeParser
  {
    public CSharpParser(string sourceCode,string fileName,CodeAssembly codeAssembly):base(sourceCode,fileName,codeAssembly)
    {
      this.sourceCode = sourceCode;
    }

    public void InitializeParser(ManualResetEvent cancelEvent)
    {
      this.cancelEvent = cancelEvent;
      //Instantiate new compile unit and errors collection for this parse
      parsingErrors = new CompilerErrorCollection();
      compileUnit = new CodeCompileUnit(FileName);
      compileUnit.Language = CodeLanguage.CSharp;


      OnParsingStarted(FileName);
      ReportProgress();
    }
    
    public void TokenizeSource(bool processComments)
    {
      if(CodeAssembly != null)
        tokens = new CSharpTokenStream(SourceCode, !processComments,CodeAssembly.CompilationConstants);
      else
        tokens = new CSharpTokenStream(SourceCode, !processComments,new string[0]);

      //If we need to process comments do it now (before parsing) and remove comments from the tokens stream so parser would work
      //fine. 
      CodeCommentCollection codeComments = null;
      if(processComments)
        codeComments = ExtractCommentsFromTokens();
    }
    
    public CodeCompileUnit Parse(ManualResetEvent cancelEvent,bool processComments)
    {
      InitializeParser(cancelEvent);
      TokenizeSource(processComments);
      try
      {
        //The only valid element for compile unit is namespace or a type declaration
        //if there is no namespace explicity specified
        //anonymouse namesapce is assumed.
        //ECMA 334. Page 345, line 41
        RecordPosition(CompileUnit.Namespace);
        ParseNamespaceBody(CompileUnit.Namespace);
      }
      catch(Exception e)
      {
        ParserException parserException = new ParserException("Unexpected Parser Exception",e);
        parserException.CurrentPosition.FileName = FileName;
        if(tokens != null && tokens.Current != null)
        {
          parserException.CurrentPosition.Line = tokens.Current.Line;
          parserException.CurrentPosition.Column = tokens.Current.Column;
          parserException.CurrentPosition.Position = tokens.Current.Position;
        }

        Errors.Add(new CompilerError(FileName,parserException.CurrentPosition.Line,parserException.CurrentPosition.Column,"",parserException.ToString()));
        throw parserException;
      }
      
      CodeCompileUnitUtils.RefreshCompileUnitElementsReferences(compileUnit);

//      if(processComments)
//      {
//        ProcessAndAssignComments(codeComments);
//      }

      ReportProgress();
      OnParsingEnded(compileUnit,parsingErrors);
      return compileUnit;
    }
    public override CodeAssemblyFile Parse(ManualResetEvent cancelEvent)
    {
      return Parse(cancelEvent,false);
    }

    public CodeStatementBlock ParseStatements(ManualResetEvent cancelEvent)
    {
      InitializeParser(cancelEvent);
      TokenizeSource(false);
      CodeStatementBlock statmentsBlock = null;
      try
      {
        statmentsBlock = ParseStatementBlock(null);
      }
      catch(Exception e)
      {
        ParserException parserException = new ParserException("Unexpected Parser Exception",e);
        parserException.CurrentPosition.FileName = FileName;
        if(tokens != null && tokens.Current != null)
        {
          parserException.CurrentPosition.Line = tokens.Current.Line;
          parserException.CurrentPosition.Column = tokens.Current.Column;
          parserException.CurrentPosition.Position = tokens.Current.Position;
        }

        Errors.Add(new CompilerError(FileName,parserException.CurrentPosition.Line,parserException.CurrentPosition.Column,"",parserException.ToString()));
        throw parserException;
      }
      
      CodeCompileUnitUtils.RefreshCodeElementsReferences(statmentsBlock);
      ReportProgress();
      OnParsingEnded(compileUnit,parsingErrors);
      return statmentsBlock;
    }

    public CodeExpression ParseExpression(ManualResetEvent cancelEvent)
    {
      InitializeParser(cancelEvent);
      TokenizeSource(false);
      CodeExpression expression = null;
      try
      {
        expression = ParseExpression();
      }
      catch(Exception e)
      {
        ParserException parserException = new ParserException("Unexpected Parser Exception",e);
        parserException.CurrentPosition.FileName = FileName;
        if(tokens != null && tokens.Current != null)
        {
          parserException.CurrentPosition.Line = tokens.Current.Line;
          parserException.CurrentPosition.Column = tokens.Current.Column;
          parserException.CurrentPosition.Position = tokens.Current.Position;
        }

        Errors.Add(new CompilerError(FileName,parserException.CurrentPosition.Line,parserException.CurrentPosition.Column,"",parserException.ToString()));
        throw parserException;
      }
      
      CodeCompileUnitUtils.RefreshCodeElementsReferences(expression);
      ReportProgress();
      OnParsingEnded(compileUnit,parsingErrors);
      return expression;
    }

    private CodeCommentCollection ExtractCommentsFromTokens()
    {
      //Preprocess tokens to extract collection of comments.
      //and remove comments from tokens collection
      CodeCommentCollection comments = new CodeCommentCollection();
      while(tokens.CurrentType != T.TID_EOF)
      {
        //Process documentation comments
        if(tokens.CurrentType == T.TID_SINGLE_LINE_COMMENT && tokens.Current.Name.Length > 0 && tokens.Current.Name[0] == '/')
        {
          CodeComment comment = new CodeComment();
          RecordPosition(comment);
          comment.Style = CodeComment.CodeCommentStyle.Documentation;

          do
          {
            comment.Lines.Add(tokens.Current.Name.Substring(1));
            tokens.Remove();
          }while(tokens.CurrentType != T.TID_EOF && tokens.CurrentType == T.TID_SINGLE_LINE_COMMENT && tokens.Current.Name.Length > 0 && tokens.Current.Name[0] == '/');

          comments.Add(comment);
          continue;
        }
        
        //Process single line comments
        if(tokens.CurrentType == T.TID_SINGLE_LINE_COMMENT)
        {
          CodeComment comment = new CodeComment();
          RecordPosition(comment);
          comment.Style = CodeComment.CodeCommentStyle.SingleLine;
          
          do
          {
            comment.Lines.Add(tokens.Current.Name);
            tokens.Remove();
          } while(tokens.CurrentType != T.TID_EOF && tokens.CurrentType == T.TID_SINGLE_LINE_COMMENT);

          comments.Add(comment);
          continue;
        }
      
        //Process multi line comments
        if(tokens.CurrentType == T.TID_MULTI_LINE_COMMENT)
        {
          CodeComment comment = new CodeComment();
          RecordPosition(comment);
          comment.Style = CodeComment.CodeCommentStyle.Multiline;
          do
          {
            //Split multiline comment by lines
            using(StringReader commentReader = new StringReader(tokens.Current.Name))
            {
              string line;
              while ((line = commentReader.ReadLine()) != null)
              {
                comment.Lines.Add(line);
              }
            }
            tokens.Remove();
          }while(tokens.CurrentType != T.TID_EOF && tokens.CurrentType == T.TID_MULTI_LINE_COMMENT);

          comments.Add(comment);
          continue;
        }
        
        tokens.Next();
      }

      tokens.Rewind(0);
      return comments;
    }

    private void ProcessAndAssignComments(CodeCommentCollection comments)
    {
      ///Comments.
      ///It will be very hard to parse comments at the same time we parse code elemnts
      ///The reason is that we always would have to check for one. We can never expect
      ///certain token. It would multiply ifs greatly. To avoid it, we process comments 
      ///after we processed the rest.
      ///The algorithm is quite simple. We add all code elements into an array and sort it 
      ///base on element position.
    
      ArrayList allCodeElements = new ArrayList();
      CodeDomWalker.WalkCompileUnit(CompileUnit,new CodeDomWalker.WalkerCallback(BuildCodeElementsArray),allCodeElements);
      allCodeElements.Sort(new CodeElementPositionComparer(true));
      
      //Now, let's assign code comments to a particular code elements
      foreach(CodeComment comment in comments)
      {
        if(comment.Style == CodeComment.CodeCommentStyle.Documentation)
        {
          foreach(CodeElement codeElement in allCodeElements)
          {
            if(comment.SourcePosition.Position < codeElement.SourcePosition.Position && 
              (codeElement is CodeTypeDeclaration || codeElement is CodeTypeMemberDeclaration))
            {
              if(codeElement.DocumentationComment != null)
              {
                foreach(String line in comment.Lines)
                  codeElement.DocumentationComment.Lines.Add(line);
              }
              else
              {
                codeElement.DocumentationComment = comment;
              }
              break;

            }
          }
        }
        else
        {
          foreach(CodeElement codeElement in allCodeElements)
          {
            if(comment.SourcePosition.Position < codeElement.SourcePosition.Position)
            {
              if(codeElement.Comment != null)
              {
                foreach(String line in comment.Lines)
                  codeElement.Comment.Lines.Add(line);
              }
              else
              {
                codeElement.Comment = comment;
              }
              break;
            }

          }
        }
        
        while(allCodeElements.Count > 0 && (allCodeElements[0] as CodeElement).SourcePosition.Position < comment.SourcePosition.Position)
          allCodeElements.RemoveAt(0);
      }

    }
    private CodeDomWalker.WalkerCallbackReturn BuildCodeElementsArray(CodeElement element,CodeDomWalker.CallBackNotificationType notification,CodeDomWalkerContext walkerContext,object applicationData)
    {
      if(notification == CodeDomWalker.CallBackNotificationType.OnElement)
      {
        (applicationData as ArrayList).Add(element);
      }
      return CodeDomWalker.WalkerCallbackReturn.Next;
    }

    private bool IsCanceled()
    {
      if(cancelEvent != null)
        return cancelEvent.WaitOne(0,false);
      else
        return false;

    }
    private void ParseNamespace(CodeNamespace parentNamespace)
    {
      if(tokens.CurrentType != T.TID_NAMESPACE)
        return;

      CodeNamespace codeNamespace = new CodeNamespace();
      codeNamespace.CompileUnit = parentNamespace.CompileUnit;
      RecordPosition(codeNamespace);

      Eat(T.TID_NAMESPACE);

      CSharpToken currentToken = tokens.Current;
      if(currentToken.TokenType != T.TID_IDENTIFIER)
      {
        ReportUnexpectedTokenError(T.TID_IDENTIFIER,currentToken.TokenType);
        if(currentToken.TokenType != T.TID_OPENCURLY)
          ReportUnexpectedTokenError(T.TID_OPENCURLY,currentToken.TokenType);
        return;
      }


      string namespaceName = ParseDottedName();

      if(tokens.CurrentType != T.TID_OPENCURLY)
      {
        ReportUnexpectedTokenError(T.TID_OPENCURLY,tokens.CurrentType);
        return;
      }
      
      Eat(T.TID_OPENCURLY);
      codeNamespace.Name = namespaceName;
      ParseNamespaceBody(codeNamespace);
      
      if(tokens.CurrentType != T.TID_CLOSECURLY)
      {
        ReportUnexpectedTokenError(T.TID_CLOSECURLY,currentToken.TokenType);
        return;
      }
      Eat(T.TID_CLOSECURLY);
      
      //Optional semilon
      if(tokens.CurrentType == T.TID_SEMICOLON)
        Eat(T.TID_SEMICOLON);

      parentNamespace.NestedNamespaces.Add(codeNamespace);
    }

    private void ParseNamespaceBody(CodeNamespace codeNamespace)
    {
      //Namespace starts with using directives or does not start at all!
      ParseNamespaceImports(codeNamespace);

      //Parse attributes section here. Attributes defined in here could be either global or 
      //related to the class. Global attributes will have scope defined.
      //class one wont.
      //So...
      if(codeNamespace == this.CompileUnit.Namespace) //Anonymouse namespace
        CompileUnit.GlobalAttributes.AddRange(ParseGlobalAttributes());

      int elementStartMark = tokens.Mark();
      while(tokens.CurrentType != T.TID_EOF && tokens.CurrentType != T.TID_CLOSECURLY)
      {
        if(IsCanceled())
          return;

        switch(tokens.CurrentType)
        {
          case T.TID_NAMESPACE:
            ParseNamespace(codeNamespace);
            elementStartMark = tokens.Mark();
            break;

          
          case T.TID_INTERFACE:
          case T.TID_STRUCT:
          case T.TID_CLASS:
          {
            //Rewind to the beginign of the element
            tokens.Rewind(elementStartMark);
            ParseClassStructInterfaceDeclaration(codeNamespace,null);
            elementStartMark = tokens.Mark();
            break;
          }

          case T.TID_ENUM:
          {
            //Rewind to the beginign of the element
            tokens.Rewind(elementStartMark);
            ParseEnumDeclaration(codeNamespace,null);
            elementStartMark = tokens.Mark();
            break;
          }

          case T.TID_DELEGATE:
          {
            //Rewind to the beginign of the element
            tokens.Rewind(elementStartMark);
            ParseDelegateDeclaration(codeNamespace,null);
            elementStartMark = tokens.Mark();
            break;
          }


          default:
            tokens.Next();
            break;
        }
      }

    }

    private void ParseMethodDeclaration(CodeTypeDeclaration parent)
    {
      methodScopeNameManager.Clear();
      CodeAttributeCollection methodAttributes = ParseAttributes();

      CodeElementPosition sourcePosition = new CodeElementPosition(CompileUnit.SourceFileName,tokens.Current.Line,tokens.Current.Column,tokens.Current.Position);
      CodeTypeMemberDeclaration.MemberDeclarationModifiers modifiers = ParseMemberDeclarationModifiers();

      CodeTypeReference returnType = new CodeTypeReference("System.Void");
      string methodName = string.Empty;
      
      bool isDestructor = false;
      bool isConstructor = false;
      
      //Is it destructor?
      if(tokens.CurrentType == T.TID_TILDE)
      {
        isDestructor = true;
        tokens.Next();
        methodName = ParseDottedName();
      }
      else
      {
        //Could be a return type or a constructor
        //Id it contructor?
        if(tokens.CurrentType == T.TID_IDENTIFIER && 
          tokens.Current.Name == parent.Name && 
          tokens.Peek(1).TokenType == T.TID_OPENPAREN)
        {
          //Definetly constructor!
          Eat(T.TID_IDENTIFIER);
          methodName = ".ctor";
          isConstructor = true;
        }
        else
        {
          RecordPosition(returnType);
          returnType.TypeName = ParseTypeName();
          methodName = ParseDottedName();
        }
      }

      Eat(T.TID_OPENPAREN);
      CodeMethodParameterCollection parameters = ParseParametersList();
      Eat(T.TID_CLOSEPAREN);

      //Create appropriate method:
      if(isConstructor)
      {
        CodeTypeConstructorDeclaration constructor = new CodeTypeConstructorDeclaration();
        
        constructor.Parameters.AddRange(parameters);
        constructor.Attributes.AddRange(methodAttributes);
        constructor.SourcePosition = sourcePosition;
        constructor.Modifiers = modifiers;
        
        //Parse base
        if(tokens.CurrentType == T.TID_COLON)
        {
          Eat(T.TID_COLON);
          if(tokens.CurrentType == T.TID_BASE)
          {
            constructor.InitializerType = CodeTypeConstructorDeclaration.ConstructorInitializerType.Base;
            Eat(T.TID_BASE);
          }
          else
            if(tokens.CurrentType == T.TID_THIS)
          {
            constructor.InitializerType = CodeTypeConstructorDeclaration.ConstructorInitializerType.This;
            Eat(T.TID_THIS);
          }
          Eat(T.TID_OPENPAREN);
          constructor.InitializerArguments.AddRange(ParseArgumentsList());
          Eat(T.TID_CLOSEPAREN);
        }
        constructor.Statements = ParseStatementBlock(null);
        //constructor.DeclaringType = parent;
        AddMemberToCodeType(parent,constructor);
      }
      else
      {
        if(isDestructor)
        {
          CodeTypeDestructorDeclaration destructor = new CodeTypeDestructorDeclaration();

          destructor.Attributes.AddRange(methodAttributes);
          destructor.Parameters.AddRange(parameters);
          destructor.Modifiers = modifiers;
          AddMemberToCodeType(parent,destructor);
          destructor.Statements = ParseStatementBlock(null);
          destructor.ReturnType = null;
          destructor.SourcePosition = sourcePosition;
        }
        else
        {
          //Just a method!
          CodeTypeMethodDeclaration method = new CodeTypeMethodDeclaration();
          method.Name = methodName;
          //method.DeclaringType = parent;
          method.Attributes.AddRange(methodAttributes);
          method.Parameters.AddRange(parameters);
          method.Modifiers = modifiers;
          AddMemberToCodeType(parent,method);
          method.Statements = ParseStatementBlock(null);
          method.ReturnType = returnType;
          method.SourcePosition = sourcePosition;
        }
      }
    }

    private void ParsePropertyDeclaration(CodeTypeDeclaration parent)
    {
      methodScopeNameManager.Clear();
      CodeTypePropertyDeclaration property = new CodeTypePropertyDeclaration();
      //property.DeclaringType = parent;

      property.Attributes.AddRange(ParseAttributes());
      RecordPosition(property);

      property.Modifiers = ParseMemberDeclarationModifiers();

      CodeTypeReference returnType = new CodeTypeReference();
      RecordPosition(returnType);
      returnType.TypeName = ParseTypeName();
      property.ReturnType = returnType;
      property.Name = ParseDottedName();

      Debug.Assert(property.Name != null && property.Name.Length != 0,"Property name cannot be empty string.");
      Debug.Assert(returnType.TypeName != null && returnType.TypeName.Length != 0,"Property return type name cannot be empty string.");
  
      //property starts
      if(!Eat(T.TID_OPENCURLY))
      {
        RecoverBySkippingCurlies(false);
        return;
      }

      //Get accessros
      while(true)
      {
        if(IsCanceled())
          return;

        CodeAttributeCollection accessorAttributes = ParseAttributes();
        if(tokens.CurrentType != T.TID_IDENTIFIER) //get or set
          break;

        string accessorType = tokens.Current.Name;
        tokens.Next();

        if(accessorType == "get")
        {
          property.HasGetter = true;
          property.GetAccessorAttributes.AddRange(accessorAttributes);
          property.GetAccessorStatements = ParseStatementBlock(null);
        }
        else
          if(accessorType == "set")
        {
          property.HasSetter = true;
          //In the set block there is a parameter - value is proerty method paramter
          //it is hidden in the grammar but it is there
          //so - add it!
          methodScopeNameManager.Register("value",new CodeMethodParameter(returnType,"value"));
          property.SetAccessorAttributes.AddRange(accessorAttributes);
          property.SetAccessorStatements = ParseStatementBlock(null);
        }
        else
        {
          ReportUnexpectedTokenError(T.TID_PROPERTY_GET_OR_SET,tokens.CurrentType);
          break;
        }
      }
      AddMemberToCodeType(parent,property);
      Eat(T.TID_CLOSECURLY);
    }

    private void ParseFieldDeclaration(CodeTypeDeclaration parent)
    {
      CodeTypeFieldDeclaration fields = new CodeTypeFieldDeclaration();
      RecordPosition(fields);
      fields.Attributes.AddRange(ParseAttributes());
      fields.Modifiers = ParseMemberDeclarationModifiers();

      fields.DeclarationType = new CodeTypeReference();
      RecordPosition(fields.DeclarationType);
      fields.DeclarationType.TypeName = ParseTypeName();
      fields.DeclaredFields.AddRange(ParseVariableDeclarationList());
      Eat(T.TID_SEMICOLON);
      if(fields.DeclaredFields.Count != 0)
      {
        AddMemberToCodeType(parent,fields);
      }
      else
      {
        //Error
        //skip statements till the next semicolomn
        RecoverBySkippingToSemicolon();
      }
    }

    /// <summary>
    /// Parses declaration of delegate
    /// </summary>
    /// <param name="codeNamespace"></param>
    /// <param name="parent"></param>
    private void ParseDelegateDeclaration(CodeNamespace codeNamespace,CodeTypeDeclaration parent)
    {
      CodeTypeDelegateDeclaration delegateDeclaration = new CodeTypeDelegateDeclaration();
      delegateDeclaration.Attributes.AddRange(ParseAttributes());

      RecordPosition(delegateDeclaration);
      delegateDeclaration.Modifiers = ParseTypeDeclarationModifiers();

      Eat(T.TID_DELEGATE);

      CodeTypeReference returnType = new CodeTypeReference();
      RecordPosition(returnType);
      returnType.TypeName = ParseTypeName();
      delegateDeclaration.ReturnType = returnType;

      delegateDeclaration.Name = ParseDottedName();
      Eat(T.TID_OPENPAREN);
      delegateDeclaration.Parameters.AddRange(ParseParametersList());
      Eat(T.TID_CLOSEPAREN);
      Eat(T.TID_SEMICOLON);
      
      //Delegate can be declared inside class or a namespace.
      if(parent == null)
      {
        codeNamespace.DeclaredTypes.Add(delegateDeclaration);
      }
      else
      {
        if(parent is CodeClassDeclaration)
          ((CodeClassDeclaration) parent).NestedTypes.Add(delegateDeclaration);

        if(parent is CodeStructDeclaration)
          ((CodeStructDeclaration) parent).NestedTypes.Add(delegateDeclaration);
      }
    }

    private void ParseIndexerDeclaration(CodeTypeDeclaration parent)
    {
      methodScopeNameManager.Clear();
      CodeTypeIndexerDeclaration indexer = new CodeTypeIndexerDeclaration();
      //indexer.DeclaringType = parent;

      indexer.Attributes.AddRange(ParseAttributes());
      RecordPosition(indexer);

      indexer.Modifiers = ParseMemberDeclarationModifiers();

      CodeTypeReference returnType = new CodeTypeReference();
      RecordPosition(returnType);
      returnType.TypeName = ParseTypeName();
      indexer.ReturnType = returnType;

      if(tokens.CurrentType == T.TID_THIS)
      {
        indexer.Name = "this";
        Eat(T.TID_THIS);
      }
      else
      {
        indexer.Name = ParseDottedName();
      }

      //When name is in form of id.id.this ParseDottedName eats this.
      //check for it and appaend it if needed
      if(tokens.Peek(-1).TokenType == T.TID_THIS)
      {
        indexer.Name += "this";
      }

      Eat(T.TID_OPENSQUARE);
      indexer.Parameters.AddRange(ParseParametersList());
      Eat(T.TID_CLOSESQUARE);
  
      //property starts
      if(!Eat(T.TID_OPENCURLY))
        return;

      //Get accessros
      while(true)
      {
        if(IsCanceled())
          return;

        CodeAttributeCollection accessorAttributes = ParseAttributes();
        if(tokens.CurrentType != T.TID_IDENTIFIER) //get or set
          break;

        string accessorType = tokens.Current.Name;
        tokens.Next();

        if(accessorType == "get")
        {
          indexer.GetAccessorAttributes.AddRange(accessorAttributes);
          indexer.GetAccessorStatements = ParseStatementBlock(null);
        }
        else
          if(accessorType == "set")
        {
          //In the set block there is a parameter - value is proerty method paramter
          //it is hidden in the grammar but it is there
          //so - add it!
          methodScopeNameManager.Register("value",new CodeMethodParameter(returnType,"value"));

          indexer.SetAccessorAttributes.AddRange(accessorAttributes);
          indexer.SetAccessorStatements = ParseStatementBlock(null);
        }
        else
        {
          ReportUnexpectedTokenError(T.TID_PROPERTY_GET_OR_SET,tokens.CurrentType);
          break;
        }
      }
      Eat(T.TID_CLOSECURLY);
      AddMemberToCodeType(parent,indexer);
    }

    private void ParseEventDeclaration(CodeTypeDeclaration parent)
    {
      methodScopeNameManager.Clear();
      CodeAttributeCollection eventAttributes = ParseAttributes();

      CodeElementPosition sourcePosition = new CodeElementPosition(CompileUnit.SourceFileName,tokens.Current.Line,tokens.Current.Column,tokens.Current.Position);
      CodeTypeMemberDeclaration.MemberDeclarationModifiers modifiers = ParseMemberDeclarationModifiers();

      Eat(T.TID_EVENT);

      CodeTypeReference eventType = new CodeTypeReference();
      RecordPosition(eventType);
      eventType.TypeName = ParseTypeName();

      bool areEventAcessorsDeclared = false;
      int currentPosition = tokens.Mark();
      //Skip the name
      ParseDottedName();
      if(tokens.CurrentType == T.TID_OPENCURLY)
        areEventAcessorsDeclared = true;

      tokens.Rewind(currentPosition);

      if(areEventAcessorsDeclared)
      {
        //An event with add/remove blocks declaration
        CodeTypeEventDeclaration eventDeclaration = new CodeTypeEventDeclaration();
        eventDeclaration.DeclarationType = eventType;
        eventDeclaration.SourcePosition = sourcePosition;
        eventDeclaration.Modifiers = modifiers;
        eventDeclaration.Attributes.AddRange(eventAttributes);
        eventDeclaration.Name= ParseDottedName();
        //eventDeclaration.DeclaringType = parent;

        //property starts
        if(!Eat(T.TID_OPENCURLY))
          return;

        //Get accessros
        while(true)
        {
          if(IsCanceled())
            return;

          CodeAttributeCollection accessorAttributes = ParseAttributes();
          if(tokens.CurrentType != T.TID_IDENTIFIER) //get or set
            break;

          string accessorType = tokens.Current.Name;
          tokens.Next();

          //Accessors define parameter - value
          //it is the same thing as with properties - it is implicit but it is there!
          methodScopeNameManager.Register("value",new CodeMethodParameter(eventType,"value"));
          if(accessorType == "add")
          {
            eventDeclaration.AddAccessorAttributes.AddRange(accessorAttributes);
            eventDeclaration.AddAccessorStatements = ParseStatementBlock(null);
          }
          else
            if(accessorType == "remove")
          {
            eventDeclaration.RemoveAccessorAttributes.AddRange(accessorAttributes);
            eventDeclaration.RemoveAccessorStatements = ParseStatementBlock(null);
          }
          else
          {
            ReportUnexpectedTokenError(T.TID_EVENT_ADD_OR_REMOVE,tokens.CurrentType);
            break;
          }
        }
        AddMemberToCodeType(parent,eventDeclaration);
        Eat(T.TID_CLOSECURLY);
      }
      else
      {
        CodeTypeEventListDeclaration eventListDeclaration = new CodeTypeEventListDeclaration();
        eventListDeclaration.DeclarationType = eventType;
        eventListDeclaration.SourcePosition = sourcePosition;
        eventListDeclaration.Modifiers = modifiers;
        eventListDeclaration.Attributes.AddRange(eventAttributes);
        //eventListDeclaration.DeclaringType = parent;

        //Field like declaration
        eventListDeclaration.DeclaredEvents.AddRange(ParseVariableDeclarationList());
        Eat(T.TID_SEMICOLON);
        AddMemberToCodeType(parent,eventListDeclaration);
      }
    }

    private void ParseOperatorDeclaration(CodeTypeDeclaration parent)
    {
      methodScopeNameManager.Clear();

      CodeAttributeCollection operatorAttributes = ParseAttributes();

      CodeElementPosition sourcePosition = new CodeElementPosition(CompileUnit.SourceFileName,tokens.Current.Line,tokens.Current.Column,tokens.Current.Position);
      CodeTypeMemberDeclaration.MemberDeclarationModifiers modifiers = ParseMemberDeclarationModifiers();
      
      if(tokens.CurrentType == T.TID_EXPLICIT || 
        tokens.CurrentType == T.TID_IMPLICIT)
      {
        //Cast operator
        CodeTypeConversionOperatorDeclaration castOperator = new CodeTypeConversionOperatorDeclaration();
        castOperator.SourcePosition = sourcePosition;

        castOperator.Attributes.AddRange(operatorAttributes);
        //castOperator.DeclaringType = parent;
        castOperator.Modifiers = modifiers;


        if(tokens.CurrentType == T.TID_EXPLICIT)
          castOperator.Explicit = true;
        else
          castOperator.Explicit = false;

        tokens.Next();
        Eat(T.TID_OPERATOR);
        
        CodeTypeReference returnType = new CodeTypeReference();
        RecordPosition(returnType);
        returnType.TypeName = ParseTypeName();

        castOperator.ReturnType = returnType;

        Eat(T.TID_OPENPAREN);
        CodeMethodParameterCollection paremeters = new CodeMethodParameterCollection(ParseParametersList());
        Eat(T.TID_CLOSEPAREN);
        if(paremeters.Count>0)
          castOperator.Parameter = paremeters[0];
        
        castOperator.Statements = ParseStatementBlock(null);

        AddMemberToCodeType(parent,castOperator);
      }
      else
      {
        //Binary or unary operator
        CodeTypeReference operatorReturnType = new CodeTypeReference();
        RecordPosition(operatorReturnType);
        operatorReturnType.TypeName = ParseTypeName();

        Eat(T.TID_OPERATOR);
        CSharpToken operation = tokens.Current;
        tokens.Next();

        Eat(T.TID_OPENPAREN);
        CodeMethodParameterCollection paremeters = new CodeMethodParameterCollection(ParseParametersList());
        Eat(T.TID_CLOSEPAREN);

        Debug.Assert(paremeters.Count != 0,"Is it unknow operator?");
        if(paremeters.Count == 1) 
        {
          //Unary operator
          CodeTypeUnaryOperatorDeclaration unaryOp= new CodeTypeUnaryOperatorDeclaration();
          unaryOp.Attributes.AddRange(operatorAttributes);
          //unaryOp.DeclaringType = parent;
          unaryOp.Modifiers = modifiers;
          unaryOp.Operation = operation.GetUnaryOperation();
          unaryOp.Parameter = paremeters[0];
          unaryOp.ReturnType = operatorReturnType;
          unaryOp.Statements = ParseStatementBlock(null);
          unaryOp.SourcePosition = sourcePosition;
          AddMemberToCodeType(parent,unaryOp);
        }
        else
        {
          //Binary operator
          CodeTypeBinaryOperatorDeclaration binaryOp= new CodeTypeBinaryOperatorDeclaration();
          binaryOp.Attributes.AddRange(operatorAttributes);
          //binaryOp.DeclaringType = parent;
          binaryOp.Modifiers = modifiers;
          binaryOp.Operation = operation.GetBinaryOperation();
          binaryOp.SourcePosition = sourcePosition;
          binaryOp.LeftParameter = paremeters[0];
          
          if(paremeters.Count > 1)
            binaryOp.RightParameter = paremeters[1];

          binaryOp.ReturnType = operatorReturnType;
          binaryOp.Statements = ParseStatementBlock(null);
          AddMemberToCodeType(parent,binaryOp);
        }
      }
    }

    /// <summary>
    /// Parses a variable declaration members list.
    /// </summary>
    /// <returns></returns>
    private CodeVariableDeclarationMemberCollection ParseVariableDeclarationList()
    {
      CodeVariableDeclarationMemberCollection variables = new CodeVariableDeclarationMemberCollection();
      
      do
      {
        if(IsCanceled())
          return variables;

        CodeVariableDeclarationMember variable = new CodeVariableDeclarationMember();
        RecordPosition(variable);
        variable.Name = ParseDottedName();
        if(tokens.CurrentType == T.TID_EQUAL)
        {
          Eat(T.TID_EQUAL);
          variable.Initializer = ParseInitializer();
        }
        
        if(tokens.CurrentType == T.TID_COMMA)
          Eat(T.TID_COMMA);

        if(variable.Name.Length != 0)
        {
          variables.Add(variable);
        }
      }while (tokens.CurrentType == T.TID_IDENTIFIER);

      return variables;
    }

    private CodeExpression ParseInitializer()
    {
      if(tokens.CurrentType == T.TID_OPENCURLY)
      {
        CodeArrayInitializerExpression arrayInitializer = new CodeArrayInitializerExpression();
        RecordPosition(arrayInitializer);
        //Array initializer!
        Eat(T.TID_OPENCURLY);
        while(tokens.CurrentType != T.TID_CLOSECURLY)
        {
          if(tokens.CurrentType == T.TID_EOF)
          {
            return arrayInitializer;
          }

          arrayInitializer.Initializers.Add(ParseInitializer());

          if(tokens.CurrentType != T.TID_COMMA)
            break;

          Eat(T.TID_COMMA);
        }

        Eat(T.TID_CLOSECURLY);
        return arrayInitializer;
      }
      else
      {
        //Regular expression initializer
        return ParseExpression();
      }
    }


    private void ParseEnumDeclaration(CodeNamespace declaringNamespace, CodeTypeDeclaration parent)
    {
      CodeEnumDeclaration enumDeclaration = new CodeEnumDeclaration();
      enumDeclaration.Attributes.AddRange(ParseAttributes());
      RecordPosition(enumDeclaration);
      enumDeclaration.Modifiers = ParseTypeDeclarationModifiers();
      Eat(T.TID_ENUM);
      enumDeclaration.Name = ParseDottedName();
      enumDeclaration.EnumBase = new CodeTypeReference(typeof(int));

      if(tokens.CurrentType == T.TID_COLON)
      {
        Eat(T.TID_COLON);
        enumDeclaration.EnumBase = new CodeTypeReference();
        RecordPosition(enumDeclaration.EnumBase);
        enumDeclaration.EnumBase.TypeName = ParseTypeName();
      }
      Eat(T.TID_OPENCURLY);
      while(tokens.CurrentType != T.TID_CLOSECURLY && tokens.CurrentType != T.TID_EOF)
      {
        CodeEnumMember enumMember = new CodeEnumMember();
        RecordPosition(enumMember);
        enumMember.Attributes.AddRange(ParseAttributes());
        enumMember.Name = ParseDottedName();
        if(tokens.CurrentType == T.TID_EQUAL)
        {
          Eat(T.TID_EQUAL);
          enumMember.Value = ParseExpression();
        }

        enumDeclaration.Members.Add(enumMember);
        if(tokens.CurrentType == T.TID_COMMA)
        {
          Eat(T.TID_COMMA);
        }
      }
      
      Eat(T.TID_CLOSECURLY);
      //Optional semilon
      if(tokens.CurrentType == T.TID_SEMICOLON)
        Eat(T.TID_SEMICOLON);


      //Enum can be declared inside class or a namespace.
      if(parent == null)
      {
        declaringNamespace.DeclaredTypes.Add(enumDeclaration);
      }
      else
      {
        if(parent is CodeClassDeclaration)
          ((CodeClassDeclaration) parent).NestedTypes.Add(enumDeclaration);

        if(parent is CodeStructDeclaration)
          ((CodeStructDeclaration) parent).NestedTypes.Add(enumDeclaration);
      }
    }
    /// <summary>
    /// This function parses class declaration including all its members.
    /// </summary>
    /// <param name="declaringNamespace"></param>
    /// <param name="parent"></param>
    private void ParseClassStructInterfaceDeclaration(CodeNamespace declaringNamespace, CodeTypeDeclaration parent)
    {
      ReportProgress();

      CodeAttributeCollection attributes = new CodeAttributeCollection(ParseAttributes());
      CodeElementPosition sourcePosition = new CodeElementPosition(CompileUnit.SourceFileName,tokens.Current.Line,tokens.Current.Column,tokens.Current.Position);
      CodeTypeDeclaration.TypeDeclarationModifiers modifiers = ParseTypeDeclarationModifiers();
      
      CodeTypeDeclaration codeType = null;
      switch(tokens.CurrentType)
      {
        case T.TID_CLASS:
        {
          codeType = new CodeClassDeclaration();
          Eat(T.TID_CLASS);
          break;
        }
        case T.TID_INTERFACE:
        {
          codeType = new CodeInterfaceDeclaration();
          Eat(T.TID_INTERFACE);
          break;
        }

        case T.TID_STRUCT:
        {
          codeType = new CodeStructDeclaration();
          Eat(T.TID_STRUCT);
          break;
        }
        default:
        {
          ReportError("CS0116",tokens.Current,tokens.Peek(1));
          //try to recover.
          RecoverBySkippingCurlies(true);
          return;
        }
      }

      if(codeType != null)
      {
        codeType.Attributes.AddRange(attributes);
        codeType.SourcePosition = sourcePosition;
        codeType.Modifiers = modifiers;
        
        if(parent is CodeClassDeclaration)
          ((CodeClassDeclaration) parent).NestedTypes.Add(codeType);

        if(parent is CodeStructDeclaration)
          ((CodeStructDeclaration) parent).NestedTypes.Add(codeType);
        
        //Do not add nested types to the list of namespace declared types
        if(parent == null)
          declaringNamespace.DeclaredTypes.Add(codeType);

        codeType.Name = ParseDottedName();
      }
      if(tokens.CurrentType == T.TID_COLON)
      {
        CodeTypeReferenceCollection baseTypes = new CodeTypeReferenceCollection();
        //Parse base types
        while(true)
        {
          if(IsCanceled())
            return;

          tokens.Next();
          CodeTypeReference baseTypeReference = new CodeTypeReference();
          RecordPosition(baseTypeReference);
          baseTypeReference.TypeName = ParseTypeName();
          baseTypes.Add(baseTypeReference);
          if(tokens.CurrentType == T.TID_COMMA)
          {
            continue;
          }
          else
          {
            break;
          }
        }

        if(codeType is CodeClassDeclaration)
          ((CodeClassDeclaration) codeType).BaseTypes.AddRange(baseTypes);

        if(codeType is CodeInterfaceDeclaration)
          ((CodeInterfaceDeclaration) codeType).Interfaces.AddRange(baseTypes);

        if(codeType is CodeStructDeclaration)
          ((CodeStructDeclaration) codeType).Interfaces.AddRange(baseTypes);

      }

      if(!Eat(T.TID_OPENCURLY))
        return;

      //Look eahead for class elements
      int elementStartMark = tokens.Mark();
      bool firstToken = true;
      while(tokens.CurrentType != T.TID_EOF && tokens.CurrentType != T.TID_CLOSECURLY)
      {
        if(IsCanceled())
          return;

        //Now, what is it?
        CSharpToken currentToken = tokens.Current;

        // if this is first token after we just parsed an element
        //then get attributes & modifiers out of the way.
        if(firstToken) 
        {
          //Parse modifiers just to get them out of th way.
          ParseMemberDeclarationModifiers();
          ParseAttributes();
        }
    
        switch(tokens.CurrentType)
        {
          case T.TID_CLASS:
          case T.TID_STRUCT:
          case T.TID_INTERFACE:
          {
            //Rewind to the beginign of the element
            tokens.Rewind(elementStartMark);
            ParseClassStructInterfaceDeclaration(declaringNamespace,codeType);
            elementStartMark = tokens.Mark();
            firstToken = true;
            break;
          }

          case T.TID_THIS:
          {
            //Rewind to the beginign of the element
            tokens.Rewind(elementStartMark);
            ParseIndexerDeclaration(codeType);
            elementStartMark = tokens.Mark();
            firstToken = true;
            break;
          }

          case T.TID_OPERATOR:
          {
            //Rewind to the beginign of the element
            tokens.Rewind(elementStartMark);
            ParseOperatorDeclaration(codeType);
            elementStartMark = tokens.Mark();
            firstToken = true;
            break;
          }

          case T.TID_OPENPAREN:
          {
            //Rewind to the beginign of the element
            tokens.Rewind(elementStartMark);
            ParseMethodDeclaration(codeType);
            elementStartMark = tokens.Mark();
            firstToken = true;
            break;
          }

          case T.TID_EVENT:
          {
            //Rewind to the beginign of the element
            tokens.Rewind(elementStartMark);
            ParseEventDeclaration(codeType);
            elementStartMark = tokens.Mark();
            firstToken = true;
            break;
          }

          case T.TID_DELEGATE:
          {
            //Rewind to the beginign of the element
            tokens.Rewind(elementStartMark);
            ParseDelegateDeclaration(declaringNamespace,codeType);
            elementStartMark = tokens.Mark();
            firstToken = true;
            break;
          }

          case T.TID_ENUM:
          {
            //Rewind to the beginign of the element
            tokens.Rewind(elementStartMark);
            ParseEnumDeclaration(declaringNamespace,codeType);
            elementStartMark = tokens.Mark();
            firstToken = true;
            break;
          }

          case T.TID_EQUAL:
          case T.TID_SEMICOLON:
          {
            //Rewind to the beginign of the element
            tokens.Rewind(elementStartMark);
            ParseFieldDeclaration(codeType);
            elementStartMark = tokens.Mark();
            firstToken = true;
            break;
          }
          case T.TID_OPENCURLY:
          {
            //Rewind to the beginign of the element
            tokens.Rewind(elementStartMark);
            ParsePropertyDeclaration(codeType);
            elementStartMark = tokens.Mark();
            firstToken = true;
            break;
          }
          default:
            firstToken = false;
            tokens.Next();
            break;
        }
      }

      Eat(T.TID_CLOSECURLY);
      
      //Optional semicolon
      if(tokens.CurrentType == T.TID_SEMICOLON)
        Eat(T.TID_SEMICOLON);
      
    }

    /// <summary>
    /// This function parses type declaration modifiers.
    /// </summary>
    /// <returns></returns>
    private CodeTypeDeclaration.TypeDeclarationModifiers ParseTypeDeclarationModifiers()
    {
      CodeTypeDeclaration.TypeDeclarationModifiers modifiers = 0;
      while(true)
      {
        if(IsCanceled())
          return modifiers;

        switch(tokens.CurrentType)
        {
          case T.TID_NEW:
            modifiers |= CodeTypeDeclaration.TypeDeclarationModifiers.New;
            break;

          case T.TID_PUBLIC:
            modifiers |= CodeTypeDeclaration.TypeDeclarationModifiers.Public;
            break;

          case T.TID_PROTECTED:
            modifiers |= CodeTypeDeclaration.TypeDeclarationModifiers.Family;
            break;

          case T.TID_INTERNAL:
            modifiers |= CodeTypeDeclaration.TypeDeclarationModifiers.Assembly;
            break;

          case T.TID_PRIVATE:
            modifiers |= CodeTypeDeclaration.TypeDeclarationModifiers.Private;
            break;

          case T.TID_SEALED:
            modifiers |= CodeTypeDeclaration.TypeDeclarationModifiers.Sealed;
            break;

          case T.TID_ABSTRACT:
            modifiers |= CodeTypeDeclaration.TypeDeclarationModifiers.Abstract;
            break;

          case T.TID_UNSAFE:
            modifiers |= CodeTypeDeclaration.TypeDeclarationModifiers.Unsafe;
            break;

          default:
          {
            if(((modifiers & CodeTypeDeclaration.TypeDeclarationModifiers.Family) != 0) && 
              ((modifiers & CodeTypeDeclaration.TypeDeclarationModifiers.Assembly) != 0))
            {
              modifiers &= ~CodeTypeDeclaration.TypeDeclarationModifiers.Family;
              modifiers &= ~CodeTypeDeclaration.TypeDeclarationModifiers.Assembly;
        
              modifiers |= CodeTypeDeclaration.TypeDeclarationModifiers.FamilyAndAssembly;
            }
            
            return modifiers;
          }
        }
        tokens.Next();
      }
    }

    /// <summary>
    /// This function parses member declaration modifiers 'new public ...'
    /// </summary>
    /// <returns></returns>
    private CodeTypeMemberDeclaration.MemberDeclarationModifiers ParseMemberDeclarationModifiers()
    {
      CodeTypeMemberDeclaration.MemberDeclarationModifiers modifiers = 0;
      while(true)
      {
        if(IsCanceled())
          return modifiers;

        switch(tokens.CurrentType)
        {
          case T.TID_NEW:
            modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.New;
            break;

          case T.TID_PUBLIC:
            modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.Public;
            break;

          case T.TID_PROTECTED:
            modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.Protected;
            break;

          case T.TID_INTERNAL:
            modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.Assembly;
            break;

          case T.TID_PRIVATE:
            modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.Private;
            break;

          case T.TID_STATIC:
            modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.Static;
            break;

          case T.TID_UNSAFE:
            modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.Unsafe;
            break;

          case T.TID_VIRTUAL:
            modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.Virtual;
            break;

          case T.TID_SEALED:
            modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.Sealed;
            break;

          case T.TID_OVERRIDE:
            modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.Override;
            break;

          case T.TID_ABSTRACT:
            modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.Abstract;
            break;

          case T.TID_EXTERN:
            modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.Extern;
            break;
          
          case T.TID_READONLY:
            modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.ReadOnly;
            break;
          case T.TID_CONST:
            modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.Const;
            break;
          case T.TID_VOLATILE:
            modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.Volatile;
            break;
          default:
          {
            if(((modifiers & CodeTypeMemberDeclaration.MemberDeclarationModifiers.Protected) != 0) && 
              ((modifiers & CodeTypeMemberDeclaration.MemberDeclarationModifiers.Assembly) != 0))
            {
              modifiers &= ~CodeTypeMemberDeclaration.MemberDeclarationModifiers.Protected;
              modifiers &= ~CodeTypeMemberDeclaration.MemberDeclarationModifiers.Assembly;
        
              modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.ProtectedAndAssembly;
            }
            return modifiers;
          }
        }
        tokens.Next();
      }
    }

    /// <summary>
    /// This function parses a set of attribute declarations in form
    /// [Attribute, Attribute, attribute(a,b)]
    /// [Attribute]
    /// </summary>
    /// <returns></returns>
    private CodeAttributeCollection ParseGlobalAttributes()
    {
      return ParseAttributes(true);
    }
  
    private CodeAttributeCollection ParseAttributes()
    {
      return ParseAttributes(false);
    }
      /// <summary>
    /// This function parses a set of attribute declarations in form
    /// [Attribute, Attribute, attribute(a,b)]
    /// [Attribute]
    /// </summary>
    /// <returns></returns>
    private CodeAttributeCollection ParseAttributes(bool parseGlobalAttributesOnly)
    {
      CodeAttributeCollection attributesCollection = new CodeAttributeCollection();
      
      //Check if we have an attributes section.
      CodeAttribute attribute;
      while(true)
      {
        int attributeStartPosition = tokens.Mark();
        if(IsCanceled())
          return attributesCollection;

        if(tokens.CurrentType != T.TID_OPENSQUARE)
          return attributesCollection;

        attribute = new CodeAttribute();
        RecordPosition(attribute);
        Eat(T.TID_OPENSQUARE);
        //Check for attribute scope
        string attributesScope = string.Empty;
        //Check if declaration has a scope to it. [<scopename>:
        if(tokens.Peek(1).TokenType == T.TID_COLON)
        {
          attributesScope = tokens.Current.Name;
          tokens.Next();
          Eat(T.TID_COLON);
        }

        if(parseGlobalAttributesOnly && attributesScope.Length == 0)
        {
          tokens.Rewind(attributeStartPosition);
          return attributesCollection;
        }


        while(true)
        {
          if(IsCanceled())
            return attributesCollection;

          attribute.Scope = attributesScope;
          attribute.AttributeType = new CodeTypeReference();
          RecordPosition(attribute.AttributeType);
          attribute.AttributeType.TypeName = ParseDottedName();

          //Check if attribute has an argument list
          if(tokens.CurrentType == T.TID_OPENPAREN) //it does
          {
            Eat(T.TID_OPENPAREN);
            attribute.Arguments.AddRange(ParseArgumentsList());
                    
            if(!Eat(T.TID_CLOSEPAREN))
            {
              tokens.SkipToUntilOneOf(T.TID_CLOSESQUARE);
              break;
            }
          }

          attributesCollection.Add(attribute);

          if(tokens.CurrentType != T.TID_COMMA)
            break;
          Eat(T.TID_COMMA);
          attribute = new CodeAttribute();
          RecordPosition(attribute);

          //This is protection against [a,b,] kind of declaration
          if(tokens.CurrentType == T.TID_CLOSESQUARE)
            break;

        }
        Eat(T.TID_CLOSESQUARE);
      }
    }

    /// <summary>
    /// This function parses an argument list in the following forms
    /// exp,exp,exp
    /// name = exp, exp,name = exp
    /// </summary>
    /// <returns></returns>
    private CodeArgumentCollection ParseArgumentsList()
    {
      CodeArgumentCollection arguments = new CodeArgumentCollection();

      //Check if we have anything to process
      if(tokens.CurrentType == T.TID_CLOSEPAREN)
        return arguments;
      
      int argumentPosition = 0;
      while(true)
      {
        if(IsCanceled())
          break;

        if(tokens.CurrentType == T.TID_EOF)
          break;

        CodeArgument argument = new CodeArgument();
        RecordPosition(argument);
        arguments.Add(argument);

        if(tokens.CurrentType == T.TID_IDENTIFIER && tokens.Peek(1).TokenType == T.TID_EQUAL)
        {
          argument.Name = tokens.Current.Name;
          tokens.Next();
          Eat(T.TID_EQUAL);
        }

        if(tokens.CurrentType == T.TID_REF)
        {
          argument.Modifier = CodeArgument.CodeArgumentModifier.Ref;
          Eat(T.TID_REF);
        }

        if(tokens.CurrentType == T.TID_OUT)
        {
          argument.Modifier = CodeArgument.CodeArgumentModifier.Out;
          Eat(T.TID_OUT);
        }

        argument.Value = ParseExpression();
        if(tokens.CurrentType != T.TID_COMMA)
          break;
        
        argumentPosition++;
        Eat(T.TID_COMMA);
      }

      return arguments;
    }

    /// <summary>
    /// This function parses an parameters list in the following forms
    /// ref int a,string b,type t
    /// </summary>
    /// <returns></returns>
    private CodeMethodParameterCollection ParseParametersList()
    {
      CodeMethodParameterCollection parameters = new CodeMethodParameterCollection();
      
      //Check if there are any parameters at all
      if(tokens.CurrentType == T.TID_CLOSEPAREN || tokens.CurrentType == T.TID_CLOSESQUARE)
        return parameters;

      while(true)
      {
        if(IsCanceled())
          break;

        if(tokens.CurrentType == T.TID_EOF)
          break;

        CodeMethodParameter parameter = new CodeMethodParameter();
        RecordPosition(parameter);
        parameters.Add(parameter);
        parameter.Attributes.AddRange(ParseAttributes());

        if(tokens.CurrentType == T.TID_REF)
        {
          parameter.Modifier = CodeMethodParameter.CodeMethodParameterModifier.Ref;
          Eat(T.TID_REF);
        }

        if(tokens.CurrentType == T.TID_OUT)
        {
          parameter.Modifier = CodeMethodParameter.CodeMethodParameterModifier.Out;
          Eat(T.TID_OUT);
        }

        if(tokens.CurrentType == T.TID_PARAMS)
        {
          parameter.IsParameterArray = true;
          Eat(T.TID_PARAMS);
        }

        parameter.Type = new CodeTypeReference();
        RecordPosition(parameter.Type);
        parameter.Type.TypeName = ParseTypeName();

        //Name is optional
        if(tokens.CurrentType == T.TID_IDENTIFIER)
          parameter.Name = ParseDottedName();
        
        //if name is not empty add to method scope manager
        if(parameter.Name.Length != 0)
        {
          methodScopeNameManager.Register(parameter.Name,parameter);
        }
        
        if(tokens.CurrentType != T.TID_COMMA)
          break;
        
        Eat(T.TID_COMMA);
      }

      return parameters;
    }

    /// <summary>
    /// Parse a++ or b-- form of expressions.
    /// </summary>
    /// <param name="leftOperand"></param>
    /// <returns></returns>
    private CodeExpression ParsePostFixExpression(CodeExpression leftOperand)
    {
      if(tokens.CurrentType == T.TID_PLUSPLUS)
      {
        Eat(T.TID_PLUSPLUS);
        CodeUnaryExpression unaryExpression = new CodeUnaryExpression();
        RecordPosition(unaryExpression);
        unaryExpression.Operator = CodeUnaryOperatorType.PostfixIncrement;
        unaryExpression.Operand = leftOperand;
        return unaryExpression;
      }
      
      if(tokens.CurrentType == T.TID_MINUSMINUS)
      {
        Eat(T.TID_MINUSMINUS);
        CodeUnaryExpression unaryExpression = new CodeUnaryExpression();
        RecordPosition(unaryExpression);
        unaryExpression.Operator = CodeUnaryOperatorType.PostfixDecrement;
        unaryExpression.Operand = leftOperand;
        return unaryExpression;
      }

      return leftOperand;
    }
    private CodeExpression ParseNewExpression()
    {
      CodeElementPosition createObjectPosition = GetCurrentPosition();

      Eat(T.TID_NEW);
      string typeName;
      int mark = tokens.Mark();
      typeName = ParseTypeName();
      tokens.Rewind(mark);
      if(typeName.IndexOf("[") >=0)
      {
        CodeArrayCreateExpression arrayCreateExpression = new CodeArrayCreateExpression();
        arrayCreateExpression.SourcePosition = createObjectPosition;
        int declarationStarts = tokens.Mark();
        arrayCreateExpression.CreateType = new CodeTypeReference();
        RecordPosition(arrayCreateExpression.CreateType);
        arrayCreateExpression.CreateType.TypeName = ParseTypeName();

        int initializersStarts = tokens.Mark();
        tokens.Rewind(declarationStarts);
        //Skip type name but leave brackets intact
        if(tokens.Current.IsPredefinedType())
          tokens.Next();
        else
          ParseDottedName();

        Eat(T.TID_OPENSQUARE);
        while(tokens.CurrentType != T.TID_CLOSESQUARE)
        {
          if(tokens.CurrentType != T.TID_COMMA)
            arrayCreateExpression.SizeInitializers.Add(ParseExpression());
          
          if(tokens.CurrentType == T.TID_CLOSESQUARE)
            break;

          if(tokens.CurrentType == T.TID_COMMA)
            Eat(T.TID_COMMA);
        }
        Eat(T.TID_CLOSESQUARE);

        //Skip all nested arrays
        tokens.Rewind(declarationStarts);
        ParseTypeName();
        //Is there initializers?
        if(tokens.CurrentType == T.TID_OPENCURLY)
        {
          CodeExpression initializer = ParseInitializer();
          Debug.Assert(initializer is CodeArrayInitializerExpression,"Must be array initializer!");
          if(initializer is CodeArrayInitializerExpression)
            arrayCreateExpression.Initializer = (CodeArrayInitializerExpression) initializer;
        }

        return arrayCreateExpression;
      }
      else
      {
        CodeObjectCreateExpression objectCreateExpression = new CodeObjectCreateExpression();
        objectCreateExpression.SourcePosition = createObjectPosition;
        CodeTypeReference createdType = new CodeTypeReference();
        RecordPosition(createdType);
        objectCreateExpression.CreateType = createdType;
        createdType.TypeName = ParseTypeName();

        // a = new A();
        Eat(T.TID_OPENPAREN);
        objectCreateExpression.Arguments.AddRange(ParseArgumentsList());
        Eat(T.TID_CLOSEPAREN);

        return objectCreateExpression;
      }
    }

    private CodeExpression ParseStackAllocExpression()
    {
      return ParseExpressionSnippet();
    }

    private CodeMethodInvokeExpression ParseMethodCall(CodeExpression targetObject)
    {
      CodeMethodInvokeExpression methodInvokeExpression = new CodeMethodInvokeExpression();
      RecordPosition(methodInvokeExpression);
      
      CodeNamedReferenceExpression methodReference = new CodeUnresolvedReferenceExpression();
      string referencedMethodName = string.Empty;
      //Somecalls may not have identifier to specify method name
      //for example casted delegate will not have method name
      //or there is a cast parenthesized expression
      //((MyDelegate)myDelegatesArray[2]) - this is an input target expression
      if(tokens.CurrentType == T.TID_IDENTIFIER)
      {
        RecordPosition(methodReference);
        referencedMethodName = tokens.Current.Name;
        Eat(T.TID_IDENTIFIER);
      }
      Eat(T.TID_OPENPAREN);

      //If name is not empty than it is method invokation by name
      //otherwise it is invokation through a delegate
      if(referencedMethodName.Length != 0)
      {
        //By default make metho reference as unresolved expression and resolve it later during linking
        methodReference.TargetObject = targetObject;
        methodReference.Name = referencedMethodName;
        methodInvokeExpression.MethodReferenceExpression = methodReference;

        //But ther is a special case:
        //If it is method invokation by name and there is no 
        //target object - let's check paramers and variables.
        //if parameter or variable with such name exists - it is a delegate call! 
        //Method names always are resolved through local parameters and variables first!
        if(targetObject == null)
        {
            CodeElement referencedElement = methodScopeNameManager.Lookup(referencedMethodName);
            if(referencedElement != null)
            {
              if(referencedElement is CodeMethodParameter)
              {
                CodeMethodParameterReferenceExpression paramReference = new CodeMethodParameterReferenceExpression();
                paramReference.SourcePosition = methodReference.SourcePosition;
                paramReference.MethodParameter = (CodeMethodParameter) referencedElement;
                methodInvokeExpression.MethodReferenceExpression = paramReference;
              }
              else
              {
                if(referencedElement is CodeVariableDeclarationStatement)
                {
                  CodeVariableReferenceExpression variableReference = new CodeVariableReferenceExpression();
                  variableReference.SourcePosition = methodReference.SourcePosition;
                  variableReference.VariableDeclaration = (CodeVariableDeclarationStatement) referencedElement;
                  variableReference.VariableName = referencedMethodName;
                  methodInvokeExpression.MethodReferenceExpression = variableReference;
                }
                else
                {
                  Debug.Assert(false,"Should not be here!");
                }
              }
            }

        }
      }
      else
      {
        methodInvokeExpression.MethodReferenceExpression = targetObject;
      }
      
      methodInvokeExpression.Arguments.AddRange(ParseArgumentsList());
      Eat(T.TID_CLOSEPAREN);
      return methodInvokeExpression;
    }

    private CodeIndexerInvokeExpression ParseIndexerExpression(CodeExpression targetObject)
    {
      Debug.Assert(tokens.CurrentType == T.TID_OPENSQUARE);
      
      CodeIndexerInvokeExpression indexerExpression = new CodeIndexerInvokeExpression();
      RecordPosition(indexerExpression);

      indexerExpression.IndexerReferenceExpression = targetObject;
      Eat(T.TID_OPENSQUARE);
      indexerExpression.Arguments.AddRange(ParseArgumentsList());
      Eat(T.TID_CLOSESQUARE);
      return indexerExpression;
    }

    private CodeParenthesizedExpression ParseParenthesizedExpression()
    {
      CodeParenthesizedExpression parenthesizedExpression = new CodeParenthesizedExpression();
      RecordPosition(parenthesizedExpression);
      Eat(T.TID_OPENPAREN);
      parenthesizedExpression.Expression = ParseSubExpression(0);
      Eat(T.TID_CLOSEPAREN);
      return parenthesizedExpression;
    }
    private CodeExpression ParseSubExpression(int precedence)
    {
      return ParseSubExpression(precedence,null);
    }
    private CodeExpression ParseSubExpression(int precedence,CodeExpression leftOperand)
    {
      if(leftOperand == null)
      {
      
        //First check unary operation.
        CodeUnaryOperatorType unaryOperator = tokens.Current.GetUnaryOperation();
        if(unaryOperator != CodeUnaryOperatorType.None)
        {
          //It can be an unary expression but it can also be just a number
          //-12; +3; check it and parse accordinly
          if(
            (unaryOperator == CodeUnaryOperatorType.UnaryNegation || unaryOperator == CodeUnaryOperatorType.UnaryPlus) && 
            tokens.Peek(1).TokenType == T.TID_NUMBER)
          {
            Eat(tokens.CurrentType);

            if(unaryOperator == CodeUnaryOperatorType.UnaryNegation)
              tokens.Current.Name = tokens.Current.Name.Insert(0,"-");
            else
              tokens.Current.Name = tokens.Current.Name.Insert(0,"+");


            tokens.Current.Position--;
            tokens.Current.Column--;
            if(tokens.Current.Column < 0)
            {
              tokens.Current.Column = 0;
              tokens.Current.Line--;
            }

            return ParseSubExpression(precedence,leftOperand);
          }

          //Notice that we do not return from the switch
          //we rather break. Reason is that unary operator is not an end
          //of the expression. Consider this:
          //int i = sizeof(string) + 12;
          //        ^^^^^^^^^^^^^^ 
          //We need postfix processing ffor
          //int i = sizeof(string)++;
          //            ^^
          CodeUnaryExpression unaryExpression = new CodeUnaryExpression();
          RecordPosition(unaryExpression);
          Eat(tokens.CurrentType);
          unaryExpression.Operator = unaryOperator;
          switch(unaryOperator)
          {
            case CodeUnaryOperatorType.SizeOf:
            case CodeUnaryOperatorType.TypeOf:
            {
              Eat(T.TID_OPENPAREN);
              CodeTypeReferenceExpression typeReferenceExpression = new CodeTypeReferenceExpression();
              RecordPosition(typeReferenceExpression);
              CodeTypeReference referencedType = new CodeTypeReference();
              RecordPosition(referencedType);
              referencedType.TypeName = ParseTypeName();
              typeReferenceExpression.ReferencedType = referencedType;
              Eat (T.TID_CLOSEPAREN);
              unaryExpression.Operand = typeReferenceExpression;
              leftOperand = ParsePostFixExpression(unaryExpression);
              break;
            }
            case CodeUnaryOperatorType.Checked:
            case CodeUnaryOperatorType.Unchecked:
            {
              Eat(T.TID_OPENPAREN);
              unaryExpression.Operand = ParseSubExpression (0);
              Eat (T.TID_CLOSEPAREN);
              leftOperand = ParsePostFixExpression(unaryExpression);
              break;
            }
            case CodeUnaryOperatorType.True:
            case CodeUnaryOperatorType.False:
            {
              //This two oprators do not have operand
              unaryExpression.Operand = null;
              leftOperand = unaryExpression;
              break;
            }
            default:
            {
              unaryExpression.Operand = ParseSubExpression (0);
              leftOperand = unaryExpression;
              break;
            }
          }
        }

        //If we still did not determine left operand it means that 
        //there is no unary operation and as such we are dealing with terminal symbol
        if(leftOperand == null)
        {
          switch(tokens.CurrentType)
          {
            case T.TID_NEW:
            {
              leftOperand = ParseNewExpression();
              break;
            }
            case T.TID_STACKALLOC:
            {
              Eat(T.TID_STACKALLOC);
              leftOperand = ParseStackAllocExpression();
              break;
            }
            case T.TID_STRING_LIT:
            {
              CodePrimitiveExpression primitiveExpression = new CodePrimitiveExpression();
              RecordPosition(primitiveExpression);
              primitiveExpression.Value = tokens.Current.Name;
              Eat(tokens.CurrentType);
              leftOperand = ParsePostFixExpression(primitiveExpression);
              break;
            }
            case T.TID_VERBATIM_STRING_LIT:
            {
              CodePrimitiveExpression primitiveExpression = new CodePrimitiveExpression();
              RecordPosition(primitiveExpression);
              primitiveExpression.Value = tokens.Current.Name;
              primitiveExpression.Format = CodePrimitiveExpressionFormat.VerbatimString;
              Eat(tokens.CurrentType);
              leftOperand = ParsePostFixExpression(primitiveExpression);
              break;
            }
            case T.TID_CHAR_LIT:
            {
              CodePrimitiveExpression primitiveExpression = new CodePrimitiveExpression();
              RecordPosition(primitiveExpression);

              if(tokens.Current.Name.ToUpper().StartsWith(@"\X"))
              {
                string hexChar = tokens.Current.Name.Substring(2);
                primitiveExpression.Value = (char) int.Parse(hexChar,System.Globalization.NumberStyles.HexNumber);
                primitiveExpression.Format = CodePrimitiveExpressionFormat.HexidecimalEscapeSequence;
              }
              else
              if(tokens.Current.Name.ToUpper().StartsWith(@"\U"))
              {
                string hexChar = tokens.Current.Name.Substring(2);
                primitiveExpression.Value = (char) int.Parse(hexChar,System.Globalization.NumberStyles.HexNumber);
                primitiveExpression.Format = CodePrimitiveExpressionFormat.UnicodeEscapeSequence;
              }
              else
              {
              
                switch(tokens.Current.Name)
                {
                  case @"\'":
                  {
                    primitiveExpression.Value = '\'';
                    break;
                  }
                  case @"\""":
                  {
                    primitiveExpression.Value = '\"';
                    break;
                  }
                  case @"\\":
                  {
                    primitiveExpression.Value = '\\';
                    break;
                  }
                  case @"\0":
                  {
                    primitiveExpression.Value = '\0';
                    break;
                  }
                  case @"\a":
                  {
                    primitiveExpression.Value = '\a';
                    break;
                  }
                  case @"\b":
                  {
                    primitiveExpression.Value = '\b';
                    break;
                  }
                  case @"\f":
                  {
                    primitiveExpression.Value = '\f';
                    break;
                  }
                  case @"\n":
                  {
                    primitiveExpression.Value = '\n';
                    break;
                  }
                  case @"\r":
                  {
                    primitiveExpression.Value = '\r';
                    break;
                  }
                  case @"\t":
                  {
                    primitiveExpression.Value = '\t';
                    break;
                  }
                  case @"\v":
                  {
                    primitiveExpression.Value = '\v';
                    break;
                  }
                  default:
                  {
                    try
                    {
                      primitiveExpression.Value = Char.Parse(tokens.Current.Name);
                    }
                    catch
                    {
                      //Add parser error here.
                      ReportUnexpectedTokenError(T.TID_CHAR,tokens.CurrentType);
                    }
                    break;
                  }
                }
              }
              Eat(tokens.CurrentType);
              leftOperand = ParsePostFixExpression(primitiveExpression);
              break;
            }
            case T.TID_NUMBER:
            {
              string number = tokens.Current.Name.ToUpper();

              CodePrimitiveExpression primitiveExpression = new CodePrimitiveExpression();
              RecordPosition(primitiveExpression);
              primitiveExpression.Value = ParseNumber(tokens.Current.Name);
              if(tokens.Current.Name.ToUpper().IndexOf("0X") != -1)
                primitiveExpression.Format = CodePrimitiveExpressionFormat.HexidecimalNumber;

              Eat(tokens.CurrentType);
              leftOperand = ParsePostFixExpression(primitiveExpression);
              break;
            }
            case T.TID_THIS:
            {
              CodeThisReferenceExpression thisReferenceExpression = new CodeThisReferenceExpression();
              RecordPosition(thisReferenceExpression);

              Eat(tokens.CurrentType);
            
              leftOperand = ParsePostFixExpression(thisReferenceExpression);
              break;
            }

            case T.TID_NULL:
            {
              CodeNullReferenceExpression nullReferenceExpression = new CodeNullReferenceExpression();
              RecordPosition(nullReferenceExpression);

              Eat(tokens.CurrentType);
            
              leftOperand = ParsePostFixExpression(nullReferenceExpression);
              break;
            }
          
            case T.TID_BASE:
            {
              CodeBaseReferenceExpression baseReferenceExpression = new CodeBaseReferenceExpression();
              RecordPosition(baseReferenceExpression);

              Eat(tokens.CurrentType);
            
              leftOperand = ParsePostFixExpression(baseReferenceExpression);
              break;
            }
            case T.TID_OPENPAREN:
            {
              //We need to parse either cast or parenthesized expression
              //look ahead to figure it out
              //what can it be:
              //(A)(a) -> cast or a method call if (A) is a delegate
              //(A)(a,b,c) -> always method call
              //(A*)&(a) ->cast
              //(A*)(&a) -> cast
              //(a) & (a) -> expresssion (bitwise and)
              //(string)"123" -> cast
              //(char)'char' -> cast
              //(A) this -> cast
              //(A) null -> cast
              int mark = tokens.Mark();

              Eat(T.TID_OPENPAREN);
              
              CodeTypeReference castedType = new CodeTypeReference();
              RecordPosition(castedType);
              castedType.TypeName = ParseTypeName();
              //
              if( tokens.CurrentType == T.TID_CLOSEPAREN  && 
                tokens.Peek(1).TokenType != T.TID_CLOSEPAREN &&
                tokens.Peek(1).TokenType != T.TID_OPENSQUARE &&
                tokens.Peek(1).TokenType != T.TID_CLOSESQUARE &&
                tokens.Peek(1).TokenType != T.TID_CLOSECURLY &&
                tokens.Peek(1).TokenType != T.TID_COMMA &&
                tokens.Peek(1).TokenType != T.TID_COLON &&
                (
                (tokens.Peek(1).TokenType == T.TID_AMPERSAND && castedType.IsPointer) ||
                (tokens.Peek(1).GetBinaryOperation() == CodeBinaryOperatorType.None)
                )
                )
              {
                tokens.Rewind(mark);
                CodeTypeCastExpression typeCastExp = new CodeTypeCastExpression();
                RecordPosition(typeCastExp);
                Eat(T.TID_OPENPAREN);
                //This is a type cast
                typeCastExp.TargetType = new CodeTypeReference();
                RecordPosition(typeCastExp.TargetType);
                typeCastExp.TargetType.TypeName = ParseTypeName();
                Eat(T.TID_CLOSEPAREN);
                typeCastExp.Expression = ParseSubExpression(0);
                if(typeCastExp.Expression == null)
                {
                  //Oops it was parenthesized expression! Bummer
                  tokens.Rewind(mark);
                  leftOperand = ParsePostFixExpression(ParseParenthesizedExpression());
                  break;
                }
                
                leftOperand = ParsePostFixExpression(typeCastExp);
                break;
              }
              else
              {
                //It is just a parenthesized expression
                tokens.Rewind(mark);
                leftOperand = ParsePostFixExpression(ParseParenthesizedExpression());
                break;
              }
            }
            case T.TID_IDENTIFIER:
            {
              if(tokens.Peek(1).TokenType == T.TID_OPENPAREN)
              {
                leftOperand = ParsePostFixExpression(ParseMethodCall(leftOperand));
                break;
              }

              //Identifier that starts the call. Variable?,Parameter?, Type?, Unresolved?
              CodeElement referencedElement = methodScopeNameManager.Lookup(tokens.Current.Name);
              if(referencedElement != null)
              {
                if(referencedElement is CodeMethodParameter)
                {
                  CodeMethodParameterReferenceExpression paramReference = new CodeMethodParameterReferenceExpression();
                  RecordPosition(paramReference);
                  Eat(T.TID_IDENTIFIER);
                  paramReference.MethodParameter = (CodeMethodParameter) referencedElement;
                  leftOperand = ParsePostFixExpression(paramReference);
                  break;
                }
                else
                {
                  if(referencedElement is CodeVariableDeclarationStatement)
                  {
                    CodeVariableReferenceExpression varReference = new CodeVariableReferenceExpression();
                    RecordPosition(varReference);
                    varReference.VariableName = tokens.Current.Name;
                    Eat(T.TID_IDENTIFIER);
                    varReference.VariableDeclaration = (CodeVariableDeclarationStatement) referencedElement;
                    leftOperand = ParsePostFixExpression(varReference);
                    break;
                  }
                  else
                  {
                    Debug.Assert(false,"Should not be here!");
                  }
                }
              }
              else
              {
                //Not a variable & not a parameter.
                //It is either type or unresolved reference.
                if(tokens.Current.IsPredefinedType())
                {
                  CodeTypeReferenceExpression typeReference = new CodeTypeReferenceExpression();
                  RecordPosition(typeReference);
                  CodeTypeReference referencedType = new CodeTypeReference(tokens.Current.GetPredefinedTypeName());
                  RecordPosition(referencedType);
                  typeReference.ReferencedType = referencedType;
                  Eat(T.TID_IDENTIFIER);
                  leftOperand = ParsePostFixExpression(typeReference);
                  break;
                }
                else
                {
                  CodeUnresolvedReferenceExpression memberReference = new CodeUnresolvedReferenceExpression();
                  RecordPosition(memberReference);
                  memberReference.Name = tokens.Current.Name;
                  Eat(T.TID_IDENTIFIER);
                  leftOperand = ParsePostFixExpression(memberReference);
                  break;
                }
              }
            
              Debug.Assert(false,"Why did we end up here? what other cases are possible???");
              break;
            }
            default:
            {
              if(tokens.Current.IsPredefinedType())
              {
                CodeTypeReferenceExpression typeReferenceExpression = new CodeTypeReferenceExpression();
                RecordPosition(typeReferenceExpression);
                CodeTypeReference referencedType = new CodeTypeReference();
                RecordPosition(referencedType);
                referencedType.TypeName = tokens.Current.GetPredefinedTypeName();
                typeReferenceExpression.ReferencedType = referencedType;
                Eat(tokens.CurrentType);
                leftOperand = ParsePostFixExpression(typeReferenceExpression);
                break;
              }

              if(tokens.CurrentType == T.TID_SEMICOLON)
                return null;

              Debug.Assert(false,"Why did we end up here? what other cases are possible???");
              ReportError("CS1525",tokens.Current,null,tokens.Current.Name);
              break;
            }
          }
        }
      }

      CodeBinaryExpression binaryExpresion = null;
      while(tokens.CurrentType == T.TID_OPENPAREN || tokens.CurrentType == T.TID_OPENSQUARE || tokens.Current.GetBinaryOperation() != CodeBinaryOperatorType.None)
      {
        if(tokens.CurrentType == T.TID_OPENSQUARE)
        {
          leftOperand = ParsePostFixExpression(ParseIndexerExpression(leftOperand));
          continue;
        }

        if(tokens.CurrentType == T.TID_OPENPAREN) //- it is a call of a delegate
        {
          leftOperand = ParsePostFixExpression(ParseMethodCall(leftOperand));
          continue;
        }


        CodeBinaryOperatorType operationType = tokens.Current.GetBinaryOperation();
        switch(operationType)
        {
          case CodeBinaryOperatorType.MemberSelection:
          {
            Eat(tokens.CurrentType); //Could be dot or arrow
            if(tokens.Peek(1).TokenType == T.TID_OPENPAREN)
            {
              leftOperand = ParsePostFixExpression(ParseMethodCall(leftOperand));
              break;
            }
            else
            {
              CodeNamedReferenceExpression unresolverReference = new CodeUnresolvedReferenceExpression();
              RecordPosition(unresolverReference);
              unresolverReference.Name = tokens.Current.Name;
              unresolverReference.TargetObject = leftOperand;
              Eat(T.TID_IDENTIFIER);
              leftOperand = ParsePostFixExpression(unresolverReference);
              break;
            }
          }
          
          case CodeBinaryOperatorType.Assign:
          case CodeBinaryOperatorType.AdditionAssignment:
          case CodeBinaryOperatorType.SubtractionAssignment:
          case CodeBinaryOperatorType.MultiplicationAssignment:
          case CodeBinaryOperatorType.DivisionAssignment:
          case CodeBinaryOperatorType.ModulusAssignment:
          case CodeBinaryOperatorType.BitwiseAndAssignment:
          case CodeBinaryOperatorType.ExclusiveOrAssignment:
          case CodeBinaryOperatorType.BitwiseOrAssignment:
          case CodeBinaryOperatorType.LeftShiftAssignment:
          case CodeBinaryOperatorType.RightShiftAssignment:
          {
            Eat(tokens.CurrentType);
            binaryExpresion = new CodeBinaryExpression();
            binaryExpresion.Operator = operationType;
            binaryExpresion.LeftOperand = leftOperand;
            binaryExpresion.RightOperand = ParseSubExpression(0);
            RecordPosition(binaryExpresion);
            break;
          }
          
          case CodeBinaryOperatorType.Question:
          {
            if(precedence != 0)
              return leftOperand;

            CodeConditionalExpression conditionalExpression = new CodeConditionalExpression();
            RecordPosition(conditionalExpression);
            conditionalExpression.Condition = leftOperand;
            Eat(T.TID_QUESTION);
            conditionalExpression.TrueExpression = ParseSubExpression(0);
            Eat(T.TID_COLON);
            conditionalExpression.FalseExpression = ParseSubExpression(0);
            leftOperand = conditionalExpression;
            break;
          }

          case CodeBinaryOperatorType.Is:
          {
            Eat(T.TID_IS);
            binaryExpresion = new CodeBinaryExpression();
            RecordPosition(binaryExpresion);
            binaryExpresion.Operator = operationType;
            binaryExpresion.LeftOperand = leftOperand;
            binaryExpresion.RightOperand = new CodeTypeReferenceExpression();
            RecordPosition(binaryExpresion.RightOperand);
            (binaryExpresion.RightOperand as CodeTypeReferenceExpression).ReferencedType = new CodeTypeReference();
            RecordPosition((binaryExpresion.RightOperand as CodeTypeReferenceExpression).ReferencedType);
            (binaryExpresion.RightOperand as CodeTypeReferenceExpression).ReferencedType.TypeName = ParseTypeName();
            leftOperand = binaryExpresion;
            binaryExpresion = null; // expression can have continuation: if(a is Type && a==2)
            break;
          }
          case CodeBinaryOperatorType.As:
          {
            Eat(T.TID_AS);
            binaryExpresion = new CodeBinaryExpression();
            RecordPosition(binaryExpresion);
            binaryExpresion.Operator = operationType;
            binaryExpresion.LeftOperand = leftOperand;
            binaryExpresion.RightOperand = new CodeTypeReferenceExpression();
            RecordPosition(binaryExpresion.RightOperand);
            (binaryExpresion.RightOperand as CodeTypeReferenceExpression).ReferencedType = new CodeTypeReference();
            RecordPosition((binaryExpresion.RightOperand as CodeTypeReferenceExpression).ReferencedType);
            (binaryExpresion.RightOperand as CodeTypeReferenceExpression).ReferencedType.TypeName = ParseTypeName();
            leftOperand = binaryExpresion;
            binaryExpresion = null; 
            break;
          }

          
          default:
          {
            binaryExpresion = new CodeBinaryExpression();
            RecordPosition(binaryExpresion);
            binaryExpresion.Operator = operationType;
            binaryExpresion.LeftOperand = leftOperand;
            int newPrecedence = CSharpToken.GetBinaryOperatorPrecedence(operationType);
            if(newPrecedence >= precedence)
            {
              Eat(tokens.CurrentType);
              binaryExpresion.RightOperand = ParseSubExpression(newPrecedence);
              leftOperand =  binaryExpresion;
              binaryExpresion = null;
              break;
            }
            else
            {
              return leftOperand;
            }
          }
        }
      }

      if(binaryExpresion == null)
        return leftOperand;
      else
        return binaryExpresion;
    }
    /// <summary>
    /// This function parses an expression
    /// </summary>
    /// <returns></returns>
    private CodeExpression ParseExpression()
    {
      int expressionStarts = tokens.Mark();
      CodeExpression expression = ParseSubExpression(0);
      if(expression == null && tokens.CurrentType != T.TID_SEMICOLON)
      {
        tokens.Rewind(expressionStarts);
        return ParseExpressionSnippet();
      }

      return expression;
    }
    private CodeExpression ParseExpressionSnippet()
    {
      //Expression ends either on ')' or ';' or ',' in between everething else is expression
      CodeExpressionSnippet expression = new CodeExpressionSnippet();

      int parenthethiesCount = 0;
      int curliesCount = 0;
      int squerliesCount = 0;
      int startSourcePosition = tokens.Current.Position;
      int isQuestionOpCount = 0;
      while(true)
      {
        if(IsCanceled())
          return expression;

        if(tokens.CurrentType == T.TID_EOF || 
          (parenthethiesCount == 0 && curliesCount == 0 && squerliesCount == 0 && 
          (tokens.CurrentType == T.TID_SEMICOLON || 
          tokens.CurrentType == T.TID_COMMA || 
          tokens.CurrentType == T.TID_CLOSECURLY)))
          break;

        if(tokens.CurrentType == T.TID_CLOSEPAREN && parenthethiesCount == 0)
          break;

        if(tokens.CurrentType == T.TID_OPENPAREN)
        {
          parenthethiesCount++;
        }

        if(tokens.CurrentType == T.TID_CLOSEPAREN)
          parenthethiesCount--;
        
        if(tokens.CurrentType == T.TID_OPENCURLY)
          curliesCount++;

        if(tokens.CurrentType == T.TID_CLOSECURLY)
          curliesCount--;

        if(tokens.CurrentType == T.TID_OPENSQUARE)
          squerliesCount++;

        if(tokens.CurrentType == T.TID_CLOSESQUARE)
          squerliesCount--;

        if(tokens.CurrentType == T.TID_QUESTION)
          isQuestionOpCount++;

        if(tokens.CurrentType == T.TID_COLON)
          if(isQuestionOpCount != 0)
            isQuestionOpCount--;
          else
            break;

        tokens.Next();
      }

      if(tokens.Current.Position - startSourcePosition > 0)
        expression.Text = sourceCode.Substring(startSourcePosition,tokens.Current.Position - startSourcePosition);
      return expression;
    }

    public CodeStatement ParseStatement()
    {
      //Start parsing statements
      switch(tokens.CurrentType)
      {
        case T.TID_SEMICOLON:
        {
          CodeStatement statement = new CodeEmptyStatement();
          RecordPosition(statement);
          Eat(T.TID_SEMICOLON);
          return statement;
        }
        case T.TID_BREAK:
        {
          CodeStatement statement = new CodeBreakStatement();
          RecordPosition(statement);

          Eat(T.TID_BREAK);
          if(tokens.CurrentType == T.TID_SEMICOLON)
            Eat(T.TID_SEMICOLON);

          return statement;
        }

        case T.TID_CONTINUE:
        {
          CodeStatement statement = new CodeContinueStatement();
          RecordPosition(statement);

          Eat(T.TID_CONTINUE);
          if(tokens.CurrentType == T.TID_SEMICOLON)
            Eat(T.TID_SEMICOLON);

          return statement;
        }

        case T.TID_GOTO:
        {
          return ParseGotoStatement();
        }
        case T.TID_RETURN:
        {
          return ParseReturnStatement();
        }
        
        case T.TID_THROW:
        {
          return ParseThrowStatement();
        }

        case T.TID_LOCK:
        {
          return ParseLockStatement();
        }

        case T.TID_USING:
        {
          return ParseUsingStatement();
        }

        case T.TID_FIXED:
        {
          return ParseFixedStatement();
        }

        case T.TID_TRY:
        {
          return ParseTryStatement();
        }

        case T.TID_IF:
        {
          return ParseIfStatement();
        }

        case T.TID_SWITCH:
        {
          return ParseSwitchStatement();
        }
        
        case T.TID_WHILE:
        {
          return ParseWhileStatement();
        }

        case T.TID_DO:
        {
          return ParseDoStatement();
        }

        case T.TID_FOR:
        {
          return ParseForStatement();
        }

        case T.TID_FOREACH:
        {
          return ParseForEachStatement();
        }

        case T.TID_CHECKED:
        {
          //It is nested checked block
          Eat(T.TID_CHECKED);
          CodeStatementBlock nestedBlock = ParseStatementBlock(null);
          nestedBlock.Modifiers = CodeStatementBlock.BlockDeclarationModifiers.Checked;
          return nestedBlock;
        }
        case T.TID_UNCHECKED:
        {
          //It is nested checked block
          Eat(T.TID_UNCHECKED);
          CodeStatementBlock nestedBlock = ParseStatementBlock(null);
          nestedBlock.Modifiers = CodeStatementBlock.BlockDeclarationModifiers.Unchecked;
          return nestedBlock;
        }
        case T.TID_UNSAFE:
        {
          //It is nested checked block
          Eat(T.TID_UNSAFE);
          CodeStatementBlock nestedBlock = ParseStatementBlock(null);
          nestedBlock.Modifiers = CodeStatementBlock.BlockDeclarationModifiers.Unsafe;
          return nestedBlock;
        }
        case T.TID_OPENCURLY:
        {
          return ParseStatementBlock(null);
        }

        default:
        {
          //Label
          if(tokens.CurrentType == T.TID_IDENTIFIER && tokens.Peek(1).TokenType == T.TID_COLON)
          {
            CodeLabelStatement labelStatement = new CodeLabelStatement();
            RecordPosition(labelStatement);
            labelStatement.Label = tokens.Current.Name;
            Eat(T.TID_IDENTIFIER);
            Eat(T.TID_COLON);
            return labelStatement;
          }

          if(tokens.CurrentType == T.TID_CONST || tokens.CurrentType == T.TID_IDENTIFIER || tokens.Current.IsPredefinedType())
          {
            //Looks like type declaration
            //let's verify
            int mark = tokens.Mark();

            if(tokens.CurrentType == T.TID_CONST)
              Eat(T.TID_CONST);

            string typeName = ParseTypeName();
            if(tokens.CurrentType == T.TID_IDENTIFIER) //It is a type declaration <type> identifier!
            {
              tokens.Rewind(mark);
              return ParseVariableDeclarationStatement();
            }
            tokens.Rewind(mark);
          }

          //If we found ourselves here it can mean only one thing: We are about to parse an expression!
          return ParseExpressionStatement();
        }
      }
    }
    private CodeVariableDeclarationStatement ParseVariableDeclarationStatement()
    {
      CodeVariableDeclarationStatement declarationStatement = new CodeVariableDeclarationStatement();
      RecordPosition(declarationStatement);
      if(tokens.CurrentType == T.TID_CONST)
      {
        declarationStatement.IsConst = true;
        Eat(T.TID_CONST);
      }

      declarationStatement.DeclarationType = new CodeTypeReference();
      RecordPosition(declarationStatement.DeclarationType);
      declarationStatement.DeclarationType.TypeName = ParseTypeName();
      declarationStatement.DeclaredVariables.AddRange(ParseVariableDeclarationList());

      foreach(CodeVariableDeclarationMember variable in declarationStatement.DeclaredVariables)
      {
        methodScopeNameManager.Register(variable.Name,declarationStatement);
      }
      
      if(tokens.CurrentType == T.TID_SEMICOLON)
        Eat(T.TID_SEMICOLON);

      return declarationStatement;
    }

    private CodeStatement ParseExpressionStatement()
    {
      CodeExpressionStatement expressionStatement = new CodeExpressionStatement();
      RecordPosition(expressionStatement);

      expressionStatement.Expression = ParseExpression();
      if(tokens.CurrentType == T.TID_SEMICOLON)
        Eat(T.TID_SEMICOLON);

      return expressionStatement;
    }
    
    private CodeStatement ParseDoStatement()
    {
      CodeDoStatement doStatement = new CodeDoStatement();
      RecordPosition(doStatement);
      Eat(T.TID_DO);
      doStatement.Statement = (CodeEmbeddedStatement) ParseStatement();
      Eat(T.TID_WHILE);
      Eat(T.TID_OPENPAREN);
      doStatement.Condition = ParseExpression();
      Eat(T.TID_CLOSEPAREN);
      Eat(T.TID_SEMICOLON);
      return doStatement;
    }
    private CodeStatement ParseWhileStatement()
    {
      CodeWhileStatement whileStatement = new CodeWhileStatement();
      RecordPosition(whileStatement);
      Eat(T.TID_WHILE);
      Eat(T.TID_OPENPAREN);
      whileStatement.Condition = ParseExpression();
      Eat(T.TID_CLOSEPAREN);
      whileStatement.Statement = (CodeEmbeddedStatement) ParseStatement();
      if(tokens.CurrentType == T.TID_SEMICOLON)
        Eat(T.TID_SEMICOLON);
      return whileStatement;
    }
    private CodeStatement ParseForStatement()
    {
      CodeForStatement forStatement = new CodeForStatement();
      RecordPosition(forStatement);
      Eat(T.TID_FOR);
      Eat(T.TID_OPENPAREN);
      
      if(tokens.CurrentType != T.TID_SEMICOLON) //If not an empty initializer
      {
        //Parse initializers
        while(true)
        {
          if(IsCanceled())
            break;

          forStatement.Initializers.Add(ParseStatement());
          //ParseStatement() has eatten our semicolon if it was there but it had left
          //colon if it was there.
          if(tokens.CurrentType == T.TID_COMMA)
          {
            Eat(T.TID_COMMA);
            continue;
          }
          else
          {
            break;
          }
        }
      }
      else
      {
        Eat(T.TID_SEMICOLON);
      }
      
      if(tokens.CurrentType != T.TID_SEMICOLON)
        forStatement.Condition = ParseExpression();

      Eat(T.TID_SEMICOLON);

      
      if(tokens.CurrentType != T.TID_CLOSEPAREN) //If not an empty iterators list
      {
        //Parse iterators
        while(true)
        {
          if(IsCanceled())
            return forStatement;

          forStatement.Iterators.Add(ParseStatement());
          
          //ParseStatement() has eatten our semicolon if it was there but it had left
          //colon if it was there.
          if(tokens.CurrentType == T.TID_COMMA)
          {
            Eat(T.TID_COMMA);
            continue;
          }
          else
          {
            break;
          }
        }
      }

      Eat(T.TID_CLOSEPAREN);
      forStatement.Statement = (CodeEmbeddedStatement) ParseStatement();

      if(tokens.CurrentType == T.TID_SEMICOLON)
        Eat(T.TID_SEMICOLON);

      return forStatement;
    }
    private CodeStatement ParseForEachStatement()
    {
      CodeForEachStatement foreachStatement = new CodeForEachStatement();
      RecordPosition(foreachStatement);
      
      Eat(T.TID_FOREACH);
      Eat(T.TID_OPENPAREN);
      foreachStatement.Type = new CodeTypeReference();
      RecordPosition(foreachStatement.Type);
      foreachStatement.Type.TypeName = ParseTypeName();
      foreachStatement.IteratorName = ParseDottedName();
      Eat(T.TID_IN);
      foreachStatement.IteratedCollection =  ParseExpression();
      Eat(T.TID_CLOSEPAREN);
      foreachStatement.Statement = (CodeEmbeddedStatement) ParseStatement();

      if(tokens.CurrentType == T.TID_SEMICOLON)
        Eat(T.TID_SEMICOLON);

      return foreachStatement;
    }
    /// <summary>
    /// This function parses a statment block
    /// </summary>
    /// <param name="parent">parent block</param>
    /// <returns></returns>
    private CodeStatementBlock ParseStatementBlock(CodeStatementBlock parent)
    {
      CodeStatementBlock block = new CodeStatementBlock();
      RecordPosition(block);

      if(tokens.CurrentType == T.TID_SEMICOLON)
      {
        Eat(T.TID_SEMICOLON);
        return null; //no implementation
      }

      Eat(T.TID_OPENCURLY);

      int blockMark = methodScopeNameManager.Mark();

      while(tokens.CurrentType != T.TID_CLOSECURLY && tokens.CurrentType != T.TID_EOF)
      {
        int lastTokenPosition = tokens.Mark();
        block.Statements.Add(ParseStatement());
        //If we are not moving - we stuck in the endless cycle.
        //try to recover.
        if(lastTokenPosition == tokens.Mark())
        {
          RecoverBySkippingToSemicolon();
        }
      }

      //Skip closing curly
      if(tokens.CurrentType == T.TID_CLOSECURLY)
        Eat(T.TID_CLOSECURLY);

      //If block ends with semicolon - eat it too.
      if(tokens.CurrentType == T.TID_SEMICOLON)
        Eat(T.TID_SEMICOLON);

      methodScopeNameManager.Rewind(blockMark);
      return block;
    }

    private CodeStatement ParseIfStatement()
    {
      CodeIfStatement ifStatement = new CodeIfStatement();
      RecordPosition(ifStatement);

      Eat(T.TID_IF);
      Eat(T.TID_OPENPAREN);
      ifStatement.Condition = ParseExpression();
      Eat(T.TID_CLOSEPAREN);
      ifStatement.TrueStatement = (CodeEmbeddedStatement) ParseStatement();
      if(tokens.CurrentType == T.TID_ELSE)
      {
        Eat(T.TID_ELSE);
        ifStatement.FalseStatement = (CodeEmbeddedStatement) ParseStatement();
      }
      return ifStatement;
    }
    private CodeStatement ParseSwitchStatement()
    {
      CodeSwitchStatement switchStatement = new CodeSwitchStatement();
      RecordPosition(switchStatement);
      Eat(T.TID_SWITCH);
      Eat(T.TID_OPENPAREN);
      switchStatement.SwitchExpression = ParseExpression();
      Eat(T.TID_CLOSEPAREN);
      Eat(T.TID_OPENCURLY);
      
      while(tokens.CurrentType != T.TID_EOF && 
        (tokens.CurrentType == T.TID_CASE || tokens.CurrentType == T.TID_DEFAULT))
      {
        CodeStatementCollection statementsCollection;
        if(tokens.CurrentType == T.TID_CASE)
        {
          Eat(T.TID_CASE);
          CodeSwitchCase switchCase = new CodeSwitchCase();
          switchCase.Expression = ParseExpression();
          Eat(T.TID_COLON);
          switchStatement.Cases.Add(switchCase);
          statementsCollection = switchCase.Statements;
        }
        else
        {
          switchStatement.DefaultCaseStatements = new CodeStatementCollection(); 
          statementsCollection = switchStatement.DefaultCaseStatements;
          Eat(T.TID_DEFAULT);
          Eat(T.TID_COLON);
        }

        while(tokens.CurrentType != T.TID_EOF && 
          (tokens.CurrentType != T.TID_CASE && 
          tokens.CurrentType != T.TID_DEFAULT && 
          tokens.CurrentType != T.TID_CLOSECURLY))
        {
          statementsCollection.Add(ParseStatement());
        }
      }

      Eat(T.TID_CLOSECURLY);
      if(tokens.CurrentType == T.TID_SEMICOLON)
        Eat(T.TID_SEMICOLON);
      
      return switchStatement;
    }

    private CodeStatement ParseTryStatement()
    {
      CodeTryStatement tryStatement = new CodeTryStatement();
      RecordPosition(tryStatement);
      Eat(T.TID_TRY);
      tryStatement.Statements = ParseStatementBlock(null);
      
      while(tokens.CurrentType == T.TID_CATCH)
      {
        CodeCatchClause catchClause = new CodeCatchClause();
        RecordPosition(catchClause);
        Eat(T.TID_CATCH);
        
        if(tokens.CurrentType == T.TID_OPENPAREN) //Does filter present?
        {
          Eat(T.TID_OPENPAREN);
          catchClause.CatchExceptionType = new CodeTypeReference();
          RecordPosition(catchClause.CatchExceptionType);
          catchClause.CatchExceptionType.TypeName = ParseTypeName();
          if(tokens.CurrentType == T.TID_IDENTIFIER) //Local name is also present
            catchClause.LocalName = ParseDottedName();
          Eat(T.TID_CLOSEPAREN);
        }
        catchClause.Statements = ParseStatementBlock(null);
        tryStatement.CatchClauses.Add(catchClause);
      }

      if(tokens.CurrentType == T.TID_FINALLY)
      {
        CodeFinallyClause finallyClause = new CodeFinallyClause();
        RecordPosition(finallyClause);
        Eat(T.TID_FINALLY);

        finallyClause.Statements = ParseStatementBlock(null);
        tryStatement.FinallyClause = finallyClause;
      }

      return tryStatement;
    }
    private CodeStatement ParseFixedStatement()
    {
      CodeFixedStatement fixedStatement = new CodeFixedStatement();
      RecordPosition(fixedStatement);
      Eat(T.TID_FIXED);
      Eat(T.TID_OPENPAREN);
      fixedStatement.PointerType = new CodeTypeReference();
      RecordPosition(fixedStatement.PointerType);
      fixedStatement.PointerType.TypeName = ParseTypeName();
      fixedStatement.DeclaredPointers.AddRange(ParseVariableDeclarationList());

//      foreach(CodeVariableDeclarationMember variable in fixedStatement.DeclaredPointers)
//      {
//        methodScopeNameManager.Register(variable.Name,declarationStatement);
//      }

      Eat(T.TID_CLOSEPAREN);
      fixedStatement.Statement = (CodeEmbeddedStatement) ParseStatement();
      if(tokens.CurrentType == T.TID_SEMICOLON)
        Eat(T.TID_SEMICOLON);
      return fixedStatement;
    }
    private CodeStatement ParseLockStatement()
    {
      CodeLockStatement lockStatement = new CodeLockStatement();
      RecordPosition(lockStatement);
      Eat(T.TID_LOCK);
      Eat(T.TID_OPENPAREN);
      lockStatement.Expression = ParseExpression();
      Eat(T.TID_CLOSEPAREN);
      CodeStatementBlock lockStatements = new CodeStatementBlock();
      lockStatement.Statement = (CodeEmbeddedStatement) ParseStatement();
      if(tokens.CurrentType == T.TID_SEMICOLON)
        Eat(T.TID_SEMICOLON);

      return lockStatement;
    }
    private CodeStatement ParseUsingStatement()
    {
      CodeUsingStatement usingStatement = new CodeUsingStatement();
      RecordPosition(usingStatement);
      Eat(T.TID_USING);
      Eat(T.TID_OPENPAREN);
      int iScopeMark = methodScopeNameManager.Mark();
      int tokensMark = tokens.Mark();
      
      //resource aquisition may be an expression or variable declaration. Look eahead to figure out what is what!
      //if currnt token is ident. it could be a beginign of type name.
      //if it is try to parse it.
      if(tokens.CurrentType == T.TID_IDENTIFIER)
      {
        ParseTypeName();
      }
      //After we parsed allegied type - see if next token is identifier - if it is 
      //it is vaviable declaration - otherwise - it is an expression.
      //If it was not identifier all along - it is an expression than.
      if(tokens.CurrentType == T.TID_IDENTIFIER)
      {
        tokens.Rewind(tokensMark);
        usingStatement.ResourceAquisition = ParseVariableDeclarationStatement();
      }
      else
      {
        tokens.Rewind(tokensMark);
        CodeExpressionStatement expressionStatement = new CodeExpressionStatement();
        expressionStatement.Expression = ParseExpression();
        usingStatement.ResourceAquisition = expressionStatement;
      }

      Eat(T.TID_CLOSEPAREN);
      CodeStatementBlock usingStatements = new CodeStatementBlock();
      usingStatement.Statement = (CodeEmbeddedStatement) ParseStatement();
      if(tokens.CurrentType == T.TID_SEMICOLON)
        Eat(T.TID_SEMICOLON);

      methodScopeNameManager.Rewind(iScopeMark);
      return usingStatement;
    }
    private CodeStatement ParseThrowStatement()
    {
      CodeThrowStatement throwStatement = new CodeThrowStatement();
      RecordPosition(throwStatement);
      Eat(T.TID_THROW);
      
      if(tokens.CurrentType != T.TID_SEMICOLON)
        throwStatement.ToThrow = ParseExpression();

      Eat(T.TID_SEMICOLON);
      return throwStatement;
    }

    private CodeStatement ParseReturnStatement()
    {
      CodeReturnStatement returnStatement = new CodeReturnStatement();
      RecordPosition(returnStatement);
      Eat(T.TID_RETURN);
      returnStatement.Expression = ParseExpression();
      Eat(T.TID_SEMICOLON);
      return returnStatement;
    }

    private CodeStatement ParseGotoStatement()
    {
      switch(tokens.Peek(1).TokenType)
      {
        case T.TID_IDENTIFIER:
        {
          CodeGotoStatement gotoStatement = new CodeGotoStatement();
          RecordPosition(gotoStatement);
          Eat(T.TID_GOTO);
          gotoStatement.TargetLabel = tokens.Current.Name;
          Eat(T.TID_IDENTIFIER);
          Eat(T.TID_SEMICOLON);
          return gotoStatement;
        }
      
        case T.TID_CASE:
        {
          CodeSwitchGotoStatement gotoStatement = new CodeSwitchGotoStatement();
          RecordPosition(gotoStatement);
          Eat(T.TID_GOTO);
          Eat(T.TID_CASE);

          gotoStatement.TargetExpression = ParseExpression();
          Eat(T.TID_SEMICOLON);
          return gotoStatement;
        }

        case T.TID_DEFAULT:
        {
          CodeSwitchGotoStatement gotoStatement = new CodeSwitchGotoStatement();
          RecordPosition(gotoStatement);
          Eat(T.TID_GOTO);
          Eat(T.TID_DEFAULT);

          gotoStatement.TargetExpression = null;
          Eat(T.TID_SEMICOLON);
          return gotoStatement;
        }
      }
      
      return null;
    }
    /// <summary>
    /// This function parses a set of using declarations i form
    /// using...; 
    /// using...;
    /// etc
    /// </summary>
    /// <param name="codeNamespace"></param>
    private void ParseNamespaceImports(CodeNamespace codeNamespace)
    {
      while(tokens.Current.TokenType == T.TID_USING)
      {
        CodeNamespaceImport import = new CodeNamespaceImport();
        RecordPosition(import);

        string alias = string.Empty;
        string typeName = string.Empty;
        if(!Eat(T.TID_USING))
        {
          tokens.SkipToUntilOneOf(T.TID_USING, T.TID_SEMICOLON,T.TID_OPENSQUARE);
          continue;
        }

        if(tokens.CurrentType == T.TID_IDENTIFIER && tokens.Peek(1).TokenType == T.TID_EQUAL)
        {
          //alias
          alias = ParseDottedName();
          Eat(T.TID_EQUAL);
          typeName = ParseTypeName();
        }
        else
        {
          //namespace
          typeName = ParseDottedName();
        }

        import.Alias = alias;
        import.ImportedName = typeName;
        codeNamespace.Imports.Add(import);

        if(!Eat(T.TID_SEMICOLON))
        {
          tokens.SkipToUntilOneOf(T.TID_USING, T.TID_SEMICOLON,T.TID_OPENSQUARE);
          continue;
        }
      }
    }

    private string ParseDottedName()
    {
      CSharpToken currentToken = tokens.Current;
      if(currentToken.TokenType != T.TID_IDENTIFIER)
      {
        ReportUnexpectedTokenError(T.TID_IDENTIFIER,currentToken.TokenType);
        return string.Empty;
      }

      StringBuilder nameBuilder = new StringBuilder();
      while(true)
      {
        if(IsCanceled())
          return string.Empty;

        if(currentToken.TokenType == T.TID_IDENTIFIER)
        {
          nameBuilder.Append(currentToken.Name);
        }
    
        currentToken = tokens.Next();
        if(currentToken.TokenType == T.TID_DOT)
        {
          nameBuilder.Append('.');
          currentToken = tokens.Next();
        }
        else
        {
          break;
        }
      }

      return nameBuilder.ToString();
    }

    private string ParseTypeName()
    {
      string typeReference = "System.Void";
      CSharpToken currentToken = tokens.Current;
      if(currentToken.TokenType == T.TID_IDENTIFIER || currentToken.IsPredefinedType())
      {
        if(currentToken.TokenType == T.TID_IDENTIFIER)
        {
          typeReference = ParseDottedName();
          //we are at next token
        }
        else
        {
          typeReference = currentToken.GetPredefinedTypeName();
          tokens.Next();
        }

        //Parse array if suitable
        while(true)
        {
          if(IsCanceled())
            return string.Empty;

          if(tokens.CurrentType != T.TID_OPENSQUARE)
            break;

          typeReference+= "[";
          tokens.Next();
          
          int openSquares = 1;
          while(tokens.CurrentType != T.TID_EOF)
          {
            //Arrays can be nested
            //String[pr.PRlengthA[0]]
            //to parse this correcly we need to balance number of square brackets in between.
            typeReference+= tokens.Current.Name;

            if(tokens.CurrentType == T.TID_OPENSQUARE)
              openSquares++;

            if(tokens.CurrentType == T.TID_CLOSESQUARE)
            {
              openSquares--;

              if(openSquares == 0)
              {
                Eat(T.TID_CLOSESQUARE);
                break;
              }
            }

            tokens.Next();
          }
        }

        while(tokens.CurrentType == T.TID_STAR)
        {
          typeReference+= '*';
          //Move to next token
          tokens.Next();
        }
        currentToken = tokens.Current;
      }

      return typeReference;
    }

    public override CompilerErrorCollection Errors
    {
      get
      {
        if(parsingErrors == null)
          parsingErrors = new CompilerErrorCollection();

        return parsingErrors;
      }
    }
    private CodeCompileUnit CompileUnit
    {
      get
      {
        if(compileUnit == null)
          compileUnit = new CodeCompileUnit();

        return compileUnit;
      }
    }

    private void ReportProgress()
    {
      if(tokens != null && currentProgress != tokens.PercentsConsumed)
      {
        currentProgress = tokens.PercentsConsumed;
        OnParsingProgress(currentProgress);
      }
    }

    /// <summary>
    /// Eats current token. 
    /// </summary>
    /// <param name="tokenType"></param>
    /// <returns></returns>
    private bool Eat (CSharpTokenType tokenType)
    {
      if(tokens.Current.TokenType != tokenType)
      {
        ReportUnexpectedTokenError(tokens.Current.TokenType,tokenType);
        return false;
      }
      tokens.Next();
      return true;
    }

    private CodeElementPosition GetCurrentPosition()
    {
      CodeElementPosition position = new CodeElementPosition();
      position.FileName = compileUnit.SourceFileName;
      position.Line = tokens.Current.Line;
      position.Column = tokens.Current.Column;
      position.Position = tokens.Current.Position;
      return position;
    }
    private void RecordPosition(CodeElement element)
    {
      element.SourcePosition.FileName = CompileUnit.SourceFileName;
      element.SourcePosition.Line = tokens.Current.Line;
      element.SourcePosition.Column = tokens.Current.Column;
      element.SourcePosition.Position = tokens.Current.Position;
    }

    private string GetCSErrorMessage(string errorCode)
    {
      if(compilerErrorsResourceManager == null)
        lock(typeof(CSharpParser))
        {
          if(compilerErrorsResourceManager == null)
            compilerErrorsResourceManager = AssemblyResourceManager.GetInstance("CSharpParser.CompilerErrors");
        }

      string fetchedString  = compilerErrorsResourceManager.GetString(errorCode);
      
      //Check that fetchedString is not null
      Debug.Assert(fetchedString != null,string.Format("String resource '{0} was not found",errorCode));
      
      if(fetchedString == null)
        fetchedString = errorCode;

      return fetchedString;
    }
    
    private void ReportUnexpectedTokenError(CSharpTokenType expectedTokenType, CSharpTokenType foundTokenType)
    {
      string errorCode = String.Empty;
      string[] errorArguments = null;
      switch(expectedTokenType)
      {
        case T.TID_IDENTIFIER:
        {
          errorCode = "CS1001";
          break;
        }

        case T.TID_SEMICOLON:
        {
          errorCode = "CS1002";
          break;
        }

        default:
        {
          errorCode = "AM1001";
          errorArguments = new string[] {expectedTokenType.ToString(),foundTokenType.ToString()};
          break;
        }
      }
  
      ReportError(errorCode,(tokens.CurrentType == T.TID_EOF ? tokens.Current : tokens.Peek(1)),tokens.Current,errorArguments);
    }

    private CompilerError ReportError(string errorNumber,CSharpToken currentToken,CSharpToken peekedToken,params string[] arguments)
    {
      if(arguments == null)
        arguments = new string[0];
      
      int line = -1;
      int column = -1;
      if(currentToken != null && peekedToken != null)
      {
        line = peekedToken.Line;
        column = peekedToken.Column;
      }
      else
      {
        if(currentToken != null)
        {
          line = currentToken.Line;
          column = currentToken.Column;
        }
      }
      
      CompilerError error = new CompilerError(CompileUnit.SourceFileName,line,column,errorNumber,String.Format(GetCSErrorMessage(errorNumber),arguments));
      Errors.Add(error);
      OnParsingError(error);
      return error;
    }

    private void AddMemberToCodeType(CodeTypeDeclaration codeType,CodeTypeMemberDeclaration member)
    {
      if(codeType is CodeClassDeclaration)
        ((CodeClassDeclaration) codeType).Members.Add(member);

      if(codeType is CodeInterfaceDeclaration)
        ((CodeInterfaceDeclaration) codeType).Members.Add(member);

      if(codeType is CodeStructDeclaration)
        ((CodeStructDeclaration) codeType).Members.Add(member);
    }


    private void RecoverBySkippingToSemicolon()
    {
      while(tokens.CurrentType != T.TID_SEMICOLON && tokens.CurrentType != T.TID_EOF)
        tokens.Next();
      Eat(T.TID_SEMICOLON);
    }
    private void RecoverBySkippingCurlies(bool lookForOpenCurly)
    {
      if(lookForOpenCurly)
        while(tokens.CurrentType != T.TID_OPENCURLY && tokens.CurrentType != T.TID_EOF)
          tokens.Next();

      if(tokens.CurrentType == T.TID_OPENCURLY)
        Eat(T.TID_OPENCURLY);

      //if not end of file look for closing curly
      int curlies = 1; //we found open.
      if(tokens.CurrentType != T.TID_EOF)
        while(curlies != 0 && tokens.CurrentType != T.TID_EOF)
        {
          if(tokens.CurrentType == T.TID_OPENCURLY)
            curlies++;

          if(tokens.CurrentType == T.TID_CLOSECURLY)
            curlies--;

          tokens.Next();
        }

      if(tokens.CurrentType == T.TID_CLOSECURLY)
        Eat(T.TID_CLOSECURLY);
    }

    private object ParseDecimalNumber(string numberString)
    {
      bool isHex = numberString.IndexOf("0X") != -1;
      bool isLong = numberString.IndexOf("L") != -1;
      bool isUnsigned = numberString.IndexOf("U") != -1;
      bool isNegative = numberString.Length > 0 && numberString[0] == '-';
      int  negativeFactor = isNegative ? -1:1;

      //Strip all the suffixes and prefixes
      if(numberString.IndexOf("0X") != -1)
        numberString = numberString.Remove(numberString.IndexOf("0X"),2);

      numberString = numberString.Trim('U','L');

      //Two special cases
      if(numberString == "-2147483648")
        return (int)(-2147483648);

      if(numberString == "-9223372036854775808")
        return (long)(-9223372036854775808);

      if(numberString.Length > 0 && (numberString[0] == '-' || numberString[0]=='+'))
        numberString = numberString.Substring(1);

      //Fair game now - try to parse. 
      //Punch MS employee how did not provide parsing functiosn that do not throw an exception.
      //Per spec try to parse the number and fit it in smallest possible type
      System.Globalization.NumberStyles numberStyle = System.Globalization.NumberStyles.Number;
      if(isHex)
        numberStyle = System.Globalization.NumberStyles.HexNumber;

      //Int
      if(!isLong && !isUnsigned)
      {
        try
        {
          return negativeFactor*int.Parse(numberString,numberStyle);
        }
        catch
        {
        }
      }

      //UInt
      if(!isLong)
      {
        try
        {
          return negativeFactor*uint.Parse(numberString,numberStyle);
        }
        catch
        {
        }
      }

      //Long
      if(!isUnsigned)
      {
        try
        {
          return negativeFactor*long.Parse(numberString,numberStyle);
        }
        catch
        {
        }
      }

      //Ulong
      try
      {
        return ulong.Parse(numberString,numberStyle);
      }
      catch
      {
      }

      //If we find ourselves here - we could not parse number
      //check out why, can be just an error in source code
      Debug.Assert(false,"Cannot parse number: " + numberString);
      return numberString;
    }

    private object ParseRealNumber(string numberString)
    {
      bool ifFloat = numberString.IndexOf("F") != -1;
      bool isDouble = numberString.IndexOf("D") != -1;
      bool isDecimal = numberString.IndexOf("M") != -1;

      numberString = numberString.Trim('F','D','M');

      //Fair game now - try to parse. 
      //Punch MS employee how did not provide parsing functiosn that do not throw an exception.
      //Per spec try to parse the number and fit it in smallest possible type

      System.Globalization.NumberStyles numberStyle = System.Globalization.NumberStyles.AllowLeadingSign |
        System.Globalization.NumberStyles.AllowDecimalPoint |
        System.Globalization.NumberStyles.AllowExponent;
      
      //float
      if(!isDouble && !isDecimal)
      {
        try
        {
          return float.Parse(numberString,numberStyle);
        }
        catch
        {
        }
      }


      //double
      if(!isDecimal)
      {
        try
        {
          return double.Parse(numberString,numberStyle);
        }
        catch
        {
        }
      }

      //Decimal
      try
      {
        return decimal.Parse(numberString,numberStyle);
      }
      catch
      {
      }


      //If we find ourselves here - we could not parse number
      //check out why, can be just an error in source code
      Debug.Assert(false,"Cannot parse number: " + numberString);
      return numberString;
    }

    private object ParseNumber(string numberString)
    {
      numberString = numberString.Trim();
      numberString = numberString.ToUpper();
      
      //Check for hexidecimals first
      if(numberString.IndexOf("0X") != -1)
        return ParseDecimalNumber(numberString);

      if(numberString.IndexOf(".") == -1 && numberString.IndexOfAny("FDM".ToCharArray()) == -1)
      {
        //Decimal number
        return ParseDecimalNumber(numberString);
      }
      else
      {
        //Real number
        return ParseRealNumber(numberString);
      }
    }

    private CSharpTokenStream tokens = null;
    private byte currentProgress = 0;
    private static AssemblyResourceManager compilerErrorsResourceManager = null;
    //Current compile unit & errors collection
    private CompilerErrorCollection parsingErrors = null;
    private CodeCompileUnit compileUnit = null;
    private string sourceCode;
    private ScopedNameManagers methodScopeNameManager = new ScopedNameManagers();
    private ManualResetEvent cancelEvent;

  }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.