Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support perspective name qualification #504

Merged
merged 3 commits into from
Jan 8, 2025
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
39 changes: 27 additions & 12 deletions pkg/corset/allocation.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,11 @@ func (r *Register) Deactivate() {
// RegisterSource provides necessary information about source-level columns
// allocated to a given register.
type RegisterSource struct {
// Module in which source-level column resides
module string
// Perspective containing source-level column. If none, then this is
// assigned "".
perspective string
// Name of source-level column.
name string
// Context is a prefix of name which, when they differ, indicates a virtual
// column (i.e. one which is subject to register allocation).
context util.Path
// Fully qualified (i.e. absolute) name of source-level column.
name util.Path
// Length multiplier of source-level column.
multiplier uint
// Underlying datatype of the source-level column.
Expand All @@ -94,6 +92,19 @@ type RegisterSource struct {
computed bool
}

// IsVirtual indicates whether or not this is a "virtual" column. That is,
// something which is subject to register allocation (i.e. because it is
// declared in a perspective).
func (p *RegisterSource) IsVirtual() bool {
return !p.name.Parent().Equals(p.context)
}

// Perspective returns the name of the "virtual perspective" in which this
// column exists.
func (p *RegisterSource) Perspective() string {
return p.name.Parent().Slice(p.context.Depth()).String()
}

// RegisterAllocation is a generic interface to support different "regsiter
// allocation" algorithms. More specifically, register allocation is the
// process of allocating columns to their underlying HIR columns (a.k.a
Expand Down Expand Up @@ -186,20 +197,24 @@ func NewRegisterAllocator(allocation RegisterAllocation) *RegisterAllocator {
// Identify all perspectives
for iter := allocation.Registers(); iter.HasNext(); {
regInfo := allocation.Register(iter.Next())
regSource := regInfo.Sources[0]
//
if len(regInfo.Sources) != 1 {
// This should be unreachable.
panic("register not associated with unique column")
} else if regInfo.Sources[0].perspective != "" {
allocator.allocatePerspective(regInfo.Sources[0].perspective)
} else if regSource.IsVirtual() {
allocator.allocatePerspective(regSource.Perspective())
}
}
// Initial allocation of perspective registers
for iter := allocation.Registers(); iter.HasNext(); {
regIndex := iter.Next()
regInfo := allocation.Register(regIndex)

if regInfo.Sources[0].perspective != "" {
allocator.allocateRegister(regInfo.Sources[0].perspective, regIndex)
regSource := regInfo.Sources[0]
//
if regSource.IsVirtual() {
perspective := regSource.Perspective()
allocator.allocateRegister(perspective, regIndex)
}
}
// Done (for now)
Expand Down
42 changes: 20 additions & 22 deletions pkg/corset/binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,9 @@ import (

"github.com/consensys/go-corset/pkg/sexp"
tr "github.com/consensys/go-corset/pkg/trace"
"github.com/consensys/go-corset/pkg/util"
)

// BindingId is an identifier is used to distinguish different forms of binding,
// as some forms are known from their use. Specifically, at the current time,
// only functions are distinguished from other categories (e.g. columns,
// parameters, etc).
type BindingId struct {
// Name of the binding
name string
// Indicates whether function binding or other.
fn bool
}

// Binding represents an association between a name, as found in a source file,
// and concrete item (e.g. a column, function, etc).
type Binding interface {
Expand Down Expand Up @@ -145,12 +135,14 @@ func (p *FunctionSignature) Apply(args []Expr, srcmap *sexp.SourceMaps[Node]) Ex

// ColumnBinding represents something bound to a given column.
type ColumnBinding struct {
// Column's enclosing module
module string
// Enclosing perspective
perspective string
// Column's name
name string
// Context determines the real (i.e. non-virtual) enclosing module of this
// column, and should always be a prefix of the path. If this column was
// declared in a perspective then it will be the perspective's enclosing
// module. Otherwise, it will exactly match the path's parent.
context util.Path
// Absolute path of column. This determines the name of the column, its
// enclosing module and/or perspective.
path util.Path
// Determines whether this is a computed column, or not.
computed bool
// Determines whether this column must be proven (or not).
Expand All @@ -167,8 +159,13 @@ type ColumnBinding struct {
// definterleaved constraint the target column information (e.g. its type) is
// not immediately available and must be determined from those columns from
// which it is constructed.
func NewComputedColumnBinding(module string, name string) *ColumnBinding {
return &ColumnBinding{module, "", name, true, false, 0, nil}
func NewComputedColumnBinding(context util.Path, path util.Path) *ColumnBinding {
return &ColumnBinding{context, path, true, false, 0, nil}
}

// AbsolutePath returns the fully resolved (absolute) path of the column in question.
func (p *ColumnBinding) AbsolutePath() *util.Path {
return &p.path
}

// IsFinalised checks whether this binding has been finalised yet or not.
Expand All @@ -185,7 +182,7 @@ func (p *ColumnBinding) Finalise(multiplier uint, datatype Type) {
// Context returns the of this column. That is, the module in which this colunm
// was declared and also the length multiplier of that module it requires.
func (p *ColumnBinding) Context() Context {
return tr.NewContext(p.module, p.multiplier)
return tr.NewContext(p.context.String(), p.multiplier)
}

// ============================================================================
Expand All @@ -194,6 +191,7 @@ func (p *ColumnBinding) Context() Context {

// ConstantBinding represents a constant definition
type ConstantBinding struct {
path util.Path
// Constant expression which, when evaluated, produces a constant value.
value Expr
// Inferred type of the given expression
Expand All @@ -202,8 +200,8 @@ type ConstantBinding struct {

// NewConstantBinding creates a new constant binding (which is initially not
// finalised).
func NewConstantBinding(value Expr) ConstantBinding {
return ConstantBinding{value, nil}
func NewConstantBinding(path util.Path, value Expr) ConstantBinding {
return ConstantBinding{path, value, nil}
}

// IsFinalised checks whether this binding has been finalised yet or not.
Expand Down
2 changes: 1 addition & 1 deletion pkg/corset/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func (p *Compiler) Compile() (*hir.Schema, []SyntaxError) {
return nil, errs
}
// Convert global scope into an environment by allocating all columns.
environment := scope.ToEnvironment(p.allocator)
environment := NewGlobalEnvironment(scope, p.allocator)
// Finally, translate everything and add it to the schema.
return TranslateCircuit(environment, p.srcmap, &p.circuit)
}
Expand Down
67 changes: 48 additions & 19 deletions pkg/corset/declaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,12 @@ func (p *DefColumns) Lisp() sexp.SExp {
// DefColumn packages together those piece relevant to declaring an individual
// column, such its name and type.
type DefColumn struct {
// Column name
name string
// Binding of this column (which may or may not be finalised).
binding ColumnBinding
}

var _ SymbolDefinition = &DefColumn{}

// IsFunction is never true for a column definition.
func (e *DefColumn) IsFunction() bool {
return false
Expand All @@ -200,9 +200,16 @@ func (e *DefColumn) Binding() Binding {
return &e.binding
}

// Name of symbol being defined
// Name returns the (unqualified) name of this symbol. For example, "X" for
// a column X defined in a module m1.
func (e *DefColumn) Name() string {
return e.name
return e.binding.path.Tail()
}

// Path returns the qualified name (i.e. absolute path) of this symbol. For
// example, "m1.X" for a column X defined in module m1.
func (e *DefColumn) Path() *util.Path {
return &e.binding.path
}

// DataType returns the type of this column. If this column have not yet been
Expand Down Expand Up @@ -241,7 +248,7 @@ func (e *DefColumn) MustProve() bool {
// for debugging purposes.
func (e *DefColumn) Lisp() sexp.SExp {
list := sexp.EmptyList()
list.Append(sexp.NewSymbol(e.name))
list.Append(sexp.NewSymbol(e.Name()))
//
if e.binding.dataType != nil {
datatype := e.binding.dataType.String()
Expand Down Expand Up @@ -326,7 +333,7 @@ func (p *DefConst) Lisp() sexp.SExp {
def.Append(sexp.NewSymbol("defconst"))
//
for _, c := range p.constants {
def.Append(sexp.NewSymbol(c.name))
def.Append(sexp.NewSymbol(c.Name()))
def.Append(c.binding.value.Lisp())
}
// Done
Expand All @@ -336,8 +343,6 @@ func (p *DefConst) Lisp() sexp.SExp {
// DefConstUnit represents the definition of exactly one constant value. As
// such, this is an instance of SymbolDefinition and provides a binding.
type DefConstUnit struct {
// Name of the constant being declared.
name string
// Binding for this constant.
binding ConstantBinding
}
Expand All @@ -353,19 +358,26 @@ func (e *DefConstUnit) Binding() Binding {
return &e.binding
}

// Name of symbol being defined
// Name returns the (unqualified) name of this symbol. For example, "X" for
// a column X defined in a module m1.
func (e *DefConstUnit) Name() string {
return e.name
return e.binding.path.Tail()
}

// Path returns the qualified name (i.e. absolute path) of this symbol. For
// example, "m1.X" for a column X defined in module m1.
func (e *DefConstUnit) Path() *util.Path {
return &e.binding.path
}

// Lisp converts this node into its lisp representation. This is primarily used
// for debugging purposes.
//
//nolint:revive
func (p *DefConstUnit) Lisp() sexp.SExp {
func (e *DefConstUnit) Lisp() sexp.SExp {
return sexp.NewList([]sexp.SExp{
sexp.NewSymbol(p.name),
p.binding.value.Lisp()})
sexp.NewSymbol(e.Name()),
e.binding.value.Lisp()})
}

// ============================================================================
Expand Down Expand Up @@ -766,9 +778,16 @@ type DefPerspective struct {
Columns []*DefColumn
}

// Name of symbol being defined
// Name returns the (unqualified) name of this symbol. For example, "X" for
// a column X defined in a module m1.
func (p *DefPerspective) Name() string {
return p.symbol.name
return p.symbol.Path().Tail()
}

// Path returns the qualified name (i.e. absolute path) of this symbol. For
// example, "m1.X" for a column X defined in module m1.
func (p *DefPerspective) Path() *util.Path {
return &p.symbol.path
}

// IsFunction is always true for a function definition!
Expand Down Expand Up @@ -903,6 +922,8 @@ type DefFun struct {
parameters []*DefParameter
}

var _ SymbolDefinition = &DefFun{}

// IsFunction is always true for a function definition!
func (p *DefFun) IsFunction() bool {
return true
Expand Down Expand Up @@ -932,9 +953,16 @@ func (p *DefFun) Binding() Binding {
return p.symbol.binding
}

// Name of symbol being defined
// Name returns the (unqualified) name of this symbol. For example, "X" for
// a column X defined in a module m1.
func (p *DefFun) Name() string {
return p.symbol.name
return p.symbol.Path().Tail()
}

// Path returns the qualified name (i.e. absolute path) of this symbol. For
// example, "m1.X" for a column X defined in module m1.
func (p *DefFun) Path() *util.Path {
return &p.symbol.path
}

// Definitions returns the set of symbols defined by this declaration. Observe
Expand All @@ -951,7 +979,8 @@ func (p *DefFun) Dependencies() util.Iterator[Symbol] {
// Filter out all parameters declared in this function, since these are not
// external dependencies.
for _, d := range deps {
if d.IsQualified() || d.IsFunction() || !p.hasParameter(d.Name()) {
n := d.Path()
if n.IsAbsolute() || d.IsFunction() || n.Depth() > 1 || !p.hasParameter(n.Head()) {
ndeps = append(ndeps, d)
}
}
Expand All @@ -976,7 +1005,7 @@ func (p *DefFun) IsFinalised() bool {
func (p *DefFun) Lisp() sexp.SExp {
return sexp.NewList([]sexp.SExp{
sexp.NewSymbol("defun"),
sexp.NewSymbol(p.symbol.name),
sexp.NewSymbol(p.symbol.path.Tail()),
sexp.NewSymbol("..."), // todo
})
}
Expand Down
Loading
Loading