Skip to content

Commit

Permalink
Some tidying up
Browse files Browse the repository at this point in the history
  • Loading branch information
DavePearce committed Nov 29, 2024
1 parent 8656c86 commit e41598e
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 98 deletions.
63 changes: 33 additions & 30 deletions pkg/corset/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,14 +404,14 @@ func (r *resolver) resolveConstraintsInModule(enclosing Scope, decls []Declarati
func (r *resolver) resolveDefConstraintInModule(enclosing Scope, decl *DefConstraint) []SyntaxError {
var (
errors []SyntaxError
scope = NewEvaluationScope(enclosing)
scope = NewLocalScope(enclosing, false)
)
// Resolve guard
if decl.Guard != nil {
errors = r.resolveExpressionInModule(scope, false, decl.Guard)
errors = r.resolveExpressionInModule(scope, decl.Guard)
}
// Resolve constraint body
errors = append(errors, r.resolveExpressionInModule(scope, false, decl.Constraint)...)
errors = append(errors, r.resolveExpressionInModule(scope, decl.Constraint)...)
// Done
return errors
}
Expand All @@ -420,10 +420,10 @@ func (r *resolver) resolveDefConstraintInModule(enclosing Scope, decl *DefConstr
func (r *resolver) resolveDefInRangeInModule(enclosing Scope, decl *DefInRange) []SyntaxError {
var (
errors []SyntaxError
scope = NewEvaluationScope(enclosing)
scope = NewLocalScope(enclosing, false)
)
// Resolve property body
errors = append(errors, r.resolveExpressionInModule(scope, false, decl.Expr)...)
errors = append(errors, r.resolveExpressionInModule(scope, decl.Expr)...)
// Done
return errors
}
Expand All @@ -432,14 +432,14 @@ func (r *resolver) resolveDefInRangeInModule(enclosing Scope, decl *DefInRange)
func (r *resolver) resolveDefFunInModule(enclosing Scope, decl *DefFun) []SyntaxError {
var (
errors []SyntaxError
scope = NewLocalScope(NewEvaluationScope(enclosing))
scope = NewLocalScope(enclosing, false)
)
// Declare parameters in local scope
for _, p := range decl.Parameters {
scope.DeclareLocal(p.Name)
}
// Resolve property body
errors = append(errors, r.resolveExpressionInModule(&scope, false, decl.Body)...)
errors = append(errors, r.resolveExpressionInModule(scope, decl.Body)...)
// Remove parameters from enclosing environment
// Done
return errors
Expand All @@ -449,14 +449,14 @@ func (r *resolver) resolveDefFunInModule(enclosing Scope, decl *DefFun) []Syntax
func (r *resolver) resolveDefLookupInModule(enclosing Scope, decl *DefLookup) []SyntaxError {
var (
errors []SyntaxError
sourceScope = NewEvaluationScope(enclosing)
targetScope = NewEvaluationScope(enclosing)
sourceScope = NewLocalScope(enclosing, true)
targetScope = NewLocalScope(enclosing, true)
)

// Resolve source expressions
errors = append(errors, r.resolveExpressionsInModule(sourceScope, true, decl.Sources)...)
errors = append(errors, r.resolveExpressionsInModule(sourceScope, decl.Sources)...)
// Resolve target expressions
errors = append(errors, r.resolveExpressionsInModule(targetScope, true, decl.Targets)...)
errors = append(errors, r.resolveExpressionsInModule(targetScope, decl.Targets)...)
// Done
return errors
}
Expand All @@ -465,22 +465,22 @@ func (r *resolver) resolveDefLookupInModule(enclosing Scope, decl *DefLookup) []
func (r *resolver) resolveDefPropertyInModule(enclosing Scope, decl *DefProperty) []SyntaxError {
var (
errors []SyntaxError
scope = NewEvaluationScope(enclosing)
scope = NewLocalScope(enclosing, false)
)
// Resolve property body
errors = append(errors, r.resolveExpressionInModule(scope, false, decl.Assertion)...)
errors = append(errors, r.resolveExpressionInModule(scope, decl.Assertion)...)
// Done
return errors
}

// Resolve a sequence of zero or more expressions within a given module. This
// simply resolves each of the arguments in turn, collecting any errors arising.
func (r *resolver) resolveExpressionsInModule(scope Scope, global bool, args []Expr) []SyntaxError {
func (r *resolver) resolveExpressionsInModule(scope LocalScope, args []Expr) []SyntaxError {
var errors []SyntaxError
// Visit each argument
for _, arg := range args {
if arg != nil {
errs := r.resolveExpressionInModule(scope, global, arg)
errs := r.resolveExpressionInModule(scope, arg)
errors = append(errors, errs...)
}
}
Expand All @@ -493,27 +493,27 @@ func (r *resolver) resolveExpressionsInModule(scope Scope, global bool, args []E
// variable accesses. As above, the goal is ensure variable refers to something
// that was declared and, more specifically, what kind of access it is (e.g.
// column access, constant access, etc).
func (r *resolver) resolveExpressionInModule(scope Scope, global bool, expr Expr) []SyntaxError {
func (r *resolver) resolveExpressionInModule(scope LocalScope, expr Expr) []SyntaxError {
if _, ok := expr.(*Constant); ok {
return nil
} else if v, ok := expr.(*Add); ok {
return r.resolveExpressionsInModule(scope, global, v.Args)
return r.resolveExpressionsInModule(scope, v.Args)
} else if v, ok := expr.(*Exp); ok {
return r.resolveExpressionInModule(scope, global, v.Arg)
return r.resolveExpressionInModule(scope, v.Arg)
} else if v, ok := expr.(*IfZero); ok {
return r.resolveExpressionsInModule(scope, global, []Expr{v.Condition, v.TrueBranch, v.FalseBranch})
return r.resolveExpressionsInModule(scope, []Expr{v.Condition, v.TrueBranch, v.FalseBranch})
} else if v, ok := expr.(*Invoke); ok {
return r.resolveInvokeInModule(scope, global, v)
return r.resolveInvokeInModule(scope, v)
} else if v, ok := expr.(*List); ok {
return r.resolveExpressionsInModule(scope, global, v.Args)
return r.resolveExpressionsInModule(scope, v.Args)
} else if v, ok := expr.(*Mul); ok {
return r.resolveExpressionsInModule(scope, global, v.Args)
return r.resolveExpressionsInModule(scope, v.Args)
} else if v, ok := expr.(*Normalise); ok {
return r.resolveExpressionInModule(scope, global, v.Arg)
return r.resolveExpressionInModule(scope, v.Arg)
} else if v, ok := expr.(*Sub); ok {
return r.resolveExpressionsInModule(scope, global, v.Args)
return r.resolveExpressionsInModule(scope, v.Args)
} else if v, ok := expr.(*VariableAccess); ok {
return r.resolveVariableInModule(scope, global, v)
return r.resolveVariableInModule(scope, v)
} else {
return r.srcmap.SyntaxErrors(expr, "unknown expression")
}
Expand All @@ -522,9 +522,9 @@ func (r *resolver) resolveExpressionInModule(scope Scope, global bool, expr Expr
// Resolve a specific invocation contained within some expression which, in
// turn, is contained within some module. Note, qualified accesses are only
// permitted in a global context.
func (r *resolver) resolveInvokeInModule(scope Scope, global bool, expr *Invoke) []SyntaxError {
func (r *resolver) resolveInvokeInModule(scope LocalScope, expr *Invoke) []SyntaxError {
// Resolve arguments
if errors := r.resolveExpressionsInModule(scope, global, expr.Args); errors != nil {
if errors := r.resolveExpressionsInModule(scope, expr.Args); errors != nil {
return errors
}
// Lookup the corresponding function definition.
Expand All @@ -541,17 +541,20 @@ func (r *resolver) resolveInvokeInModule(scope Scope, global bool, expr *Invoke)
// Resolve a specific variable access contained within some expression which, in
// turn, is contained within some module. Note, qualified accesses are only
// permitted in a global context.
func (r *resolver) resolveVariableInModule(scope Scope, global bool,
func (r *resolver) resolveVariableInModule(scope LocalScope,
expr *VariableAccess) []SyntaxError {
// Will identify module of variable
//var module string = scope.EnclosingModule()
var mid *uint = nil
var mid *uint
// Check whether this is a qualified access, or not.
if !global && expr.Module != nil {
if !scope.IsGlobal() && expr.Module != nil {
return r.srcmap.SyntaxErrors(expr, "qualified access not permitted here")
} else if expr.Module != nil && !scope.HasModule(*expr.Module) {
return r.srcmap.SyntaxErrors(expr, fmt.Sprintf("unknown module %s", *expr.Module))
} else if expr.Module != nil {
tmp := scope.Module(*expr.Module)
mid = &tmp
} else {
tmp := scope.EnclosingModule()
mid = &tmp
}
Expand Down
105 changes: 37 additions & 68 deletions pkg/corset/scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,10 @@ type Scope interface {
// Get the name of the enclosing module. This is generally useful for
// reporting errors.
EnclosingModule() uint
// Fix the context for this scope. Since every scope requires exactly one
// context, this fails if we fix it to incompatible contexts.
FixContext(tr.Context) bool
// HasModule checks whether a given module exists, or not.
HasModule(string) bool
// Module determines the module index for a given module. This assumes the
// module exists, and will panic otherwise.
// Lookup the identifier for a given module. This assumes that the module
// exists, and will panic otherwise.
Module(string) uint
// Lookup a given variable being referenced with an optional module
// specifier. This variable could correspond to a column, a function, a
Expand Down Expand Up @@ -49,12 +46,6 @@ func (p *ModuleScope) EnclosingModule() uint {
return p.module
}

// FixContext fixes the context for this scope. Since every scope requires
// exactly one context, this fails if we fix it to incompatible contexts.
func (p *ModuleScope) FixContext(context tr.Context) bool {
panic("unreachable")
}

// HasModule checks whether a given module exists, or not.
func (p *ModuleScope) HasModule(module string) bool {
return p.environment.HasModule(module)
Expand Down Expand Up @@ -96,75 +87,50 @@ func (p *ModuleScope) DeclareFunction(name string, arity uint, body Expr) {
p.functions[name] = FunctionBinding{arity, body}
}

// =============================================================================
// Evaluation Scope
// =============================================================================

// EvaluationScope represents a scope in which a given expression can be
// evaluated. The key feature of an evaluation scope is that it must have a
// single context.
type EvaluationScope struct {
// Represents the enclosing scope
enclosing Scope
// Context for this scope
context tr.Context
}

// NewEvaluationScope creates a fresh scope representing the evaluation of some
// expression.
func NewEvaluationScope(enclosing Scope) *EvaluationScope {
return &EvaluationScope{enclosing, tr.VoidContext()}
}

// EnclosingModule returns the name of the enclosing module. This is generally
// useful for reporting errors.
func (p *EvaluationScope) EnclosingModule() uint {
return p.enclosing.EnclosingModule()
}

// FixContext fixes the context for this scope. Since every scope requires
// exactly one context, this fails if we fix it to incompatible contexts.
func (p *EvaluationScope) FixContext(context tr.Context) bool {
// Join contexts together
p.context = p.context.Join(context)
// Check they were compatible
return !p.context.IsConflicted()
}

// HasModule checks whether a given module exists, or not.
func (p *EvaluationScope) HasModule(module string) bool {
return p.enclosing.HasModule(module)
}

// Module determines the module index for a given module. This assumes the
// module exists, and will panic otherwise.
func (p *EvaluationScope) Module(module string) uint {
return p.enclosing.Module(module)
}

// Bind looks up a given variable being referenced within a given module.
func (p *EvaluationScope) Bind(module *uint, name string, fn bool) Binding {
return p.enclosing.Bind(module, name, fn)
}

// =============================================================================
// Local Scope
// =============================================================================

// LocalScope represents a simple implementation of scope in which local
// variables can be declared.
// variables can be declared. A local scope must have a single context
// associated with it, and this will be inferred by resolving those expressions
// which must be evaluated within.
type LocalScope struct {
global bool
// Represents the enclosing scope
enclosing Scope
// Context for this scope
context *tr.Context
// Maps inputs parameters to the declaration index.
locals map[string]uint
}

// NewLocalScope constructs a new local scope within a given scope. A local
// scope can have local variables declared within it.
func NewLocalScope(enclosing Scope) LocalScope {
// NewLocalScope constructs a new local scope within a given enclosing scope. A
// local scope can have local variables declared within it. A local scope can
// also be "global" in the sense that accessing symbols from other modules is
// permitted.
func NewLocalScope(enclosing Scope, global bool) LocalScope {
context := tr.VoidContext()
locals := make(map[string]uint)
return LocalScope{enclosing, locals}
//
return LocalScope{global, enclosing, &context, locals}
}

// NestedScope creates a nested scope within this local scope.
func (p LocalScope) NestedScope() LocalScope {
nlocals := make(map[string]uint)
// Clone allocated variables
for k, v := range p.locals {
nlocals[k] = v
}
// Done
return LocalScope{p.global, p.enclosing, p.context, nlocals}
}

// IsGlobal determines whether symbols can be accessed in modules other than the
// enclosing module.
func (p LocalScope) IsGlobal() bool {
return p.global
}

// EnclosingModule returns the name of the enclosing module. This is generally
Expand All @@ -176,7 +142,10 @@ func (p LocalScope) EnclosingModule() uint {
// FixContext fixes the context for this scope. Since every scope requires
// exactly one context, this fails if we fix it to incompatible contexts.
func (p LocalScope) FixContext(context tr.Context) bool {
return p.enclosing.FixContext(context)
// Join contexts together
*p.context = p.context.Join(context)
// Check they were compatible
return !p.context.IsConflicted()
}

// HasModule checks whether a given module exists, or not.
Expand Down

0 comments on commit e41598e

Please sign in to comment.