-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtokenizer.go
118 lines (113 loc) · 2.24 KB
/
tokenizer.go
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package main
import (
"reflect"
"strconv"
"strings"
"unicode"
)
type TokenType int
const (
TokenTypeHead TokenType = iota
TokenTypeReserved
TokenTypeIdentifier
TokenTypeNumber
TokenTypeEof
)
type Token struct {
tokenType TokenType
str string
value int
next *Token
}
func Tokenize(input string) *Token {
head := &Token{tokenType: TokenTypeHead, str: "head"}
current := head
i := 0
runes := []rune(input)
limit := len(runes)
for i < limit {
r := runes[i]
isSpace := unicode.IsSpace(r)
if isSpace {
i++
continue
}
c := string(r)
prefixes := [...]string{"==", "!=", "<=", ">=", "var", "return", "if", "else", "fnc", "for", "break"}
matchedPrefix := ""
for _, prefix := range prefixes {
prefixRunes := []rune(prefix)
length := len(prefixRunes)
if i+length < limit {
searchRunes := runes[i : i+length]
if reflect.DeepEqual(prefixRunes, searchRunes) {
matchedPrefix = prefix
i = i + length
break
}
}
}
if matchedPrefix != "" {
token := &Token{tokenType: TokenTypeReserved, str: matchedPrefix}
current.next = token
current = token
continue
}
if unicode.IsLetter(r) {
vi := i
identifier := ""
for {
if vi >= limit {
break
}
vc := runes[vi]
if unicode.IsLetter(vc) {
identifier = identifier + string(vc)
vi++
} else {
break
}
}
token := &Token{tokenType: TokenTypeIdentifier, str: identifier}
current.next = token
current = token
i = vi
continue
}
if strings.Contains("+-*/()=<>;{}", c) {
token := &Token{tokenType: TokenTypeReserved, str: c}
current.next = token
current = token
i++
continue
}
value, err := strconv.Atoi(c)
if err == nil {
vi := i
vc := ""
resolvedValue := value
for {
if vi >= limit {
break
}
vc = vc + string(runes[vi])
value, err := strconv.Atoi(vc)
if err == nil {
resolvedValue = value
vi++
} else {
break
}
}
token := &Token{tokenType: TokenTypeNumber, value: resolvedValue, str: strconv.Itoa(resolvedValue)}
current.next = token
current = token
i = vi
continue
}
panic("Invalid Token")
}
eof := &Token{tokenType: TokenTypeEof, str: "eof"}
current.next = eof
return head.next
}