mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-04 10:57:50 +08:00
127 lines
2.1 KiB
Go
127 lines
2.1 KiB
Go
package eval
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// Error definitions.
|
|
var (
|
|
ErrNeedIntIndex = errors.New("need integer index")
|
|
ErrIndexOutOfRange = errors.New("index out of range")
|
|
)
|
|
|
|
type ListLike interface {
|
|
Lener
|
|
Elemser
|
|
IndexOneer
|
|
}
|
|
|
|
// List is a list of Value's.
|
|
type List struct {
|
|
inner *[]Value
|
|
}
|
|
|
|
// NewList creates a new List.
|
|
func NewList(vs ...Value) List {
|
|
return List{&vs}
|
|
}
|
|
|
|
func (List) Kind() string {
|
|
return "list"
|
|
}
|
|
|
|
func (l List) Repr(indent int) string {
|
|
var b ListReprBuilder
|
|
b.Indent = indent
|
|
for _, v := range *l.inner {
|
|
b.WriteElem(v.Repr(indent + 1))
|
|
}
|
|
return b.String()
|
|
}
|
|
|
|
func (l List) Len() int {
|
|
return len(*l.inner)
|
|
}
|
|
|
|
func (l List) Elems() <-chan Value {
|
|
ch := make(chan Value)
|
|
go func() {
|
|
for _, v := range *l.inner {
|
|
ch <- v
|
|
}
|
|
close(ch)
|
|
}()
|
|
return ch
|
|
}
|
|
|
|
func (l List) IndexOne(idx Value) Value {
|
|
i := intIndexWithin(idx, len(*l.inner))
|
|
return (*l.inner)[i]
|
|
}
|
|
|
|
func (l List) IndexSet(idx Value, v Value) {
|
|
i := intIndexWithin(idx, len(*l.inner))
|
|
(*l.inner)[i] = v
|
|
}
|
|
|
|
func intIndexWithin(idx Value, n int) int {
|
|
i := intIndex(idx)
|
|
|
|
if i < 0 {
|
|
i += n
|
|
}
|
|
if i < 0 || i >= n {
|
|
throw(ErrIndexOutOfRange)
|
|
}
|
|
return i
|
|
}
|
|
|
|
func intIndex(idx Value) int {
|
|
i, err := strconv.Atoi(ToString(idx))
|
|
if err != nil {
|
|
err := err.(*strconv.NumError)
|
|
if err.Err == strconv.ErrRange {
|
|
throw(ErrIndexOutOfRange)
|
|
} else {
|
|
throw(ErrNeedIntIndex)
|
|
}
|
|
}
|
|
return i
|
|
}
|
|
|
|
// ListReprBuilder helps to build Repr of list-like Values.
|
|
type ListReprBuilder struct {
|
|
Indent int
|
|
buf bytes.Buffer
|
|
}
|
|
|
|
func (b *ListReprBuilder) WriteElem(v string) {
|
|
if b.buf.Len() == 0 {
|
|
b.buf.WriteByte('[')
|
|
}
|
|
if b.Indent >= 0 {
|
|
// Pretty printing.
|
|
//
|
|
// Add a newline and indent+1 spaces, so that the
|
|
// starting & lines up with the first pair.
|
|
b.buf.WriteString("\n" + strings.Repeat(" ", b.Indent+1))
|
|
} else if b.buf.Len() > 1 {
|
|
b.buf.WriteByte(' ')
|
|
}
|
|
b.buf.WriteString(v)
|
|
}
|
|
|
|
func (b *ListReprBuilder) String() string {
|
|
if b.buf.Len() == 0 {
|
|
return "[]"
|
|
}
|
|
if b.Indent >= 0 {
|
|
b.buf.WriteString("\n" + strings.Repeat(" ", b.Indent))
|
|
}
|
|
b.buf.WriteByte(']')
|
|
return b.buf.String()
|
|
}
|