public unsafe void Preprocess(string path, TextReader reader, TextWriter writer) { const int tokenBufferSize = 32 * 1024; char *tokenBuffer = stackalloc char [tokenBufferSize]; var tokenizer = new Tokenizer (reader, tokenBuffer, tokenBufferSize) { Path = path }; var parser = new Parser (tokenizer); var astVisitor = new XamarinPreprocessorVisitor (this); var csharpWriter = new CSharpWriter (writer); var enumState = EnumState.None; while (true) { // we may have tokens consumed by the expression parser that // failed to actually parse, so dequeue them until they've // been blitted - they will not be parsed again; otherwise // read a token from the reader var token = parser.ConsumedTokens.Count > 0 ? parser.ConsumedTokens.Dequeue () : tokenizer.Scan (); switch (token.Type) { case TokenType.Eof: return; case TokenType.None: break; case TokenType.StringLiteral: case TokenType.VerbatimStringLiteral: case TokenType.InterpolatedStringLiteral: case TokenType.CharLiteral: case TokenType.WhiteSpace: case TokenType.SingleLineComment: case TokenType.MultiLineComment: writer.Write (token.Value); break; case TokenType.UnknownChar: writer.Write (token.UnknownChar); break; case TokenType.RawLiteral: string replacementToken = null; switch (enumState) { case EnumState.None: if (token.Value == "enum") enumState = EnumState.Keyword; break; case EnumState.Keyword: enumState = EnumState.Name; break; case EnumState.Colon: case EnumState.LeftCurlyBracket: Profile.EnumBackingTypeReplacements.Evaluate (token.Value, out replacementToken); break; } if (replacementToken == null) Profile.GlobalReplacements.Evaluate (token.Value, out replacementToken); writer.Write (replacementToken ?? token.Value); break; case TokenType.LeftSquareBracket: writer.Write ("["); if (parser.ConsumedTokens.Count > 0) break; try { var exprList = parser.ParseExpressionList ( TokenType.Comma, TokenType.RightSquareBracket); if (exprList != null) { exprList.AcceptVisitor (astVisitor); exprList.AcceptVisitor (csharpWriter); } parser.ConsumedTokens.Clear (); writer.Write ("]"); } catch (Parser.SyntaxException) { // we will unwind the parsed tokens starting on the // next scan to blit them verbatim in the case that // we cannot parse them into a valid expression } break; default: if (enumState == EnumState.Name && token.Type == TokenType.Colon) enumState = EnumState.Colon; else if ((enumState == EnumState.Colon || enumState == EnumState.Keyword) && token.Type == TokenType.LeftCurlyBracket) enumState = EnumState.LeftCurlyBracket; else if (enumState == EnumState.LeftCurlyBracket && token.Type == TokenType.RightCurlyBracket) enumState = EnumState.None; writer.Write (token.Type.AsWritten ()); break; } } }
public unsafe void Preprocess(string path, TextReader reader, TextWriter writer) { const int tokenBufferSize = 32 * 1024; char * tokenBuffer = stackalloc char [tokenBufferSize]; var tokenizer = new Tokenizer(reader, tokenBuffer, tokenBufferSize) { Path = path }; var parser = new Parser(tokenizer); var astVisitor = new XamarinPreprocessorVisitor(this); var csharpWriter = new CSharpWriter(writer); var enumState = EnumState.None; while (true) { // we may have tokens consumed by the expression parser that // failed to actually parse, so dequeue them until they've // been blitted - they will not be parsed again; otherwise // read a token from the reader var token = parser.ConsumedTokens.Count > 0 ? parser.ConsumedTokens.Dequeue() : tokenizer.Scan(); switch (token.Type) { case TokenType.Eof: return; case TokenType.None: break; case TokenType.StringLiteral: case TokenType.VerbatimStringLiteral: case TokenType.InterpolatedStringLiteral: case TokenType.CharLiteral: case TokenType.WhiteSpace: case TokenType.SingleLineComment: case TokenType.MultiLineComment: writer.Write(token.Value); break; case TokenType.UnknownChar: writer.Write(token.UnknownChar); break; case TokenType.RawLiteral: string replacementToken = null; switch (enumState) { case EnumState.None: if (token.Value == "enum") { enumState = EnumState.Keyword; } break; case EnumState.Keyword: enumState = EnumState.Name; break; case EnumState.Colon: case EnumState.LeftCurlyBracket: Profile.EnumBackingTypeReplacements.Evaluate(token.Value, out replacementToken); break; } if (replacementToken == null) { Profile.GlobalReplacements.Evaluate(token.Value, out replacementToken); } writer.Write(replacementToken ?? token.Value); break; case TokenType.LeftSquareBracket: writer.Write("["); if (parser.ConsumedTokens.Count > 0) { break; } try { var exprList = parser.ParseExpressionList( TokenType.Comma, TokenType.RightSquareBracket); if (exprList != null) { exprList.AcceptVisitor(astVisitor); exprList.AcceptVisitor(csharpWriter); } parser.ConsumedTokens.Clear(); writer.Write("]"); } catch (Parser.SyntaxException) { // we will unwind the parsed tokens starting on the // next scan to blit them verbatim in the case that // we cannot parse them into a valid expression } break; default: if (enumState == EnumState.Name && token.Type == TokenType.Colon) { enumState = EnumState.Colon; } else if ((enumState == EnumState.Colon || enumState == EnumState.Keyword) && token.Type == TokenType.LeftCurlyBracket) { enumState = EnumState.LeftCurlyBracket; } else if (enumState == EnumState.LeftCurlyBracket && token.Type == TokenType.RightCurlyBracket) { enumState = EnumState.None; } writer.Write(token.Type.AsWritten()); break; } } }