6 Commits

Author SHA1 Message Date
amery 7a5dc59929 parser: WIP
Signed-off-by: Alejandro Mery <amery@jpi.io>
2023-08-30 02:15:55 +00:00
amery 7c0688e3b1 parser: emitError
Signed-off-by: Alejandro Mery <amery@jpi.io>
2023-08-30 02:15:40 +00:00
amery e0155b5103 parser: callbacks [WIP]
Signed-off-by: Alejandro Mery <amery@jpi.io>
2023-08-30 02:12:35 +00:00
amery 8f34cdf891 build-sys: use local asciigoat.org/core [DO-NOT-MERGE]
Signed-off-by: Alejandro Mery <amery@jpi.io>
2023-08-30 02:11:26 +00:00
amery 70c8ed1d34 parser: implement initial tokeniser
only logging position, errors and non-whitespace elements

Signed-off-by: Alejandro Mery <amery@jpi.io>
2023-08-30 02:10:37 +00:00
amery 00fcde4c5b parser: add placeholder for ini Parser
Signed-off-by: Alejandro Mery <amery@jpi.io>
2023-08-30 02:06:31 +01:00
5 changed files with 119 additions and 28 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ go 1.19
replace asciigoat.org/core => ../core
require (
asciigoat.org/core v0.3.2
asciigoat.org/core v0.3.4
github.com/mgechev/revive v1.3.3
)
+57 -27
View File
@@ -8,6 +8,8 @@ import (
// Run parses the source
func (p *Parser) Run() error {
p.setDefaults()
p.pos.Reset()
return lexer.Run(p.lexStart)
}
@@ -18,27 +20,74 @@ func (p *Parser) lexStart() (lexer.StateFn, error) {
switch {
case err != nil:
// read error
log.Printf("%s: %s: %s", p.pos, "error", err)
return nil, err
return p.emitError("", err)
case IsNewLine(r):
// new line
p.src.UnreadRune()
p.lexNewLine()
p.lexNewLine(r)
p.src.Discard()
p.pos.StepLine()
case IsSpace(r):
// whitespace
p.src.Discard()
p.pos.Step()
default:
// token
case IsCommentStart(r):
// switch to comment lexer
p.src.UnreadRune()
return p.lexToken, nil
return p.lexComment, nil
case IsSectionStart(r):
// section
p.src.Discard()
p.pos.Step()
return p.lexSectionStart, nil
default:
// entry
p.src.UnreadRune()
return p.lexEntryStart, nil
}
}
}
func (p *Parser) lexNewLine(r1 rune) {
// r1 is warrantied to be either \n or \r
r2, _, err := p.src.ReadRune()
switch r1 {
case '\r':
switch {
case r2 == '\n':
// CR LN
case err == nil:
// CR
p.src.UnreadRune()
default:
// CR EOF
}
case '\n':
switch {
case r2 == '\r':
// LN CR
case err == nil:
// LN
p.src.UnreadRune()
default:
// LN EOF
}
default:
panic("unreachable")
}
}
func (p *Parser) lexComment() (lexer.StateFn, error) {
// until the end of the line
p.src.AcceptAll(IsNotNewLine)
err := p.OnComment(p.pos, p.src.Emit())
return p.lexStart, err
}
func (*Parser) lexSectionStart() (lexer.StateFn, error) { return nil, nil }
func (*Parser) lexEntryStart() (lexer.StateFn, error) { return nil, nil }
func (p *Parser) lexToken() (lexer.StateFn, error) {
p.src.AcceptAll(IsNotSpace)
@@ -48,22 +97,3 @@ func (p *Parser) lexToken() (lexer.StateFn, error) {
return p.lexStart, nil
}
func (p *Parser) lexNewLine() {
// r1 is warrantied to be either \n or \r
r1, _, _ := p.src.ReadRune()
r2, _, err := p.src.ReadRune()
switch {
case r1 == '\r' && r2 == '\n':
// CR LN
case r1 == '\r' && err == nil:
// CR
p.src.UnreadRune()
case r2 == '\r':
// LN CR
case err == nil:
// LN
p.src.UnreadRune()
}
}
+19
View File
@@ -0,0 +1,19 @@
package parser
import "asciigoat.org/core/lexer"
func (p *Parser) emitError(content string, err error) (lexer.StateFn, error) {
err2 := p.OnError(p.pos, content, err)
switch {
case err2 != nil:
// return wrapped error
return nil, err2
default:
// return original error
return nil, err
}
}
func (p *Parser) emitInvalidRune(r rune) (lexer.StateFn, error) {
return p.emitError(string([]rune{r}), lexer.ErrUnacceptableRune)
}
+6
View File
@@ -11,4 +11,10 @@ var (
IsNotNewLine = lexer.NewIsNot(IsNewLine)
// IsNotSpace tells if a rune is anything other than whitespace
IsNotSpace = lexer.NewIsNot(IsSpace)
IsCommentStart = lexer.NewIsIn(";#")
)
func IsSectionStart(r rune) bool {
return r == '['
}
+36
View File
@@ -12,6 +12,42 @@ type Parser struct {
src *lexer.Reader
pos lexer.Position
OnSection func(pos lexer.Position, name, subname string, hasSubname bool) error
OnField func(pos lexer.Position, key, value string) error
OnComment func(pos lexer.Position, comment string) error
OnError func(pos lexer.Position, content string, err error) error
}
func defaultOnSection(_ lexer.Position, _, _ string, _ bool) error { return nil }
func defaultOnField(_ lexer.Position, _, _ string) error { return nil }
func defaultOnComment(_ lexer.Position, _ string) error { return nil }
func defaultOnError(pos lexer.Position, content string, err error) error {
return &lexer.Error{
Line: pos.Line,
Column: pos.Column,
Content: content,
Err: err,
}
}
func (p *Parser) setDefaults() {
if p.OnSection == nil {
p.OnSection = defaultOnSection
}
if p.OnField == nil {
p.OnField = defaultOnField
}
if p.OnComment == nil {
p.OnComment = defaultOnComment
}
if p.OnError == nil {
p.OnError = defaultOnError
}
}
// NewParser creates a dosini-style parser using