Skip to content
Merged
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
5 changes: 5 additions & 0 deletions lib/jsonmarshaller.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"go.starlark.net/starlark"
"go.starlark.net/starlarkstruct"
"sort"
"strings"
)

Expand Down Expand Up @@ -84,6 +85,10 @@ func MarshalJSONStarlarkValue(m starlark.Value, depth int) ([]byte, error) {
return []byte(buf.String()), nil
case "genericmap", "dict":
items := m.(starlark.IterableMapping).Items()
// Sort items by key to have deterministic output
sort.Slice(items, func(i, j int) bool {
return items[i][0].String() < items[j][0].String()
})
buf := strings.Builder{}
buf.WriteString("{")
first := true
Expand Down
41 changes: 30 additions & 11 deletions lib/starlark_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package lib
import (
ast "fizz/proto"
"fmt"
"go.starlark.net/starlark"
"strings"

"go.starlark.net/starlark"
)

var (
Expand All @@ -22,14 +23,16 @@ func ClearRoleRefs() {
}

type Role struct {
Ref int64
ID starlark.Value // Can be *ModelValue or *SymmetricValue
Name string
Symmetric bool
Params *Struct
Fields *Struct
Methods map[string]*starlark.Function
RoleMethods map[string]*starlark.Builtin
InitValues *Struct

// Ref field is removed. Use GetRef() to retrieve the integer ID from the ID field.
}

func (r *Role) AddMethod(name string, val starlark.Value) error {
Expand Down Expand Up @@ -81,10 +84,18 @@ func (r *Role) Attr(name string) (starlark.Value, error) {
}

func (r *Role) GetId() starlark.Value {
if r.Symmetric {
return NewSymmetricValue(r.Name, r.Ref)
return r.ID
}

// GetRef returns the integer reference ID from the underlying ID object
func (r *Role) GetRef() int64 {
if sv, ok := r.ID.(*SymmetricValue); ok {
return sv.GetId()
}
return NewModelValue(r.Name, r.Ref)
if mv, ok := r.ID.(*ModelValue); ok {
return mv.id
}
return -1
}

func (r *Role) AttrNames() []string {
Expand All @@ -93,7 +104,7 @@ func (r *Role) AttrNames() []string {

func (r *Role) String() string {
b := strings.Builder{}
b.WriteString(fmt.Sprintf("role %s#%d (", r.Name, r.Ref))
b.WriteString(fmt.Sprintf("role %s#%d (", r.Name, r.GetRef()))
if len(r.Params.AttrNames()) > 0 {
b.WriteString(r.Params.String())
b.WriteString(",")
Expand All @@ -107,7 +118,7 @@ func (r *Role) MarshalJSON() ([]byte, error) {
b := strings.Builder{}
b.WriteString("{")
b.WriteString(fmt.Sprintf("\"name\": \"%s\",", r.Name))
b.WriteString(fmt.Sprintf("\"ref\": %d,", r.Ref))
b.WriteString(fmt.Sprintf("\"ref\": %d,", r.GetRef()))
b.WriteString(fmt.Sprintf("\"ref_string\": \"%s\",", r.RefStringShort()))
b.WriteString("\"params\": ")
params, err := r.Params.MarshalJSON()
Expand All @@ -128,15 +139,15 @@ func (r *Role) MarshalJSON() ([]byte, error) {
}

func (r *Role) RefString() string {
return GenerateRefString(r.Name, r.Ref)
return GenerateRefString(r.Name, r.GetRef())
}

func GenerateRefString(name string, ref int64) string {
return fmt.Sprintf("role %s#%d", name, ref)
}

func (r *Role) RefStringShort() string {
return fmt.Sprintf("%s#%d", r.Name, r.Ref)
return fmt.Sprintf("%s#%d", r.Name, r.GetRef())
}

func (r *Role) Type() string {
Expand All @@ -153,7 +164,7 @@ func (r *Role) Truth() starlark.Bool {

func (r *Role) Hash() (uint32, error) {
hash, _ := starlark.String(r.Name).Hash()
return hash + uint32(r.Ref), nil
return hash + uint32(r.GetRef()), nil
}

func (r *Role) IsSymmetric() bool {
Expand Down Expand Up @@ -181,7 +192,15 @@ func CreateRoleBuiltin(astRole *ast.Role, symmetric bool, roles *[]*Role) *starl
for _, function := range astRole.Functions {
roleMethods[function.Name] = starlark.NewBuiltin(function.Name, fizz_func_always_error)
}
r := &Role{Ref: nextRef, Name: name, Symmetric: symmetric, Params: params, Fields: fields, Methods: map[string]*starlark.Function{}, RoleMethods: roleMethods, InitValues: initValues}

var id starlark.Value
if symmetric {
id = NewSymmetricValue(name, nextRef)
} else {
id = NewModelValue(name, nextRef)
}

r := &Role{ID: id, Name: name, Symmetric: symmetric, Params: params, Fields: fields, Methods: map[string]*starlark.Function{}, RoleMethods: roleMethods, InitValues: initValues}
*roles = append(*roles, r)
return r, nil
})
Expand Down
24 changes: 17 additions & 7 deletions modelchecker/clone.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,16 +222,26 @@ func deepCloneStarlarkValueWithPermutations(value starlark.Value, refs map[starl
case "role":
r := value.(*lib.Role)
prefix := r.Name
id := r.Ref
id := r.GetId() // Get the ID object directly
if r.IsSymmetric() {
oldSymVal := lib.NewSymmetricValue(r.Name, r.Ref)
newVal, err := deepCloneStarlarkValueWithPermutations(oldSymVal, refs, permutations, alt)
// Cloning the ID object checks permutations
newVal, err := deepCloneStarlarkValueWithPermutations(r.ID, refs, permutations, alt)
if err != nil {
return nil, err
}
newRoleId := newVal.(*lib.SymmetricValue)
prefix = newRoleId.GetPrefix()
id = newRoleId.GetId()
id = newVal // Use the new (permuted) ID object

// If we need prefix from the new ID (though it shouldn't change for roles usually)
if sv, ok := id.(*lib.SymmetricValue); ok {
prefix = sv.GetPrefix()
}
} else {
// For non-symmetric roles, we still want to clone the ID model value
newVal, err := deepCloneStarlarkValueWithPermutations(r.ID, refs, permutations, alt)
if err != nil {
return nil, err
}
id = newVal
}

if cached, ok := refs[value]; ok {
Expand All @@ -246,7 +256,7 @@ func deepCloneStarlarkValueWithPermutations(value starlark.Value, refs map[starl
return nil, err
}
newRole := &lib.Role{
Ref: id,
ID: id,
Name: prefix,
Symmetric: r.IsSymmetric(),
Params: params.(*lib.Struct),
Expand Down
Loading