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; } }
internal static Token VisitSimpleQualifiedName(TokenStream tokenStream, TokenType replacementType) { var eventIdentifiers = new NameVisitor(tokenStream).ConsumeQualifiedName(replacementType); var identifierBuilder = new StringBuilder(); foreach (var token in eventIdentifiers) { identifierBuilder.Append(token.TextUnit.Text); } TextUnit textUnit = new TextUnit(identifierBuilder.ToString(), eventIdentifiers[0].TextUnit.Line); return(new Token(textUnit, replacementType)); }
/// <summary> /// Visits the syntax node. /// </summary> /// <param name="parentNode">Node</param> internal void Visit(StateDeclaration parentNode) { if (parentNode.Machine.IsMonitor) { throw new ParsingException("Monitors cannot \"defer\".", new List<TokenType>()); } base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); var nameVisitor = new NameVisitor(base.TokenStream); // Consumes multiple generic event names. var eventIdentifiers = nameVisitor.ConsumeMultipleNames(TokenType.EventIdentifier, tt => nameVisitor.ConsumeGenericEventName(tt)); var resolvedEventIdentifiers = new Dictionary<Token, List<Token>>(); foreach (var eventIdentifier in eventIdentifiers) { if (eventIdentifier.Count == 1) { // We don't want to collapse halt and default // events to event identifiers. resolvedEventIdentifiers.Add(eventIdentifier[0], eventIdentifier); } else { var identifierBuilder = new StringBuilder(); foreach (var token in eventIdentifier) { identifierBuilder.Append(token.TextUnit.Text); } TextUnit textUnit = new TextUnit(identifierBuilder.ToString(), eventIdentifier[0].TextUnit.Line); resolvedEventIdentifiers.Add(new Token(textUnit, TokenType.EventIdentifier), eventIdentifier); } } foreach (var kvp in resolvedEventIdentifiers) { if (!parentNode.AddDeferredEvent(kvp.Key, kvp.Value)) { throw new ParsingException("Unexpected defer declaration.", new List<TokenType>()); } } if (!base.TokenStream.Done && base.TokenStream.Peek().Type == TokenType.Identifier) { throw new ParsingException("Expected \",\".", new List<TokenType> { TokenType.Comma }); } if (!base.TokenStream.Done && (base.TokenStream.Peek().Type == TokenType.LeftAngleBracket || base.TokenStream.Peek().Type == TokenType.RightAngleBracket)) { throw new ParsingException("Invalid generic expression.", new List<TokenType> { }); } if (base.TokenStream.Done || base.TokenStream.Peek().Type != TokenType.Semicolon) { throw new ParsingException("Expected \";\".", new List<TokenType> { TokenType.Semicolon }); } }
/// <summary> /// Visits the syntax node. /// </summary> /// <param name="parentNode">Node</param> internal void Visit(StateDeclaration parentNode) { if (parentNode.Machine.IsMonitor) { throw new ParsingException("Monitors cannot \"defer\".", new List <TokenType>()); } base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); var nameVisitor = new NameVisitor(base.TokenStream); // Consumes multiple generic event names. var eventIdentifiers = nameVisitor.ConsumeMultipleNames(TokenType.EventIdentifier, tt => nameVisitor.ConsumeGenericEventName(tt)); var resolvedEventIdentifiers = new Dictionary <Token, List <Token> >(); foreach (var eventIdentifier in eventIdentifiers) { if (eventIdentifier.Count == 1) { // We don't want to collapse halt and default // events to event identifiers. resolvedEventIdentifiers.Add(eventIdentifier[0], eventIdentifier); } else { var identifierBuilder = new StringBuilder(); foreach (var token in eventIdentifier) { identifierBuilder.Append(token.TextUnit.Text); } TextUnit textUnit = new TextUnit(identifierBuilder.ToString(), eventIdentifier[0].TextUnit.Line); resolvedEventIdentifiers.Add(new Token(textUnit, TokenType.EventIdentifier), eventIdentifier); } } foreach (var kvp in resolvedEventIdentifiers) { if (!parentNode.AddDeferredEvent(kvp.Key, kvp.Value)) { throw new ParsingException("Unexpected defer declaration.", new List <TokenType>()); } } if (!base.TokenStream.Done && base.TokenStream.Peek().Type == TokenType.Identifier) { throw new ParsingException("Expected \",\".", new List <TokenType> { TokenType.Comma }); } if (!base.TokenStream.Done && (base.TokenStream.Peek().Type == TokenType.LeftAngleBracket || base.TokenStream.Peek().Type == TokenType.RightAngleBracket)) { throw new ParsingException("Invalid generic expression.", new List <TokenType> { }); } if (base.TokenStream.Done || base.TokenStream.Peek().Type != TokenType.Semicolon) { throw new ParsingException("Expected \";\".", new List <TokenType> { TokenType.Semicolon }); } }
/// <summary> /// Visits the syntax node. /// </summary> /// <param name="parentNode">Node</param> internal void Visit(StateDeclaration parentNode) { base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); if (base.TokenStream.Done || (base.TokenStream.Peek().Type != TokenType.Identifier && base.TokenStream.Peek().Type != TokenType.MulOp && 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 }); } var nameVisitor = new NameVisitor(base.TokenStream); // Consumes multiple generic event names. var eventIdentifiers = nameVisitor.ConsumeMultipleNames(TokenType.EventIdentifier, tt => nameVisitor.ConsumeGenericEventName(tt)); if (!base.TokenStream.Done && base.TokenStream.Peek().Type == TokenType.Identifier) { throw new ParsingException("Expected \",\".", new List <TokenType> { TokenType.Comma }); } if (!base.TokenStream.Done && (base.TokenStream.Peek().Type == TokenType.LeftAngleBracket || base.TokenStream.Peek().Type == TokenType.RightAngleBracket)) { throw new ParsingException("Invalid generic expression.", new List <TokenType> { }); } if (base.TokenStream.Done || (base.TokenStream.Peek().Type != TokenType.DoAction && base.TokenStream.Peek().Type != TokenType.GotoState && base.TokenStream.Peek().Type != TokenType.PushState)) { throw new ParsingException("Expected \"do\", \"goto\" or \"push\".", new List <TokenType> { TokenType.DoAction, TokenType.GotoState, TokenType.PushState }); } var resolvedEventIdentifiers = new Dictionary <Token, List <Token> >(); foreach (var eventIdentifier in eventIdentifiers) { if (eventIdentifier.Count == 1) { // We don't want to collapse halt and default // events to event identifiers. resolvedEventIdentifiers.Add(eventIdentifier[0], eventIdentifier); } else { var identifierBuilder = new StringBuilder(); foreach (var token in eventIdentifier) { identifierBuilder.Append(token.TextUnit.Text); } TextUnit textUnit = new TextUnit(identifierBuilder.ToString(), eventIdentifier[0].TextUnit.Line); resolvedEventIdentifiers.Add(new Token(textUnit, TokenType.EventIdentifier), eventIdentifier); } } if (base.TokenStream.Peek().Type == TokenType.DoAction) { base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); bool isAsync = false; if (base.TokenStream.Peek().Type == TokenType.Async) { isAsync = true; base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); } if (base.TokenStream.Peek().Type == TokenType.Await) { throw new ParsingException("'await' should not be used on actions.", new List <TokenType>()); } if (base.TokenStream.Done || (base.TokenStream.Peek().Type != TokenType.Identifier && base.TokenStream.Peek().Type != TokenType.LeftCurlyBracket)) { var message = isAsync ? "Expected action identifier or opening curly bracket." : "Expected async keyword, action identifier, or opening curly bracket."; var list = new List <TokenType> { TokenType.Identifier, TokenType.LeftCurlyBracket }; if (!isAsync) { list.Insert(0, TokenType.Async); } throw new ParsingException(message, list); } if (base.TokenStream.Peek().Type == TokenType.LeftCurlyBracket) { var blockNode = new BlockSyntax(base.TokenStream.Program, parentNode.Machine, null); new BlockSyntaxVisitor(base.TokenStream).Visit(blockNode); foreach (var kvp in resolvedEventIdentifiers) { if (!parentNode.AddActionBinding(kvp.Key, kvp.Value, new AnonymousActionHandler(blockNode, isAsync))) { throw new ParsingException("Unexpected action handler.", new List <TokenType>()); } } } else { if (isAsync) { throw new ParsingException("'async' should only be used on anonymous actions.", new List <TokenType>()); } base.TokenStream.Swap(new Token(base.TokenStream.Peek().TextUnit, TokenType.ActionIdentifier)); var actionIdentifier = base.TokenStream.Peek(); foreach (var kvp in resolvedEventIdentifiers) { if (!parentNode.AddActionBinding(kvp.Key, kvp.Value, actionIdentifier)) { throw new ParsingException("Unexpected action handler.", new List <TokenType>()); } } 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 }); } } } else if (base.TokenStream.Peek().Type == TokenType.GotoState) { var stateIdentifiers = this.ConsumeState(); if (base.TokenStream.Done || (base.TokenStream.Peek().Type != TokenType.WithExit && base.TokenStream.Peek().Type != TokenType.Semicolon)) { throw new ParsingException("Expected \";\".", new List <TokenType> { TokenType.Semicolon }); } if (base.TokenStream.Peek().Type == TokenType.WithExit) { base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); bool isAsync = false; if (base.TokenStream.Peek().Type == TokenType.Async) { isAsync = true; base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); } if (base.TokenStream.Done || base.TokenStream.Peek().Type != TokenType.LeftCurlyBracket) { throw new ParsingException("Expected \"{\".", new List <TokenType> { TokenType.LeftCurlyBracket }); } var blockNode = new BlockSyntax(base.TokenStream.Program, parentNode.Machine, null); new BlockSyntaxVisitor(base.TokenStream).Visit(blockNode); foreach (var kvp in resolvedEventIdentifiers) { if (!parentNode.AddGotoStateTransition(kvp.Key, kvp.Value, stateIdentifiers, new AnonymousActionHandler(blockNode, isAsync))) { throw new ParsingException("Unexpected goto state transition.", new List <TokenType>()); } } } else { foreach (var kvp in resolvedEventIdentifiers) { if (!parentNode.AddGotoStateTransition(kvp.Key, kvp.Value, stateIdentifiers)) { throw new ParsingException("Unexpected goto state transition.", new List <TokenType>()); } } } } else if (base.TokenStream.Peek().Type == TokenType.PushState) { if (parentNode.Machine.IsMonitor) { throw new ParsingException("Monitors cannot \"push\".", new List <TokenType>()); } var stateIdentifiers = this.ConsumeState(); if (base.TokenStream.Done || base.TokenStream.Peek().Type != TokenType.Semicolon) { throw new ParsingException("Expected \";\".", new List <TokenType> { TokenType.Semicolon }); } foreach (var kvp in resolvedEventIdentifiers) { if (!parentNode.AddPushStateTransition(kvp.Key, kvp.Value, stateIdentifiers)) { throw new ParsingException("Unexpected push state transition.", new List <TokenType>()); } } } }
/// <summary> /// Visits the syntax node. /// </summary> internal void Visit(NamespaceDeclaration parentNode, bool isMonitor, ModifierSet modSet, TokenRange tokenRange) { if (isMonitor) { this.CheckMonitorModifierSet(modSet); } else { this.CheckMachineModifierSet(modSet); } var node = new MachineDeclaration(this.TokenStream.Program, parentNode, isMonitor, modSet); node.MachineKeyword = this.TokenStream.Peek(); this.TokenStream.Index++; this.TokenStream.SkipWhiteSpaceAndCommentTokens(); if (this.TokenStream.Done || this.TokenStream.Peek().Type != TokenType.Identifier) { throw new ParsingException("Expected machine identifier.", this.TokenStream.Peek(), TokenType.Identifier); } this.TokenStream.Swap(TokenType.MachineIdentifier); node.Identifier = this.TokenStream.Peek(); node.HeaderTokenRange = tokenRange.FinishAndClone(); this.TokenStream.Index++; this.TokenStream.SkipWhiteSpaceAndCommentTokens(); var nameVisitor = new NameVisitor(this.TokenStream); node.TemplateParameters = nameVisitor.ConsumeTemplateParams(); if (this.TokenStream.Program is PSharpProgram) { if (this.TokenStream.Done || (this.TokenStream.Peek().Type != TokenType.Colon && this.TokenStream.Peek().Type != TokenType.LeftCurlyBracket)) { throw new ParsingException("Expected \":\" or \"{\".", this.TokenStream.Peek(), TokenType.Colon, TokenType.LeftCurlyBracket); } if (this.TokenStream.Peek().Type == TokenType.Colon) { node.ColonToken = this.TokenStream.Peek(); this.TokenStream.Index++; this.TokenStream.SkipWhiteSpaceAndCommentTokens(); var baseNameTokensVisitor = new NameVisitor(this.TokenStream, node.HeaderTokenRange); node.BaseNameTokens = baseNameTokensVisitor.ConsumeGenericName(TokenType.MachineIdentifier); } } if (this.TokenStream.Done || this.TokenStream.Peek().Type != TokenType.LeftCurlyBracket) { throw new ParsingException("Expected \"{\".", this.TokenStream.Peek(), TokenType.LeftCurlyBracket); } this.TokenStream.Swap(TokenType.MachineLeftCurlyBracket); node.LeftCurlyBracketToken = this.TokenStream.Peek(); this.TokenStream.Index++; this.TokenStream.SkipWhiteSpaceAndCommentTokens(); this.VisitNextPSharpIntraMachineDeclaration(node); parentNode.MachineDeclarations.Add(node); var stateDeclarations = node.GetAllStateDeclarations(); if (stateDeclarations.Count == 0 && node.BaseNameTokens.Count == 0) { throw new ParsingException("A machine must declare at least one state.", this.TokenStream.Peek()); } var startStates = stateDeclarations.FindAll(s => s.IsStart); if (startStates.Count == 0 && node.BaseNameTokens.Count == 0) { throw new ParsingException("A machine must declare a start state.", this.TokenStream.Peek()); } else if (startStates.Count > 1) { throw new ParsingException("A machine can declare only a single start state.", this.TokenStream.Peek()); } }
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); }
/// <summary> /// Visits the syntax node. /// </summary> /// <param name="parentNode">Node</param> internal void Visit(StateDeclaration parentNode) { 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 }); } var nameVisitor = new NameVisitor(base.TokenStream); // Consumes multiple generic event names. var eventIdentifiers = nameVisitor.ConsumeMultipleNames(TokenType.EventIdentifier, tt => nameVisitor.ConsumeGenericEventName(tt)); if (!base.TokenStream.Done && base.TokenStream.Peek().Type == TokenType.Identifier) { throw new ParsingException("Expected \",\".", new List<TokenType> { TokenType.Comma }); } if (!base.TokenStream.Done && (base.TokenStream.Peek().Type == TokenType.LeftAngleBracket || base.TokenStream.Peek().Type == TokenType.RightAngleBracket)) { throw new ParsingException("Invalid generic expression.", new List<TokenType> { }); } if (base.TokenStream.Done || (base.TokenStream.Peek().Type != TokenType.DoAction && base.TokenStream.Peek().Type != TokenType.GotoState && base.TokenStream.Peek().Type != TokenType.PushState)) { throw new ParsingException("Expected \"do\", \"goto\" or \"push\".", new List<TokenType> { TokenType.DoAction, TokenType.GotoState, TokenType.PushState }); } var resolvedEventIdentifiers = new Dictionary<Token, List<Token>>(); foreach (var eventIdentifier in eventIdentifiers) { if (eventIdentifier.Count == 1) { // We don't want to collapse halt and default // events to event identifiers. resolvedEventIdentifiers.Add(eventIdentifier[0], eventIdentifier); } else { var identifierBuilder = new StringBuilder(); foreach (var token in eventIdentifier) { identifierBuilder.Append(token.TextUnit.Text); } TextUnit textUnit = new TextUnit(identifierBuilder.ToString(), eventIdentifier[0].TextUnit.Line); resolvedEventIdentifiers.Add(new Token(textUnit, TokenType.EventIdentifier), eventIdentifier); } } if (base.TokenStream.Peek().Type == TokenType.DoAction) { base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); if (base.TokenStream.Done || (base.TokenStream.Peek().Type != TokenType.Identifier && base.TokenStream.Peek().Type != TokenType.LeftCurlyBracket)) { throw new ParsingException("Expected action identifier.", new List<TokenType> { TokenType.Identifier }); } if (base.TokenStream.Peek().Type == TokenType.LeftCurlyBracket) { var blockNode = new BlockSyntax(base.TokenStream.Program, parentNode.Machine, null); new BlockSyntaxVisitor(base.TokenStream).Visit(blockNode); foreach (var kvp in resolvedEventIdentifiers) { if (!parentNode.AddActionBinding(kvp.Key, kvp.Value, blockNode)) { throw new ParsingException("Unexpected action handler.", new List<TokenType>()); } } } else { base.TokenStream.Swap(new Token(base.TokenStream.Peek().TextUnit, TokenType.ActionIdentifier)); var actionIdentifier = base.TokenStream.Peek(); foreach (var kvp in resolvedEventIdentifiers) { if (!parentNode.AddActionBinding(kvp.Key, kvp.Value, actionIdentifier)) { throw new ParsingException("Unexpected action handler.", new List<TokenType>()); } } 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 }); } } } else if (base.TokenStream.Peek().Type == TokenType.GotoState) { var stateIdentifiers = this.ConsumeState(); if (base.TokenStream.Done || (base.TokenStream.Peek().Type != TokenType.WithExit && base.TokenStream.Peek().Type != TokenType.Semicolon)) { throw new ParsingException("Expected \";\".", new List<TokenType> { TokenType.Semicolon }); } if (base.TokenStream.Peek().Type == TokenType.WithExit) { base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); if (base.TokenStream.Done || base.TokenStream.Peek().Type != TokenType.LeftCurlyBracket) { throw new ParsingException("Expected \"{\".", new List<TokenType> { TokenType.LeftCurlyBracket }); } var blockNode = new BlockSyntax(base.TokenStream.Program, parentNode.Machine, null); new BlockSyntaxVisitor(base.TokenStream).Visit(blockNode); foreach (var kvp in resolvedEventIdentifiers) { if (!parentNode.AddGotoStateTransition(kvp.Key, kvp.Value, stateIdentifiers, blockNode)) { throw new ParsingException("Unexpected goto state transition.", new List<TokenType>()); } } } else { foreach (var kvp in resolvedEventIdentifiers) { if (!parentNode.AddGotoStateTransition(kvp.Key, kvp.Value, stateIdentifiers)) { throw new ParsingException("Unexpected goto state transition.", new List<TokenType>()); } } } } else if (base.TokenStream.Peek().Type == TokenType.PushState) { if (parentNode.Machine.IsMonitor) { throw new ParsingException("Monitors cannot \"push\".", new List<TokenType>()); } var stateIdentifiers = this.ConsumeState(); if (base.TokenStream.Done || base.TokenStream.Peek().Type != TokenType.Semicolon) { throw new ParsingException("Expected \";\".", new List<TokenType> { TokenType.Semicolon }); } foreach (var kvp in resolvedEventIdentifiers) { if (!parentNode.AddPushStateTransition(kvp.Key, kvp.Value, stateIdentifiers)) { throw new ParsingException("Unexpected push state transition.", new List<TokenType>()); } } } }