package eval

import (
	
	
	
	
	
	
	

	
	
	
)

// Input and output.

func () {
	addBuiltinFns(map[string]interface{}{
		// Value output
		"put": put,

		// Bytes input
		"read-upto": readUpto,
		"read-line": readLine,

		// Bytes output
		"print":  print,
		"echo":   echo,
		"pprint": pprint,
		"repr":   repr,
		"show":   show,
		"printf": printf,

		// Only bytes or values
		//
		// These are now implemented as commands forwarding one part of input to
		// output and discarding the other. A future optimization the evaler can
		// do is to connect the relevant parts directly together without any
		// kind of forwarding.
		"only-bytes":  onlyBytes,
		"only-values": onlyValues,

		// Bytes to value
		"slurp":      slurp,
		"from-lines": fromLines,
		"from-json":  fromJSON,

		// Value to bytes
		"to-lines": toLines,
		"to-json":  toJSON,

		// File and pipe
		"fopen":   fopen,
		"fclose":  fclose,
		"pipe":    pipe,
		"prclose": prclose,
		"pwclose": pwclose,
	})
}

//elvdoc:fn put
//
// ```elvish
// put $value...
// ```
//
// Takes arbitrary arguments and write them to the structured stdout.
//
// Examples:
//
// ```elvish-transcript
// ~> put a
// ▶ a
// ~> put lorem ipsum [a b] { ls }
// ▶ lorem
// ▶ ipsum
// ▶ [a b]
// ▶ <closure 0xc4202607e0>
// ```
//
// Etymology: Various languages, in particular
// [C](https://manpages.debian.org/stretch/manpages-dev/puts.3.en.html) and
// [Ruby](https://ruby-doc.org/core-2.2.2/IO.html#method-i-puts) as `puts`.

func ( *Frame,  ...interface{}) {
	 := .OutputChan()
	for ,  := range  {
		 <- 
	}
}

//elvdoc:fn read-upto
//
// ```elvish
// read-upto $delim
// ```
//
// Reads byte input until `$delim` or end-of-file is encountered, and outputs
// the part of the input read as a string value. The output contains the
// trailing `$delim`, unless `read-upto` terminated at end-of-file.
//
// The `$delim` argument must be a single rune in the ASCII range.
//
// Examples:
//
// ```elvish-transcript
// ~> echo "a,b,c" | read-upto ","
// ▶ 'a,'
// ~> echo "foo\nbar" | read-upto "\n"
// ▶ "foo\n"
// ~> echo "a.elv\x00b.elv" | read-upto "\x00"
// ▶ "a.elv\x00"
// ~> print "foobar" | read-upto "\n"
// ▶ foobar
// ```

func ( *Frame,  string) (string, error) {
	if len() != 1 {
		return "", ErrArgs
	}
	 := .InputFile()
	var  []byte
	for {
		var  [1]byte
		,  := .Read([:])
		if  != nil {
			if  == io.EOF {
				break
			}
			return "", 
		}
		 = append(, [0])
		if [0] == [0] {
			break
		}
	}
	return string(), nil
}

//elvdoc:fn read-line
//
// ```elvish
// read-line
// ```
//
// Reads a single line from byte input, and writes the line to the value output,
// stripping the line ending. A line can end with `"\r\n"`, `"\n"`, or end of
// file. Examples:
//
// ```elvish-transcript
// ~> print line | read-line
// ▶ line
// ~> print "line\n" | read-line
// ▶ line
// ~> print "line\r\n" | read-line
// ▶ line
// ~> print "line-with-extra-cr\r\r\n" | read-line
// ▶ "line-with-extra-cr\r"
// ```

func ( *Frame) (string, error) {
	,  := readUpto(, "\n")
	if  != nil {
		return "", 
	}
	return strutil.ChopLineEnding(), nil
}

//elvdoc:fn print
//
// ```elvish
// print &sep=' ' $value...
// ```
//
// Like `echo`, just without the newline.
//
// @cf echo
//
// Etymology: Various languages, in particular
// [Perl](https://perldoc.perl.org/functions/print.html) and
// [zsh](http://zsh.sourceforge.net/Doc/Release/Shell-Builtin-Commands.html), whose
// `print`s do not print a trailing newline.

