/// <summary> /// Constructor. /// </summary> /// <param name="program">Program</param> /// <param name="machineNode">MachineDeclarationNode</param> /// <param name="stateNode">StateDeclarationNode</param> /// <param name="isModel">Is a model</param> internal BlockSyntax(IPSharpProgram program, MachineDeclaration machineNode, StateDeclaration stateNode, bool isModel) : base(program, isModel) { this.Machine = machineNode; this.State = stateNode; }
/// <summary> /// Visits the syntax node. /// </summary> /// <param name="parentNode">Node</param> internal void Visit(StateDeclaration parentNode) { if (parentNode.ExitDeclaration != null) { throw new ParsingException("Duplicate exit declaration.", new List<TokenType>()); } var node = new ExitDeclaration(base.TokenStream.Program, parentNode.IsModel); node.ExitKeyword = base.TokenStream.Peek(); 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, parentNode, node.IsModel); new BlockSyntaxVisitor(base.TokenStream).Visit(blockNode); node.StatementBlock = blockNode; parentNode.ExitDeclaration = node; }
/// <summary> /// Initializes a new instance of the <see cref="BlockSyntax"/> class. /// </summary> internal BlockSyntax(IPSharpProgram program, MachineDeclaration machineNode, StateDeclaration stateNode) : base(program) { this.Machine = machineNode; this.State = stateNode; }
/// <summary> /// Visits the syntax node. /// </summary> /// <param name="parentNode">Node</param> /// <param name="isStart">Is start state</param> /// <param name="accMod">Access modifier</param> internal void Visit(MachineDeclaration parentNode, bool isStart, AccessModifier accMod) { var node = new StateDeclaration(base.TokenStream.Program, parentNode, isStart, parentNode.IsModel); node.AccessModifier = accMod; node.StateKeyword = base.TokenStream.Peek(); base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); if (base.TokenStream.Done || base.TokenStream.Peek().Type != TokenType.Identifier) { throw new ParsingException("Expected state identifier.", new List<TokenType> { TokenType.Identifier }); } base.TokenStream.CurrentState = base.TokenStream.Peek().Text; base.TokenStream.Swap(new Token(base.TokenStream.Peek().TextUnit, TokenType.StateIdentifier)); node.Identifier = base.TokenStream.Peek(); 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 }); } base.TokenStream.Swap(new Token(base.TokenStream.Peek().TextUnit, TokenType.StateLeftCurlyBracket)); node.LeftCurlyBracketToken = base.TokenStream.Peek(); base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); if (base.TokenStream.Program is PSharpProgram) { this.VisitNextPSharpIntraStateDeclaration(node); } else { this.VisitNextPIntraStateDeclaration(node); } parentNode.StateDeclarations.Add(node); }
private void ProcessEntryOrExitDeclaration <T>(StateDeclaration state, T declaration, ref string text, int indentLevel, ref string newLine, int offset) where T : PSharpSyntaxNode { // This should be a local function, but it cannot because of the ref parameter. if (declaration != null) { // For the C# rewriting here, the parent is actually the machine instance. // on which the rewritten method resides. state.ProjectionNode.AddChild(declaration.ProjectionNode, this.ProjectionNode); declaration.Rewrite(indentLevel); text += newLine; // The rewritten offset is relative to the machine, which is the C# parent. declaration.ProjectionNode.SetOffsetInParent(offset + text.Length); text += declaration.TextUnit.Text; newLine = "\n"; } }
/// <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> /// Constructor. /// </summary> /// <param name="program">Program</param> /// <param name="stateNode">StateDeclaration</param> internal EntryDeclaration(IPSharpProgram program, StateDeclaration stateNode) : base(program) { this.State = stateNode; }
/// <summary> /// Visits the next intra-state declration. /// </summary> /// <param name="node">Node</param> private void VisitNextPIntraStateDeclaration(StateDeclaration node) { bool fixpoint = false; while (!fixpoint) { var token = base.TokenStream.Peek(); switch (token.Type) { case TokenType.WhiteSpace: case TokenType.Comment: case TokenType.NewLine: base.TokenStream.Index++; break; case TokenType.CommentLine: case TokenType.Region: base.TokenStream.SkipWhiteSpaceAndCommentTokens(); break; case TokenType.CommentStart: base.TokenStream.SkipWhiteSpaceAndCommentTokens(); break; case TokenType.Entry: new StateEntryDeclarationVisitor(base.TokenStream).Visit(node); base.TokenStream.Index++; break; case TokenType.Exit: new StateExitDeclarationVisitor(base.TokenStream).Visit(node); base.TokenStream.Index++; break; case TokenType.OnAction: new StateActionDeclarationVisitor(base.TokenStream).Visit(node); base.TokenStream.Index++; break; case TokenType.DeferEvent: new DeferEventsDeclarationVisitor(base.TokenStream).Visit(node); base.TokenStream.Index++; break; case TokenType.IgnoreEvent: new IgnoreEventsDeclarationVisitor(base.TokenStream).Visit(node); base.TokenStream.Index++; break; case TokenType.RightCurlyBracket: base.TokenStream.Swap(new Token(base.TokenStream.Peek().TextUnit, TokenType.StateRightCurlyBracket)); node.RightCurlyBracketToken = base.TokenStream.Peek(); base.TokenStream.CurrentState = ""; fixpoint = true; break; default: throw new ParsingException("Unexpected token.", new List<TokenType>()); } if (base.TokenStream.Done) { throw new ParsingException("Expected \"}\".", new List<TokenType> { TokenType.Entry, TokenType.Exit, TokenType.OnAction, TokenType.DeferEvent, TokenType.IgnoreEvent }); } } }
/// <summary> /// Visits the next intra-state declration. /// </summary> /// <param name="node">Node</param> private void VisitNextPSharpIntraStateDeclaration(StateDeclaration node) { bool fixpoint = false; while (!fixpoint) { var token = base.TokenStream.Peek(); switch (token.Type) { case TokenType.WhiteSpace: case TokenType.Comment: case TokenType.NewLine: base.TokenStream.Index++; break; case TokenType.CommentLine: case TokenType.Region: base.TokenStream.SkipWhiteSpaceAndCommentTokens(); break; case TokenType.CommentStart: base.TokenStream.SkipWhiteSpaceAndCommentTokens(); break; case TokenType.Entry: new StateEntryDeclarationVisitor(base.TokenStream).Visit(node); base.TokenStream.Index++; break; case TokenType.Exit: new StateExitDeclarationVisitor(base.TokenStream).Visit(node); base.TokenStream.Index++; break; case TokenType.OnAction: new StateActionDeclarationVisitor(base.TokenStream).Visit(node); base.TokenStream.Index++; break; case TokenType.DeferEvent: new DeferEventsDeclarationVisitor(base.TokenStream).Visit(node); base.TokenStream.Index++; break; case TokenType.IgnoreEvent: new IgnoreEventsDeclarationVisitor(base.TokenStream).Visit(node); base.TokenStream.Index++; break; case TokenType.LeftSquareBracket: base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); new AttributeListVisitor(base.TokenStream).Visit(); base.TokenStream.Index++; break; case TokenType.RightCurlyBracket: base.TokenStream.Swap(new Token(base.TokenStream.Peek().TextUnit, TokenType.StateRightCurlyBracket)); node.RightCurlyBracketToken = base.TokenStream.Peek(); base.TokenStream.CurrentState = ""; fixpoint = true; break; case TokenType.Private: case TokenType.Protected: case TokenType.Internal: case TokenType.Public: throw new ParsingException("State actions cannot have modifiers.", new List<TokenType>()); case TokenType.Abstract: case TokenType.Virtual: throw new ParsingException("State actions cannot be abstract or virtual.", new List<TokenType>()); default: throw new ParsingException("Unexpected token.", new List<TokenType>()); } if (base.TokenStream.Done) { throw new ParsingException("Expected \"}\".", new List<TokenType> { TokenType.Entry, TokenType.Exit, TokenType.OnAction, TokenType.DeferEvent, TokenType.IgnoreEvent, TokenType.LeftSquareBracket, TokenType.RightCurlyBracket }); } } }
/// <summary> /// Initializes a new instance of the <see cref="EntryDeclaration"/> class. /// </summary> internal EntryDeclaration(IPSharpProgram program, StateDeclaration stateNode, bool isAsync = false) : base(program) { this.State = stateNode; this.IsAsync = isAsync; }
/// <summary> /// Constructor. /// </summary> /// <param name="program">Program</param> /// <param name="stateNode">StateDeclaration</param> internal ExitDeclaration(IPSharpProgram program, StateDeclaration stateNode) : base(program) { this.State = stateNode; }
/// <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 }); } bool expectsComma = false; while (!base.TokenStream.Done && base.TokenStream.Peek().Type != TokenType.Semicolon) { if (!expectsComma && (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 }); } if (expectsComma && base.TokenStream.Peek().Type != TokenType.Comma) { throw new ParsingException("Expected \",\".", new List<TokenType> { TokenType.Comma }); } if (base.TokenStream.Peek().Type == TokenType.Identifier) { base.TokenStream.Swap(new Token(base.TokenStream.Peek().TextUnit, TokenType.EventIdentifier)); if (!parentNode.AddIgnoredEvent(base.TokenStream.Peek())) { throw new ParsingException("Unexpected event identifier.", new List<TokenType>()); } expectsComma = true; } else if (base.TokenStream.Peek().Type == TokenType.HaltEvent || base.TokenStream.Peek().Type == TokenType.DefaultEvent) { if (!parentNode.AddDeferredEvent(base.TokenStream.Peek())) { throw new ParsingException("Unexpected event identifier.", new List<TokenType>()); } expectsComma = true; } else if (base.TokenStream.Peek().Type == TokenType.Comma) { expectsComma = false; } 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 }); } }
/// <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 eventIdentifiers = new List<Token>(); bool expectsComma = false; while (!base.TokenStream.Done && base.TokenStream.Peek().Type != TokenType.DoAction && base.TokenStream.Peek().Type != TokenType.GotoState && base.TokenStream.Peek().Type != TokenType.PushState) { if ((!expectsComma && base.TokenStream.Peek().Type != TokenType.Identifier && base.TokenStream.Peek().Type != TokenType.HaltEvent && base.TokenStream.Peek().Type != TokenType.DefaultEvent) || (expectsComma && base.TokenStream.Peek().Type != TokenType.Comma)) { break; } if (base.TokenStream.Peek().Type == TokenType.Identifier || base.TokenStream.Peek().Type == TokenType.HaltEvent || base.TokenStream.Peek().Type == TokenType.DefaultEvent) { if (base.TokenStream.Peek().Type == TokenType.Identifier) { base.TokenStream.Swap(new Token(base.TokenStream.Peek().TextUnit, TokenType.EventIdentifier)); } eventIdentifiers.Add(base.TokenStream.Peek()); base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); expectsComma = true; } else if (base.TokenStream.Peek().Type == TokenType.Comma) { base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); expectsComma = false; } } 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 }); } 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, parentNode.IsModel); new BlockSyntaxVisitor(base.TokenStream).Visit(blockNode); base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); foreach (var eventIdentifier in eventIdentifiers) { if (!parentNode.AddActionBinding(eventIdentifier, 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 eventIdentifier in eventIdentifiers) { if (!parentNode.AddActionBinding(eventIdentifier, 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) { base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); if (base.TokenStream.Done || base.TokenStream.Peek().Type != TokenType.Identifier) { throw new ParsingException("Expected state identifier.", new List<TokenType> { TokenType.Identifier }); } base.TokenStream.Swap(new Token(base.TokenStream.Peek().TextUnit, TokenType.StateIdentifier)); var stateIdentifier = base.TokenStream.Peek(); base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); 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, parentNode.IsModel); new BlockSyntaxVisitor(base.TokenStream).Visit(blockNode); base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); foreach (var eventIdentifier in eventIdentifiers) { if (!parentNode.AddGotoStateTransition(eventIdentifier, stateIdentifier, blockNode)) { throw new ParsingException("Unexpected goto state transition.", new List<TokenType>()); } } if (base.TokenStream.Done || base.TokenStream.Peek().Type != TokenType.Semicolon) { throw new ParsingException("Expected \";\".", new List<TokenType> { TokenType.Semicolon }); } } else { foreach (var eventIdentifier in eventIdentifiers) { if (!parentNode.AddGotoStateTransition(eventIdentifier, stateIdentifier)) { 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>()); } base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); if (base.TokenStream.Done || base.TokenStream.Peek().Type != TokenType.Identifier) { throw new ParsingException("Expected state identifier.", new List<TokenType> { TokenType.Identifier }); } base.TokenStream.Swap(new Token(base.TokenStream.Peek().TextUnit, TokenType.StateIdentifier)); var stateIdentifier = 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 }); } foreach (var eventIdentifier in eventIdentifiers) { if (!parentNode.AddPushStateTransition(eventIdentifier, stateIdentifier)) { throw new ParsingException("Unexpected push state transition.", new List<TokenType>()); } } } }
/// <summary> /// Visits the syntax node. /// </summary> /// <param name="parentNode">Node</param> /// <param name="groupNode">Parent state group</param> /// <param name="isStart">Is start state</param> /// <param name="isHot">Is start state</param> /// <param name="isCold">Is start state</param> /// <param name="accMod">Access modifier</param> internal void Visit(MachineDeclaration parentNode, StateGroupDeclaration groupNode, bool isStart, bool isHot, bool isCold, AccessModifier accMod) { var node = new StateDeclaration(base.TokenStream.Program, parentNode, groupNode, isStart, isHot, isCold); node.AccessModifier = accMod; node.StateKeyword = base.TokenStream.Peek(); base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); if (base.TokenStream.Done || base.TokenStream.Peek().Type != TokenType.Identifier) { throw new ParsingException("Expected state identifier.", new List<TokenType> { TokenType.Identifier }); } base.TokenStream.Swap(new Token(base.TokenStream.Peek().TextUnit, TokenType.StateIdentifier)); node.Identifier = base.TokenStream.Peek(); 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 }); } base.TokenStream.Swap(new Token(base.TokenStream.Peek().TextUnit, TokenType.StateLeftCurlyBracket)); node.LeftCurlyBracketToken = base.TokenStream.Peek(); base.TokenStream.Index++; base.TokenStream.SkipWhiteSpaceAndCommentTokens(); if (base.TokenStream.Program is PSharpProgram) { this.VisitNextPSharpIntraStateDeclaration(node); } else { this.VisitNextPIntraStateDeclaration(node); } // Insert into (immediately) containing group or machine declaration. if (groupNode != null) { groupNode.StateDeclarations.Add(node); } else { parentNode.StateDeclarations.Add(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>()); } } } }