veyron/tools/naming/simulator: reworked to use new modules and to be more useful.

Change-Id: Ieef4412b995b289957326cc06f2c48990ba99112
diff --git a/lib/modules/core/core.go b/lib/modules/core/core.go
index 980313e..98a6656 100644
--- a/lib/modules/core/core.go
+++ b/lib/modules/core/core.go
@@ -53,6 +53,10 @@
 	ResolveMTCommand         = "resolveMT"
 	EchoServerCommand        = "echoServer"
 	EchoClientCommand        = "echoClient"
+	SleepCommand             = "sleep"
+	TimeCommand              = "time"
+	MountCommand             = "mount"
+	NamespaceCacheCommand    = "cache"
 )
 
 // NewShell returns a new Shell instance with the core commands installed.
@@ -77,6 +81,14 @@
 	resolves name to obtain a mount table address`)
 	shell.AddFunction(SetNamespaceRootsCommand, setNamespaceRoots, `<name>...
 	set the in-process namespace roots to <name>...`)
+	shell.AddFunction(SleepCommand, sleep, `[duration]
+	sleep for a time (in go time.Duration format): defaults to 1s`)
+	shell.AddFunction(TimeCommand, now, `
+	prints the current time`)
+	shell.AddFunction(NamespaceCacheCommand, namespaceCache, `on|off
+	turns the namespace cache on or off`)
+	shell.AddFunction(MountCommand, mountServer, `<mountpoint> <server> <ttl>
+	invokes namespace.Mount(<mountpoint>, <server>, <ttl>)`)
 	shell.AddSubprocess(EchoClientCommand, `<name> <message>...
 	invokes name.Echo(message)`)
 	shell.AddSubprocess(EchoServerCommand, `<name> <text>
diff --git a/lib/modules/core/echo.go b/lib/modules/core/echo.go
index ae37372..55bc787 100644
--- a/lib/modules/core/echo.go
+++ b/lib/modules/core/echo.go
@@ -8,6 +8,7 @@
 	"veyron.io/veyron/veyron2/ipc"
 	"veyron.io/veyron/veyron2/naming"
 	"veyron.io/veyron/veyron2/rt"
+	"veyron.io/veyron/veyron2/security"
 
 	"veyron.io/veyron/veyron/lib/modules"
 )
@@ -17,19 +18,29 @@
 	modules.RegisterChild(EchoClientCommand, echoClient)
 }
 
+type treeDispatcher struct{ id string }
+
+func (d treeDispatcher) Lookup(suffix, method string) (ipc.Invoker, security.Authorizer, error) {
+	return ipc.ReflectInvoker(&echoServerObject{d.id, suffix}), nil, nil
+}
+
 type echoServerObject struct {
-	id string
+	id, suffix string
 }
 
 func (es *echoServerObject) Echo(call ipc.ServerCall, m string) (string, error) {
-	return es.id + ": " + m + "\n", nil
+	if len(es.suffix) > 0 {
+		return fmt.Sprintf("%s.%s: %s\n", es.id, es.suffix, m), nil
+	}
+	return fmt.Sprintf("%s: %s\n", es.id, m), nil
 }
 
 func echoServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
 	if len(args) != 2 {
 		return fmt.Errorf("wrong # args")
 	}
-	id, mountPoint := args[0], args[1]
+	id, mp := args[0], args[1]
+	disp := &treeDispatcher{id: id}
 	server, err := rt.R().NewServer()
 	if err != nil {
 		return err
@@ -39,7 +50,7 @@
 	if err != nil {
 		return err
 	}
-	if err := server.Serve(mountPoint, ipc.LeafDispatcher(&echoServerObject{id: id}, nil)); err != nil {
+	if err := server.Serve(mp, disp); err != nil {
 		return err
 	}
 	fmt.Fprintf(stdout, "NAME=%s\n", naming.MakeTerminal(naming.JoinAddressName(ep.String(), "")))
@@ -50,7 +61,6 @@
 }
 
 func echoClient(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
-
 	if len(args) < 2 {
 		return fmt.Errorf("wrong # args")
 	}
diff --git a/lib/modules/core/misc.go b/lib/modules/core/misc.go
new file mode 100644
index 0000000..e0c1496
--- /dev/null
+++ b/lib/modules/core/misc.go
@@ -0,0 +1,64 @@
+package core
+
+import (
+	"fmt"
+	"io"
+	"time"
+
+	"veyron.io/veyron/veyron2/naming"
+	"veyron.io/veyron/veyron2/rt"
+)
+
+func sleep(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+	d := time.Second
+	if len(args) > 0 {
+		var err error
+		if d, err = time.ParseDuration(args[0]); err != nil {
+			return err
+		}
+	}
+	fmt.Fprintf(stdout, "Sleeping for %s", d)
+	// TODO(cnicolaou): we should probably also listen for stdin closing
+	// and return before the sleep completes.
+	time.Sleep(d)
+	return nil
+}
+
+func now(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+	fmt.Fprintf(stdout, "%s\n", time.Now())
+	return nil
+}
+
+func mountServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+	if len(args) != 3 {
+		return fmt.Errorf("wrong # args")
+	}
+	mp, server, ttlstr := args[0], args[1], args[2]
+	ttl, err := time.ParseDuration(ttlstr)
+	if err != nil {
+		return fmt.Errorf("failed to parse time from %q", ttlstr)
+	}
+	ns := rt.R().Namespace()
+	if err := ns.Mount(rt.R().NewContext(), mp, server, ttl); err != nil {
+		return err
+	}
+	fmt.Fprintf(stdout, "Mount(%s, %s, %s)\n", mp, server, ttl)
+	return nil
+}
+
+func namespaceCache(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+	if len(args) != 1 {
+		return fmt.Errorf("wrong # args")
+	}
+	disable := true
+	switch args[0] {
+	case "on":
+		disable = false
+	case "off":
+		disable = true
+	default:
+		return fmt.Errorf("arg must be 'on' or 'off'")
+	}
+	rt.R().Namespace().CacheCtl(naming.DisableCache(disable))
+	return nil
+}
diff --git a/lib/modules/core/mounttable.go b/lib/modules/core/mounttable.go
index 1c523e0..8d63006 100644
--- a/lib/modules/core/mounttable.go
+++ b/lib/modules/core/mounttable.go
@@ -58,6 +58,7 @@
 	}
 	name := naming.JoinAddressName(ep.String(), "")
 	fmt.Fprintf(stdout, "MT_NAME=%s\n", name)