type printOpts struct{ Sep string }

func ( *printOpts) () { .Sep = " " }

func ( *Frame,  printOpts,  ...interface{}) {
	 := .OutputFile()
	for ,  := range  {
		if  > 0 {
			.WriteString(.Sep)
		}
		.WriteString(vals.ToString())
	}
}

//elvdoc:fn printf
//
// ```elvish
// printf $template $value...
// ```
//
// Prints values to the byte stream according to a template.
//
// Like [`print`](#print), this command does not add an implicit newline; use
// an explicit `"\n"` in the formatting template instead.
//
// See Go's [`fmt`](https://golang.org/pkg/fmt/#hdr-Printing) package for
// details about the formatting verbs and the various flags that modify the
// default behavior, such as padding and justification.
//
// Unlike Go, each formatting verb has a single associated internal type, and
// accepts any argument that can reasonably be converted to that type:
//
// - The verbs `%s`, `%q` and `%v` convert the corresponding argument to a
//   string in different ways:
//
//     - `%s` uses [to-string](#to-string) to convert a value to string.
//
//     - `%q` uses [repr](#repr) to convert a value to string.
//
//     - `%v` is equivalent to `%s`, and `%#v` is equivalent to `%q`.
//
// - The verb `%t` first convert the corresponding argument to a boolean using
//   [bool](#bool), and then uses its Go counterpart to format the boolean.
//
// - The verbs `%b`, `%c`, `%d`, `%o`, `%O`, `%x`, `%X` and `%U` first convert
//   the corresponding argument to an integer using an internal algorithm, and
//   use their Go counterparts to format the integer.
//
// - The verbs `%e`, `%E`, `%f`, `%F`, `%g` and `%G` first convert the
//   corresponding argument to a floating-point number using
//   [float64](#float64), and then use their Go counterparts to format the
//   number.
//
// The special verb `%%` prints a literal `%` and consumes no argument.
//
// Verbs not documented above are not supported.
//
// Examples:
//
// ```elvish-transcript
// ~> printf "%10s %.2f\n" Pi $math:pi
//         Pi 3.14
// ~> printf "%-10s %.2f %s\n" Pi $math:pi $math:pi
// Pi         3.14 3.141592653589793
// ~> printf "%d\n" 0b11100111
// 231
// ~> printf "%08b\n" 231
// 11100111
// ~> printf "list is: %q\n" [foo bar 'foo bar']
// list is: [foo bar 'foo bar']
// ```
//
// **Note**: Compared to the [POSIX `printf`
// command](https://pubs.opengroup.org/onlinepubs/007908799/xcu/printf.html)
// found in other shells, there are 3 key differences:
//
// - The behavior of the formatting verbs are based on Go's
//   [`fmt`](https://golang.org/pkg/fmt/) package instead of the POSIX
//   specification.
//
// - The number of arguments after the formatting template must match the number
//   of formatting verbs. The POSIX command will repeat the template string to
//   consume excess values; this command does not have that behavior.
//
// - This command does not interpret escape sequences such as `\n`; just use
//   [double-quoted strings](language.html#double-quoted-string).
//
// @cf print echo pprint repr

func ( *Frame,  string,  ...interface{}) {
	 := make([]interface{}, len())
	for ,  := range  {
		[] = formatter{}
	}

	fmt.Fprintf(.OutputFile(), , ...)
}

type formatter struct {
	wrapped interface{}
}

func ( formatter) ( fmt.State,  rune) {
	 := .wrapped
	switch  {
	case 's':
		writeFmt(, 's', vals.ToString())
	case 'q':
		// TODO: Support using the precision flag to specify indentation.
		writeFmt(, 's', vals.Repr(, vals.NoPretty))
	case 'v':
		var  string
		if .Flag('#') {
			 = vals.Repr(, vals.NoPretty)
		} else {
			 = vals.ToString()
		}
		writeFmt(, 's', )
	case 't':
		writeFmt(, 't', vals.Bool())
	case 'b', 'c', 'd', 'o', 'O', 'x', 'X', 'U':
		var  int
		if  := vals.ScanToGo(, &);  != nil {
			fmt.Fprintf(, "%%!%c(%s)", , .Error())
			return
		}
		writeFmt(, , )
	case 'e', 'E', 'f', 'F', 'g', 'G':
		var  float64
		if  := vals.ScanToGo(, &);  != nil {
			fmt.Fprintf(, "%%!%c(%s)", , .Error())
			return
		}
		writeFmt(, , )
	default:
		fmt.Fprintf(, "%%!%c(unsupported formatting verb)", )
	}
}

