diff options
Diffstat (limited to 'conflang.go')
-rw-r--r-- | conflang.go | 160 |
1 files changed, 0 insertions, 160 deletions
diff --git a/conflang.go b/conflang.go deleted file mode 100644 index 0b4a856..0000000 --- a/conflang.go +++ /dev/null @@ -1,160 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "io" -) - -type toktype int - -const ( - tText toktype = iota - tNextCmd -) - -type token struct { - Type toktype - Data string - Line int -} - -func scan(r io.Reader, tokens chan<- token, errch chan<- error) { - emit := func(t toktype, d []byte, line int) { - if t == tText && len(d) == 0 { - return - } - tokens <- token{t, string(d), line} - } - - err := func() error { - br := bufio.NewReader(r) - - escaped := false - data := []byte{} - line := 1 - - for { - b, err := br.ReadByte() - - switch err { - case nil: - case io.EOF: - return nil - default: - return ErrorAtLine{line, err} - } - - if b == '\n' { - line++ - } - - if escaped { - data = append(data, b) - escaped = false - continue - } - - switch b { - case '\\': - escaped = true - case ' ', '\t': - emit(tText, data, line) - data = data[:0] - case '\n': - emit(tText, data, line) - data = data[:0] - emit(tNextCmd, nil, line) - default: - data = append(data, b) - } - } - - emit(tText, data, line) - emit(tNextCmd, nil, line) - return nil - }() - - close(tokens) - errch <- err -} - -type command struct { - Name string - Params []string - Line int -} - -func parse(tokens <-chan token, cmds chan<- command) { - defer close(cmds) - - startcmd := true - cmd := command{"", make([]string, 0), 0} - - for tok := range tokens { - switch tok.Type { - case tText: - if startcmd { - cmd.Name = tok.Data - cmd.Line = tok.Line - startcmd = false - } else { - cmd.Params = append(cmd.Params, tok.Data) - } - case tNextCmd: - if !startcmd { - cmds <- cmd - cmd.Name = "" - cmd.Params = make([]string, 0) - startcmd = true - } - } - } -} - -type cmdfunc func(params []string) error - -var commands = map[string]cmdfunc{ - "nop": func(_ []string) error { return nil }, -} - -func RegisterCommand(name string, f cmdfunc) { - commands[name] = f -} - -type ErrorAtLine struct { - Line int - Err error -} - -func (err ErrorAtLine) Error() string { - return fmt.Sprintf("%s (at line %d)", err.Err, err.Line) -} - -type CommandNotFound string - -func (c CommandNotFound) Error() string { - return fmt.Sprintf("Command \"%s\" not found", c) -} - -func RunCommands(r io.Reader) error { - errch := make(chan error) - tokens := make(chan token) - cmds := make(chan command) - - go scan(r, tokens, errch) - go parse(tokens, cmds) - - for cmd := range cmds { - f, ok := commands[cmd.Name] - if !ok { - return ErrorAtLine{cmd.Line, CommandNotFound(cmd.Name)} - } - - if err := f(cmd.Params); err != nil { - return ErrorAtLine{cmd.Line, err} - } - } - - return <-errch -} |