stack_machine.go 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. /*
  2. This Source Code Form is subject to the terms of the Mozilla Public
  3. License, v. 2.0. If a copy of the MPL was not distributed with this
  4. file, You can obtain one at https://mozilla.org/MPL/2.0/.
  5. */
  6. package parser
  7. import (
  8. "errors"
  9. "fmt"
  10. )
  11. func NewUnrecognized(msg string, val rune) error {
  12. return &UnrecognizedInputError{msg: msg, val: val}
  13. }
  14. type UnrecognizedInputError struct {
  15. msg string
  16. val rune
  17. }
  18. func (e *UnrecognizedInputError) Error() string {
  19. return fmt.Sprintf("%s: unrecognized input: '%s'", e.msg, string(e.val))
  20. }
  21. func (e *UnrecognizedInputError) Unwrap() error {
  22. return e
  23. }
  24. type SM struct {
  25. stack []*CSTNode
  26. line, col int
  27. }
  28. func (m *SM) Top() *CSTNode {
  29. return m.stack[len(m.stack)-1]
  30. }
  31. func (m *SM) Push(t ASTNode) ASTNode {
  32. m.stack = append(m.stack, &CSTNode{ASTNode: t})
  33. return t
  34. }
  35. func (m *SM) shift(e rune) (err error) {
  36. m.col++
  37. for {
  38. err = m.Top().ASTNode.Shift(m, e)
  39. if !errors.Is(err, &UnrecognizedInputError{}) {
  40. break
  41. }
  42. if !m.reduce() {
  43. break
  44. }
  45. }
  46. return err
  47. }
  48. func (m *SM) reduce() bool {
  49. if len(m.stack) < 2 {
  50. return false
  51. }
  52. last := len(m.stack) - 1
  53. nodes := m.stack[last-1].Nodes
  54. nodes = append(nodes, m.stack[last])
  55. m.stack[last-1].Nodes = nodes
  56. m.stack = m.stack[:last]
  57. return true
  58. }