aboutsummaryrefslogtreecommitdiff
path: root/cpe/token.go
blob: d88e773f3dfeb1cbc2e2a673396ed46a05c9f3ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package cpe

//go:generate stringer -linecomment -type=tokenType

import (
  "errors"
  "fmt"
)

// token type
type tokenType byte

const (
  anyToken tokenType = iota // any
  naToken // na
  valToken // val
)

// token
type token struct {
  Type tokenType // token type
  Val string // token value
}

// parse buffer into token.
func newToken(val []byte) token {
  if len(val) > 0 {
    switch val[0] {
    case '*':
      return token { Type: anyToken }
    case '-':
      return token { Type: naToken }
    default:
      return token { Type: valToken, Val: string(val) }
    }
  } else {
    // empty value
    return token { Type: valToken }
  }
}

// unterminated escape error
var unterminatedEsc = errors.New("unterminated escape at end of buffer")

// Parse buffer into list of tokens.
func tokenize(buf []byte) ([]token, error) {
  // build result
  var r []token

  // current token and escape state
  var curr []byte
  esc := false

  // build result
  for _, b := range(buf) {
    if esc {
      switch b {
      // valid escaped characters
      case '\\', '*', '-', '!', '"', '#', '$', '%', '&', '\'', '(', ')',
           '+', ',', '/', ':', ';', '<', '=', '>', '@', '[', ']', '^', '`',
           '{', '|', '}', '~':
        curr = append(curr, b)
        esc = false
      default:
        return r, fmt.Errorf("invalid escape byte: 0x%02x", b)
      }
    } else {
      switch b {
      case '\\':
        esc = true
      case ':':
        // push token, clear buffer
        r = append(r, newToken(curr))
        curr = nil
      case 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
           'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
           'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
           '-', '.', '_', '*', '?':
        curr = append(curr, b)
      default:
        return r, fmt.Errorf("invalid byte: 0x%02x", b)
      }
    }
  }

  // check for unterminated escape
  if esc {
    return r, unterminatedEsc
  }

  if len(curr) > 0 {
    // push token, clear buffer
    r = append(r, newToken(curr))
    curr = nil
  }

  // return success
  return r, nil
}