parser.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. package mar
  2. import (
  3. "crypto/md5"
  4. "encoding/binary"
  5. "fmt"
  6. "strconv"
  7. )
  8. // Parse parses data in to a MAR document.
  9. func Parse(party string, data []byte) (*Document, error) {
  10. return NewParser(party).Parse(data)
  11. }
  12. // MustParse parses data in to a MAR document. Panic on error.
  13. func MustParse(party string, data []byte) *Document {
  14. doc, err := Parse(party, data)
  15. if err != nil {
  16. panic(err)
  17. }
  18. return doc
  19. }
  20. // Parser represents a Marionette DSL parser.
  21. //
  22. // The parser will automatically convert certain actions to their complement
  23. // depending on the party that is parsing the document. No transformation is
  24. // performed if the party is blank.
  25. type Parser struct {
  26. party string
  27. }
  28. // NewParser returns a new instance of Parser.
  29. func NewParser(party string) *Parser {
  30. return &Parser{party: party}
  31. }
  32. // Parse parses s into an AST.
  33. func (p *Parser) Parse(data []byte) (*Document, error) {
  34. scanner := NewScanner(data)
  35. var doc Document
  36. doc.UUID = GenerateUUID(data)
  37. // Read 'connection' keyword.
  38. tok, lit, pos := scanner.ScanIgnoreWhitespace()
  39. if err := expect(IDENT, "connection", tok, lit, pos); err != nil {
  40. return nil, err
  41. }
  42. doc.Connection = pos
  43. // Read opening parenthesis.
  44. tok, lit, pos = scanner.ScanIgnoreWhitespace()
  45. if err := expect(LPAREN, "", tok, lit, pos); err != nil {
  46. return nil, err
  47. }
  48. doc.Lparen = pos
  49. // Read transport type.
  50. tok, lit, pos = scanner.ScanIgnoreWhitespace()
  51. if tok != IDENT {
  52. return nil, newSyntaxError("expected transport type ('tcp' or 'udp')", tok, lit, pos)
  53. }
  54. doc.Transport = lit
  55. doc.TransportPos = pos
  56. // Read comma.
  57. tok, lit, pos = scanner.ScanIgnoreWhitespace()
  58. if err := expect(COMMA, "", tok, lit, pos); err != nil {
  59. return nil, err
  60. }
  61. doc.Comma = pos
  62. // Read port.
  63. tok, lit, pos = scanner.ScanIgnoreWhitespace()
  64. if tok != IDENT && tok != INTEGER {
  65. return nil, newSyntaxError("expected named or numeric port", tok, lit, pos)
  66. }
  67. doc.Port = lit
  68. doc.PortPos = pos
  69. // Read closing parenthesis.
  70. tok, lit, pos = scanner.ScanIgnoreWhitespace()
  71. if err := expect(RPAREN, "", tok, lit, pos); err != nil {
  72. return nil, err
  73. }
  74. doc.Rparen = pos
  75. // Read colon.
  76. tok, lit, pos = scanner.ScanIgnoreWhitespace()
  77. if err := expect(COLON, "", tok, lit, pos); err != nil {
  78. return nil, err
  79. }
  80. doc.Colon = pos
  81. transitions, err := p.parseTransitions(scanner)
  82. if err != nil {
  83. return nil, err
  84. }
  85. doc.Transitions = transitions
  86. actionBlocks, err := p.parseActionBlocks(scanner)
  87. if err != nil {
  88. return nil, err
  89. }
  90. doc.ActionBlocks = actionBlocks
  91. if err := doc.Normalize(); err != nil {
  92. return nil, err
  93. }
  94. return &doc, nil
  95. }
  96. func (p *Parser) parseTransitions(scanner *Scanner) ([]*Transition, error) {
  97. var transitions []*Transition
  98. for {
  99. // Exit once we hit an 'action' keyword or end-of-file.
  100. if tok, _, _ := scanner.PeekIgnoreWhitespace(); tok == ACTION || tok == EOF {
  101. break
  102. }
  103. transition, err := p.parseTransition(scanner)
  104. if err != nil {
  105. return nil, err
  106. }
  107. transitions = append(transitions, transition)
  108. }
  109. return transitions, nil
  110. }
  111. func (p *Parser) parseTransition(scanner *Scanner) (*Transition, error) {
  112. var transition Transition
  113. // Read transition source.
  114. tok, lit, pos := scanner.ScanIgnoreWhitespace()
  115. if tok != START && tok != IDENT {
  116. return nil, newSyntaxError("expected source or 'start'", tok, lit, pos)
  117. }
  118. transition.Source = lit
  119. transition.SourcePos = pos
  120. // Read transition destination.
  121. tok, lit, pos = scanner.ScanIgnoreWhitespace()
  122. if tok != IDENT && tok != END {
  123. return nil, newSyntaxError("expected destination or 'end'", tok, lit, pos)
  124. }
  125. transition.Destination = lit
  126. transition.DestinationPos = pos
  127. // Read action block name.
  128. tok, lit, pos = scanner.ScanIgnoreWhitespace()
  129. if tok != IDENT && tok != NULL {
  130. return nil, newSyntaxError("expected action block name or NULL", tok, lit, pos)
  131. }
  132. transition.ActionBlock = lit
  133. transition.ActionBlockPos = pos
  134. // Read probability.
  135. tok, lit, pos = scanner.ScanIgnoreWhitespace()
  136. if tok != IDENT && tok != INTEGER && tok != FLOAT {
  137. return nil, newSyntaxError("expected probability or 'error'", tok, lit, pos)
  138. }
  139. transition.Probability, _ = strconv.ParseFloat(lit, 64)
  140. transition.ProbabilityPos = pos
  141. transition.IsErrorTransition = lit == "error"
  142. return &transition, nil
  143. }
  144. func (p *Parser) parseActionBlocks(scanner *Scanner) ([]*ActionBlock, error) {
  145. var blks []*ActionBlock
  146. for {
  147. if tok, _, _ := scanner.PeekIgnoreWhitespace(); tok == EOF {
  148. break
  149. }
  150. blk, err := p.parseActionBlock(scanner)
  151. if err != nil {
  152. return nil, err
  153. }
  154. blks = append(blks, blk)
  155. }
  156. return blks, nil
  157. }
  158. func (p *Parser) parseActionBlock(scanner *Scanner) (*ActionBlock, error) {
  159. var blk ActionBlock
  160. // Read action keyword.
  161. tok, lit, pos := scanner.ScanIgnoreWhitespace()
  162. if err := expect(ACTION, "", tok, lit, pos); err != nil {
  163. return nil, err
  164. }
  165. blk.Action = pos
  166. // Read block name.
  167. tok, lit, pos = scanner.ScanIgnoreWhitespace()
  168. if tok != START && tok != IDENT {
  169. return nil, newSyntaxError("expected block name", tok, lit, pos)
  170. }
  171. blk.Name = lit
  172. blk.NamePos = pos
  173. // Read colon.
  174. tok, lit, pos = scanner.ScanIgnoreWhitespace()
  175. if err := expect(COLON, "", tok, lit, pos); err != nil {
  176. return nil, err
  177. }
  178. blk.Colon = pos
  179. // Read action list.
  180. actions, err := p.parseActions(scanner)
  181. if err != nil {
  182. return nil, err
  183. }
  184. blk.Actions = actions
  185. return &blk, nil
  186. }
  187. func (p *Parser) parseActions(scanner *Scanner) ([]*Action, error) {
  188. var actions []*Action
  189. for {
  190. if tok, _, _ := scanner.PeekIgnoreWhitespace(); tok == ACTION || tok == EOF {
  191. break
  192. }
  193. action, err := p.parseAction(scanner)
  194. if err != nil {
  195. return nil, err
  196. }
  197. actions = append(actions, action)
  198. }
  199. return actions, nil
  200. }
  201. func (p *Parser) parseAction(scanner *Scanner) (*Action, error) {
  202. var action Action
  203. // Read client/server keyword.
  204. tok, lit, pos := scanner.ScanIgnoreWhitespace()
  205. if tok != CLIENT && tok != SERVER {
  206. return nil, newSyntaxError("expected party name ('client' or 'server')", tok, lit, pos)
  207. }
  208. action.Party = lit
  209. action.PartyPos = pos
  210. // Read module name.
  211. tok, lit, pos = scanner.ScanIgnoreWhitespace()
  212. if tok != IDENT {
  213. return nil, newSyntaxError("expected module name", tok, lit, pos)
  214. }
  215. action.Module = lit
  216. action.ModulePos = pos
  217. // Read dot.
  218. tok, lit, pos = scanner.Scan()
  219. if tok != DOT {
  220. return nil, newSyntaxError("expected dot", tok, lit, pos)
  221. }
  222. action.Dot = pos
  223. // Read method name.
  224. tok, lit, pos = scanner.Scan()
  225. if tok != IDENT {
  226. return nil, newSyntaxError("expected method name", tok, lit, pos)
  227. }
  228. action.Method = lit
  229. action.MethodPos = pos
  230. // Read parens & args.
  231. tok, lit, pos = scanner.Scan()
  232. if tok != LPAREN {
  233. return nil, newSyntaxError("expected '('", tok, lit, pos)
  234. }
  235. action.Lparen = pos
  236. args, err := p.parseArgs(scanner)
  237. if err != nil {
  238. return nil, err
  239. }
  240. action.Args = args
  241. tok, lit, pos = scanner.Scan()
  242. if tok != RPAREN {
  243. return nil, newSyntaxError("expected ')'", tok, lit, pos)
  244. }
  245. action.Rparen = pos
  246. // Parse incoming regex match.
  247. if tok, _, _ := scanner.PeekIgnoreWhitespace(); tok == IF {
  248. // Read "if" statement.
  249. _, _, action.If = scanner.ScanIgnoreWhitespace()
  250. // Read 'regex_match_incoming' keyword.
  251. tok, lit, pos = scanner.ScanIgnoreWhitespace()
  252. if tok != REGEX_MATCH_INCOMING {
  253. return nil, newSyntaxError("expected 'regex_match_incoming'", tok, lit, pos)
  254. }
  255. action.RegexMatchIncoming = pos
  256. // Read parens and regex string.
  257. tok, lit, pos = scanner.Scan()
  258. if tok != LPAREN {
  259. return nil, newSyntaxError("expected '('", tok, lit, pos)
  260. }
  261. action.RegexMatchIncomingLparen = pos
  262. tok, lit, pos = scanner.ScanIgnoreWhitespace()
  263. if tok != STRING {
  264. return nil, newSyntaxError("expected regex string", tok, lit, pos)
  265. }
  266. action.Regex = lit
  267. action.RegexPos = pos
  268. tok, lit, pos = scanner.ScanIgnoreWhitespace()
  269. if tok != RPAREN {
  270. return nil, newSyntaxError("expected ')'", tok, lit, pos)
  271. }
  272. action.RegexMatchIncomingRparen = pos
  273. }
  274. // Perform transformation depending on party.
  275. action.Transform(p.party)
  276. return &action, nil
  277. }
  278. func (p *Parser) parseArgs(scanner *Scanner) ([]*Arg, error) {
  279. if tok, _, _ := scanner.PeekIgnoreWhitespace(); tok == RPAREN {
  280. return nil, nil
  281. }
  282. var args []*Arg
  283. for {
  284. tok, lit, pos := scanner.ScanIgnoreWhitespace()
  285. arg := &Arg{Pos: pos, EndPos: Pos{Line: pos.Line, Char: pos.Char + len(lit)}}
  286. switch tok {
  287. case STRING:
  288. arg.Value = lit
  289. case INTEGER:
  290. i, err := strconv.Atoi(lit)
  291. if err != nil {
  292. return nil, err
  293. }
  294. arg.Value = i
  295. case FLOAT:
  296. f, err := strconv.ParseFloat(lit, 64)
  297. if err != nil {
  298. return nil, err
  299. }
  300. arg.Value = f
  301. default:
  302. return nil, newSyntaxError("expected string, integer, or float argument", tok, lit, pos)
  303. }
  304. args = append(args, arg)
  305. if tok, _, _ := scanner.PeekIgnoreWhitespace(); tok == COMMA {
  306. scanner.ScanIgnoreWhitespace()
  307. } else if tok == RPAREN {
  308. break
  309. } else {
  310. return nil, newSyntaxError("expected ',' or ')'", tok, lit, pos)
  311. }
  312. }
  313. return args, nil
  314. }
  315. func expect(expectedTok Token, expectedLit string, tok Token, lit string, pos Pos) error {
  316. switch expectedTok {
  317. case IDENT:
  318. if tok != IDENT || expectedLit != lit {
  319. return newSyntaxError(fmt.Sprintf("expected '%s'", expectedLit), tok, lit, pos)
  320. }
  321. default:
  322. if expectedTok != tok {
  323. return newSyntaxError(fmt.Sprintf("expected %s", expectedTok.String()), tok, lit, pos)
  324. }
  325. }
  326. return nil
  327. }
  328. type SyntaxError struct {
  329. Message string
  330. Pos Pos
  331. }
  332. func (e *SyntaxError) Error() string { return e.Message }
  333. func newSyntaxError(exp string, tok Token, lit string, pos Pos) *SyntaxError {
  334. return &SyntaxError{
  335. Message: fmt.Sprintf("%s at line %d, found %s", exp, pos.Line, tok.String()),
  336. Pos: pos,
  337. }
  338. }
  339. func GenerateUUID(data []byte) int {
  340. sum := md5.Sum(data)
  341. return int(binary.BigEndian.Uint32(sum[:4]))
  342. }