mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-21 10:27:26 +08:00
* v2.1.0 [omit consensus and adjacent] - this commit will be amended with the full release after the file copy is complete * 2.1.0 main node rollup
243 lines
4.9 KiB
Go
243 lines
4.9 KiB
Go
//
|
|
// Copyright (c) 2020-2023 Markku Rossi
|
|
//
|
|
// All rights reserved.
|
|
//
|
|
|
|
package ssa
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"source.quilibrium.com/quilibrium/monorepo/bedlam/types"
|
|
)
|
|
|
|
var (
|
|
_ BindingValue = &Value{}
|
|
_ BindingValue = &Select{}
|
|
)
|
|
|
|
// Bindings defines value bindings.
|
|
type Bindings struct {
|
|
shared bool
|
|
Values []Binding
|
|
}
|
|
|
|
// Debug prints the bindings.
|
|
func (bindings *Bindings) Debug() {
|
|
fmt.Printf("Bindings: shared=%v, Values=[\n", bindings.shared)
|
|
for _, value := range bindings.Values {
|
|
fmt.Printf("\t%s,\n", value)
|
|
}
|
|
fmt.Println("]")
|
|
}
|
|
|
|
// Count returns the number of variable bindings the Bindings
|
|
// contains.
|
|
func (bindings *Bindings) Count() int {
|
|
return len(bindings.Values)
|
|
}
|
|
|
|
// Clone makes a copy of the bindings.
|
|
func (bindings Bindings) Clone() *Bindings {
|
|
result := &Bindings{
|
|
shared: true,
|
|
Values: bindings.Values,
|
|
}
|
|
bindings.shared = true
|
|
|
|
return result
|
|
}
|
|
|
|
// Define defines name v in the bindings. The argument val specifies
|
|
// an optional value for the name. If val is nil, the value of the
|
|
// name will be v.
|
|
func (bindings *Bindings) Define(v Value, val *Value) {
|
|
bindings.set(v, v.Type, val)
|
|
}
|
|
|
|
// Set sets a new binding for the name. It is an error if the name is
|
|
// not defined.
|
|
func (bindings *Bindings) Set(v Value, val *Value) error {
|
|
b, ok := bindings.Get(v.Name)
|
|
if !ok {
|
|
return fmt.Errorf("name %s not defined", v.Name)
|
|
}
|
|
bindings.set(v, b.Type, val)
|
|
return nil
|
|
}
|
|
|
|
func (bindings *Bindings) set(v Value, t types.Info, val *Value) {
|
|
if bindings.shared {
|
|
// Make our own copy of the values.
|
|
values := make([]Binding, len(bindings.Values))
|
|
copy(values, bindings.Values)
|
|
bindings.Values = values
|
|
bindings.shared = false
|
|
}
|
|
|
|
for idx, b := range bindings.Values {
|
|
if b.Name == v.Name && b.Scope == v.Scope {
|
|
b.Type = t
|
|
if val != nil {
|
|
b.Bound = val
|
|
} else {
|
|
b.Bound = &v
|
|
}
|
|
bindings.Values[idx] = b
|
|
return
|
|
}
|
|
}
|
|
|
|
b := Binding{
|
|
Name: v.Name,
|
|
Scope: v.Scope,
|
|
Type: t,
|
|
}
|
|
if val != nil {
|
|
b.Bound = val
|
|
} else {
|
|
b.Bound = &v
|
|
}
|
|
|
|
bindings.Values = append(bindings.Values, b)
|
|
}
|
|
|
|
// Get gets the value binding.
|
|
func (bindings Bindings) Get(name string) (ret Binding, ok bool) {
|
|
for _, b := range bindings.Values {
|
|
if b.Name == name {
|
|
if len(ret.Name) == 0 || b.Scope > ret.Scope {
|
|
ret = b
|
|
}
|
|
}
|
|
}
|
|
if len(ret.Name) == 0 {
|
|
return ret, false
|
|
}
|
|
return ret, true
|
|
}
|
|
|
|
func contains(values []Binding, name string) bool {
|
|
for _, v := range values {
|
|
if v.Name == name {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Merge merges the argument false-branch bindings into this bindings
|
|
// instance that represents the true-branch values.
|
|
func (bindings Bindings) Merge(cond Value, falseBindings *Bindings) *Bindings {
|
|
var result []Binding
|
|
for _, b := range bindings.Values {
|
|
name := b.Name
|
|
if contains(result, name) {
|
|
continue
|
|
}
|
|
|
|
bTrue, okTrue := bindings.Get(name)
|
|
bFalse, okFalse := falseBindings.Get(name)
|
|
if !okTrue && !okFalse {
|
|
continue
|
|
} else if !okTrue {
|
|
result = append(result, bFalse)
|
|
} else if !okFalse {
|
|
result = append(result, bTrue)
|
|
} else {
|
|
if bTrue.Bound.Equal(bFalse.Bound) {
|
|
result = append(result, bTrue)
|
|
} else {
|
|
var phiType types.Info
|
|
if bTrue.Type.Bits > bFalse.Type.Bits {
|
|
phiType = bTrue.Type
|
|
} else {
|
|
phiType = bFalse.Type
|
|
}
|
|
|
|
result = append(result, Binding{
|
|
Name: name,
|
|
Scope: bTrue.Scope,
|
|
Type: phiType,
|
|
Bound: &Select{
|
|
Cond: cond,
|
|
Type: phiType,
|
|
True: bTrue.Bound,
|
|
False: bFalse.Bound,
|
|
},
|
|
})
|
|
}
|
|
}
|
|
}
|
|
return &Bindings{
|
|
Values: result,
|
|
}
|
|
}
|
|
|
|
// Binding implements a value binding.
|
|
type Binding struct {
|
|
Name string
|
|
Scope Scope
|
|
Type types.Info
|
|
Bound BindingValue
|
|
}
|
|
|
|
func (b Binding) String() string {
|
|
return fmt.Sprintf("%s@%d/%s=%s", b.Name, b.Scope, b.Type, b.Bound)
|
|
}
|
|
|
|
// Value returns the binding value.
|
|
func (b Binding) Value(block *Block, gen *Generator) Value {
|
|
return b.Bound.Value(block, gen)
|
|
}
|
|
|
|
// BindingValue represents value binding.
|
|
type BindingValue interface {
|
|
Equal(o BindingValue) bool
|
|
Value(block *Block, gen *Generator) Value
|
|
}
|
|
|
|
// Select implements Phi-bindings for value.
|
|
type Select struct {
|
|
Cond Value
|
|
Type types.Info
|
|
True BindingValue
|
|
False BindingValue
|
|
Resolved Value
|
|
}
|
|
|
|
func (phi *Select) String() string {
|
|
return fmt.Sprintf("\u03D5(%s|%s|%s)/%s",
|
|
phi.Cond, phi.True, phi.False, phi.Type)
|
|
}
|
|
|
|
// Equal tests if this select binding is equal to the argument bindind
|
|
// value.
|
|
func (phi *Select) Equal(other BindingValue) bool {
|
|
o, ok := other.(*Select)
|
|
if !ok {
|
|
return false
|
|
}
|
|
if !phi.Cond.Equal(&o.Cond) {
|
|
return false
|
|
}
|
|
return phi.True.Equal(o.True) && phi.False.Equal(o.False)
|
|
}
|
|
|
|
// Value returns the binding value.
|
|
func (phi *Select) Value(block *Block, gen *Generator) Value {
|
|
if phi.Resolved.Type.Type != types.TUndefined {
|
|
return phi.Resolved
|
|
}
|
|
|
|
t := phi.True.Value(block, gen)
|
|
f := phi.False.Value(block, gen)
|
|
v := gen.AnonVal(phi.Type)
|
|
block.AddInstr(NewPhiInstr(phi.Cond, t, f, v))
|
|
|
|
phi.Resolved = v
|
|
|
|
return v
|
|
}
|