ah, this is a bit cleaner
parent
4e12cefbba
commit
fb3b11d63c
@ -0,0 +1,118 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func eval(v interface{}, env *environment) (interface{}, error) {
|
||||
if v == nil {
|
||||
return &sexp{}, nil
|
||||
}
|
||||
|
||||
switch t := v.(type) {
|
||||
|
||||
case symbol:
|
||||
debugPrint("eval symbol")
|
||||
s, err := env.get(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return eval(s, env)
|
||||
|
||||
case *sexp:
|
||||
debugPrint("eval sexp")
|
||||
if t.len() == 0 {
|
||||
return nil, errors.New("illegal evaluation of empty sexp ()")
|
||||
}
|
||||
|
||||
if t.quotelvl > 0 {
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// eval the first item
|
||||
v, err := eval(t.items[0], env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c, ok := v.(callable)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`expected special form or builtin procedure, received %v`, reflect.TypeOf(v))
|
||||
}
|
||||
if len(t.items) > 1 {
|
||||
return c.call(env, t.items[1:])
|
||||
}
|
||||
return c.call(env, nil)
|
||||
|
||||
default:
|
||||
debugPrint("default eval")
|
||||
return v, nil
|
||||
}
|
||||
|
||||
panic("not reached")
|
||||
}
|
||||
|
||||
type interpreter struct {
|
||||
in io.Reader // reader of input source code
|
||||
out1 io.Writer // writer of evaluated values
|
||||
out2 io.Writer // writer of error info
|
||||
tokens chan token // tokens returns from the lexer (internal only)
|
||||
values chan interface{} // values returned from the interpreter (internal only)
|
||||
errors chan error // errors returned from the interpreter (internal only)
|
||||
}
|
||||
|
||||
func newInterpreter(in io.Reader, out1, out2 io.Writer) *interpreter {
|
||||
return &interpreter{
|
||||
in: in,
|
||||
out1: out1,
|
||||
out2: out2,
|
||||
tokens: make(chan token),
|
||||
values: make(chan interface{}),
|
||||
errors: make(chan error),
|
||||
}
|
||||
}
|
||||
|
||||
func (i interpreter) run(env *environment) {
|
||||
go lex(bufio.NewReader(i.in), i.tokens)
|
||||
go i.send()
|
||||
for {
|
||||
v, err := parse(i.tokens)
|
||||
switch err {
|
||||
case io.EOF:
|
||||
fmt.Println("EOF lol")
|
||||
return
|
||||
case nil:
|
||||
i.eval(v, env)
|
||||
default:
|
||||
i.errors <- err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (i interpreter) eval(v interface{}, env *environment) {
|
||||
val, err := eval(v, env)
|
||||
if err != nil {
|
||||
i.errors <- err
|
||||
return
|
||||
}
|
||||
i.values <- val
|
||||
}
|
||||
|
||||
func (i interpreter) send() {
|
||||
for {
|
||||
select {
|
||||
case v := <-i.values:
|
||||
if _, err := fmt.Fprintln(i.out1, v); err != nil {
|
||||
fmt.Println("can't write out to client: ", err)
|
||||
}
|
||||
case e := <-i.errors:
|
||||
if _, err := fmt.Fprintln(i.out2, e); err != nil {
|
||||
fmt.Println("can't write error to client: ", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue