Skip to content

Commit

Permalink
Support for two iteration variable comprehensions
Browse files Browse the repository at this point in the history
  • Loading branch information
TristonianJones committed Aug 3, 2024
1 parent d3ec907 commit a5a8dd2
Show file tree
Hide file tree
Showing 8 changed files with 262 additions and 13 deletions.
8 changes: 4 additions & 4 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ http_archive(
],
)

# googleapis as of 08/31/2023
# googleapis as of 08/02/2024
http_archive(
name = "com_google_googleapis",
sha256 = "5c56500adf7b1b7a3a2ee5ca5b77500617ad80afb808e3d3979f582e64c0523d",
strip_prefix = "googleapis-25f99371444ea7fd0dc1523ca6925e91cc48a664",
sha256 = "b3b566c234d557be444ae9e88266e0e089398dc49175509c55907c941b95258a",
strip_prefix = "googleapis-24be099a87c35691e18261c0da28f7b711cc6416",
urls = [
"https://github.com/googleapis/googleapis/archive/25f99371444ea7fd0dc1523ca6925e91cc48a664.tar.gz",
"https://github.com/googleapis/googleapis/archive/24be099a87c35691e18261c0da28f7b711cc6416.tar.gz",
],
)

Expand Down
18 changes: 18 additions & 0 deletions common/types/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,15 @@ func (l *baseList) IsZeroValue() bool {
return l.size == 0
}

// Fold calls the FoldEntry method for each (index, value) pair in the list.
func (l *baseList) Fold(f traits.Folder) {
for i := 0; i < l.size; i++ {
if !f.FoldEntry(ListType, i, l.get(i)) {
break
}
}
}

// Iterator implements the traits.Iterable interface method.
func (l *baseList) Iterator() traits.Iterator {
return newListIterator(l)
Expand Down Expand Up @@ -433,6 +442,15 @@ func (l *concatList) IsZeroValue() bool {
return l.Size().(Int) == 0
}

// Fold calls the FoldEntry method for each (index, value) pair in the list.
func (l *concatList) Fold(f traits.Folder) {
for i := Int(0); i < l.Size().(Int); i++ {
if !f.FoldEntry(ListType, i, l.Get(i)) {
break
}
}
}

// Iterator implements the traits.Iterable interface method.
func (l *concatList) Iterator() traits.Iterator {
return newListIterator(l)
Expand Down
56 changes: 56 additions & 0 deletions common/types/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ type mapAccessor interface {

// Iterator returns an Iterator over the map key set.
Iterator() traits.Iterator

// Fold calls the FoldEntry method for each (key, value) pair in the map.
Fold(traits.Folder)
}

// baseMap is a reflection based map implementation designed to handle a variety of map-like types.
Expand Down Expand Up @@ -350,6 +353,15 @@ func (a *jsonStructAccessor) Iterator() traits.Iterator {
}
}

// Fold calls the FoldEntry method for each (key, value) pair in the map.
func (a *jsonStructAccessor) Fold(f traits.Folder) {
for k, v := range a.st {
if !f.FoldEntry(MapType, k, v) {
break
}
}
}

func newReflectMapAccessor(adapter Adapter, value reflect.Value) mapAccessor {
keyType := value.Type().Key()
return &reflectMapAccessor{
Expand Down Expand Up @@ -424,6 +436,16 @@ func (m *reflectMapAccessor) Iterator() traits.Iterator {
}
}

// Fold calls the FoldEntry method for each (key, value) pair in the map.
func (m *reflectMapAccessor) Fold(f traits.Folder) {
mapRange := m.refValue.MapRange()
for mapRange.Next() {
if !f.FoldEntry(MapType, mapRange.Key(), mapRange.Next()) {
break
}
}
}

func newRefValMapAccessor(mapVal map[ref.Val]ref.Val) mapAccessor {
return &refValMapAccessor{mapVal: mapVal}
}
Expand Down Expand Up @@ -477,6 +499,15 @@ func (a *refValMapAccessor) Iterator() traits.Iterator {
}
}

// Fold calls the FoldEntry method for each (key, value) pair in the map.
func (a *refValMapAccessor) Fold(f traits.Folder) {
for k, v := range a.mapVal {
if !f.FoldEntry(MapType, k, v) {
break
}
}
}

func newStringMapAccessor(strMap map[string]string) mapAccessor {
return &stringMapAccessor{mapVal: strMap}
}
Expand Down Expand Up @@ -515,6 +546,15 @@ func (a *stringMapAccessor) Iterator() traits.Iterator {
}
}