// Writes to State using the flag it stores, but with a potentially different
// verb and value.
func ( fmt.State,  rune,  interface{}) {
	// Reconstruct the verb string.
	var  strings.Builder
	.WriteRune('%')
	for ,  := range "+-# 0" {
		if .Flag(int()) {
			.WriteRune()
		}
	}
	if ,  := .Width();  {
		.WriteString(strconv.Itoa())
	}
	if ,  := .Precision();  {
		.WriteRune('.')
		.WriteString(strconv.Itoa())
	}
	.WriteRune()

	fmt.Fprintf(, .String(), )
}

//elvdoc:fn echo
//
// ```elvish
// echo &sep=' ' $value...
// ```
//
// Print all arguments, joined by the `sep` option, and followed by a newline.
//
// Examples:
//
// ```elvish-transcript
// ~> echo Hello   elvish
// Hello elvish
// ~> echo "Hello   elvish"
// Hello   elvish
// ~> echo &sep=, lorem ipsum
// lorem,ipsum
// ```
//
// Notes: The `echo` builtin does not treat `-e` or `-n` specially. For instance,
// `echo -n` just prints `-n`. Use double-quoted strings to print special
// characters, and `print` to suppress the trailing newline.
//
// @cf print
//
// Etymology: Bourne sh.

func ( *Frame,  printOpts,  ...interface{}) {
	print(, , ...)
	.OutputFile().WriteString("\n")
}

//elvdoc:fn pprint
//
// ```elvish
// pprint $value...
// ```
//
// Pretty-print representations of Elvish values. Examples:
//
// ```elvish-transcript
// ~> pprint [foo bar]
// [
// foo
// bar
// ]
// ~> pprint [&k1=v1 &k2=v2]
// [
// &k2=
// v2
// &k1=
// v1
// ]
// ```
//
// The output format is subject to change.
//
// @cf repr

func ( *Frame,  ...interface{}) {
	 := .OutputFile()
	for ,  := range  {
		.WriteString(vals.Repr(, 0))
		.WriteString("\n")
	}
}

//elvdoc:fn repr
//
// ```elvish
// repr $value...
// ```
//
// Writes representation of `$value`s, separated by space and followed by a
// newline. Example:
//
// ```elvish-transcript
// ~> repr [foo 'lorem ipsum'] "aha\n"
// [foo 'lorem ipsum'] "aha\n"
// ```
//
// @cf pprint
//
// Etymology: [Python](https://docs.python.org/3/library/functions.html#repr).

func ( *Frame,  ...interface{}) {
	 := .OutputFile()
	for ,  := range  {
		if  > 0 {
			.WriteString(" ")
		}
		.WriteString(vals.Repr(, vals.NoPretty))
	}
	.WriteString("\n")
}

//elvdoc:fn show
//
// ```elvish
// show $e
// ```
//
// Shows the value to the output, which is assumed to be a VT-100-compatible
// terminal.
//
// Currently, the only type of value that can be showed is exceptions, but this
// will likely expand in future.
//
// Example:
//
// ```elvish-transcript
// ~> e = ?(fail lorem-ipsum)
// ~> show $e
// Exception: lorem-ipsum
// [tty 3], line 1: e = ?(fail lorem-ipsum)
// ```

func ( *Frame,  diag.Shower) {
	.OutputFile().WriteString(.Show(""))
	.OutputFile().WriteString("\n")
}

const bytesReadBufferSize = 512

//elvdoc:fn only-bytes
//
// ```elvish
// only-bytes
// ```
//
// Passes byte input to output, and discards value inputs.
//
// Example:
//
// ```elvish-transcript
// ~> { put value; echo bytes } | only-bytes
// bytes
// ```

