From e11bcf3d91e613363efa9e9c91d2aeb81faa0c75 Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Sun, 16 Jun 2013 22:23:35 -0400 Subject: [PATCH] added very sloppy tcp functionality can now send multi-line sexps over TCP. Max line limit is 40 lines in a single sexp. A max needed to be selected to prevent clients from filling up enormous buffers. --- skeam.go | 16 +++++------ tcp_connections.go | 67 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 71 insertions(+), 12 deletions(-) diff --git a/skeam.go b/skeam.go index 650302a..0842d19 100644 --- a/skeam.go +++ b/skeam.go @@ -137,27 +137,27 @@ func (s *sexp) readIn(c chan token) error { s.append(v) } } + fmt.Println("sexp.readIn hit weird EOF") return errors.New("unexpected EOF in sexp.readIn") } // parses one value that can be evaled from the channel -func parse(c chan token) (interface{}, bool, error) { +func parse(c chan token) (interface{}, error) { for t := range c { switch t.t { case closeParenToken: - return nil, false, errors.New("unexpected EOF in read") + return nil, errors.New("unexpected close paren in read") case openParenToken: s := newSexp() if err := s.readIn(c); err != nil { - return nil, true, err + return nil, err } - return s, false, nil + return s, nil default: - v, err := atom(t) - return v, false, err + return atom(t) } } - return nil, false, io.EOF + return nil, io.EOF } func eval(v interface{}, env *environment) (interface{}, error) { @@ -210,7 +210,7 @@ func eval(v interface{}, env *environment) (interface{}, error) { func evalall(c chan token, out chan interface{}, e chan error, env *environment) { for { - v, _, err := parse(c) + v, err := parse(c) switch err { case io.EOF: return diff --git a/tcp_connections.go b/tcp_connections.go index 98e7c50..09413be 100644 --- a/tcp_connections.go +++ b/tcp_connections.go @@ -3,14 +3,48 @@ package main import ( "./cm" "bufio" + "errors" "fmt" "io" "net" + "strings" ) +const MAX_SEXP_LINES = 40 + var manager = cm.New() +var errSexpTooLong = errors.New("error: sexp is too long") + +func depth(s string) int { + n := 0 + for _, r := range s { + switch r { + case '(': + n += 1 + case ')': + n -= 1 + } + } + return n +} func tcpInterpreter(conn net.Conn, userinput chan string, out chan interface{}, errors chan error) { + lines := make([]string, 0, MAX_SEXP_LINES) + currentDepth := 0 + addLine := func(line string) error { + if len(lines) >= MAX_SEXP_LINES { + return errSexpTooLong + } + lines = append(lines, line) + return nil + } + errorMode := false + skipLine := func(line string) { + currentDepth += depth(line) + if currentDepth == 0 { + errorMode = false + } + } for { select { case v := <-out: @@ -18,10 +52,35 @@ func tcpInterpreter(conn net.Conn, userinput chan string, out chan interface{}, case err := <-errors: fmt.Fprintf(conn, "error: %v", err) case line := <-userinput: - tokens := make(chan token, 32) - // this is probably dumb - go lexs(line+"\n", tokens) - go evalall(tokens, out, errors, universe) + if errorMode { + skipLine(line) + break + } + lineDepth := depth(line) + currentDepth += lineDepth + + if len(lines) == 0 && lineDepth == 0 { + tokens := make(chan token, 32) + go lexs(line+"\n", tokens) + go evalall(tokens, out, errors, universe) + break + } + + if err := addLine(line); err != nil { + fmt.Fprintf(conn, "error in addLine: %v", err) + errorMode = true + lines = lines[:0] + currentDepth = 0 + break + } + + if currentDepth == 0 { + runnable := strings.Join(lines, " ") + lines = lines[:0] + tokens := make(chan token, 32) + go lexs(runnable+"\n", tokens) + go evalall(tokens, out, errors, universe) + } } } }