@@ -1318,6 +1318,10 @@ func (p *Parser) parseBeginStatement() (ast.Statement, error) {
13181318 return p .parseBeginTransactionStatementContinued (false )
13191319 case TokenTry :
13201320 return p .parseTryCatchStatement ()
1321+ case TokenDialog :
1322+ return p .parseBeginDialogStatement ()
1323+ case TokenConversation :
1324+ return p .parseBeginConversationTimerStatement ()
13211325 case TokenIdent :
13221326 // Check for DISTRIBUTED
13231327 if strings .ToUpper (p .curTok .Literal ) == "DISTRIBUTED" {
@@ -1660,6 +1664,221 @@ func (p *Parser) parseBeginEndBlockStatementContinued() (*ast.BeginEndBlockState
16601664 return stmt , nil
16611665}
16621666
1667+ func (p * Parser ) parseBeginDialogStatement () (* ast.BeginDialogStatement , error ) {
1668+ p .nextToken () // consume DIALOG
1669+
1670+ stmt := & ast.BeginDialogStatement {}
1671+
1672+ // Check for optional CONVERSATION keyword
1673+ if p .curTok .Type == TokenConversation {
1674+ stmt .IsConversation = true
1675+ p .nextToken () // consume CONVERSATION
1676+ }
1677+
1678+ // Parse dialog handle (variable reference)
1679+ if p .curTok .Type == TokenIdent && len (p .curTok .Literal ) > 0 && p .curTok .Literal [0 ] == '@' {
1680+ stmt .Handle = & ast.VariableReference {Name : p .curTok .Literal }
1681+ p .nextToken ()
1682+ } else {
1683+ return nil , fmt .Errorf ("expected variable for dialog handle" )
1684+ }
1685+
1686+ // Parse FROM SERVICE
1687+ if p .curTok .Type != TokenFrom {
1688+ return nil , fmt .Errorf ("expected FROM after dialog handle" )
1689+ }
1690+ p .nextToken () // consume FROM
1691+
1692+ if strings .ToUpper (p .curTok .Literal ) != "SERVICE" {
1693+ return nil , fmt .Errorf ("expected SERVICE after FROM" )
1694+ }
1695+ p .nextToken () // consume SERVICE
1696+
1697+ // Parse initiator service name (identifier)
1698+ id := p .parseIdentifier ()
1699+ stmt .InitiatorServiceName = & ast.IdentifierOrValueExpression {
1700+ Value : id .Value ,
1701+ Identifier : id ,
1702+ }
1703+
1704+ // Parse TO SERVICE
1705+ if p .curTok .Type != TokenTo {
1706+ return nil , fmt .Errorf ("expected TO after initiator service name" )
1707+ }
1708+ p .nextToken () // consume TO
1709+
1710+ if strings .ToUpper (p .curTok .Literal ) != "SERVICE" {
1711+ return nil , fmt .Errorf ("expected SERVICE after TO" )
1712+ }
1713+ p .nextToken () // consume SERVICE
1714+
1715+ // Parse target service name (string literal or variable)
1716+ if p .curTok .Type == TokenString || p .curTok .Type == TokenNationalString {
1717+ strLit , err := p .parseStringLiteral ()
1718+ if err != nil {
1719+ return nil , err
1720+ }
1721+ stmt .TargetServiceName = strLit
1722+ } else if p .curTok .Type == TokenIdent && len (p .curTok .Literal ) > 0 && p .curTok .Literal [0 ] == '@' {
1723+ stmt .TargetServiceName = & ast.VariableReference {Name : p .curTok .Literal }
1724+ p .nextToken ()
1725+ } else {
1726+ return nil , fmt .Errorf ("expected string literal or variable for target service name" )
1727+ }
1728+
1729+ // Check for optional instance spec (after comma)
1730+ if p .curTok .Type == TokenComma {
1731+ p .nextToken () // consume comma
1732+ if p .curTok .Type == TokenString || p .curTok .Type == TokenNationalString {
1733+ strLit , err := p .parseStringLiteral ()
1734+ if err != nil {
1735+ return nil , err
1736+ }
1737+ stmt .InstanceSpec = strLit
1738+ } else if p .curTok .Type == TokenIdent && len (p .curTok .Literal ) > 0 && p .curTok .Literal [0 ] == '@' {
1739+ stmt .InstanceSpec = & ast.VariableReference {Name : p .curTok .Literal }
1740+ p .nextToken ()
1741+ }
1742+ }
1743+
1744+ // Parse optional ON CONTRACT
1745+ if p .curTok .Type == TokenOn && strings .ToUpper (p .peekTok .Literal ) == "CONTRACT" {
1746+ p .nextToken () // consume ON
1747+ p .nextToken () // consume CONTRACT
1748+ id := p .parseIdentifier ()
1749+ stmt .ContractName = & ast.IdentifierOrValueExpression {
1750+ Value : id .Value ,
1751+ Identifier : id ,
1752+ }
1753+ }
1754+
1755+ // Parse optional WITH options
1756+ if p .curTok .Type == TokenWith {
1757+ p .nextToken () // consume WITH
1758+ for {
1759+ optName := strings .ToUpper (p .curTok .Literal )
1760+ p .nextToken () // consume option name
1761+
1762+ if p .curTok .Type == TokenEquals {
1763+ p .nextToken () // consume =
1764+ }
1765+
1766+ switch optName {
1767+ case "RELATED_CONVERSATION" :
1768+ if p .curTok .Type == TokenIdent && len (p .curTok .Literal ) > 0 && p .curTok .Literal [0 ] == '@' {
1769+ stmt .Options = append (stmt .Options , & ast.ScalarExpressionDialogOption {
1770+ Value : & ast.VariableReference {Name : p .curTok .Literal },
1771+ OptionKind : "RelatedConversation" ,
1772+ })
1773+ p .nextToken ()
1774+ }
1775+ case "RELATED_CONVERSATION_GROUP" :
1776+ if p .curTok .Type == TokenIdent && len (p .curTok .Literal ) > 0 && p .curTok .Literal [0 ] == '@' {
1777+ stmt .Options = append (stmt .Options , & ast.ScalarExpressionDialogOption {
1778+ Value : & ast.VariableReference {Name : p .curTok .Literal },
1779+ OptionKind : "RelatedConversationGroup" ,
1780+ })
1781+ p .nextToken ()
1782+ }
1783+ case "ENCRYPTION" :
1784+ optState := strings .ToUpper (p .curTok .Literal )
1785+ if optState == "ON" {
1786+ stmt .Options = append (stmt .Options , & ast.OnOffDialogOption {
1787+ OptionState : "On" ,
1788+ OptionKind : "Encryption" ,
1789+ })
1790+ } else if optState == "OFF" {
1791+ stmt .Options = append (stmt .Options , & ast.OnOffDialogOption {
1792+ OptionState : "Off" ,
1793+ OptionKind : "Encryption" ,
1794+ })
1795+ }
1796+ p .nextToken ()
1797+ case "LIFETIME" :
1798+ if p .curTok .Type == TokenNumber {
1799+ stmt .Options = append (stmt .Options , & ast.ScalarExpressionDialogOption {
1800+ Value : & ast.IntegerLiteral {
1801+ LiteralType : "Integer" ,
1802+ Value : p .curTok .Literal ,
1803+ },
1804+ OptionKind : "Lifetime" ,
1805+ })
1806+ p .nextToken ()
1807+ }
1808+ }
1809+
1810+ if p .curTok .Type != TokenComma {
1811+ break
1812+ }
1813+ p .nextToken () // consume comma
1814+ }
1815+ }
1816+
1817+ // Skip optional semicolon
1818+ if p .curTok .Type == TokenSemicolon {
1819+ p .nextToken ()
1820+ }
1821+
1822+ return stmt , nil
1823+ }
1824+
1825+ func (p * Parser ) parseBeginConversationTimerStatement () (* ast.BeginConversationTimerStatement , error ) {
1826+ p .nextToken () // consume CONVERSATION
1827+
1828+ // Expect TIMER
1829+ if strings .ToUpper (p .curTok .Literal ) != "TIMER" {
1830+ return nil , fmt .Errorf ("expected TIMER after BEGIN CONVERSATION" )
1831+ }
1832+ p .nextToken () // consume TIMER
1833+
1834+ stmt := & ast.BeginConversationTimerStatement {}
1835+
1836+ // Parse handle in parentheses
1837+ if p .curTok .Type != TokenLParen {
1838+ return nil , fmt .Errorf ("expected ( after TIMER" )
1839+ }
1840+ p .nextToken () // consume (
1841+
1842+ if p .curTok .Type == TokenIdent && len (p .curTok .Literal ) > 0 && p .curTok .Literal [0 ] == '@' {
1843+ stmt .Handle = & ast.VariableReference {Name : p .curTok .Literal }
1844+ p .nextToken ()
1845+ } else {
1846+ return nil , fmt .Errorf ("expected variable for conversation handle" )
1847+ }
1848+
1849+ if p .curTok .Type != TokenRParen {
1850+ return nil , fmt .Errorf ("expected ) after handle" )
1851+ }
1852+ p .nextToken () // consume )
1853+
1854+ // Parse TIMEOUT = value
1855+ if strings .ToUpper (p .curTok .Literal ) != "TIMEOUT" {
1856+ return nil , fmt .Errorf ("expected TIMEOUT" )
1857+ }
1858+ p .nextToken () // consume TIMEOUT
1859+
1860+ if p .curTok .Type == TokenEquals {
1861+ p .nextToken () // consume =
1862+ }
1863+
1864+ if p .curTok .Type == TokenNumber {
1865+ stmt .Timeout = & ast.IntegerLiteral {
1866+ LiteralType : "Integer" ,
1867+ Value : p .curTok .Literal ,
1868+ }
1869+ p .nextToken ()
1870+ } else {
1871+ return nil , fmt .Errorf ("expected integer for timeout value" )
1872+ }
1873+
1874+ // Skip optional semicolon
1875+ if p .curTok .Type == TokenSemicolon {
1876+ p .nextToken ()
1877+ }
1878+
1879+ return stmt , nil
1880+ }
1881+
16631882func (p * Parser ) parseBeginEndBlockStatement () (* ast.BeginEndBlockStatement , error ) {
16641883 // Consume BEGIN
16651884 p .nextToken ()
0 commit comments