func ( *Frame) error {
	// Discard values in a goroutine.
	 := make(chan struct{})
	go func() {
		for range .InputChan() {
		}
		close()
	}()
	// Make sure the goroutine has finished before returning.
	defer func() { <- }()

	// Forward bytes.
	 := make([]byte, bytesReadBufferSize)
	for {
		,  := .InputFile().Read([:])
		if  > 0 {
			// Even when there are write errors, we will continue reading. So we
			// ignore the error.
			.OutputFile().Write([:])
		}
		if  != nil {
			if  == io.EOF {
				return nil
			}
			return 
		}
	}
}

//elvdoc:fn only-values
//
// ```elvish
// only-values
// ```
//
// Passes value input to output, and discards byte inputs.
//
// Example:
//
// ```elvish-transcript
// ~> { put value; echo bytes } | only-values
// ▶ value
// ```

func ( *Frame) error {
	// Forward values in a goroutine.
	 := make(chan struct{})
	go func() {
		for  := range .InputChan() {
			.OutputChan() <- 
		}
		close()
	}()
	// Make sure the goroutine has finished before returning.
	defer func() { <- }()

	// Discard bytes.
	 := make([]byte, bytesReadBufferSize)
	for {
		,  := .InputFile().Read([:])
		if  != nil {
			if  == io.EOF {
				return nil
			}
			return 
		}
	}
}

//elvdoc:fn slurp
//
// ```elvish
// slurp
// ```
//
// Reads bytes input into a single string, and put this string on structured
// stdout.
//
// Example:
//
// ```elvish-transcript
// ~> echo "a\nb" | slurp
// ▶ "a\nb\n"
// ```
//
// Etymology: Perl, as
// [`File::Slurp`](http://search.cpan.org/~uri/File-Slurp-9999.19/lib/File/Slurp.pm).

func ( *Frame) (string, error) {
	,  := ioutil.ReadAll(.InputFile())
	return string(), 
}

//elvdoc:fn from-lines
//
// ```elvish
// from-lines
// ```
//
// Splits byte input into lines, and writes them to the value output. Value
// input is ignored.
//
// ```elvish-transcript
// ~> { echo a; echo b } | from-lines
// ▶ a
// ▶ b
// ~> { echo a; put b } | from-lines
// ▶ a
// ```
//
// @cf to-lines

func ( *Frame) {
	linesToChan(.InputFile(), .OutputChan())
}

//elvdoc:fn from-json
//
// ```elvish
// from-json
// ```
//
// Takes bytes stdin, parses it as JSON and puts the result on structured stdout.
// The input can contain multiple JSONs, which can, but do not have to, be
// separated with whitespaces.
//
// Examples:
//
// ```elvish-transcript
// ~> echo '"a"' | from-json
// ▶ a
// ~> echo '["lorem", "ipsum"]' | from-json
// ▶ [lorem ipsum]
// ~> echo '{"lorem": "ipsum"}' | from-json
// ▶ [&lorem=ipsum]
// ~> # multiple JSONs running together
// echo '"a""b"["x"]' | from-json
// ▶ a
// ▶ b
// ▶ [x]
// ~> # multiple JSONs separated by newlines
// echo '"a"
// {"k": "v"}' | from-json
// ▶ a
// ▶ [&k=v]
// ```
//
// @cf to-json

func ( *Frame) error {
	 := .InputFile()
	 := .OutputChan()

	 := json.NewDecoder()
	for {
		var  interface{}
		 := .Decode(&)
		if  != nil {
			if  == io.EOF {
				return nil
			}
			return 
		}
		,  := fromJSONInterface()
		if  != nil {
			return 
		}
		 <- 
	}
}

// Converts a interface{} that results from json.Unmarshal to an Elvish value.
func ( interface{}) (interface{}, error) {
	switch v := .(type) {
	case nil, bool, string:
		return , nil
	case float64:
		return , nil
	case []interface{}:
		 := vals.EmptyList
		for ,  := range  {
			,  := ()
			if  != nil {
				return nil, 
			}
			 = .Cons()
		}
		return , nil
	case map[string]interface{}:
		 := vals.EmptyMap
		for ,  := range  {
			,  := ()
			if  != nil {
				return nil, 
			}
			 = .Assoc(, )
		}
		return , nil
	default:
		return nil, fmt.Errorf("unexpected json type: %T", )
	}
}

