hmm, tcp should work more like local...

master
Jordan Orelli 12 years ago
parent a85d6b869f
commit d672d51f7d

@ -10,13 +10,9 @@ import (
var tcpAddr = flag.String("tcp", "", "foo") var tcpAddr = flag.String("tcp", "", "foo")
func args() { func runfile() {
flag.Parse() filename := flag.Args()[0]
if *tcpAddr != "" { fmt.Println(filename)
runTCPServer()
return
}
filename := flag.Args()[1]
f, err := os.Open(filename) f, err := os.Open(filename)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "unable to read file ", filename) fmt.Fprintln(os.Stderr, "unable to read file ", filename)

@ -2,12 +2,14 @@ package cm
import ( import (
"net" "net"
"strings"
) )
type Manager struct { type Manager struct {
active map[net.Conn]bool active map[net.Conn]bool
connect chan net.Conn connect chan net.Conn
disconnect chan net.Conn disconnect chan net.Conn
write chan writeOp
} }
func New() *Manager { func New() *Manager {
@ -15,6 +17,7 @@ func New() *Manager {
active: make(map[net.Conn]bool, 10), active: make(map[net.Conn]bool, 10),
connect: make(chan net.Conn), connect: make(chan net.Conn),
disconnect: make(chan net.Conn), disconnect: make(chan net.Conn),
write: make(chan writeOp),
} }
go m.run() go m.run()
return m return m
@ -27,10 +30,20 @@ func (m *Manager) run() {
m.active[conn] = true m.active[conn] = true
case conn := <-m.disconnect: case conn := <-m.disconnect:
delete(m.active, conn) delete(m.active, conn)
case op := <-m.write:
m.broadcast(op)
} }
} }
} }
func (m *Manager) broadcast(op writeOp) {
var res writeResponse
for conn, _ := range m.active {
res.add(conn.Write(op.data))
}
op.reply <- res
}
func (m *Manager) Add(conn net.Conn) { func (m *Manager) Add(conn net.Conn) {
m.connect <- conn m.connect <- conn
} }
@ -38,3 +51,51 @@ func (m *Manager) Add(conn net.Conn) {
func (m *Manager) Remove(conn net.Conn) { func (m *Manager) Remove(conn net.Conn) {
m.disconnect <- conn m.disconnect <- conn
} }
func (m *Manager) Write(b []byte) (int, error) {
op := *newWriteOp(b)
m.write <- op
res := <-op.reply
return res.i, res.e
}
type multiError []error
func (e multiError) add(err error) {
if e == nil {
e = make([]error, 0, 4)
}
e = append(e, err)
}
func (e multiError) Error() string {
messages := make([]string, len(e))
for i, _ := range e {
messages[i] = e[i].Error()
}
return strings.Join(messages, " | ")
}
type writeResponse struct {
i int
e multiError
}
func (res writeResponse) add(n int, e error) {
if e != nil {
res.e.add(e)
}
res.i += n
}
type writeOp struct {
data []byte
reply chan writeResponse
}
func newWriteOp(b []byte) *writeOp {
return &writeOp{
data: b,
reply: make(chan writeResponse),
}
}

@ -3,6 +3,7 @@ package main
import ( import (
"bufio" "bufio"
"errors" "errors"
"flag"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -140,22 +141,23 @@ func (s *sexp) readIn(c chan token) error {
} }
// parses one value that can be evaled from the channel // parses one value that can be evaled from the channel
func parse(c chan token) (interface{}, error) { func parse(c chan token) (interface{}, bool, error) {
for t := range c { for t := range c {
switch t.t { switch t.t {
case closeParenToken: case closeParenToken:
return nil, errors.New("unexpected EOF in read") return nil, false, errors.New("unexpected EOF in read")
case openParenToken: case openParenToken:
s := newSexp() s := newSexp()
if err := s.readIn(c); err != nil { if err := s.readIn(c); err != nil {
return nil, err return nil, true, err
} }
return s, nil return s, false, nil
default: default:
return atom(t) v, err := atom(t)
return v, false, err
} }
} }
return nil, io.EOF return nil, false, io.EOF
} }
func eval(v interface{}, env *environment) (interface{}, error) { func eval(v interface{}, env *environment) (interface{}, error) {
@ -208,7 +210,7 @@ func eval(v interface{}, env *environment) (interface{}, error) {
func evalall(c chan token, out chan interface{}, e chan error, env *environment) { func evalall(c chan token, out chan interface{}, e chan error, env *environment) {
for { for {
v, err := parse(c) v, _, err := parse(c)
switch err { switch err {
case io.EOF: case io.EOF:
return return
@ -237,37 +239,23 @@ func defaultInterpreter(out chan interface{}, errors chan error) {
} }
func main() { func main() {
flag.Parse()
if DEBUG { if DEBUG {
fmt.Println(universe) fmt.Println(universe)
} }
if len(os.Args) > 1 { if *tcpAddr != "" {
args() runTCPServer()
return
}
if len(flag.Args()) > 0 {
runfile()
return return
} }
out, errors := make(chan interface{}), make(chan error) out, errors := make(chan interface{}), make(chan error)
go defaultInterpreter(out, errors) go defaultInterpreter(out, errors)
r := bufio.NewReader(os.Stdin) c := make(chan token, 32)
for { go lex(bufio.NewReader(os.Stdin), c)
fmt.Print("> ") evalall(c, out, errors, universe)
line, prefix, err := r.ReadLine()
if prefix {
fmt.Println("(prefix)")
}
switch err {
case nil:
break
case io.EOF:
fmt.Print("\n")
return
default:
fmt.Println("error: ", err)
continue
}
c := make(chan token, 32)
go lexs(string(line)+"\n", c)
evalall(c, out, errors, universe)
}
} }

@ -11,19 +11,15 @@ import (
var manager = cm.New() var manager = cm.New()
func tcpInterpreter(conn net.Conn, userinput chan string, out chan interface{}, errors chan error) { func tcpInterpreter(conn net.Conn, userinput chan string, out chan interface{}, errors chan error) {
prompt := func() {
io.WriteString(conn, "> ")
}
prompt()
for { for {
select { select {
case v := <-out: case v := <-out:
fmt.Fprintln(conn, v) fmt.Fprintln(manager, v)
prompt()
case err := <-errors: case err := <-errors:
fmt.Fprintf(conn, "error: %v", err) fmt.Fprintf(conn, "error: %v", err)
case line := <-userinput: case line := <-userinput:
tokens := make(chan token, 32) tokens := make(chan token, 32)
// this is probably dumb
go lexs(line+"\n", tokens) go lexs(line+"\n", tokens)
go evalall(tokens, out, errors, universe) go evalall(tokens, out, errors, universe)
} }

Loading…
Cancel
Save