package muesli import "io" import "fmt" import "os" // Consoler is an interface to a virtual console that the VM 's frames use for // stdin, stdout, stderr, and logging output. // This allows you to redirect the output of the VM and any built-in functions // to whatever you like. type Consoler interface { LogTo() io.Writer // logs should be written to this writer of not nil Out() io.Writer // standard output goes to this writer of not nil. Err() io.Writer // standard error go to this writer if not nil In() io.Reader // can read standard input from this reader if not nil } // BasicConsole is a reusable virtual console struct. // It implements the BasicConsoler interface type BasicConsole struct { log io.Writer out io.Writer err io.Writer in io.Reader } func (c BasicConsole) LogTo() io.Writer { return c.log } func (c BasicConsole) Out() io.Writer { return c.out } func (c BasicConsole) Err() io.Writer { return c.err } func (c BasicConsole) In() io.Reader { return c.in } func NewBasicConsole(log, out, err io.Writer, in io.Reader) BasicConsole { return BasicConsole { log, out, err, in } } var _ Consoler = BasicConsole{} // Console is a fully features wrapper BasicConsole, easier to use with Printf // and Log, etc, and implements the Logger and Consoler interface. type Console struct { LoggerWrapper Consoler } func (c *Console) Fprintf(out io.Writer, format string, args ... interface{}) (int, error) { if out != nil { return fmt.Fprintf(out, format, args...) } return 0, nil } func (c *Console) Fprintln(out io.Writer, args ... interface{}) (int, error) { if out != nil { return fmt.Fprintln(out, args...) } return 0, nil } func (c *Console) Log(level string, file string, line int, format string, args ...interface{}) { log := c.Consoler.LogTo() c.Fprintf(log, "%s:%s:%d: ", level, file, line) c.Fprintf(log, format, args...) } func (c *Console) Printf(format string, args ...interface{}) { out := c.Out() c.Fprintf(out, format, args...) } func (c *Console) Println(args ...interface{}) { out := c.Out() c.Fprintln(out, args...) } func (c *Console) Errf(format string, args ...interface{}) { err := c.Err() c.Fprintf(err, format, args...) } func NewConsole(log, out, err io.Writer, in io.Reader) *Console { console := &Console{} console.Consoler = NewBasicConsole(log, out, err, in) return console } // also implement the tracer interface func (c *Console) Trace(vm VM, format string, args ... interface{}) bool { args = append([]interface{}{vm.BackTrace()}, args...) c.LogTrace("%s: " + format, args...) return false } func NewStdConsole() *Console { return NewConsole(os.Stdout, os.Stdout, os.Stderr, os.Stdin) }