/// <summary> /// Create a new cascade message sequence. /// </summary> /// <param name="parent">Parent node that defines this cascade message node.</param> /// <param name="token">Token representing the semicolon used to delimit cascase message sequences.</param> protected internal CascadeMessageSequenceNode(ICascadeMessageSequenceParentNode parent, SpecialCharacterToken token) { #if DEBUG if (parent == null) throw new ArgumentNullException("parent"); if (token == null) throw new ArgumentNullException("token"); #endif this.Parent = parent; this.Semicolon = token; }
/// <summary> /// Create a new block argument. /// </summary> /// <param name="parent">Block closure that defines the argument node.</param> /// <param name="colon">Colon that preceeds the argument name.</param> /// <param name="token">Identifier token containing the name of the argument.</param> protected internal BlockArgumentNode(BlockNode parent, SpecialCharacterToken colon, IdentifierToken token) : base(token) { #if DEBUG if (parent == null) throw new ArgumentNullException("parent"); if (colon == null) throw new ArgumentNullException("colon"); #endif this.Colon = colon; this.Parent = parent; }
/// <summary> /// Create and initialize a new literal array node. /// </summary> /// <param name="parent">Parent node that defines this literal node.</param> /// <param name="arrayToken">Hash token that defines the start of array literals.</param> /// <param name="leftParenthesis">Opening left parenthesis of the literal array.</param> protected internal ArrayLiteralNode(ILiteralNodeParent parent, SpecialCharacterToken arrayToken, SpecialCharacterToken leftParenthesis) : base(parent) { #if DEBUG if (!Parser.IsLiteralArrayPrefix(arrayToken)) throw new ArgumentException("arrayToken"); if (!Parser.IsOpeningParenthesis(leftParenthesis)) throw new ArgumentException("leftParenthesis"); #endif this.ArrayToken = arrayToken; this.LeftParenthesis = leftParenthesis; this.Elements = new List<LiteralNode>(); }
/// <summary> /// Create and initialize a new literal array node. /// </summary> /// <param name="parent">Parent node that defines this literal node.</param> /// <param name="arrayToken">Hash token that defines the start of array literals.</param> /// <param name="leftParenthesis">Opening left parenthesis of the literal array.</param> protected internal ByteArrayLiteralNode(ILiteralNodeParent parent, SpecialCharacterToken arrayToken, SpecialCharacterToken leftBracket) : base(parent) { #if DEBUG if (!Parser.IsLiteralArrayPrefix(arrayToken)) throw new ArgumentException("arrayToken"); if (!VseCompatibleParser.IsOpeningByteArrayBracket(leftBracket)) throw new ArgumentException("leftBracket"); #endif this.ArrayToken = arrayToken; this.LeftBracket = leftBracket; this.Elements = new List<SmallIntegerLiteralNode>(); }
/// <summary> /// Create a new parenthesized expression node. /// </summary> /// <param name="parent">Parent node that defines this expression.</param> /// <param name="token">Left opening parenthesis of the parenthesized expression.</param> protected internal ParenthesizedExpressionNode(IPrimaryParentNode parent, SpecialCharacterToken token) { #if DEBUG if (parent == null) throw new ArgumentNullException("parent"); if (!Parser.IsOpeningParenthesis(token)) // We do expect the caller to this method to have ensured that we are actually parsing a parethesis. throw new InvalidParserOperationException("Expected opening parenthesis token ... '('"); #endif this.Parent = parent; this.LeftParenthesis = (SpecialCharacterToken)token; }
/// <summary> /// Initializes the node after being parsed by the parser. /// </summary> /// <param name="elements">Collection with literal nodes that compose the elements of the literal array.</param> /// <param name="rightParenthesis">Closing right parenthesis of the literal array.</param> protected internal void SetContents(IEnumerable<LiteralNode> elements, SpecialCharacterToken rightParenthesis) { if (elements == null) throw new ArgumentNullException("elements"); if ((rightParenthesis != null) && !Parser.IsClosingParenthesis(rightParenthesis)) // NB: We allow null value. throw new ArgumentException("rightParenthesis"); this.RightParenthesis = rightParenthesis; foreach (LiteralNode elem in elements) this.Elements.Add(elem); }
/// <summary> /// Initializes the node after being parsed by the parser. /// </summary> /// <param name="arguments">Collection of block arguments for this block.</param> /// <param name="argumentsBar">The vertical bar after the block arguments.</param> /// <param name="leftBar">Left vertical bar "|" token, if temporary variable definition is present.</param> /// <param name="temporaries">A collection of temporary variable nodes.</param> /// <param name="rightBar">Right vertical bar "|" token, if temporary variable definition is present.</param> /// <param name="statements">Executable statements defining the function.</param> /// <param name="rightBracket">Token for the right / closing square bracket of the block.</param> protected internal void SetContents(IEnumerable<BlockArgumentNode> arguments, VerticalBarToken argumentsBar, VerticalBarToken leftBar, IEnumerable<TemporaryVariableNode> temporaries, VerticalBarToken rightBar, StatementNode statements, SpecialCharacterToken rightBracket) { if (arguments == null) throw new ArgumentNullException("arguments"); this.SetContents(leftBar, temporaries, rightBar, statements); this.Arguments.Clear(); this.Arguments.AddRange(arguments); this.ArgumentsBar = argumentsBar; // OK with null if no args. or illegal source this.RightBracket = rightBracket; // OK with null if illegal source }
/// <summary> /// Create and intialize a block node. /// </summary> /// <param name="parent">The parent node to the block node.</param> /// <param name="token">Token for the left / opening square bracket of the block.</param> protected internal BlockNode(IPrimaryParentNode parent, SpecialCharacterToken token) { #if DEBUG if (parent == null) throw new ArgumentNullException("parent"); if (token == null) throw new ArgumentNullException("token"); #endif this.Arguments = new List<BlockArgumentNode>(); this.Parent = parent; this.LeftBracket = token; }
protected virtual BlockNode ParseBlock(IPrimaryParentNode parent, SpecialCharacterToken leftBracket) { // PARSE: <block constructor> ::= '[' <block body> ']' // <block body> ::= [<block argument>* '|'] [<temporaries>] [<statements>] // <block argument> ::= ':' identifier BlockNode result = new BlockNode(parent, leftBracket); // PARSE: [<block argument>* '|'] // ISSUE: It this a bug in X3J20. Shouldn't it be: [<block argument>+ '|'] // The current definition allows blocks like: [ | ] ... or ... [ | self doStuff ] ... or ... [ | | temp | temp := self something ] // We assume X3J20 bug and expect: [<block argument>+ '|'] VerticalBarToken argumentsBar = null; List<BlockArgumentNode> arguments = new List<BlockArgumentNode>(); Token token = this.GetNextTokenxx(Preference.VerticalBar | Preference.NegativeSign); // Check if the block has arguments if (Parser.IsBlockArgumentPrefix(token)) { // ... yes arguments ... parse them ... while (true) { if (Parser.IsBlockArgumentPrefix(token)) { // <block argument> arguments.Add(this.ParseBlockArgument(result, (SpecialCharacterToken)token)); } else if (token is VerticalBarToken) { // The '|' after the arguments. argumentsBar = (VerticalBarToken)token; token = this.GetNextTokenxx(Preference.NegativeSign | Preference.VerticalBar); break; // Done with block arguments } else { this.ReportParserError(result, SemanticErrors.MissingBlockClosingArgsBar, token); break; } // Get the next token token = this.GetNextTokenxx(Preference.VerticalBar | Preference.NegativeSign); } } // PARSE: [<temporaries>] ParseTemporariesResult ptr = this.ParseTemporaries(result, token); // PARSE: <statements> token = this.GetNextTokenxx(Preference.NegativeSign); StatementNode statements = this.ParseStatement(result, token); // Ensure the block is properly closed. SpecialCharacterToken rightBracket = null; token = this.GetNextTokenxx(Preference.Default) ; if (!Parser.IsBlockEndDelimiter(token)) { this.ReportParserError(result, SemanticErrors.MissingBlockClosingBracket, token); this.ResidueToken = token; } else { rightBracket = (SpecialCharacterToken)token; } result.SetContents(arguments, argumentsBar, ptr.LeftBar, ptr.Temporaries, ptr.RightBar, statements, rightBracket); return result; }
protected ByteArrayLiteralNode ParseByteArrayLiteral(ILiteralNodeParent parent, SpecialCharacterToken arrayToken, SpecialCharacterToken leftBracket) { // PARSE: <array literal> ::= '#[' <number literal>* ']' List<SmallIntegerLiteralNode> elements = new List<SmallIntegerLiteralNode>(); ByteArrayLiteralNode result = new ByteArrayLiteralNode(parent, arrayToken, leftBracket); // Process tokens inside the array ... while (true) { // ... get next token in the array ... Token token = this.GetNextTokenxx(Preference.NegativeSign); // Is this closing parenthesis? if (VseCompatibleParser.IsClosingByteArrayBracket(token)) { // Closing parenthesis ... done with the array, return litral array node. result.SetContents(elements, (SpecialCharacterToken)token); this.ResidueToken = null; return result; } if (token is EofToken) { // Unfinished source code ... return result.SetContents(elements, null); this.ReportParserError(parent, "Missing literal byte array closing bracket.", token); this.ResidueToken = token; return result; } // PARSE: <numeric liteal> if (token is SmallIntegerToken) { elements.Add(new SmallIntegerLiteralNode(result, (SmallIntegerToken)token, null)); } else if (token is NegativeSignToken) { NegativeSignToken negativeSign = (NegativeSignToken)token; token = this.GetNextTokenxx(Preference.NegativeSign); if (token is SmallIntegerToken) { elements.Add(new SmallIntegerLiteralNode(result, (SmallIntegerToken)token, negativeSign)); } else { this.ReportParserError(parent, "Unrecognized literal.", token); this.ResidueToken = token; result.SetContents(elements, null); return result; } } else { this.ReportParserError(parent, "Unrecognized literal.", token); this.ResidueToken = token; result.SetContents(elements, null); return result; } } }
protected override LiteralNode ParseLiteral(ILiteralNodeParent parent, Token token) { if ((parent is ArrayLiteralNode) && Parser.IsOpeningParenthesis(token)) { // Stupid VSE allows declarations of arrays like: #( 1 2 ( 3 4 ) 5 6), // which is identical to: #( 1 2 #( 3 4 ) 5 6). // Only the inner (child) arrays may omit the hash prefix. // Here we emulate this and create a 'fake' hash token. // The fake hash token gets the same source positions and the parenthesis token. SpecialCharacterToken hash = new SpecialCharacterToken(SemanticConstants.LiteralArrayPrefix); hash.SetTokenValues(token.StartPosition, token.StopPosition, null); this.ResidueToken = token; return this.ParseArrayLiteral(parent, hash); } if (!Parser.IsLiteralArrayPrefix(token)) return base.ParseLiteral(parent, token); Token token2 = this.GetNextTokenxx(Preference.Default); if (VseCompatibleParser.IsOpeningByteArrayBracket(token2)) return this.ParseByteArrayLiteral(parent, (SpecialCharacterToken) token, (SpecialCharacterToken)token2); this.ResidueToken = token2; return base.ParseLiteral(parent, token); }
/// <summary> /// Initializes the node after being parsed by the parser. /// </summary> /// <param name="elements">Collection with literal nodes that compose the elements of the literal array.</param> /// <param name="rightParenthesis">Closing right parenthesis of the literal array.</param> protected internal void SetContents(IEnumerable<SmallIntegerLiteralNode> elements, SpecialCharacterToken rightBracket) { if (elements == null) throw new ArgumentNullException("elements"); if ((rightBracket != null) && !VseCompatibleParser.IsClosingByteArrayBracket(rightBracket)) // NB: We allow null value. throw new ArgumentException("rightBracket"); this.RightBracket = rightBracket; foreach (SmallIntegerLiteralNode elem in elements) this.Elements.Add(elem); }
protected virtual ParenthesizedExpressionNode ParseParenthesizedExpression(IPrimaryParentNode parent, SpecialCharacterToken leftParenthesis) { // PARSE: '(' <expression> ')' ParenthesizedExpressionNode result = new ParenthesizedExpressionNode(parent, leftParenthesis); Token token = this.GetNextTokenxx(Preference.NegativeSign); ExpressionNode expression = this.ParseExpression(result, token); if (expression == null) { this.ReportParserError(result, SemanticErrors.MissingExpression, token); return result; } // Ensure the parenthese are properly closed. token = this.GetNextTokenxx(Preference.Default); SpecialCharacterToken rightParenthesis = null; if (Parser.IsClosingParenthesis(token)) { rightParenthesis = (SpecialCharacterToken)token; } else { this.ReportParserError(result, SemanticErrors.MissingExpressionClosingParenthesis, token); this.ResidueToken = token; } result.SetContents(expression, rightParenthesis); return result; }
protected virtual BlockArgumentNode ParseBlockArgument(BlockNode parent, SpecialCharacterToken colon) { // PARSE: <block argument> ::= ':' identifier Token token = this.GetNextTokenxx(Preference.Default); if (!(token is IdentifierToken)) { this.ReportParserError(parent, SemanticErrors.MissingBlockArgument, token); this.ResidueToken = token; // NB: BlockArgumentNode must be able to handle null for arg. name token. return new BlockArgumentNode(parent, colon, null); } return new BlockArgumentNode(parent, colon, (IdentifierToken)token); }
/// <summary> /// Initializes the node after being parsed by the parser. /// </summary> /// <param name="expression">Expression that's being enclosed by the parentheses.</param> /// <param name="rightParenthesis">Right closingparenthesis of the parenthesized expression.</param> protected internal void SetContents(ExpressionNode expression, SpecialCharacterToken rightParenthesis) { if (expression == null) throw new ArgumentNullException("expression"); if ((rightParenthesis != null) && !Parser.IsClosingParenthesis(rightParenthesis)) // Must allow for null throw new ArgumentException("rightParenthesis"); this.Expression = expression; this.RightParenthesis = rightParenthesis; }
/// <summary> /// Initializes the node after being parsed by the parser. /// </summary> /// <param name="expression">Expression node defining the statement.</param> /// <param name="period">Optional period that terminates a statement.</param> /// <param name="nextStatement">Optional statement node that follows this statement.</param> protected internal void SetContents(ExpressionNode expression, SpecialCharacterToken period, StatementNode nextStatement) { if (expression == null) throw new ArgumentNullException("expression"); this.Expression = expression; this.Period = period; // Null is OK here. this.NextStatement = nextStatement; // Null is OK here. }
protected virtual ArrayLiteralNode ParseArrayLiteral(ILiteralNodeParent parent, SpecialCharacterToken arrayToken) { // PARSE: <array literal> ::= '#(' <array element>* ')' // <array element> ::= <literal> | identifier Token token = this.GetNextTokenxx(Preference.Default); if (!Parser.IsOpeningParenthesis(token)) { this.ReportParserError(parent, SemanticErrors.MissingLiteralArrayOpeningParenthesis, token); // The hash token is thrown away and lost :-/ ... only the current token is passed on. this.ResidueToken = token; return null; } List<LiteralNode> elements = new List<LiteralNode>(); ArrayLiteralNode result = new ArrayLiteralNode(parent, arrayToken, (SpecialCharacterToken)token); // Process tokens inside the array ... while (true) { // ... get next token in the array ... token = this.GetNextTokenxx(Preference.NegativeSign | Preference.UnquotedSelector); // Is this closing parenthesis? if (Parser.IsClosingParenthesis(token)) { // Closing parenthesis ... done with the array, return litral array node. result.SetContents(elements, (SpecialCharacterToken)token); this.ResidueToken = null; return result; } if (token is EofToken) { // Unfinished source code ... return result.SetContents(elements, null); this.ReportParserError(parent, SemanticErrors.MissingLiteralArrayClosingParenthesis, token); this.ResidueToken = token; return result; } // PARSE: <array element> ::= <literal> | identifier if (token is ILiteralArrayIdentifierToken) { // identifier ... special case only inside arrays. elements.Add(new IdentifierLiteralNode(result, (ILiteralArrayIdentifierToken)token)); } else { // ... it's not identifier, so it must be an literal LiteralNode element = this.ParseLiteral(result, token); if (element == null) { // Report error in souce code ... here, it must be a literal this.ReportParserError(result, SemanticErrors.UnrecognizedLiteral, token); result.SetContents(elements, null); return result; } else { // ... add the child element to the array elements. elements.Add(element); } } } }