private void VisitBaseEventDeclaration(EventDeclaration node, EventDeclarations declarations) { if (!this.TokenStream.Done && this.TokenStream.Peek().Type == TokenType.Colon) { this.TokenStream.Index++; this.TokenStream.SkipWhiteSpaceAndCommentTokens(); if (this.TokenStream.Done || this.TokenStream.Peek().Type != TokenType.Identifier) { throw new ParsingException("Expected event identifier.", this.TokenStream.Peek(), TokenType.Identifier); } // We only use referencingNode to verify the name exists and the generic type matches. var referencingNode = new EventDeclaration(this.TokenStream.Program, null, ModifierSet.CreateDefault()) { Identifier = NameVisitor.VisitSimpleQualifiedName(this.TokenStream, TokenType.EventIdentifier) }; if (!declarations.Find(referencingNode.Identifier.Text, out var baseEventDecl)) { throw new ParsingException($"Could not find definition or extern declaration of base event {referencingNode.Identifier.Text}.", this.TokenStream.Peek()); } if (!this.TokenStream.Done) { this.VisitGenericType(referencingNode); if (referencingNode.GenericType.Count != baseEventDecl.GenericType.Count) { throw new ParsingException($"Mismatch in number of generic type arguments for base event {referencingNode.Identifier.Text}.", this.TokenStream.Peek()); } } node.BaseClassDecl = baseEventDecl; } }
private EventDeclaration VisitEventDeclaration(NamespaceDeclaration namespaceNode, MachineDeclaration machineNode, ModifierSet modSet, bool isExtern) { // Lookup or Insert into (immediately) containing namespace or machine declaration. var declarations = (machineNode != null) ? machineNode.EventDeclarations : namespaceNode.EventDeclarations; var node = new EventDeclaration(base.TokenStream.Program, machineNode, modSet) { EventKeyword = base.TokenStream.Peek() }; base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); if (base.TokenStream.Done || (base.TokenStream.Peek().Type != TokenType.Identifier && base.TokenStream.Peek().Type != TokenType.HaltEvent && base.TokenStream.Peek().Type != TokenType.DefaultEvent)) { throw new ParsingException("Expected event identifier.", new List <TokenType> { TokenType.Identifier, TokenType.HaltEvent, TokenType.DefaultEvent }); } node.Identifier = NameVisitor.VisitSimpleQualifiedName(base.TokenStream, TokenType.EventIdentifier); if (declarations.Find(node.Identifier.Text, out var existingDecl)) { var details = existingDecl.IsExtern ? "declared \"extern\"" : "defined"; throw new ParsingException($"Event {node.Identifier.Text} has already been {details} earlier in this file.", new List <TokenType> { }); } if (base.TokenStream.Done || (base.TokenStream.Peek().Type != TokenType.Assert && base.TokenStream.Peek().Type != TokenType.Assume && base.TokenStream.Peek().Type != TokenType.LeftAngleBracket && base.TokenStream.Peek().Type != TokenType.LeftParenthesis && base.TokenStream.Peek().Type != TokenType.Colon && base.TokenStream.Peek().Type != TokenType.Semicolon)) { // TODO: Create an overload of ParsingException ctor that generates the message with a predefined format enum. var expectedTokenTypes = new List <TokenType> { TokenType.Assert, TokenType.Assume, TokenType.LeftAngleBracket, TokenType.LeftParenthesis, TokenType.Semicolon, TokenType.Colon }; var itemsString = string.Join("\", \"", expectedTokenTypes.Select(l => TokenTypeRegistry.GetText(l)).ToArray()); throw new ParsingException($"Expected one of: \"{itemsString}\".", expectedTokenTypes); } VisitGenericType(node); VisitBaseEventDeclaration(node, declarations); if (base.TokenStream.Done || (base.TokenStream.Peek().Type != TokenType.Assert && base.TokenStream.Peek().Type != TokenType.Assume && base.TokenStream.Peek().Type != TokenType.LeftParenthesis && base.TokenStream.Peek().Type != TokenType.Semicolon)) { throw new ParsingException("Expected \"(\" or \";\".", new List <TokenType> { TokenType.Assert, TokenType.Assume, TokenType.LeftParenthesis, TokenType.Semicolon }); } if (base.TokenStream.Peek().Type == TokenType.Assert || base.TokenStream.Peek().Type == TokenType.Assume) { if (isExtern) { throw new ParsingException("\"extern\" cannot have an Assert or Assume specification.", new List <TokenType> { }); } bool isAssert = true; if (base.TokenStream.Peek().Type == TokenType.Assert) { node.AssertKeyword = base.TokenStream.Peek(); } else { node.AssumeKeyword = base.TokenStream.Peek(); isAssert = false; } base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); if (base.TokenStream.Done || base.TokenStream.Peek().Type != TokenType.Identifier || !int.TryParse(base.TokenStream.Peek().TextUnit.Text, out int value)) { throw new ParsingException("Expected integer.", new List <TokenType> { TokenType.Identifier }); } if (isAssert) { node.AssertValue = value; } else { node.AssumeValue = value; } base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); if (base.TokenStream.Done || (base.TokenStream.Peek().Type != TokenType.LeftParenthesis && base.TokenStream.Peek().Type != TokenType.Semicolon)) { throw new ParsingException("Expected \"(\" or \";\".", new List <TokenType> { TokenType.LeftParenthesis, TokenType.Semicolon }); } } if (base.TokenStream.Peek().Type == TokenType.LeftParenthesis) { node.LeftParenthesis = base.TokenStream.Peek(); base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); bool isType = false; while (!base.TokenStream.Done && base.TokenStream.Peek().Type != TokenType.RightParenthesis) { if (isType && base.TokenStream.Peek().Type != TokenType.Colon && base.TokenStream.Peek().Type != TokenType.Comma) { TextUnit textUnit = null; new TypeIdentifierVisitor(base.TokenStream).Visit(ref textUnit); var typeIdentifier = new Token(textUnit, TokenType.TypeIdentifier); node.PayloadTypes.Add(typeIdentifier); } else if (base.TokenStream.Peek().Type != TokenType.Colon && base.TokenStream.Peek().Type != TokenType.Comma) { node.PayloadIdentifiers.Add(base.TokenStream.Peek()); isType = true; base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); } if (!base.TokenStream.Done) { if (base.TokenStream.Peek().Type == TokenType.Comma) { isType = false; base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); } else if (base.TokenStream.Peek().Type == TokenType.Colon) { base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); } } } if (node.PayloadIdentifiers.Count != node.PayloadTypes.Count) { throw new ParsingException("The payload type of event '" + node.Identifier.TextUnit.Text + "' was not declared correctly.\n" + " You must declare both a type and a name identifier, for example:\n\n" + " event e (a:int, b:bool)\n", new List <TokenType> { TokenType.RightParenthesis }); } if (base.TokenStream.Done || base.TokenStream.Peek().Type != TokenType.RightParenthesis) { throw new ParsingException("Expected \")\".", new List <TokenType> { TokenType.RightParenthesis }); } node.RightParenthesis = base.TokenStream.Peek(); base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); } if (base.TokenStream.Done || base.TokenStream.Peek().Type != TokenType.Semicolon) { throw new ParsingException("Expected \";\".", new List <TokenType> { TokenType.Semicolon }); } node.SemicolonToken = base.TokenStream.Peek(); declarations.Add(node, isExtern); return(node); }