/// <summary> /// Test if the given token represents opening bracket of a byte array, i.e. "]". /// </summary> /// <param name="token">Token to perform the test on.</param> /// <returns>True, if the test succeeds, otherwise false.</returns> public static bool IsOpeningByteArrayBracket(Token token) { SpecialCharacterToken sctoken = token as SpecialCharacterToken; if (sctoken == null) return false; return (sctoken.Value == '['); }
/// <summary> /// Test for block argument prefix, defined in "3.4.4 Blocks". /// This is the colon in block argument. /// </summary> /// <param name="token">Token to perform the test on.</param> /// <returns>True, if the test succeeds, otherwise false.</returns> public static bool IsBlockArgumentPrefix(Token token) { SpecialCharacterToken sctoken = token as SpecialCharacterToken; if (sctoken == null) return false; return (sctoken.Value == SemanticConstants.BlockArgumentPrefix); }
/// <summary> /// Test if the token is opening delimiter for Primitive API call statement. /// This is IronSmalltalk extension to the grammer. /// </summary> /// <param name="token">Token to perform the test on.</param> /// <returns>True, if the test succeeds, otherwise false.</returns> public static bool IsApiOpeningDelimiter(Token token) { BinarySelectorToken apitoken = token as BinarySelectorToken; if (apitoken == null) return false; return (apitoken.Value == SemanticConstants.PrimitiveOpeningDelimiter); }
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); }
private string GetTokenValue(Token token) { Type t = token.GetType(); PropertyInfo[] infos = t.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public); Dictionary<string, string> map = new Dictionary<string, string>(); foreach (PropertyInfo info in infos) { if (!(new string[] { "StartPosition", "StopPosition", "IsValid", "ScanError", "SourceString" }).Contains(info.Name)) { object value = info.GetValue(token, null); map[info.Name] = String.Format("{0}", value); } } if ((map.Count == 1) && map.ContainsKey("Value")) return map["Value"]; StringBuilder sb = new StringBuilder(); foreach (var pair in map) { if (sb.Length != 0) sb.Append(", "); sb.AppendFormat("{0}: {1}", pair.Key, pair.Value); } return sb.ToString(); }
protected virtual ParseTemporariesResult ParseTemporaries(FunctionNode function, Token token) { // PARSE: <temporaries> ::= '|' <temporary variable list> '|' ParseTemporariesResult result = new ParseTemporariesResult(); if (!(token is VerticalBarToken)) { this.ResidueToken = token; return result; } result.LeftBar = (VerticalBarToken)token; while (true) { token = this.GetNextTokenxx(Preference.VerticalBar); if (token is VerticalBarToken) { // Done with temp variables. result.RightBar = (VerticalBarToken)token; return result; } if (token is IdentifierToken) { result.Temporaries.Add(new TemporaryVariableNode(function, (IdentifierToken)token)); } else { this.ReportParserError(function, SemanticErrors.MissingClosingTempBar, token); this.ResidueToken = token; return result; } } }
protected virtual BasicExpressionNode ParseBasicExpression(SemanticNode parent, Token token) { // PARSE: <basic expression> ::= <primary> [<messages> <cascaded messages>] BasicExpressionNode result = new BasicExpressionNode(parent); IPrimaryNode primary = this.ParsePrimary(result, token); if (primary == null) { this.ReportParserError(result, SemanticErrors.MissingPrimary, token); return result; } token = this.GetNextTokenxx(Preference.Default); this.ParseBaseicExpressionMessages(result, primary, token); return result; }
/// <summary> /// Test if the given token represents opening parenthesis, i.e. "(". /// </summary> /// <param name="token">Token to perform the test on.</param> /// <returns>True, if the test succeeds, otherwise false.</returns> public static bool IsOpeningParenthesis(Token token) { SpecialCharacterToken sctoken = token as SpecialCharacterToken; if (sctoken == null) return false; return (sctoken.Value == SemanticConstants.OpeningParenthesis); }
/// <summary> /// Test if the token is reference to the reserved identifier "self". /// </summary> /// <param name="token">Token to perform the test on.</param> /// <returns>True, if the test succeeds, otherwise false.</returns> public static bool IsIdentifierTrue(Token token) { IdentifierToken idtoken = token as IdentifierToken; if (idtoken == null) return false; return (idtoken.Value == SemanticConstants.True); }
protected virtual MessageSequenceNode ParseMessages(IMessageSequenceParentNode parent, Token token, MessageType type) { // <messages> ::= // (<unary message>+ <binary message>* [<keyword message>] ) | // (<binary message>+ [<keyword message>] ) | // <keyword message> // <unary message> ::= unarySelector // <binary message> ::= binarySelector <binary argument> // <binary argument> ::= <primary> <unary message>* // <keyword message> ::= (keyword <keyword argument> )+ // <keyword argument> ::= <primary> <unary message>* <binary message>* if ((token is IdentifierToken) && ((type & MessageType.Unary) != 0)) // (<unary message>+ <binary message>* [<keyword message>] ) return this.ParseUnaryBinaryKeywordMessageSequence(parent, (IdentifierToken)token); if ((token is BinarySelectorToken) && ((type & MessageType.Binary) != 0)) // (<binary message>+ [<keyword message>] ) return this.ParseBinaryKeywordMessageSequence(parent, (BinarySelectorToken)token); if ((token is KeywordToken) && ((type & MessageType.Keyword) != 0)) // <keyword message> return this.ParseKeywordMessageSequence(parent, (KeywordToken)token); this.ResidueToken = token; // Not for us ... let others give it a try. return null; }
/// <summary> /// Parses a message sequence as defined in X3J20 "3.4.5.3 Messages". /// </summary> /// <param name="parent"></param> /// <param name="token">First token of the message node. If the token is message token, it is returned in the residueToken parameter.</param> /// <returns>Message sequence node or null if the given token is not a message token.</returns> /// <remarks> /// This mehtod does not registers errors if the given token is not a message token. /// The 'offending' token is returned in the residueToken parameter, and it is /// responsibility of the called to determine what to do. /// </remarks> protected virtual MessageSequenceNode ParseMessages(IMessageSequenceParentNode parent, Token token) { return this.ParseMessages(parent, token, MessageType.All); }
/// <summary> /// Parse a literal node as described in X3J20 "3.4.6 Literals". /// </summary> /// <remarks> /// If the given token is not a legal token for a literal node, /// it is simply returned in the residueToken output parameter, /// and the function returns null. /// </remarks> /// <param name="parent">Parent node that defines the literal node.</param> /// <param name="token">First token of the literal node.</param> /// <returns>A literal node, or null in case of non-literal token.</returns> protected virtual LiteralNode ParseLiteral(ILiteralNodeParent parent, Token token) { // PARSE: <literal> ::= <number literal> | <string literal> | <character literal> | // <symbol literal> | <selector literal> | <array literal> // <string literal> ::= quotedString if (token is StringToken) // 'example' return new StringLiteralNode(parent, (StringToken)token); // <symbol literal> ::= hashedString if (token is HashedStringToken) // #'example' return new SymbolLiteralNode(parent, (HashedStringToken)token); // <character literal> ::= quotedCharacter if (token is CharacterToken) // $e return new CharacterLiteralNode(parent, (CharacterToken)token); // <selector literal> ::= quotedSelector if (token is QuotedSelectorToken) // #example ..or.. #example: ..or.. #example:example: ..or.. #+ return new SelectorLiteralNode(parent, (QuotedSelectorToken)token); // <number literal> ::= ['-'] <number> if (token is NegativeSignToken) return this.ParseNegativeNumericLiteralNode(parent, (NegativeSignToken)token); // <number> ::= integer | float | scaledDecimal if (token is SmallIntegerToken) return new SmallIntegerLiteralNode(parent, (SmallIntegerToken)token, null); if (token is LargeIntegerToken) return new LargeIntegerLiteralNode(parent, (LargeIntegerToken)token, null); if (token is FloatEToken) return new FloatELiteralNode(parent, (FloatEToken)token, null); if (token is FloatDToken) return new FloatDLiteralNode(parent, (FloatDToken)token, null); if (token is ScaledDecimalToken) return new ScaledDecimalLiteralNode(parent, (ScaledDecimalToken)token, null); // <array literal> ::= '#(' <array element>* ')' // <array element> ::= <literal> | identifier if (Parser.IsLiteralArrayPrefix(token)) return this.ParseArrayLiteral(parent, (SpecialCharacterToken)token); this.ResidueToken = token; return null; }
protected virtual KeywordArgumentNode ParseKeywordArgument(KeywordMessageNode parent, Token token) { // PARSE: <keyword argument> ::= <primary> <unary message>* <binary message>* KeywordArgumentNode result = new KeywordArgumentNode(parent); IPrimaryNode primary = this.ParsePrimary(result, token); if (primary == null) { this.ReportParserError(result, SemanticErrors.MissingPrimary, token); return result; } token = this.GetNextTokenxx(Preference.Default); BinaryOrBinaryUnaryMessageSequenceNode messages = null; if (token is IdentifierToken) // <unary message>* messages = this.ParseUnaryBinaryMessageSequence(result, (IdentifierToken)token); else if (token is BinarySelectorToken) messages = this.ParseBinaryMessageSequence(result, (BinarySelectorToken)token); else this.ResidueToken = token; result.SetContents(primary, messages); return result; }
// <expression> ::= // <assignment> | // <basic expression> // <assignment> ::= <assignment target> assignmentOperator <expression> // <basic expression> ::= <primary> [<messages> <cascaded messages>] // <assignment target> := identifier // <primary> ::= // identifier | // <literal> | // <block constructor> | // ( '(' <expression> ')' ) protected virtual ExpressionNode ParseExpression(SemanticNode parent, Token token) { // Tricky ... first try for <assignment> if (token is IdentifierToken) { // In here, we either have an <assignment target> or <primary> of a <basic expression> IdentifierToken identifier = (IdentifierToken)token; // Try to check for assignmentOperator token = this.GetNextTokenxx(Preference.Default); if (token is AssignmentOperatorToken) // OK, it's <assignment> return this.ParseAssignment(parent, identifier, (AssignmentOperatorToken)token); // Must recover ... it is a <basic expression> anyway. // PARSE: identifier [<messages> <cascaded messages>] BasicExpressionNode result = new BasicExpressionNode(parent); this.ParseBaseicExpressionMessages(result, new VariableReferenceleNode(result, identifier), token); return result; }; return this.ParseBasicExpression(parent, token); }
protected virtual CascadeMessageSequenceNode ParseCascadeMessageSequenceNode(ICascadeMessageSequenceParentNode parent, Token semicolon) { // PARSE: <cascaded messages> ::= (';' <messages>)* if (!Parser.IsCascadeDelimiter(semicolon)) { this.ResidueToken = semicolon; return null; // Not a cascade message ... return null. } CascadeMessageSequenceNode result = new CascadeMessageSequenceNode(parent, (SpecialCharacterToken)semicolon); Token token = this.GetNextTokenxx(Preference.Default); MessageSequenceNode messages = this.ParseMessages(result, token); if (messages == null) { this.ReportParserError(result, SemanticErrors.MissingMessagePattern, token); return result; } token = this.GetNextTokenxx(Preference.Default); CascadeMessageSequenceNode nextCascade = null; if (Parser.IsCascadeDelimiter(token)) nextCascade = this.ParseCascadeMessageSequenceNode(result, (SpecialCharacterToken)token); else this.ResidueToken = token; result.SetContents(messages, nextCascade); return result; }
protected virtual Token GetNextTokenxx(Preference preference) { Token token; if (this.ResidueToken != null) { token = this.ResidueToken; this.ResidueToken = null; return token; } do { token = this.Scanner.GetToken(preference); //if ((parent.Comments != null) && (token is CommentToken)) // parent.Comments.Add((CommentToken)token); } while (token is WhitespaceToken); return token; }
protected virtual MethodArgumentNode ParseMethodArgument(MethodNode parent, Token token) { // PARSE: identifier ... NB: X3J20 bug - definition missing ... but this one is easy. if (!(token is IdentifierToken)) { this.ReportParserError(parent, SemanticErrors.MissingMethodArgument, token); this.ResidueToken = token; // NB: MethodArgumentNode must be able to handle null for arg. name token. return new MethodArgumentNode(parent, null); } return new MethodArgumentNode(parent, (IdentifierToken)token); }
/// <summary> /// Test if the given token represents a literal array prefix hash mark, i.e. "#". /// </summary> /// <param name="token">Token to perform the test on.</param> /// <returns>True, if the test succeeds, otherwise false.</returns> public static bool IsLiteralArrayPrefix(Token token) { SpecialCharacterToken sctoken = token as SpecialCharacterToken; if (sctoken == null) return false; return (sctoken.Value == SemanticConstants.LiteralArrayPrefix); }
protected virtual IPrimaryNode ParsePrimary(IPrimaryParentNode parent, Token token) { // PARSE: <primary> ::= identifier | <literal> | <block constructor> | ( '(' <expression> ')' ) if (token is IdentifierToken) return new VariableReferenceleNode(parent, (IdentifierToken)token); else if (Parser.IsBlockStartDelimiter(token)) return this.ParseBlock(parent, (SpecialCharacterToken)token); else if (Parser.IsOpeningParenthesis(token)) return this.ParseParenthesizedExpression(parent, (SpecialCharacterToken)token); else return this.ParseLiteral(parent, token); }
protected virtual StatementNode ParseStatement(IStatementParentNode parent, Token token) { // PARSE: <statements> ::= // (<return statement> ['.'] ) | // (<expression> ['.' [<statements>]]) if ((token is EofToken) || Parser.IsBlockEndDelimiter(token)) { this.ResidueToken = token; return null; } if (token is ReturnOperatorToken) return this.ParseReturnStatement(parent, (ReturnOperatorToken)token); else return this.ParseStatementSequence(parent, token); }
protected virtual StatementSequenceNode ParseStatementSequence(IStatementParentNode parent, Token token) { // PARSE: (<expression> ['.' [<statements>]]) StatementSequenceNode result = new StatementSequenceNode(parent); ExpressionNode expression = this.ParseExpression(result, token); if (expression == null) this.ReportParserError(result, SemanticErrors.MissingExpression, token); SpecialCharacterToken period = null; token = this.GetNextTokenxx(Preference.Default); if (Parser.IsStatementDelimiter(token)) { period = (SpecialCharacterToken)token; } else { result.SetContents(expression, null, null); this.ResidueToken = token; return result; } // ['.' [<statements>]]) token = this.GetNextTokenxx(Preference.NegativeSign); if (token is EofToken) { result.SetContents(expression, period, null); this.ResidueToken = token; return result; } if (Parser.IsBlockEndDelimiter(token)) { result.SetContents(expression, period, null); this.ResidueToken = token; return result; } else if (Parser.IsStatementDelimiter(token)) { this.ReportParserError(result, SemanticErrors.MissingStatement, token); result.SetContents(expression, period, null); this.ResidueToken = token; return result; } StatementNode nextStatement = this.ParseStatement(result, token); result.SetContents(expression, period, nextStatement); return result; }
/// <summary> /// Test for block end bracket, defined in "3.4.4 Blocks". /// This is the closing square bracket "]" used for defining blocks. /// </summary> /// <param name="token">Token to perform the test on.</param> /// <returns>True, if the test succeeds, otherwise false.</returns> public static bool IsBlockEndDelimiter(Token token) { SpecialCharacterToken sctoken = token as SpecialCharacterToken; if (sctoken == null) return false; return (sctoken.Value == SemanticConstants.BlockEndDelimiter); }
protected virtual void ParseBaseicExpressionMessages(BasicExpressionNode expression, IPrimaryNode primary, Token token) { MessageSequenceNode messages = this.ParseMessages(expression, token); if (messages == null) { expression.SetContents(primary, null, null); return; } token = this.GetNextTokenxx(Preference.Default); CascadeMessageSequenceNode cascadeMessages = this.ParseCascadeMessageSequenceNode(expression, token); expression.SetContents(primary, messages, cascadeMessages); }