// Fold calls the FoldEntry method for each (key, value) pair in the map.
func (a *stringMapAccessor) Fold(f traits.Folder) {
for k, v := range a.mapVal {
if !f.FoldEntry(MapType, k, v) {
break
}
}
}

func newStringIfaceMapAccessor(adapter Adapter, mapVal map[string]any) mapAccessor {
return &stringIfaceMapAccessor{
Adapter: adapter,
Expand Down Expand Up @@ -557,6 +597,15 @@ func (a *stringIfaceMapAccessor) Iterator() traits.Iterator {
}
}

// Fold calls the FoldEntry method for each (key, value) pair in the map.
func (a *stringIfaceMapAccessor) Fold(f traits.Folder) {
for k, v := range a.mapVal {
if !f.FoldEntry(MapType, k, v) {
break
}
}
}

// protoMap is a specialized, separate implementation of the traits.Mapper interfaces tailored to
// accessing protoreflect.Map values.
type protoMap struct {
Expand Down Expand Up @@ -769,6 +818,13 @@ func (m *protoMap) Iterator() traits.Iterator {
}
}

// Fold calls the FoldEntry method for each (key, value) pair in the map.
func (m *protoMap) Fold(f traits.Folder) {
m.value.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
return f.FoldEntry(MapType, k.Interface(), v.Interface())
})
}

// Size returns the number of entries in the protoreflect.Map.
func (m *protoMap) Size() ref.Val {
return Int(m.value.Len())
Expand Down
4 changes: 2 additions & 2 deletions common/types/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,8 @@ func nativeToValue(a Adapter, value any) (ref.Val, bool) {
switch v := value.(type) {
case nil:
return NullValue, true
case ref.Val:
return v, true
case *Bool:
if v != nil {
return *v, true
Expand Down Expand Up @@ -549,8 +551,6 @@ func nativeToValue(a Adapter, value any) (ref.Val, bool) {
return NewJSONList(a, v), true
case *structpb.Struct:
return NewJSONStruct(a, v), true
case ref.Val:
return v, true
case protoreflect.EnumNumber:
return Int(v), true
case proto.Message:
Expand Down
13 changes: 13 additions & 0 deletions common/types/traits/iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,16 @@ type Iterator interface {
// Next returns the next element.
Next() ref.Val
}

// Foldable aggregate types support iteration over (key, value) or (index, value) pairs.
type Foldable interface {
// Fold invokes the Folder.FoldEntry for all entries in the type
Fold(Folder)
}

// Folder performs a fold on a given entry and indicates whether to continue folding.
type Folder interface {
// FoldEntry indicates the calling type and the (key, value) pair associated with the entry.
// If the output is true, continue folding. Otherwise, terminate the fold.
FoldEntry(t ref.Type, key, val any) bool
}
5 changes: 4 additions & 1 deletion common/types/traits/traits.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ const (
// SizerType types support the size() method.
SizerType

// SubtractorType type support '-' operations.
// SubtractorType types support '-' operations.
SubtractorType

// FoldableType types support comprehensions v2 macros which iterate over (key, value) pairs.
FoldableType
)
9 changes: 4 additions & 5 deletions interpreter/decorators.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,11 @@ func decObserveEval(observer EvalObserver) InterpretableDecorator {
// where the interrupt state is communicated via a hidden variable on the Activation.
func decInterruptFolds() InterpretableDecorator {
return func(i Interpretable) (Interpretable, error) {
fold, ok := i.(*evalFold)
if !ok {
return i, nil
if fold, ok := i.(*evalFold); ok {
fold.interruptable = true
return fold, nil
}
fold.interruptable = true
return fold, nil
return i, nil
}
}

Expand Down
Loading

0 comments on commit a5a8dd2

Please sign in to comment.