From c9634625455d622db90c3fc389e5036943b81d38 Mon Sep 17 00:00:00 2001 From: Nick Dumas Date: Sat, 1 Jul 2023 19:25:25 -0400 Subject: [PATCH] Synchronizing access to state --- lexer.go | 72 +++++++++++++++++++++++++++++++++++++++++++------------ states.go | 22 ++++++----------- 2 files changed, 64 insertions(+), 30 deletions(-) diff --git a/lexer.go b/lexer.go index b488d77..fe50d92 100644 --- a/lexer.go +++ b/lexer.go @@ -4,6 +4,7 @@ package wikilink import ( "fmt" "strings" + "sync" // "unicode" "unicode/utf8" @@ -67,19 +68,20 @@ func (l *Lexer) NextItem() Item { } func (l *Lexer) ignore() { - l.start = l.pos + l.SetStart(l.pos) } func (l *Lexer) backup() { - l.pos -= l.width + l.SetPos(l.GetPos() - l.GetWidth()) } type Lexer struct { - L *zap.SugaredLogger - name, input string - start, pos, width int - state stateFn - items chan Item + L *zap.SugaredLogger + name, input string + start, pos, width int + state stateFn + items chan Item + widthMutex, startMutex, posMutex, chanMutex sync.Mutex } func (l *Lexer) peek() rune { @@ -106,17 +108,19 @@ func (l *Lexer) acceptRun(valid string) { } func (l *Lexer) emit(t ItemType) { - i := Item{t, l.input[l.start:l.pos]} + defer l.chanMutex.Unlock() + l.chanMutex.Lock() + i := Item{t, l.input[l.GetStart():l.GetPos()]} L := l.L.With( - zap.Int("pos", l.pos), - zap.Int("width", l.width), + zap.Int("pos", l.GetPos()), + zap.Int("width", l.GetWidth()), ).Named("emit") L.Debugw("emitting item", zap.String("item", i.String()), ) l.items <- i - l.start = l.pos + l.SetStart(l.GetPos()) } func (l *Lexer) errorf(format string, args ...interface{}) stateFn { @@ -135,12 +139,13 @@ func (l *Lexer) errorf(format string, args ...interface{}) stateFn { func (l *Lexer) next() rune { var r rune - if l.pos >= len(l.input) { - l.width = 0 + if l.GetPos() >= len(l.input) { + l.SetWidth(0) return EOF } - r, l.width = utf8.DecodeRuneInString(l.input[l.pos:]) - l.pos += l.width + r, width := utf8.DecodeRuneInString(l.input[l.GetPos():]) + l.SetWidth(width) + l.SetPos(l.GetPos() + l.GetWidth()) return r } @@ -148,9 +153,46 @@ func (l *Lexer) run() { for state := lexText; state != nil; { state = state(l) } + l.chanMutex.Lock() close(l.items) } +func (l *Lexer) GetPos() int { + defer l.posMutex.Unlock() + l.posMutex.Lock() + return l.pos +} + +func (l *Lexer) SetPos(pos int) { + defer l.posMutex.Unlock() + l.posMutex.Lock() + l.pos = pos +} + +func (l *Lexer) GetWidth() int { + defer l.widthMutex.Unlock() + l.widthMutex.Lock() + return l.width +} + +func (l *Lexer) SetWidth(width int) { + defer l.widthMutex.Unlock() + l.widthMutex.Lock() + l.width = width +} + +func (l *Lexer) GetStart() int { + defer l.startMutex.Unlock() + l.startMutex.Lock() + return l.start +} + +func (l *Lexer) SetStart(start int) { + defer l.startMutex.Unlock() + l.startMutex.Lock() + l.start = start +} + type stateFn func(*Lexer) stateFn type ItemType int diff --git a/states.go b/states.go index 07fe9b1..6725eb0 100644 --- a/states.go +++ b/states.go @@ -1,7 +1,6 @@ package wikilink import ( - "log" "strings" ) @@ -26,10 +25,9 @@ func isBlockRef(s string) bool { } func lexIdent(l *Lexer) stateFn { - log.Println("lexIdent") for { r := l.next() - s := l.input[l.pos:] + s := l.input[l.GetPos():] if r == '\\' { // i think this will handle escape characters? break } @@ -53,33 +51,29 @@ func lexIdent(l *Lexer) stateFn { } func lexHeading(l *Lexer) stateFn { - log.Println("lexHeading") - l.pos += len(Heading) + l.SetPos(l.GetPos() + len(Heading)) l.emit(ItemHeading) return lexIdent } func lexBlockRef(l *Lexer) stateFn { - log.Println("lexBlockRef") - l.pos += len(BlockRef) + l.SetPos(l.GetPos() + len(BlockRef)) l.emit(ItemBlockRef) return lexIdent } func lexAlias(l *Lexer) stateFn { - log.Println("lexAlias") - l.pos += len(Alias) + l.SetPos(l.GetPos() + len(Alias)) l.emit(ItemAlias) return lexIdent } func lexText(l *Lexer) stateFn { - log.Println("lexText") for { - if isOpenLink(l.input[l.pos:]) { + if isOpenLink(l.input[l.GetPos():]) { return lexOpenLink } r := l.next() @@ -92,16 +86,14 @@ func lexText(l *Lexer) stateFn { } func lexOpenLink(l *Lexer) stateFn { - log.Println("lexOpenLink") - l.pos += len(OpenLink) + l.SetPos(l.GetPos() + len(OpenLink)) l.emit(ItemOpenLink) return lexIdent } func lexCloseLink(l *Lexer) stateFn { - log.Println("lexCloseLink") - l.pos += len(CloseLink) + l.SetPos(l.GetPos() + len(CloseLink)) l.emit(ItemCloseLink) return lexText