public Type Parse(ParserContext context) { // Capture current type token. Token token = context.Stream.Current; // Ensure current token is a type. if (!TokenIdentifier.IsType(token, context)) { throw new Exception($"Expected a type but got '{token.Type}'"); } // Skip and capture the next token. Token nextToken = context.Stream.Next(); // Create the array length (and flag), defaulting to null. uint?arrayLength = null; // Determine if type is an array. if (nextToken.Type == TokenType.SymbolBracketL) { // Skip bracket start token. context.Stream.Skip(); // TODO: Must ensure array length is integer somehow. // TODO: Invoke expression parser to capture array length. // TODO: arrayLength.Value = new ExprParser().Parse(context); // TODO: BEGIN temporary solution. // Ensure current token is an integer. context.Stream.EnsureCurrent(TokenType.LiteralInteger); // Capture the current integer token. Token integerToken = context.Stream.Current; // Assign the token value as the array length. arrayLength = uint.Parse(integerToken.Value); // Skip over the captured integer token. context.Stream.Skip(); // TODO: END temporary solution. // Ensure the current token is a closing bracket. context.Stream.EnsureCurrent(TokenType.SymbolBracketR); // Skip bracket end token. context.Stream.Skip(); } // Update the next token buffer. nextToken = context.Stream.Get(); // Create the pointer flag. bool isPointer = false; // Determine if pointer sequence exists. if (nextToken.Type == TokenType.OperatorMultiplication) { // Raise the pointer flag. isPointer = true; // Skip the pointer token. context.Stream.Skip(); } // Create the type. return(new Type(context.SymbolTable, token, isPointer, arrayLength)); }
public Block Parse(ParserContext context) { // Capture current token. Either block start or arrow for anonymous functions. Token begin = context.Stream.Current; // Skip begin token. context.Stream.Skip(); // Create the block. Block block = new Block(); // Set the block as active in the symbol table. context.SymbolTable.activeBlock = block; // Mark the block as default. if (begin.Type == TokenType.SymbolBlockL) { block.Type = BlockType.Default; } // Mark the block as short. else if (begin.Type == TokenType.SymbolArrow) { block.Type = BlockType.Short; } // Otherwise, the block type could not be identified. else { throw new Exception("Unexpected block type"); } // Begin the iteration. context.Stream.NextUntil(TokenType.SymbolBlockR, (Token token) => { // Returning a value. if (token.Type == TokenType.KeywordReturn) { // Invoke the return parser. It's okay if it returns null, as it will be emitted as void. Expr returnExpr = new FunctionReturnParser().Parse(context); // Assign the return expression to the block. block.ReturnExpr = returnExpr; // Return immediatly, signal to update the token buffer to the current token. return(true); } // Token must be a statement. Expr statement = new StatementParser().Parse(context); // Ensure statement was successfully parsed. if (statement == null) { throw new Exception("Unexpected statement to be null"); } // Append the parsed statement to the block's expression list. block.Expressions.Add(statement); // Ensure current token is a semi-colon, if previous statement did not parse a block. if (statement.ExprType != ExprType.If) { // Ensure semi-colon token. context.Stream.EnsureCurrent(SyntaxAnalysis.TokenType.SymbolSemiColon); // Skip over the semi-colon. context.Stream.Skip(); } // Signal to update the token buffer with the current token. return(true); }); // Skip onto default block end or short block end. context.Stream.Skip(); // Return the resulting block. return(block); }
public FormalArgs Parse(ParserContext context) { // Ensure position. context.Stream.EnsureCurrent(TokenType.SymbolParenthesesL); // Skip parentheses start. context.Stream.Skip(); // Create the formal args entity. FormalArgs args = new FormalArgs(); // Create the loop buffer token. Token buffer = context.Stream.Current; // Loop until parentheses end. while (buffer.Type != TokenType.SymbolParenthesesR) { // Continuous arguments. if (!args.Continuous && buffer.Type == TokenType.SymbolContinuous) { // Set the continuous flag. args.Continuous = true; // Advance stream immediatly. buffer = context.Stream.Next(TokenType.SymbolParenthesesR); // Continue loop. continue; } // Continuous arguments must be final. else if (args.Continuous) { throw new Exception("Unexpected token after continuous arguments"); } // Invoke the arg parser. FormalArg arg = new FormalArgParser().Parse(context); // Update the buffer. buffer = context.Stream.Current; // Ensure next token is valid. if (buffer.Type != TokenType.SymbolComma && buffer.Type != TokenType.SymbolParenthesesR) { throw new Exception($"Unexpected token of type '{buffer.Type}'; Expected comma or parentheses end in argument list"); } // Skip the comma token. else if (buffer.Type == TokenType.SymbolComma) { context.Stream.Skip(); // Make sure to update the buffer after skipping the comma token. buffer = context.Stream.Current; } // Append the parsed argument. args.Values.Add(arg); } // Ensure current token is parentheses end. context.Stream.EnsureCurrent(TokenType.SymbolParenthesesR); // Skip parentheses end token. context.Stream.Skip(); // Finish process. return(args); }