//elvdoc:fn to-lines
//
// ```elvish
// to-lines $input?
// ```
//
// Writes each value input to a separate line in the byte output. Byte input is
// ignored.
//
// ```elvish-transcript
// ~> put a b | to-lines
// a
// b
// ~> to-lines [a b]
// a
// b
// ~> { put a; echo b } | to-lines
// b
// a
// ```
//
// @cf from-lines

func ( *Frame,  Inputs) {
	 := .OutputFile()

	(func( interface{}) {
		fmt.Fprintln(, vals.ToString())
	})
}

//elvdoc:fn to-json
//
// ```elvish
// to-json
// ```
//
// Takes structured stdin, convert it to JSON and puts the result on bytes stdout.
//
// ```elvish-transcript
// ~> put a | to-json
// "a"
// ~> put [lorem ipsum] | to-json
// ["lorem","ipsum"]
// ~> put [&lorem=ipsum] | to-json
// {"lorem":"ipsum"}
// ```
//
// @cf from-json

func ( *Frame,  Inputs) error {
	 := json.NewEncoder(.OutputFile())

	var  error
	(func( interface{}) {
		if  != nil {
			return
		}
		 = .Encode()
	})
	return 
}

//elvdoc:fn fopen
//
// ```elvish
// fopen $filename
// ```
//
// Open a file. Currently, `fopen` only supports opening a file for reading. File
// must be closed with `fclose` explicitly. Example:
//
// ```elvish-transcript
// ~> cat a.txt
// This is
// a file.
// ~> f = (fopen a.txt)
// ~> cat < $f
// This is
// a file.
// ~> fclose $f
// ```
//
// This function is deprecated; use [file:open](./file.html#open) instead.
//
// @cf fclose

func ( string) (vals.File, error) {
	// TODO support opening files for writing etc as well.
	return os.Open()
}

//elvdoc:fn fclose
//
// ```elvish
// fclose $file
// ```
//
// Close a file opened with `fopen`.
//
// This function is deprecated; use [file:close](./file.html#close) instead.
//
// @cf fopen

func ( vals.File) error {
	return .Close()
}

//elvdoc:fn pipe
//
// ```elvish
// pipe
// ```
//
// Create a new Unix pipe that can be used in redirections.
//
// A pipe contains both the read FD and the write FD. When redirecting command
// input to a pipe with `<`, the read FD is used. When redirecting command output
// to a pipe with `>`, the write FD is used. It is not supported to redirect both
// input and output with `<>` to a pipe.
//
// Pipes have an OS-dependent buffer, so writing to a pipe without an active reader
// does not necessarily block. Pipes **must** be explicitly closed with `prclose`
// and `pwclose`.
//
// Putting values into pipes will cause those values to be discarded.
//
// Examples (assuming the pipe has a large enough buffer):
//
// ```elvish-transcript
// ~> p = (pipe)
// ~> echo 'lorem ipsum' > $p
// ~> head -n1 < $p
// lorem ipsum
// ~> put 'lorem ipsum' > $p
// ~> head -n1 < $p
// # blocks
// # $p should be closed with prclose and pwclose afterwards
// ```
//
// This function is deprecated; use [file:pipe](./file.html#pipe) instead.
//
// @cf prclose pwclose

func () (vals.Pipe, error) {
	, ,  := os.Pipe()
	return vals.NewPipe(, ), 
}

//elvdoc:fn prclose
//
// ```elvish
// prclose $pipe
// ```
//
// Close the read end of a pipe.
//
// This function is deprecated; use [file:prclose](./file.html#prclose) instead.
//
// @cf pwclose pipe

func ( vals.Pipe) error {
	return .ReadEnd.Close()
}

//elvdoc:fn pwclose
//
// ```elvish
// pwclose $pipe
// ```
//
// Close the write end of a pipe.
//
// This function is deprecated; use [file:pwclose](./file.html#pwclose) instead.
//
// @cf prclose pipe

func ( vals.Pipe) error {
	return .WriteEnd.Close()
}