diff --git a/lex.go b/lex.go index de374e5..83ed143 100644 --- a/lex.go +++ b/lex.go @@ -10,27 +10,27 @@ type typ3 int const ( invalid typ3 = iota - int3ger - symbol - openParen - closeParen - str1ng - fl0at + integerToken + symbolToken + openParenToken + closeParenToken + stringToken + floatToken ) func (t typ3) String() string { switch t { - case int3ger: + case integerToken: return "integer" - case symbol: + case symbolToken: return "symbol" - case openParen: + case openParenToken: return "open_paren" - case closeParen: + case closeParenToken: return "close_paren" - case str1ng: + case stringToken: return "string" - case fl0at: + case floatToken: return "float" } panic("wtf") @@ -85,7 +85,7 @@ func debugPrint(s string) { // lexes an open parenthesis func lexOpenParen(l *lexer) (stateFn, error) { debugPrint("-->lexOpenParen") - l.out <- token{"(", openParen} + l.out <- token{"(", openParenToken} l.depth++ r, _, err := l.ReadRune() if err != nil { @@ -146,7 +146,7 @@ func lexString(l *lexer) (stateFn, error) { } switch r { case '"': - l.emit(str1ng) + l.emit(stringToken) return lexWhitespace, nil case '\\': return lexStringEsc, nil @@ -177,16 +177,16 @@ func lexInt(l *lexer) (stateFn, error) { } switch r { case ' ', '\t', '\n', '\r': - l.emit(int3ger) + l.emit(integerToken) return lexWhitespace, nil case '.': l.append(r) return lexFloat, nil case ')': - l.emit(int3ger) + l.emit(integerToken) return lexCloseParen, nil case ';': - l.emit(int3ger) + l.emit(integerToken) return lexComment, nil } if isDigit(r) { @@ -207,13 +207,13 @@ func lexFloat(l *lexer) (stateFn, error) { switch r { case ' ', '\t', '\n', '\r': - l.emit(fl0at) + l.emit(floatToken) return lexWhitespace, nil case ')': - l.emit(fl0at) + l.emit(floatToken) return lexCloseParen, nil case ';': - l.emit(fl0at) + l.emit(floatToken) return lexComment, nil } if isDigit(r) { @@ -234,13 +234,13 @@ func lexSymbol(l *lexer) (stateFn, error) { switch r { case ' ', '\t', '\n', '\r': debugPrint("ending lexSymbol on whitespace") - l.emit(symbol) + l.emit(symbolToken) return lexWhitespace, nil case ')': - l.emit(symbol) + l.emit(symbolToken) return lexCloseParen, nil case ';': - l.emit(symbol) + l.emit(symbolToken) return lexComment, nil default: l.append(r) @@ -252,7 +252,7 @@ func lexSymbol(l *lexer) (stateFn, error) { // lex a close parenthesis func lexCloseParen(l *lexer) (stateFn, error) { debugPrint("-->lexCloseParen") - l.out <- token{")", closeParen} + l.out <- token{")", closeParenToken} l.depth-- r, _, err := l.ReadRune() if err != nil { diff --git a/skeam.go b/skeam.go index 9b93e7a..6203353 100644 --- a/skeam.go +++ b/skeam.go @@ -2,13 +2,92 @@ package main import ( "bufio" + "errors" "fmt" "io" "os" + "strconv" ) var DEBUG = false +type sexp []interface{} + +type symbol string + +// parses the string lexeme into a value that can be eval'd +func atom(t token) (interface{}, error) { + switch t.t { + case integerToken: + val, err := strconv.ParseInt(t.lexeme, 10, 64) + if err != nil { + return nil, err + } + return val, nil + + case floatToken: + val, err := strconv.ParseFloat(t.lexeme, 64) + if err != nil { + return nil, err + } + return val, nil + + case stringToken: + return t.lexeme, nil + + case symbolToken: + return symbol(t.lexeme), nil + } + + return nil, fmt.Errorf("unable to atomize token: %v", t) +} + +// reads in tokens on the channel until a matching close paren is found. +func (s *sexp) readIn(c chan token) error { + for t := range c { + switch t.t { + case closeParenToken: + return nil + case openParenToken: + child := make(sexp, 0) + if err := child.readIn(c); err != nil { + return err + } + *s = append(*s, child) + default: + v, err := atom(t) + if err != nil { + return err + } + *s = append(*s, v) + } + } + return errors.New("unexpected EOF in sexp.readIn") +} + +// parses one value that can be evaled from the channel +func parse(c chan token) (interface{}, error) { + for t := range c { + switch t.t { + case closeParenToken: + return nil, errors.New("unexpected EOF in read") + case openParenToken: + s := make(sexp, 0) + if err := s.readIn(c); err != nil { + return nil, err + } + return s, nil + default: + return atom(t) + } + } + return nil, io.EOF +} + +func eval(v interface{}) { + fmt.Println(v) +} + func args() { filename := os.Args[1] f, err := os.Open(filename) @@ -21,9 +100,17 @@ func args() { c := make(chan token, 32) go lex(bufio.NewReader(f), c) - for s := range c { - fmt.Printf("%11s %s\n", s.t, s.lexeme) - } + for { + v, err := parse(c) + switch err { + case io.EOF: + return + case nil: + eval(v) + default: + fmt.Println("error in args(): %v", err) + } + } } func main() { @@ -52,8 +139,17 @@ func main() { c := make(chan token, 32) go lexs(string(line)+"\n", c) - for s := range c { - fmt.Printf("%11s %s\n", s.t, s.lexeme) - } + for { + v, err := parse(c) + switch err { + case io.EOF: + goto OUT + case nil: + eval(v) + default: + fmt.Println("error in repl: %v", err) + } + } + OUT: } }