From 79c570c53e7b2ea94b2ca35eb01cf6f18dda25b9 Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Sat, 13 Oct 2012 21:16:48 -0400 Subject: [PATCH] basic lexing --- input.lisp | 11 ++++ skeam.go | 169 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 input.lisp create mode 100644 skeam.go diff --git a/input.lisp b/input.lisp new file mode 100644 index 0000000..d529718 --- /dev/null +++ b/input.lisp @@ -0,0 +1,11 @@ +(+ 1 (+ 1 1) (dave (sam 1))) + +(+ 1 + 2 + 3 + 4 + (dave + 1 + 2 + 3 + (sam 3 2 2))) diff --git a/skeam.go b/skeam.go new file mode 100644 index 0000000..8b933e5 --- /dev/null +++ b/skeam.go @@ -0,0 +1,169 @@ +package main + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "os" +) + +type stateFn func(*lexer) (stateFn, error) + +type lexer struct { + input io.ReadCloser + buf *bytes.Buffer + cur []rune + depth int + out chan string +} + +func (l *lexer) next() (rune, error) { + r, _, err := l.buf.ReadRune() + return r, err +} + +func (l *lexer) emit() { + l.out <- string(l.cur) + l.cur = nil +} + +func (l *lexer) append(r rune) { + if l.cur == nil { + l.cur = []rune{r} + return + } + l.cur = append(l.cur, r) +} + +func lexRoot(l *lexer) (stateFn, error) { + r, err := l.next() + if err != nil { + return nil, err + } + switch r { + case '(': + l.append(r) + l.emit() + return lexOpenParen, nil + case ' ', '\t', '\n': + return lexRoot, nil + } + return nil, fmt.Errorf("unexpected rune in lexRoot: %c", r) +} + +func lexOpenParen(l *lexer) (stateFn, error) { + l.depth++ + r, err := l.next() + if err != nil { + return nil, err + } + switch r { + case ' ', '\t', '\n': + return lexRoot, nil + case '(': + return nil, fmt.Errorf("the whole (( thing isn't supported yet") + default: + l.append(r) + return lexOnSymbol, nil + } + panic("not reached") +} + +func lexOnSymbol(l *lexer) (stateFn, error) { + r, err := l.next() + if err != nil { + return nil, err + } + switch r { + case ' ', '\t', '\n': + l.emit() + return lexWhitespace, nil + case ')': + l.emit() + l.append(r) + l.emit() + return lexCloseParen, nil + default: + l.append(r) + return lexOnSymbol, nil + } + panic("not reached") +} + +func lexWhitespace(l *lexer) (stateFn, error) { + r, err := l.next() + if err != nil { + return nil, err + } + switch r { + case ' ', '\t', '\n': + return lexWhitespace, nil + case '(': + l.append(r) + l.emit() + return lexOpenParen, nil + default: + l.append(r) + return lexOnSymbol, nil + } + panic("not reached") +} + +func lexCloseParen(l *lexer) (stateFn, error) { + l.depth-- + r, err := l.next() + if err != nil { + return nil, err + } + switch r { + case ' ', '\t', '\n': + if l.depth == 0 { + return lexRoot, nil + } else { + return lexWhitespace, nil + } + case ')': + l.append(r) + l.emit() + return lexCloseParen, nil + } + return nil, fmt.Errorf("unimplemented") +} + +func lex(b []byte, c chan string) { + defer close(c) + l := &lexer{ + buf: bytes.NewBuffer(b), + out: c, + } + + var err error + f := stateFn(lexRoot) + for err == nil { + f, err = f(l) + } + if err != io.EOF { + fmt.Println(err) + } + if l.depth != 0 { + fmt.Println("error: unbalanced parenthesis") + } +} + +func main() { + filename := "input.lisp" + + b, err := ioutil.ReadFile(filename) + if err != nil { + fmt.Fprintln(os.Stderr, "unable to read file ", filename) + os.Exit(1) + } + + c := make(chan string) + go lex(b, c) + + for s := range c { + fmt.Println(s) + } +}