You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

151 lines
2.3 KiB

  1. package circuit
  2. import (
  3. "bufio"
  4. "bytes"
  5. "io"
  6. )
  7. // OperatorSymbol is ...
  8. type OperatorSymbol int
  9. // Token is ...
  10. type Token int
  11. // Tokens
  12. const (
  13. ILLEGAL Token = iota
  14. WS
  15. EOF
  16. IDENT // val
  17. VAR // var
  18. CONST // const value
  19. EQ // =
  20. PLUS // +
  21. MINUS // -
  22. MULTIPLY // *
  23. DIVIDE // /
  24. EXP // ^
  25. OUT
  26. )
  27. var eof = rune(0)
  28. func isWhitespace(ch rune) bool {
  29. return ch == ' ' || ch == '\t' || ch == '\n'
  30. }
  31. func isLetter(ch rune) bool {
  32. return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
  33. }
  34. func isDigit(ch rune) bool {
  35. return (ch >= '0' && ch <= '9')
  36. }
  37. // Scanner holds the bufio.Reader
  38. type Scanner struct {
  39. r *bufio.Reader
  40. }
  41. // NewScanner creates a new Scanner with the given io.Reader
  42. func NewScanner(r io.Reader) *Scanner {
  43. return &Scanner{r: bufio.NewReader(r)}
  44. }
  45. func (s *Scanner) read() rune {
  46. ch, _, err := s.r.ReadRune()
  47. if err != nil {
  48. return eof
  49. }
  50. return ch
  51. }
  52. func (s *Scanner) unread() {
  53. _ = s.r.UnreadRune()
  54. }
  55. // Scan returns the Token and literal string of the current value
  56. func (s *Scanner) scan() (tok Token, lit string) {
  57. ch := s.read()
  58. if isWhitespace(ch) {
  59. // space
  60. s.unread()
  61. return s.scanWhitespace()
  62. } else if isLetter(ch) {
  63. // letter
  64. s.unread()
  65. return s.scanIndent()
  66. } else if isDigit(ch) {
  67. s.unread()
  68. return s.scanIndent()
  69. }
  70. switch ch {
  71. case eof:
  72. return EOF, ""
  73. case '=':
  74. return EQ, "="
  75. case '+':
  76. return PLUS, "+"
  77. case '-':
  78. return MINUS, "-"
  79. case '*':
  80. return MULTIPLY, "*"
  81. case '/':
  82. return DIVIDE, "/"
  83. case '^':
  84. return EXP, "^"
  85. }
  86. return ILLEGAL, string(ch)
  87. }
  88. func (s *Scanner) scanWhitespace() (token Token, lit string) {
  89. var buf bytes.Buffer
  90. buf.WriteRune(s.read())
  91. for {
  92. if ch := s.read(); ch == eof {
  93. break
  94. } else if !isWhitespace(ch) {
  95. s.unread()
  96. break
  97. } else {
  98. _, _ = buf.WriteRune(ch)
  99. }
  100. }
  101. return WS, buf.String()
  102. }
  103. func (s *Scanner) scanIndent() (tok Token, lit string) {
  104. var buf bytes.Buffer
  105. buf.WriteRune(s.read())
  106. for {
  107. if ch := s.read(); ch == eof {
  108. break
  109. } else if !isLetter(ch) && !isDigit(ch) {
  110. s.unread()
  111. break
  112. } else {
  113. _, _ = buf.WriteRune(ch)
  114. }
  115. }
  116. switch buf.String() {
  117. case "var":
  118. return VAR, buf.String()
  119. }
  120. if len(buf.String()) == 1 {
  121. return Token(rune(buf.String()[0])), buf.String()
  122. }
  123. if buf.String() == "out" {
  124. return OUT, buf.String()
  125. }
  126. return IDENT, buf.String()
  127. }