Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 24 additions & 7 deletions evaluator/evaluator.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package evaluator

import (
"bufio"
"bytes"
"fmt"
"io"
"io/ioutil"
"math"
"os"
Expand Down Expand Up @@ -1526,13 +1528,9 @@ func evalCommandExpression(tok token.Token, cmd string, env *object.Environment)
c := exec.Command(parts[0], append(parts[1:], cmd)...)
c.Env = os.Environ()
c.Stdin = os.Stdin
var stdout bytes.Buffer
var stderr bytes.Buffer
c.Stdout = &stdout
c.Stderr = &stderr
var stdoutStderr bytes.Buffer

s.Stdout = &stdout
s.Stderr = &stderr
s.StdoutStderr = &stdoutStderr
s.Cmd = c
s.Token = tok

Expand All @@ -1543,14 +1541,33 @@ func evalCommandExpression(tok token.Token, cmd string, env *object.Environment)
// wait for it by calling s.Wait().
s.SetRunning()

err := c.Start()
stdoutPipe, err := s.Cmd.StdoutPipe()
if err != nil {
s.SetCmdResult(FALSE)
return FALSE
}

stderrPipe, err := s.Cmd.StderrPipe()
if err != nil {
s.SetCmdResult(FALSE)
return FALSE
}

combinedReader := io.MultiReader(stdoutPipe, stderrPipe)

s.Scanner = bufio.NewScanner(combinedReader)
s.Scanner.Split(bufio.ScanLines)

if err := s.Cmd.Start(); err != nil {
s.SetCmdResult(FALSE)
return FALSE
}

go evalCommandInBackground(s)
} else {
c.Stdout = &stdoutStderr
c.Stderr = &stdoutStderr

err = c.Run()
}

Expand Down
57 changes: 40 additions & 17 deletions object/object.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package object

import (
"bufio"
"bytes"
"fmt"
"os/exec"
Expand Down Expand Up @@ -211,14 +212,15 @@ func (f *Function) Json() string { return f.Inspect() }
// cmd.wait() // ...
// cmd.done // TRUE
type String struct {
Token token.Token
Value string
Ok *Boolean // A special property to check whether a command exited correctly
Cmd *exec.Cmd // A special property to access the underlying command
Stdout *bytes.Buffer
Stderr *bytes.Buffer
Done *Boolean
mux *sync.Mutex
Token token.Token
Value string
Ok *Boolean // A special property to check whether a command exited correctly
Cmd *exec.Cmd // A special property to access the underlying command
StdoutStderr *bytes.Buffer
Scanner *bufio.Scanner
Done *Boolean
lineno int64
mux *sync.Mutex
}

func (s *String) Type() ObjectType { return STRING_OBJ }
Expand Down Expand Up @@ -259,6 +261,15 @@ func (s *String) SetRunning() {
// wait on the background command
// to be done.
func (s *String) Wait() {
// Read all 'unread bytes' from stdout/stderr but just in case it hasn't been read yet
if s.Scanner != nil {
for s.Scanner.Scan() {
s.StdoutStderr.Write(s.Scanner.Bytes())
}

s.Value = strings.TrimSpace(s.StdoutStderr.String())
}

s.mustHaveMutex()
s.mux.Lock()
s.mux.Unlock()
Expand All @@ -271,9 +282,8 @@ func (s *String) Kill() error {

// The command value includes output and possible error
// We might want to change this
output := s.Stdout.String()
outputErr := s.Stderr.String()
s.Value = strings.TrimSpace(output) + strings.TrimSpace(outputErr)
output := s.StdoutStderr.String()
s.Value = strings.TrimSpace(output)

if err != nil {
return err
Expand All @@ -291,19 +301,32 @@ func (s *String) Kill() error {
// - str.done
func (s *String) SetCmdResult(Ok *Boolean) {
s.Ok = Ok
var output string

if Ok.Value {
output = s.Stdout.String()
} else {
output = s.Stderr.String()
}
output := s.StdoutStderr.String()

// trim space at both ends of out.String(); works in both linux and windows
s.Value = strings.TrimSpace(output)
s.Done = TRUE
}

func (s *String) Next() (Object, Object) {
if s.Scanner == nil {
return nil, nil
}

for s.Scanner.Scan() {
line := s.Scanner.Text()
s.lineno += 1
return &Number{Value: float64(s.lineno - 1)}, &String{Value: line, Scanner: s.Scanner, lineno: s.lineno}
}

return nil, nil
}

func (s *String) Reset() {
s.lineno = 0
}

type Builtin struct {
Token token.Token
Fn BuiltinFunction
Expand Down