+	fmt.Fprintf(stdout, "MT_ADDR=%s\n", ep.String())
 	fmt.Fprintf(stdout, "PID=%d\n", os.Getpid())
 	modules.WaitForEOF(stdin)
 	return nil
@@ -82,7 +83,7 @@
 				output += fmt.Sprintf("R%d=%s[", entry, n.Name)
 				t := ""
 				for _, s := range n.Servers {
-					output += fmt.Sprintf("%s:%ss, ", s.Server, s.TTL)
+					t += fmt.Sprintf("%s:%s, ", s.Server, s.TTL)
 				}
 				t = strings.TrimSuffix(t, ", ")
 				output += fmt.Sprintf("%s]\n", t)
@@ -110,6 +111,7 @@
 	name := args[0]
 	servers, err := fn(rt.R().NewContext(), name)
 	if err != nil {
+		fmt.Fprintf(stdout, "RN=0\n")
 		return err
 	}
 	fmt.Fprintf(stdout, "RN=%d\n", len(servers))
diff --git a/lib/modules/exec.go b/lib/modules/exec.go
index 20137b1..e2e35db 100644
--- a/lib/modules/exec.go
+++ b/lib/modules/exec.go
@@ -54,8 +54,9 @@
 	return fl
 }
 
-// IsTestSubprocess returns true if it is called in via -run=TestHelperProcess
-// which normally only ever happens for subprocess run from tests.
+// IsTestHelperProces returns true if it is called in via
+// -run=TestHelperProcess which normally only ever happens for subprocesses
+// run from tests.
 func IsTestHelperProcess() bool {
 	runFlag := flag.Lookup("test.run")
 	if runFlag == nil {
@@ -188,7 +189,7 @@
 	return eh.cmd.Wait()
 }
 
-const shellEntryPoint = "VEYRON_SHELL_HELPER_PROCESS_ENTRY_POINT"
+const ShellEntryPoint = "VEYRON_SHELL_HELPER_PROCESS_ENTRY_POINT"
 
 func RegisterChild(name string, main Main) {
 	child.Lock()
@@ -208,9 +209,9 @@
 }
 
 func (child *childRegistrar) dispatch() error {
-	command := os.Getenv(shellEntryPoint)
+	command := os.Getenv(ShellEntryPoint)
 	if len(command) == 0 {
-		return fmt.Errorf("Failed to find entrypoint %q", shellEntryPoint)
+		return fmt.Errorf("Failed to find entrypoint %q", ShellEntryPoint)
 	}
 	child.Lock()
 	m := child.mains[command]
diff --git a/lib/modules/func.go b/lib/modules/func.go
index f44127b..319a673 100644
--- a/lib/modules/func.go
+++ b/lib/modules/func.go
@@ -70,6 +70,9 @@
 
 		err := main(stdin, stdout, stderr, sh.mergeOSEnv(), args...)
 		if err != nil {
+			// Print the error to stdout to ensure that anyone reading
+			// only stdout sees the error.
+			fmt.Fprintf(stdout, "%s\n", err)
 			fmt.Fprintf(stderr, "%s\n", err)
 		}
 
diff --git a/lib/modules/modules_internal_test.go b/lib/modules/modules_internal_test.go
index 920538d..000819b 100644
--- a/lib/modules/modules_internal_test.go
+++ b/lib/modules/modules_internal_test.go
@@ -31,6 +31,7 @@
 
 func TestState(t *testing.T) {
 	sh := NewShell()
+
 	sh.AddSubprocess("echonotregistered", "[args]*")
 	sh.AddSubprocess("echos", "[args]*")
 	sh.AddFunction("echof", Echo, "[args]*")
diff --git a/lib/modules/shell.go b/lib/modules/shell.go
index 2e35c97..561e3b2 100644
--- a/lib/modules/shell.go
+++ b/lib/modules/shell.go
@@ -129,7 +129,7 @@
 	if !child.hasCommand(name) {
 		vlog.Infof("Warning: %q is not registered with modules.Dispatcher", name)
 	}
-	entryPoint := shellEntryPoint + "=" + name
+	entryPoint := ShellEntryPoint + "=" + name
 	sh.mu.Lock()
 	sh.cmds[name] = &commandDesc{func() command { return newExecHandle(entryPoint) }, help}
 	sh.mu.Unlock()
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index 2dfecec..ebabe5a 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -493,7 +493,7 @@
 		return fc.close(verror.ConvertWithDefault(verror.Internal, fc.response.Error))
 	}
 	if got, want := fc.response.NumPosResults, uint64(len(resultptrs)); got != want {
-		return fc.close(verror.BadProtocolf("ipc: server sent %d results, client expected %d", got, want))
+		return fc.close(verror.BadProtocolf("ipc: server sent %d results, client expected %d (%#v)", got, want, resultptrs))
 	}
 	for ix, r := range resultptrs {
 		if err := fc.dec.Decode(r); err != nil {
diff --git a/tools/naming/simulator/ambiguity.scr b/tools/naming/simulator/ambiguity.scr
new file mode 100644
index 0000000..2974986
--- /dev/null
+++ b/tools/naming/simulator/ambiguity.scr
@@ -0,0 +1,45 @@
+# This is p's 'ambiguity' example
+#
+# mountMT("/s1/a", "/s2/b")
+# mountMT("/s2/b", "/s3/c")
+# mount("/s3/c", "/s4/d")
+#
+# Bogdan points out that: 'we will actually have d == "" in the echo example
+# below (since Serve only mounts endpoints without suffixes)'
+#
+# I'm not using any local names because its easier to not get confused
+# this way.
+#
+# resolve("/s1/a") can now have 4 possible objects, the mount point in server1,
+# the mount point in server2, the mount point in server3, and the object d in
+# server4.  When we make a call, like SetACL, how do we tell which one to
+# modify?   If we glob("/s1/a") we get:
+#
+# "s1/a", ["/s2/b"(mountpoint)]
+# "s1/a", ["/s3/c"(mountpoint)]
+# "s1/a", ["/s4/d"(mountpoint)]
+# "s1/a", []
+
+root
+eval $_
+set s1=$MT_NAME
+
+root
+eval $_
+set s2=$MT_NAME
+
+root
+eval $_
+set s3=$MT_NAME
+
+mount $s1/a $s2/b 1h
+
+mount $s2/b $s3/c 1h
+
+echoServer "Echo" $s3/c
+
+ls $s1/...
+wait $_
+
+ls $s1/a
+wait $_
diff --git a/tools/naming/simulator/clock.scr b/tools/naming/simulator/clock.scr
deleted file mode 100644
index ac1dd39..0000000
--- a/tools/naming/simulator/clock.scr
+++ /dev/null
@@ -1,57 +0,0 @@
-#
-# Simple example to show how names work and are used both without
-# and with a mount table.
-#
-
-# A 'stand-alone' server
-clockServer "" ""
-set STAND_ALONE_CLOCK_NAME=$NAME
-
-set N=$STAND_ALONE_CLOCK_NAME
-print "Stand alone clock server at" $N
-time $N "Using $N"
-set N=/$ADDR
-time $N "Using $N"
-
-# Run a root MountTable.
-rootMT
-set ROOT_ADDR=$MT_ADDR ROOT_NAME=$MT_NAME
-print ""
-print "Root MountTable at $ROOT_NAME"
-
-clockServer $MT_NAME clock
-set CLOCK_NAME=/$ADDR
-print "Running Clock Server at $CLOCK_NAME"
-
-# Still bypassing the MountTable
-time $CLOCK_NAME bar
-
-# Now, let's use the MountTable
-setLocalRoots $ROOT_NAME
-
-set N=clock
-resolve $N
-print $N -> $R0
-
-set N=/$ROOT_ADDR/clock
-resolve $N
-print $N -> $R0
-
-# ls * returns clock
-ls *
-# ls ... returns "" and clock - i.e two items. Is this a bug?
-ls ...
-
-# These all behave as above
-lsmt $ROOT_NAME *
-lsmt $ROOT_NAME ...
-
-# Conclusion: some of this behaviour seems a little awkward. In particular:
-#
-# The client neeeds to use a different form of the name depending on whether
-# a MountTable is used or not. If a MountTable is not used, then the internal
-# 'suffix' (/mt) in the examples above must be used. If a MountTable is used
-# then the internal suffix must not be included in the name.
-#
-# ls ... seems to always return an extra, zero length, string as entry
-#
diff --git a/tools/naming/simulator/commands.go b/tools/naming/simulator/commands.go
index 712e2e6..b05538a 100644
--- a/tools/naming/simulator/commands.go
+++ b/tools/naming/simulator/commands.go
@@ -2,142 +2,171 @@
 
 import (
 	"fmt"
-	"time"
+	"os"
+	"regexp"
+	"strings"
 
-	"veyron.io/veyron/veyron/lib/testutil/modules"
-
-	"veyron.io/veyron/veyron2/vlog"
+	"veyron.io/veyron/veyron/lib/modules"
 )
 
-type tag int
+type builtinCmd func(sh *modules.Shell, state *cmdState, args ...string) (string, error)
 
-const (
-	helpTag tag = iota
-	getTag
-	setTag
-	printTag
-	sleepTag
-)
+var varRE = regexp.MustCompile("(.*)=(.*)")
 
-type builtin struct{ tag }
-
-func helpF() modules.T {
-	return &builtin{helpTag}
+var builtins = map[string]*struct {
+	nargs       int
+	usage       string
+	needsHandle bool
+	fn          builtinCmd
+}{
+	"print":  {-1, "print <args>...", false, print},
+	"help":   {-1, "help", false, nil},
+	"set":    {-1, "set <var>=<val>...", false, set},
+	"assert": {2, "val1 val2", false, assert},
+	"read":   {-1, "read <handle> [var]", true, read},
+	"eval":   {1, "eval <handle>", true, eval},
+	"wait":   {1, "wait <handle>", true, wait},
+	"list":   {0, "list", false, list},
+	"quit":   {0, "quit", false, quit},
 }
 
-func sleepF() modules.T {
-	return &builtin{sleepTag}
+func init() {
+	builtins["help"].fn = help
 }
 
-func getF() modules.T {
-	return &builtin{getTag}
+func print(_ *modules.Shell, _ *cmdState, args ...string) (string, error) {
+	r := strings.Join(args, " ")
+	return r, nil
 }
 
-func setF() modules.T {
-	return &builtin{setTag}
-}
-
-func printF() modules.T {
-	return &builtin{printTag}
-}
-
-func (b *builtin) Help() string {
-	switch b.tag {
-	case helpTag:
-		return "[command]"
-	case sleepTag:
-		return `[duration]
-	sleep for a time (in go time.Duration format): defaults to 1s`
-	case getTag:
-		return "[<global variable name>]*"
-	case setTag:
-		return "[<var>=<val>]+"
-	case printTag:
-		return "[$<var>]*"
-	default:
-		return fmt.Sprintf("unrecognised tag for builtin: %d", b.tag)
-	}
-}
-
-func (*builtin) Daemon() bool { return false }
-
-func (b *builtin) Run(args []string) (modules.Variables, []string, modules.Handle, error) {
-	switch b.tag {
-	case helpTag:
-		return helpCmd(args)
-	case sleepTag:
-		return sleep(args)
-	case getTag:
-		return get(args)
-	case setTag:
-		return set(args)
-	case printTag:
-		return print(args)
-	default:
-		return nil, nil, nil, fmt.Errorf("unrecognised tag for builtin: %d",
-			b.tag)
-	}
-}
-
-func helpCmd([]string) (modules.Variables, []string, modules.Handle, error) {
-	for k, v := range commands {
-		if k == "help" {
-			continue
-		}
-		h := v().Help()
-		if len(h) > 0 {
-			fmt.Printf("%s %s\n\n", k, h)
-		} else {
-			fmt.Println(k)
-		}
-	}
-	return nil, nil, nil, nil
-}
-
-func sleep(args []string) (modules.Variables, []string, modules.Handle, error) {
+func help(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
+	r := ""
 	if len(args) == 0 {
-		vlog.Infof("Sleeping for %s", time.Second)
-		time.Sleep(time.Second)
-		return nil, nil, nil, nil
-	}
-	if d, err := time.ParseDuration(args[0]); err != nil {
-		return nil, nil, nil, err
-	} else {
-		vlog.Infof("Sleeping for %s", d)
-		time.Sleep(d)
-	}
-	return nil, nil, nil, nil
-}
-
-func get(args []string) (modules.Variables, []string, modules.Handle, error) {
-	var r []string
-	if len(args) == 0 {
-		for k, v := range globals {
-			r = append(r, fmt.Sprintf("\t%q=%q\n", k, v))
+		for k, _ := range builtins {
+			if k == "help" {
+				continue
+			}
+			r += k + ", "
 		}
+		r += sh.String()
+		return r, nil
 	} else {
 		for _, a := range args {
-			if v, present := globals[a]; present {
-				r = append(r, fmt.Sprintf("\t%q=%q\n", a, v))
+			if v := builtins[a]; v != nil {
+				r += v.usage + "\n"
+				continue
+			}
+			h := sh.Help(a)
+			if len(h) == 0 {
+				return "", fmt.Errorf("unknown command: %q", a)
 			} else {
-				return nil, nil, nil, fmt.Errorf("unknown variable %q", a)
+				r += h
 			}
 		}
 	}
-	return nil, r, nil, nil
+	return r, nil
 }
 
-func set(args []string) (modules.Variables, []string, modules.Handle, error) {
-	for _, a := range args {
-		globals.UpdateFromString(a)
+func parseVar(expr string) (string, string, error) {
+	m := varRE.FindAllStringSubmatch(expr, 1)
+	if len(m) != 1 || len(m[0]) != 3 {
+		return "", "", fmt.Errorf("%q is not an assignment statement", expr)
 	}
-	return nil, nil, nil, nil
+	return m[0][1], m[0][2], nil
 }
 
-func print(args []string) (modules.Variables, []string, modules.Handle, error) {
-	var r []string
-	for _, a := range args {
-		r = append(r, a)
+func set(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
+	r := ""
+	if len(args) == 0 {
+		for _, v := range sh.Env() {
+			r += v + "\n"
+		}
+		return r, nil
 	}
-	return nil, r, nil, nil
+	for _, a := range args {
+		k, v, err := parseVar(a)
+		if err != nil {
+			return "", err
+		}
+		sh.SetVar(k, v)
+	}
+	return "", nil
+}
+
+func assert(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
+	if args[0] != args[1] {
+		return "", fmt.Errorf("assertion failed: %q != %q", args[0], args[1])
+	}
+	return "", nil
+}
+
+func handleWrapper(sh *modules.Shell, fn builtinCmd, args ...string) (string, error) {
+	if len(args) < 1 {
+		return "", fmt.Errorf("missing handle argument")
+	}
+	state := handles[args[0]]
+	if state == nil {
+		return "", fmt.Errorf("invalid handle")
+	}
+	return fn(sh, state, args...)
+}
+
+func read(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
+	l := state.Session.ReadLine()
+	for _, a := range args[1:] {
+		sh.SetVar(a, l)
+	}
+	err := state.Session.Error()
+	if err != nil && strings.HasSuffix(err.Error(), "EOF") {
+		return l, fmt.Errorf("EOF")
+	}
+	return l, state.Session.Error()
+}
+
+func eval(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
+	l := state.Session.ReadLine()
+	k, v, err := parseVar(l)
+	if err != nil {
+		return "", err
+	}
+	sh.SetVar(k, v)
+	return l, nil
+}
+
+func wait(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
+	state.Handle.CloseStdin()
+	r, err := state.Session.Finish(nil)
+	delete(handles, args[0])
+	return r, err
+}
+
+func list(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
+	r := ""
+	for h, v := range handles {
+		r += h + ": " + v.line + "\n"
+	}
+	return r, nil
+}
+
+func quit(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
+	r := ""
+	for k, h := range handles {
+		if err := h.Handle.Shutdown(os.Stdout); err != nil {
+			r += fmt.Sprintf("%s: %v\n", k, err)
+		} else {
+			r += fmt.Sprintf("%s: ok\n", k)
+		}
+	}
+	fmt.Fprintf(os.Stdout, r)
+	os.Exit(0)
+	panic("unreachable")
+}
+
+func getLine(sh *modules.Shell, args ...string) (string, error) {
+	handle := handles[args[0]]
+	if handle == nil {
+		return "", fmt.Errorf("invalid handle")
+	}
+	l := handle.Session.ReadLine()
+	return l, handle.Session.Error()
 }
diff --git a/tools/naming/simulator/driver.go b/tools/naming/simulator/driver.go
index 207c626..3643eda 100644
--- a/tools/naming/simulator/driver.go
+++ b/tools/naming/simulator/driver.go
@@ -2,8 +2,8 @@
 // services as subprocesses and testing interactions between them. It is
 // structured as an interpreter, with global variables and variable
 // expansion, but no control flow. The command set that it supports is
-// extendable by adding new 'modules' that implement the API defined
-// by veyron/lib/testutil/modules.
+// extendable by adding new 'commands' that implement the API defined
+// by veyron/lib/modules.
 package main
 
 import (
@@ -11,55 +11,78 @@
 	"flag"
 	"fmt"
 	"os"
+	"strconv"
 	"strings"
+	"time"
 	"unicode"
 
-	"veyron.io/veyron/veyron/lib/testutil/modules"
-
 	"veyron.io/veyron/veyron2/rt"
+
+	"veyron.io/veyron/veyron/lib/expect"
+	"veyron.io/veyron/veyron/lib/modules"
+	"veyron.io/veyron/veyron/lib/modules/core"
 )
 
-type commandFunc func() modules.T
+type cmdState struct {
+	modules.Handle
+	*expect.Session
+	line string
+}
 
 var (
-	commands    map[string]commandFunc
-	globals     modules.Variables
-	debug       bool
 	interactive bool
+	handles     map[string]*cmdState
 )
 
 func init() {
 	flag.BoolVar(&interactive, "interactive", true, "set interactive/batch mode")
-	flag.BoolVar(&debug, "debug", false, "set debug mode")
+	handles = make(map[string]*cmdState)
+	flag.Usage = usage
+}
 
-	commands = make(map[string]commandFunc)
+var usage = func() {
+	fmt.Println(
+		`Welcome to this simple shell that lets you run mount tables, a simple server
+and sundry other commands from an interactive command line or as scripts. Type
+'help' at the prompt to see a list of available commands, or 'help command' to
+get specific help about that command. The shell provides environment variables
+with expansion and intrinsic support for managing subprocess, but it does not
+provide any flow control commands.
 
-	// We maintaing a single, global, dictionary for variables.
-	globals = make(modules.Variables)
+All commands, except builtin ones (such as help, set, eval etc) are run
+asynchronously in background. That is, the prompt returns as soon as they are
+started and no output is displayed from them unless an error is encountered
+when they are being started. Each input line is numbered and that number is
+used to refer to the standard output of previous started commands. The variable
+_ always contains the number of the immediately preceeding line. It is
+possible to read the output of a command (using the 'read' builtin) and assign
+it that output to an environment variable. The 'eval' builtin parses output of
+the form <var>=<val>. In this way subproccess may be started, their output
+read and used to configure subsequent subprocesses. For example:
 
-	// 'bultins'
-	commands["help"] = helpF
-	commands["get"] = getF
-	commands["set"] = setF
-	commands["print"] = printF
-	commands["sleep"] = sleepF
+1> time
+2> read 1 t
+3> print $t
 
-	// TODO(cnicolaou): add 'STOP' command to shutdown a running server,
-	// need to return the handle and then call Stop on it.
+will print the first line of output from the time command, as will the
+following:
 
-	// modules
-	commands["rootMT"] = modules.NewRootMT
-	commands["nodeMT"] = modules.NewNodeMT
-	commands["setLocalRoots"] = modules.NewSetRoot
-	commands["ls"] = modules.NewGlob
-	commands["lsat"] = modules.NewGlobAt
-	commands["lsmt"] = modules.NewGlobAtMT
-	commands["resolve"] = modules.NewResolve
-	commands["resolveMT"] = modules.NewResolveMT
-	commands["echoServer"] = modules.NewEchoServer
-	commands["echo"] = modules.NewEchoClient
-	commands["clockServer"] = modules.NewClockServer
-	commands["time"] = modules.NewClockClient
+or:
+time
+read $_ t
+print $t
+
+The eval builtin is used to directly to assign to variables specified
+in the output of the command. For example, if the root command
+prints out MT_NAME=foo then eval will set MT_NAME to foo as follows:
+
+root
+eval $_
+print $MT_NAME
+
+will print the value of MT_NAME that is output by the root command.
+`)
+	flag.PrintDefaults()
 }
 
 func prompt(lineno int) {
@@ -69,9 +92,26 @@
 }
 
 func main() {
-	modules.InModule()
 	rt.Init()
 
+	// Subprocesses commands are run by fork/execing this binary
+	// so we must test to see if this instance is a subprocess or the
+	// the original command line instance.
+	if os.Getenv(modules.ShellEntryPoint) != "" {
+		// Subprocess, run the requested command.
+		if err := modules.Dispatch(); err != nil {
+			fmt.Fprintf(os.Stdout, "failed: %v\n", err)
+			fmt.Fprintf(os.Stderr, "failed: %v\n", err)
+			return
+		}
+		return
+	}
+
+	shell := modules.NewShell()
+	defer shell.Cleanup(os.Stderr)
+
+	core.Install(shell)
+
 	scanner := bufio.NewScanner(os.Stdin)
 	lineno := 1
 	prompt(lineno)
@@ -81,14 +121,12 @@
 			if line == "eof" {
 				break
 			}
-			if err := process(line, lineno); err != nil {
-				if debug {
-					fmt.Printf("%d> %s: %v\n", lineno, line, err)
-				} else {
-					fmt.Printf("%d> %v\n", lineno, err)
-				}
+			if err := process(shell, line, lineno); err != nil {
+				fmt.Printf("ERROR: %d> %q: %v\n", lineno, line, err)
+				os.Exit(1)
 			}
 		}
+		shell.SetVar("_", strconv.Itoa(lineno))
 		lineno++
 		prompt(lineno)
 	}
@@ -96,10 +134,19 @@
 		fmt.Printf("error reading input: %v\n", err)
 	}
 
-	modules.Cleanup()
 }
 
-func process(line string, lineno int) error {
+func output(lineno int, line string) {
+	if len(line) > 0 {
+		if !interactive {
+			fmt.Printf("%d> ", lineno)
+		}
+		line = strings.TrimSuffix(line, "\n")
+		fmt.Printf("%s\n", line)
+	}
+}
+
+func process(sh *modules.Shell, line string, lineno int) error {
 	fields, err := splitQuotedFields(line)
 	if err != nil {
 		return err
@@ -115,36 +162,37 @@
 	} else {
 		args = []string{}
 	}
-
-	sub, err := subVariables(args, globals)
-	if err != nil {
-		return err
-	}
-
-	factory := commands[name]
-	if factory == nil {
-		return fmt.Errorf("unrecognised command %q", name)
-	}
-	if vars, output, _, err := factory().Run(sub); err != nil {
-		return err
+	sub, err := subVariables(sh, args)
+	if cmd := builtins[name]; cmd != nil {
+		if cmd.nargs >= 0 && len(sub) != cmd.nargs {
+			return fmt.Errorf("wrong (%d) # args for %q: usage %s", len(sub), name, cmd.usage)
+		}
+		l := ""
+		var err error
+		if cmd.needsHandle {
+			l, err = handleWrapper(sh, cmd.fn, sub...)
+		} else {
+			l, err = cmd.fn(sh, nil, sub...)
+		}
+		if err != nil {
+			return err
+		}
+		output(lineno, l)
 	} else {
-		if debug || interactive {
+		handle, err := sh.Start(name, sub...)
+		if err != nil {
+			return err
+		}
+		handles[strconv.Itoa(lineno)] = &cmdState{
+			handle,
+			expect.NewSession(nil, handle.Stdout(), time.Minute),
+			line,
+		}
+		if !interactive {
 			fmt.Printf("%d> %s\n", lineno, line)
 		}
-		if len(output) > 0 {
-			if !interactive {
-				fmt.Printf("%d> ", lineno)
-			}
-			fmt.Printf("%s\n", strings.Join(output, " "))
-		}
-		if debug && len(vars) > 0 {
-			for k, v := range vars {
-				fmt.Printf("\t%s=%q .... \n", k, v)
-			}
-			fmt.Println()
-		}
-		globals.UpdateFromVariables(vars)
 	}
+
 	return nil
 }
 
@@ -187,11 +235,11 @@
 }
 
 // subVariables substitutes variables that occur in the string slice
-// args with values from vars.
-func subVariables(args []string, vars modules.Variables) ([]string, error) {
+// args with values from the Shell.
+func subVariables(sh *modules.Shell, args []string) ([]string, error) {
 	var results []string
 	for _, a := range args {
-		if r, err := subVariablesInArgument(a, vars); err != nil {
+		if r, err := subVariablesInArgument(sh, a); err != nil {
 			return results, err
 		} else {
 			results = append(results, r)
@@ -206,7 +254,7 @@
 // A variable, is introduced by $, terminated by \t, space, / , : or !.
 // Variables may also be enclosed by {} (as in ${VAR}) to allow for embedding
 // within strings.
-func subVariablesInArgument(a string, vars modules.Variables) (string, error) {
+func subVariablesInArgument(sh *modules.Shell, a string) (string, error) {
 	first := strings.Index(a, "$")
 	if first < 0 {
 		return a, nil
@@ -226,7 +274,7 @@
 			}
 			rem = end + 1
 		} else {
-			end = strings.IndexAny(p, "\t/,:! ")
+			end = strings.IndexAny(p, "\t/,:!= ")
 			if end < 0 {
 				end = len(p)
 			}
@@ -234,9 +282,9 @@
 		}
 		vn = p[start:end]
 		r := p[rem:]
-		v, present := vars[vn]
+		v, present := sh.GetVar(vn)
 		if !present {
-			return "", fmt.Errorf("unknown variable: %q", vn)
+			return a, nil
 		}
 		result += v
 		result += r
diff --git a/tools/naming/simulator/driver_test.go b/tools/naming/simulator/driver_test.go
index ed6f168..b448103 100644
--- a/tools/naming/simulator/driver_test.go
+++ b/tools/naming/simulator/driver_test.go
@@ -4,6 +4,8 @@
 	"fmt"
 	"reflect"
 	"testing"
+
+	"veyron.io/veyron/veyron/lib/modules"
 )
 
 func TestFields(t *testing.T) {
@@ -38,7 +40,8 @@
 }
 
 func TestVariables(t *testing.T) {
-	globals["foo"] = "bar"
+	sh := modules.NewShell()
+	sh.SetVar("foo", "bar")
 	cases := []struct {
 		input  string
 		output []string
@@ -56,7 +59,7 @@
 		if err != nil {
 			t.Errorf("%d: %q: unexpected error: %v", i, c.input, err)
 		}
-		got, err := subVariables(fields, globals)
+		got, err := subVariables(sh, fields)
 		if err != nil {
 			t.Errorf("%d: %q: unexpected error: %v", i, c.input, err)
 		}
@@ -73,7 +76,7 @@
 		{"${fo", fmt.Errorf("unterminated variable: %q", "{fo")},
 	}
 	for i, c := range errors {
-		_, got := subVariables([]string{c.input}, globals)
+		_, got := subVariables(sh, []string{c.input})
 		if got.Error() != c.err.Error() {
 			t.Errorf("%d: %q: expected error: got %q, want %q", i, c.input, got, c.err)
 		}
diff --git a/tools/naming/simulator/echo.scr b/tools/naming/simulator/echo.scr
new file mode 100644
index 0000000..eb5cefc
--- /dev/null
+++ b/tools/naming/simulator/echo.scr
@@ -0,0 +1,55 @@
+# Simple example to show how names work both without and with a mount table
+# and the difference between resolve and resolveMT.
+
+# A 'stand-alone' server
+echoServer "text" ""
+set es=$_
+eval $es
+eval $es
+read $es
+set esName=$NAME
+set esAddr=$ADDR
+
+echoClient $esName "test"
+set ec=$_
+read $ec line
+assert $line "text: test"
+
+wait $es
+wait $ec
+
+# now use a nameserver.
+root
+eval $_
+set root=$MT_NAME
+
+set NAMESPACE_ROOT=$root
+echoServer "text2" "a/b"
+set es=$_
+eval $es
+set es_name=$NAME
+set es_addr=$ADDR
+read $es
+
+echoClient "a/b" "test 2"
+set ec=$_
+read $ec line
+assert $line "text2: test 2"
+
+# resolve will return the server's address
+setRoots $root
+resolve a/b
+set r=$_
+eval $r
+assert $RN 1
+eval $r
+assert $R0 $es_name//
+
+# resolveMT will return the mount table's address (the part before the //)
+resolveMT a/b
+set r=$_
+eval $r
+assert $RN 1
+eval $r
+assert $R0 $root//a/b
+
diff --git a/tools/naming/simulator/mt.scr b/tools/naming/simulator/mt.scr
deleted file mode 100644
index 6f89f70..0000000
--- a/tools/naming/simulator/mt.scr
+++ /dev/null
@@ -1,80 +0,0 @@
-#
-# Example showing multiple mount tables, servers and globing
-#
-
-rootMT
-set ROOT_MT_NAME=$MT_NAME ROOT_MT_ADDR=$MT_ADDR
-set ROOT=$ROOT_MT_NAME
-
-nodeMT $ROOT usa
-set USA_MT=$MT_NAME
-
-nodeMT $USA_MT "palo alto"
-set PA_MT=$MT_NAME
-
-
-print "ROOT MT" $ROOT
-print "USA MT" $USA_MT
-print "Palo Alto MT" $PA_MT
-
-print "--------- Resolve ROOT, ROOT/usa, ROOT/usa/palo alto"
-print "--------- Each should return a different address"
-resolve $ROOT
-resolve $ROOT/usa
-resolve "$ROOT/usa/palo alto"
-
-print "--------- ResolveMT ROOT, ROOT/usa - should return the ROOT MT"
-resolveMT $ROOT
-resolveMT $ROOT/usa
-
-print "--------- ResolveMT ROOT/usa/palo alto/bar should return the palo alto MT"
-resolveMT "$ROOT/usa/palo alto/bar"
-
-# should return a complete hiearchy....
-setLocalRoots $ROOT
-print "--------- setLocalRoots to global root"
-print "--------- ls ..."
-ls ...
-print "--------- ls *"
-ls *
-
-print "--------- setLocalRoots to usa"
-setLocalRoots $USA_MT
-ls ...
-
-print "--------- setLocalRoots to palo alto"
-setLocalRoots $PA_MT
-ls ...
-
-nodeMT $ROOT uk
-set UK_MT=$MT_NAME
-
-nodeMT $UK_MT "cambridge"
-set CAM_MT=$MT_NAME
-
-setLocalRoots $ROOT
-ls ...
-setLocalRoots $UK_MT
-ls ...
-setLocalRoots $CAM_MT
-ls ...
-
-# Create a MountTable tree without using the internal 'mt' suffix as in the
-# examples above.
-nodeMT $ROOT "france"
-set FRANCE_MT=$MT_NAME
-nodeMT $FRANCE_MT "paris"
-setLocalRoots $ROOT
-ls ...
-
-# Conclusion: some of this behaviour seems a little awkward. In particular:
-#
-# ls using the local namespace on a rooted name doesn't seem to work either,
-# thus making it impossible to see the whole name space without setting the
-# local namespace's root which will clearly cause problems for concurrent
-# clients.
-#
-
-
-
-
diff --git a/tools/naming/simulator/mt_complex.scr b/tools/naming/simulator/mt_complex.scr
new file mode 100644
index 0000000..a16a1f1
--- /dev/null
+++ b/tools/naming/simulator/mt_complex.scr
@@ -0,0 +1,255 @@
+# Some more complex uses of mount tables and mounts
+#
+# TODO - list the examples and any issues.
+
+cache off
+
+root
+eval $_
+set root=$MT_NAME
+
+set NAMESPACE_ROOT=$root
+mt tl/a
+set m=$_
+eval $m
+eval $m
+set mt_a_name=$MT_NAME
+set mt_a_addr=$MT_ADDR
+
+mt tl/b
+set m=$_
+eval $m
+eval $m
+set mt_b_name=$MT_NAME
+set mt_b_addr=$MT_ADDR
+
+setRoots $root
+
+#
+# Using glob 'correctly' takes some care. There are (at least?) three
+# forms that you need to consider...
+#
+
+# ls ... finds all of the mount points, as relative names
+ls ...
+set l=$_
+eval $l
+assert $RN 3
+wait $l
+
+# ls /... does not.. - it just finds itself... seems a little weird.
+ls /...
+set l=$_
+eval $l
+assert $RN 1
+wait $l
+
+# a rooted glob finds all of the mount points, include an entry for the root
+# itself. It returns rooted names.
+ls $root/...
+set l=$_
+eval $l
+assert $RN 4
+wait $l
+
+resolve tl/a
+set r=$_
+eval $r
+assert $RN 1
+eval $r
+assert $R0 $mt_a_name
+wait $r
+
+#
+# Now, let's run some echo servers, invoke rpc's on them, see what
+# glob and resolve do.
+#
+
+# run an echo server on tl.
+echoServer "E1" tl
+set es_E1=$_
+read $es_E1
+eval $es_E1
+set es_E1_addr=$ADDR
+
+# the echo server above, obscures the mount tables below it.
+# each of the ls (i.e. glob) calls below will lead to 'ipc:unknown method'
+# errors generated by the echo server.
+ls ...
+set l=$_
+eval $l
+assert $RN 1
+
+ls $root/...
+set l=$_
+eval $l
+assert $RN 2
+
+echoClient tl test
+read $_ o
+assert $o "E1: test"
+
+# resolve will find the address of the echo server.
+resolve tl
+set r=$_
+eval $r
+assert $RN 1
+eval $r
+assert $R0 /$es_E1_addr//
+
+# let's have the echo server shut down
+wait $es_E1
+
+# and now, we can see the mount tables again.
+ls ...
+set l=$_
+eval $l
+assert $RN 3
+wait $l
+
+resolve tl/a
+set r=$_
+eval $r
+assert $RN 1
+eval $r
+assert $R0 $mt_a_name
+
+# run an echo server on tl/a
+echoServer "E2" tl/a
+set es_E2=$_
+read $es_E2
+eval $es_E2
+read $es_E2
+set es_E2_addr=$ADDR
+
+# we can invoke the echo server 'E2' just fine, probably because
+# we just get lucky and get the most recently mounted address back first.
+echoClient "tl/a" bar
+read $_ o
+assert $o "E2: bar"
+
+# but, when we resolve it's name, we get back two servers, one for the
+# mount table and another for the server!
+resolve tl/a
+set r=$_
+eval $r
+assert $RN 2
+eval $r
+assert $R0 /$es_E2_addr//
+eval $r
+assert $R1 $mt_a_name
+
+# resolveMT correctly returns the root's address.
+resolveMT tl/a
+set r=$_
+eval $r
+assert $RN 1
+eval $r
+assert $R0 $root//tl/a
+
+#
+# NOTE: I propose to fix the above ambiguity by having resolve only
+# ever return non-mountpoint servers. To do so, requires that the mount table
+# can tell them apart, which requires the separate Mount and MountMT calls.
+#
+
+# Mount the same server somewhere else
+mount tl/a/c /$es_E2_addr// 1h
+wait $_
+
+ls ...
+wait $_
+
+# this leads to 1 call of ResolveStep for //c on the echo server.
+resolve tl/a/c
+wait $_
+
+# this leads to 2 calls of ResolveStep for //c on the echo server.
+echoClient tl/a/c baz
+read $_ o
+assert $o "E2: baz"
+
+#
+# Can the spurious calls to ResolveStep above be avoided??
+#
+
+# Mount the same server with a really long name.
+set long_name=tl/b/x/y/z/really/long
+mount $long_name /$es_E2_addr// 1h
+wait $_
+
+echoClient $long_name "long baz"
+read $_ o
+assert $o "E2: long baz"
+
+# This example just creates a 'pointer' into the Echo servers name space.
+# NOTE: do we really need this functionality?
+#
+# ResolveStep is again called on the server for //tl/b/x/y/z/really/long
+mount tl/b/short1 /$es_E2_addr/$long_name 1h
+wait $_
+
+echoClient tl/b/short1 "short baz"
+read $_ o
+assert $o E2.${long_name}": short baz"
+
+# Create a mount table with a 'long' name
+set long_name=tl/b/some/deep/name/that/is/a/mount/table
+mt $long_name
+set m=$_
+eval $m
+eval $m
+set mt_l_name=$MT_NAME
+set mt_l_addr=$MT_ADDR
+
+
+# Create a second mount table with a 'long' name
+set second_long_name=tl/a/some/deep/name/that/is/a/mount/table
+mt $second_long_name
+set m=$_
+eval $m
+eval $m
+set mt_l2_name=$MT_NAME
+set mt_l2_addr=$MT_ADDR
+
+# Run an echo server that uses that mount table
+echoServer "E3" $long_name/echo
+set es_E3=$_
+read $es_E3
+eval $es_E3
+set es_E3_addr=$ADDR
+
+echoClient $long_name/echo "long E3"
+read $_ o
+assert $o "E3: long E3"
+
+# make sure that the mount table is the one we expect.
+resolveMT $long_name/echo
+set r=$_
+eval $r
+assert $RN 1
+eval $r
+assert $R0 /$mt_l_addr//echo
+
+# Now, use mount directly to create a 'symlink'
+set symlink_target=some/deep/name/that/is/a/mount
+mount tl/b/symlink /$mt_b_addr/$symlink_target 1h
+wait $_
+
+ls -l tl/b/symlink
+wait $_
+
+resolve tl/b/symlink
+set r=$_
+eval $r
+# returns nothing since symlink is an 'interior' node.
+assert $RN 0
+
+# resolveMT will return the original mount point
+resolveMT tl/b/symlink
+set r=$_
+eval $r
+assert $RN 1
+eval $r
+assert $R0 /$mt_b_addr//$symlink_target
+
diff --git a/tools/naming/simulator/mt_simple.scr b/tools/naming/simulator/mt_simple.scr
new file mode 100644
index 0000000..c09e1eb
--- /dev/null
+++ b/tools/naming/simulator/mt_simple.scr
@@ -0,0 +1,72 @@
+# Simple example showing multiple mount tables, servers and globing
+
+root
+eval $_
+set root=$MT_NAME
+
+set NAMESPACE_ROOT=$root
+mt usa
+eval $_
+set usa_mt=$MT_NAME
+mt uk
+eval $_
+set uk_mt=$MT_NAME
+
+ls $root/...
+set l=$_
+eval $l
+assert $RN 3
+wait $l
+
+set NAMESPACE_ROOT=$usa_mt
+mt "palo alto"
+eval $_
+set pa_mt=$MT_NAME
+
+set NAMESPACE_ROOT=$uk_mt
+mt "cambridge"
+eval $_
+set cam_mt=$MT_NAME
+
+ls $root/...
+set l=$_
+eval $l
+assert $RN 5
+
+ls -l $root/...
+wait $_
+
+resolve $root/usa
+set r=$_
+eval $r
+assert $RN 1
+eval $r
+assert $R0 $usa_mt
+wait $r
+
+resolve  "$root/usa/palo alto"
+set r=$_
+assert $RN 1
+eval $r
+# this resolves to the mount table hosting palo alto, not the mount table
+# that would host any objects mounted on .../palo alto/...
+# but the uk/cambridge example below seems to behave the opposite way?
+assert $R0 $usa_mt
+wait $r
+
+resolve $root/uk
+set r=$_
+eval $r
+assert $RN 1
+eval $r
+assert $R0 $uk_mt
+wait $r
+
+resolve "$root/uk/cambridge"
+set r=$_
+eval $r
+assert $RN 1
+eval $r
+# this behaves differently to the usa/palo alto case?
+assert $R0 $cam_mt
+wait $r
\ No newline at end of file
diff --git a/tools/naming/simulator/t.scr b/tools/naming/simulator/t.scr
new file mode 100644
index 0000000..adf0571
--- /dev/null
+++ b/tools/naming/simulator/t.scr
@@ -0,0 +1,5 @@
+mount a b
+set w=$_
+read $w
+read $w
+wait $w