Skip to content

Commit fa05ec6

Browse files
author
MochiOS Team
committed
fix: lexer indent counting broken by premature skipWhitespace, blank line DEDENT ordering
1 parent 3ca7000 commit fa05ec6

1 file changed

Lines changed: 66 additions & 56 deletions

File tree

‎mochi/lang/lexer.go‎

Lines changed: 66 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,15 @@ func Lex(input string) []Token {
2525
var tokens []Token
2626
for {
2727
tok := l.nextToken()
28-
tokens = append(tokens, tok)
2928
if tok.Type == EOF {
29+
for len(l.indentStack) > 1 {
30+
l.indentStack = l.indentStack[:len(l.indentStack)-1]
31+
tokens = append(tokens, Token{Type: DEDENT, Line: l.line, Col: l.col})
32+
}
33+
tokens = append(tokens, tok)
3034
break
3135
}
32-
}
33-
for len(l.indentStack) > 1 {
34-
tokens = append(tokens, Token{Type: DEDENT, Line: l.line, Col: l.col})
35-
l.indentStack = l.indentStack[:len(l.indentStack)-1]
36+
tokens = append(tokens, tok)
3637
}
3738
return tokens
3839
}
@@ -44,38 +45,49 @@ func (l *Lexer) nextToken() Token {
4445
return tok
4546
}
4647

47-
l.skipWhitespace()
48-
49-
if l.pos >= len(l.input) {
50-
return Token{Type: EOF, Literal: "", Line: l.line, Col: l.col}
51-
}
52-
53-
ch := l.input[l.pos]
54-
5548
if l.atLineStart {
5649
l.atLineStart = false
57-
indent := l.countIndent()
50+
indent := l.countAndSkipIndent()
5851
last := l.indentStack[len(l.indentStack)-1]
59-
if ch == '#' || ch == '\n' || l.pos >= len(l.input) {
52+
53+
if l.pos >= len(l.input) {
54+
if indent < last {
55+
return l.emitDedent()
56+
}
57+
return Token{Type: EOF, Line: l.line, Col: l.col}
58+
}
59+
60+
ch := l.input[l.pos]
61+
if ch == '#' {
6062
l.skipLine()
63+
l.atLineStart = true
6164
return l.nextToken()
6265
}
66+
if ch == '\n' {
67+
l.pos++
68+
l.line++
69+
l.col = 0
70+
l.atLineStart = true
71+
return Token{Type: NEWLINE, Literal: "\\n", Line: l.line - 1, Col: l.col}
72+
}
73+
6374
if indent > last {
6475
l.indentStack = append(l.indentStack, indent)
65-
return Token{Type: INDENT, Literal: "", Line: l.line, Col: l.col}
66-
} else if indent < last {
67-
for len(l.indentStack) > 1 && l.indentStack[len(l.indentStack)-1] != indent {
68-
l.indentStack = l.indentStack[:len(l.indentStack)-1]
69-
l.pending = append(l.pending, Token{Type: DEDENT, Line: l.line, Col: l.col})
70-
}
71-
if len(l.indentStack) > 1 && l.indentStack[len(l.indentStack)-1] > indent {
72-
l.indentStack = l.indentStack[:len(l.indentStack)-1]
73-
l.pending = append(l.pending, Token{Type: DEDENT, Line: l.line, Col: l.col})
74-
}
75-
return l.nextToken()
76+
return Token{Type: INDENT, Line: l.line, Col: l.col}
77+
}
78+
if indent < last {
79+
return l.emitDedent()
7680
}
81+
} else {
82+
l.skipInlineSpace()
83+
}
84+
85+
if l.pos >= len(l.input) {
86+
return Token{Type: EOF, Line: l.line, Col: l.col}
7787
}
7888

89+
ch := l.input[l.pos]
90+
7991
switch {
8092
case ch == '\n':
8193
l.pos++
@@ -84,10 +96,6 @@ func (l *Lexer) nextToken() Token {
8496
l.atLineStart = true
8597
return Token{Type: NEWLINE, Literal: "\\n", Line: l.line - 1, Col: l.col}
8698

87-
case ch == '#':
88-
l.skipLine()
89-
return l.nextToken()
90-
9199
case ch == '=':
92100
l.pos++
93101
l.col++
@@ -182,42 +190,49 @@ func (l *Lexer) nextToken() Token {
182190
}
183191
}
184192

185-
func (l *Lexer) skipWhitespace() {
186-
for l.pos < len(l.input) {
187-
ch := l.input[l.pos]
188-
if ch == ' ' || ch == '\t' || ch == '\r' {
189-
l.pos++
190-
l.col++
191-
} else {
192-
break
193-
}
193+
func (l *Lexer) emitDedent() Token {
194+
for len(l.indentStack) > 1 {
195+
l.indentStack = l.indentStack[:len(l.indentStack)-1]
196+
l.pending = append(l.pending, Token{Type: DEDENT, Line: l.line, Col: l.col})
194197
}
195-
}
196-
197-
func (l *Lexer) skipLine() {
198-
for l.pos < len(l.input) && l.input[l.pos] != '\n' {
199-
l.pos++
198+
if len(l.pending) > 0 {
199+
tok := l.pending[0]
200+
l.pending = l.pending[1:]
201+
return tok
200202
}
203+
return Token{Type: DEDENT, Line: l.line, Col: l.col}
201204
}
202205

203-
func (l *Lexer) countIndent() int {
204-
pos := l.pos
206+
func (l *Lexer) countAndSkipIndent() int {
205207
count := 0
206-
for pos < len(l.input) {
207-
ch := l.input[pos]
208+
for l.pos < len(l.input) {
209+
ch := l.input[l.pos]
208210
if ch == ' ' {
209211
count++
210-
pos++
212+
l.pos++
211213
} else if ch == '\t' {
212214
count += 4
213-
pos++
215+
l.pos++
214216
} else {
215217
break
216218
}
217219
}
218220
return count
219221
}
220222

223+
func (l *Lexer) skipInlineSpace() {
224+
for l.pos < len(l.input) && (l.input[l.pos] == ' ' || l.input[l.pos] == '\t') {
225+
l.pos++
226+
l.col++
227+
}
228+
}
229+
230+
func (l *Lexer) skipLine() {
231+
for l.pos < len(l.input) && l.input[l.pos] != '\n' {
232+
l.pos++
233+
}
234+
}
235+
221236
func (l *Lexer) readString(quote rune) Token {
222237
start := l.pos
223238
l.pos++
@@ -245,14 +260,9 @@ func (l *Lexer) readString(quote rune) Token {
245260

246261
func (l *Lexer) readNumber() Token {
247262
start := l.pos
248-
hasDot := false
249263
for l.pos < len(l.input) {
250264
ch := l.input[l.pos]
251-
if ch == '.' && !hasDot {
252-
hasDot = true
253-
l.pos++
254-
l.col++
255-
} else if unicode.IsDigit(ch) {
265+
if unicode.IsDigit(ch) || ch == '.' {
256266
l.pos++
257267
l.col++
258268
} else {

0 commit comments

Comments
 (0)