mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-05 03:17:50 +08:00
Ditch IndexVarer interface in favor of IndexSetter.
This complicates indexing a little bit, but makes it easier to implement new containers.
This commit is contained in:
parent
34fddcd100
commit
60a7f59ea9
|
@ -323,19 +323,38 @@ func (cp *compiler) indexingVar(n *parse.Indexing, msg string) VariableOp {
|
|||
if variable == nil {
|
||||
ec.errorf(p, "variable $%s does not exisit, compiler bug", varname)
|
||||
}
|
||||
for i, op := range indexOps {
|
||||
indexer, ok := variable.Get().(IndexVarer)
|
||||
if len(indexOps) == 0 {
|
||||
// Just a variable, return directly.
|
||||
return variable
|
||||
}
|
||||
|
||||
// Indexing. Do Index up to the last but one index.
|
||||
value := variable.Get()
|
||||
n := len(indexOps)
|
||||
for i, op := range indexOps[:n-1] {
|
||||
indexer, ok := value.(Indexer)
|
||||
if !ok {
|
||||
ec.errorf( /* from p to */ indexBegins[i], "cannot be indexing for setting (type %T)", variable.Get())
|
||||
}
|
||||
values := op(ec)
|
||||
if len(values) != 1 {
|
||||
ec.errorf(indexBegins[i], "index must eval to a single Value (got %v)", values)
|
||||
ec.errorf( /* from p to */ indexBegins[i], "cannot be indexed (value is %s, type %s)", value.Repr(), value.Type())
|
||||
}
|
||||
|
||||
variable = indexer.IndexVar(values[0])
|
||||
indicies := op(ec)
|
||||
if len(indicies) != 1 {
|
||||
ec.errorf(indexBegins[i], "index must eval to a single Value (got %v)", indicies)
|
||||
}
|
||||
|
||||
value = indexer.Index(indicies[0])
|
||||
}
|
||||
return variable
|
||||
// Now this must be an IndexSetter.
|
||||
indexSetter, ok := value.(IndexSetter)
|
||||
if !ok {
|
||||
ec.errorf( /* from p to */ indexBegins[n-1], "cannot be indexed for setting (value is %s, type %s)", value.Repr(), value.Type())
|
||||
}
|
||||
// XXX Duplicate code.
|
||||
indicies := indexOps[n-1](ec)
|
||||
if len(indicies) != 1 {
|
||||
ec.errorf(indexBegins[n-1], "index must eval to a single Value (got %v)", indicies)
|
||||
}
|
||||
return elemVariable{indexSetter, indicies[0]}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,9 +42,10 @@ type Indexer interface {
|
|||
Index(idx Value) Value
|
||||
}
|
||||
|
||||
// IndexVarer is anything that can be indexed by a Value and yields a Variable.
|
||||
type IndexVarer interface {
|
||||
IndexVar(idx Value) Variable
|
||||
// IndexSetter is a Value whose elements can be get as well as set.
|
||||
type IndexSetter interface {
|
||||
Indexer
|
||||
IndexSet(idx Value, v Value)
|
||||
}
|
||||
|
||||
// Caller is anything may be called on an evalCtx with a list of Value's.
|
||||
|
@ -283,8 +284,15 @@ func (l List) Index(idx Value) Value {
|
|||
return (*l.inner)[i]
|
||||
}
|
||||
|
||||
func (l List) IndexVar(idx Value) Variable {
|
||||
return listElem{l, intIndex(idx)}
|
||||
func (l List) IndexSet(idxv Value, v Value) {
|
||||
idx := intIndex(idxv)
|
||||
if idx < 0 {
|
||||
idx += len(*l.inner)
|
||||
}
|
||||
if idx < 0 || idx >= len(*l.inner) {
|
||||
throw(ErrIndexOutOfRange)
|
||||
}
|
||||
(*l.inner)[idx] = v
|
||||
}
|
||||
|
||||
// Map is a map from string to Value.
|
||||
|
@ -328,8 +336,8 @@ func (m Map) Index(idx Value) Value {
|
|||
return v
|
||||
}
|
||||
|
||||
func (m Map) IndexVar(idx Value) Variable {
|
||||
return mapElem{m, idx}
|
||||
func (m Map) IndexSet(idx Value, v Value) {
|
||||
(*m.inner)[idx] = v
|
||||
}
|
||||
|
||||
// Closure is a closure.
|
||||
|
|
|
@ -24,43 +24,18 @@ func (iv ptrVariable) Get() Value {
|
|||
return *iv.valuePtr
|
||||
}
|
||||
|
||||
// listElem is the Variable generated by indexing a List.
|
||||
type listElem struct {
|
||||
parent List
|
||||
idx int
|
||||
// elemVariable is an element of a IndexSetter.
|
||||
type elemVariable struct {
|
||||
container IndexSetter
|
||||
index Value
|
||||
}
|
||||
|
||||
func (le listElem) Set(val Value) {
|
||||
(*le.parent.inner)[le.index()] = val
|
||||
func (ev elemVariable) Set(val Value) {
|
||||
ev.container.IndexSet(ev.index, val)
|
||||
}
|
||||
|
||||
func (le listElem) Get() Value {
|
||||
return (*le.parent.inner)[le.index()]
|
||||
}
|
||||
|
||||
func (le listElem) index() int {
|
||||
idx := le.idx
|
||||
if idx < 0 {
|
||||
idx += len(*le.parent.inner)
|
||||
}
|
||||
if idx < 0 || idx >= len(*le.parent.inner) {
|
||||
throw(ErrIndexOutOfRange)
|
||||
}
|
||||
return idx
|
||||
}
|
||||
|
||||
// mapElem is the Variable generated by indexing a Map.
|
||||
type mapElem struct {
|
||||
parent Map
|
||||
idx Value
|
||||
}
|
||||
|
||||
func (me mapElem) Set(val Value) {
|
||||
(*me.parent.inner)[me.idx] = val
|
||||
}
|
||||
|
||||
func (me mapElem) Get() Value {
|
||||
return (*me.parent.inner)[me.idx]
|
||||
func (ev elemVariable) Get() Value {
|
||||
return ev.container.Index(ev.index)
|
||||
}
|
||||
|
||||
type envVariable struct {
|
||||
|
|
Loading…
Reference in New Issue
Block a user