ah, this is a bit cleaner

master
Jordan Orelli 11 years ago
parent 4e12cefbba
commit fb3b11d63c

@ -1,7 +1,6 @@
package main
import (
"bufio"
"flag"
"fmt"
"io"
@ -20,12 +19,8 @@ func runfile() {
}
defer f.Close()
out, errors := make(chan interface{}), make(chan error)
go defaultInterpreter(out, errors)
c := make(chan token, 32)
go lex(bufio.NewReader(f), c)
evalall(c, out, errors, universe)
i := newInterpreter(f, os.Stdout, os.Stderr)
i.run(universe)
}
func printErrorMsg(message string) {

@ -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)
}
}
}
}

@ -1,13 +1,11 @@
package main
import (
"bufio"
"errors"
"flag"
"fmt"
"io"
"os"
"reflect"
"strconv"
"strings"
)
@ -162,84 +160,6 @@ func parse(c chan token) (interface{}, error) {
return nil, io.EOF
}
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")
}
func evalall(c chan token, out chan interface{}, e chan error, env *environment) {
for {
v, err := parse(c)
switch err {
case io.EOF:
return
case nil:
if v, err := eval(v, env); err != nil {
e <- err
return
} else {
out <- v
}
default:
e <- err
}
}
}
func defaultInterpreter(out chan interface{}, errors chan error) {
for {
select {
case v := <-out:
fmt.Println(v)
case err := <-errors:
fmt.Printf("error: %v", err)
}
}
}
func main() {
flag.BoolVar(&DEBUG, "debug", false, "puts the interpreter in debug mode")
flag.Parse()
@ -255,10 +175,6 @@ func main() {
return
}
out, errors := make(chan interface{}), make(chan error)
go defaultInterpreter(out, errors)
c := make(chan token, 32)
go lex(bufio.NewReader(os.Stdin), c)
evalall(c, out, errors, universe)
i := newInterpreter(os.Stdin, os.Stdout, os.Stderr)
i.run(universe)
}

@ -1,26 +1,13 @@
package main
import (
"bufio"
"errors"
"fmt"
"github.com/jordanorelli/skeam/cm"
"io"
"net"
)
const MAX_SEXP_LINES = 40
var manager = cm.New()
var errSexpTooLong = errors.New("error: sexp is too long")
type tcpInterpreter struct {
fout io.Writer // buffered file-like output stream
ferr io.Writer // buffered file-like error stream
tokens chan token // tokens returns from the lexer
values chan interface{} // values returned from the interpreter
errors chan error // errors returned from the interpreter
}
func runTCPServer() {
addr, err := net.ResolveTCPAddr("tcp", *tcpAddr)
@ -41,43 +28,10 @@ func runTCPServer() {
}
}
func newTcpInterpreter() *tcpInterpreter {
return &tcpInterpreter{
tokens: make(chan token),
values: make(chan interface{}),
errors: make(chan error),
}
}
func (t *tcpInterpreter) send() {
for {
select {
case v := <-t.values:
if _, err := fmt.Fprintln(t.fout, v); err != nil {
fmt.Println("can't write out to client: ", err)
}
case e := <-t.errors:
if _, err := fmt.Fprintln(t.ferr, e); err != nil {
fmt.Println("can't write error to client: ", err)
}
}
}
}
func (t *tcpInterpreter) Run(in io.Reader, out, errors io.Writer) {
go lex(bufio.NewReader(in), t.tokens)
t.fout = out
t.ferr = errors
go t.send()
evalall(t.tokens, t.values, t.errors, universe)
}
func startConnection(conn net.Conn, m *cm.Manager) {
m.Add(conn)
defer m.Remove(conn)
i := newTcpInterpreter()
i.Run(conn, conn, conn)
i := newInterpreter(conn, conn, conn)
i.run(universe)
}

Loading…
Cancel
Save