Skip to content

Commit

Permalink
add error return value to interpreter and checker handlers
Browse files Browse the repository at this point in the history
- interpreter UUID handler
- interpreter event emission handler
- checker location handler
  • Loading branch information
turbolent committed Nov 27, 2020
1 parent 8771879 commit d37c9f3
Show file tree
Hide file tree
Showing 11 changed files with 116 additions and 77 deletions.
4 changes: 2 additions & 2 deletions runtime/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,9 @@ func PrepareInterpreter(filename string) (*interpreter.Interpreter, *sema.Checke
inter, err := interpreter.NewInterpreter(
checker,
interpreter.WithPredefinedValues(valueDeclarations.ToValues()),
interpreter.WithUUIDHandler(func() uint64 {
interpreter.WithUUIDHandler(func() (uint64, error) {
defer func() { uuid++ }()
return uuid
return uuid, nil
}),
)
must(err)
Expand Down
34 changes: 27 additions & 7 deletions runtime/interpreter/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ func (e DestroyedCompositeError) Error() string {
}

// ForceAssignmentToNonNilResourceError

//
type ForceAssignmentToNonNilResourceError struct {
LocationRange
}
Expand All @@ -206,7 +206,7 @@ func (e ForceAssignmentToNonNilResourceError) Error() string {
}

// ForceNilError

//
type ForceNilError struct {
LocationRange
}
Expand All @@ -216,7 +216,7 @@ func (e ForceNilError) Error() string {
}

// TypeMismatchError

//
type TypeMismatchError struct {
ExpectedType sema.Type
LocationRange
Expand All @@ -230,7 +230,7 @@ func (e TypeMismatchError) Error() string {
}

// InvalidPathDomainError

//
type InvalidPathDomainError struct {
ActualDomain common.PathDomain
ExpectedDomains []common.PathDomain
Expand All @@ -257,7 +257,7 @@ func (e InvalidPathDomainError) SecondaryError() string {
}

// OverwriteError

//
type OverwriteError struct {
Address AddressValue
Path PathValue
Expand All @@ -273,7 +273,7 @@ func (e OverwriteError) Error() string {
}

// CyclicLinkError

//
type CyclicLinkError struct {
Address AddressValue
Paths []PathValue
Expand All @@ -298,7 +298,7 @@ func (e CyclicLinkError) Error() string {
}

// ArrayIndexOutOfBoundsError

//
type ArrayIndexOutOfBoundsError struct {
Index int
MaxIndex int
Expand All @@ -312,3 +312,23 @@ func (e ArrayIndexOutOfBoundsError) Error() string {
e.MaxIndex,
)
}

// EventEmissionUnavailableError
//
type EventEmissionUnavailableError struct {
LocationRange
}

func (e EventEmissionUnavailableError) Error() string {
return "cannot emit event: unavailable"
}

// UUIDUnavailableError
//
type UUIDUnavailableError struct {
LocationRange
}

func (e UUIDUnavailableError) Error() string {
return "cannot get UUID: unavailable"
}
28 changes: 24 additions & 4 deletions runtime/interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ type OnEventEmittedFunc func(
inter *Interpreter,
event *CompositeValue,
eventType *sema.CompositeType,
)
) error

// OnStatementFunc is a function that is triggered when a statement is about to be executed.
//
Expand Down Expand Up @@ -160,7 +160,7 @@ type ImportLocationHandlerFunc func(
) Import

// UUIDHandlerFunc is a function that handles the generation of UUIDs.
type UUIDHandlerFunc func() uint64
type UUIDHandlerFunc func() (uint64, error)

// CompositeTypeCode contains the the "prepared" / "callable" "code"
// for the functions and the destructor of a composite
Expand Down Expand Up @@ -2557,7 +2557,18 @@ func (interpreter *Interpreter) declareNonEnumCompositeValue(
fields := map[string]Value{}

if declaration.CompositeKind == common.CompositeKindResource {
uuid := interpreter.uuidHandler()

if interpreter.uuidHandler == nil {
panic(UUIDUnavailableError{
LocationRange: invocation.LocationRange,
})
}

uuid, err := interpreter.uuidHandler()
if err != nil {
panic(err)
}

fields[sema.ResourceUUIDFieldName] = UInt64Value(uuid)
}

Expand Down Expand Up @@ -3489,7 +3500,16 @@ func (interpreter *Interpreter) VisitEmitStatement(statement *ast.EmitStatement)

eventType := interpreter.Checker.Elaboration.EmitStatementEventTypes[statement]

interpreter.onEventEmitted(interpreter, event, eventType)
if interpreter.onEventEmitted == nil {
panic(EventEmissionUnavailableError{
LocationRange: interpreter.locationRange(statement),
})
}

err := interpreter.onEventEmitted(interpreter, event, eventType)
if err != nil {
panic(err)
}

// NOTE: no result, so it does *not* act like a return-statement
return Done{}
Expand Down
4 changes: 2 additions & 2 deletions runtime/repl.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ func NewREPL(onError func(error), onResult func(interpreter.Value), checkerOptio
inter, err := interpreter.NewInterpreter(
checker,
interpreter.WithPredefinedValues(values),
interpreter.WithUUIDHandler(func() uint64 {
interpreter.WithUUIDHandler(func() (uint64, error) {
defer func() { uuid++ }()
return uuid
return uuid, nil
}),
)
if err != nil {
Expand Down
86 changes: 40 additions & 46 deletions runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -542,44 +542,44 @@ func (r *interpreterRuntime) parseAndCheckProgram(
sema.WithPredeclaredValues(valueDeclarations),
sema.WithPredeclaredTypes(typeDeclarations),
sema.WithValidTopLevelDeclarationsHandler(validTopLevelDeclarations),
sema.WithLocationHandler(func(identifiers []Identifier, location Location) (res []ResolvedLocation) {
var err error
wrapPanic(func() {
res, err = runtimeInterface.ResolveLocation(identifiers, location)
})
if err != nil {
panic(err)
}
return
}),
sema.WithImportHandler(func(checker *sema.Checker, location ast.Location) (sema.Import, *sema.CheckerError) {
switch location {
case stdlib.CryptoChecker.Location:
return sema.CheckerImport{
Checker: stdlib.CryptoChecker,
}, nil

default:
var program *ast.Program
var err error
checker, checkerErr := checker.EnsureLoaded(location, func() *ast.Program {
program, err = importResolver(location)
return program
sema.WithLocationHandler(
func(identifiers []Identifier, location Location) (res []ResolvedLocation, err error) {
wrapPanic(func() {
res, err = runtimeInterface.ResolveLocation(identifiers, location)
})
// TODO: improve
if err != nil {
return nil, &sema.CheckerError{
Errors: []error{err},
return
},
),
sema.WithImportHandler(
func(checker *sema.Checker, location ast.Location) (sema.Import, *sema.CheckerError) {
switch location {
case stdlib.CryptoChecker.Location:
return sema.CheckerImport{
Checker: stdlib.CryptoChecker,
}, nil

default:
var program *ast.Program
var err error
checker, checkerErr := checker.EnsureLoaded(location, func() *ast.Program {
program, err = importResolver(location)
return program
})
// TODO: improve
if err != nil {
return nil, &sema.CheckerError{
Errors: []error{err},
}
}
if checkerErr != nil {
return nil, checkerErr
}
return sema.CheckerImport{
Checker: checker,
}, nil
}
if checkerErr != nil {
return nil, checkerErr
}
return sema.CheckerImport{
Checker: checker,
}, nil
}
}),
},
),
sema.WithCheckHandler(func(location ast.Location, check func()) {
reportMetric(
func() {
Expand Down Expand Up @@ -630,8 +630,8 @@ func (r *interpreterRuntime) newInterpreter(
inter *interpreter.Interpreter,
eventValue *interpreter.CompositeValue,
eventType *sema.CompositeType,
) {
r.emitEvent(inter, runtimeInterface, eventValue, eventType)
) error {
return r.emitEvent(inter, runtimeInterface, eventValue, eventType)
},
),
interpreter.WithStorageKeyHandler(
Expand All @@ -642,14 +642,10 @@ func (r *interpreterRuntime) newInterpreter(
interpreter.WithInjectedCompositeFieldsHandler(
r.injectedCompositeFieldsHandler(runtimeInterface, runtimeStorage),
),
interpreter.WithUUIDHandler(func() (uuid uint64) {
var err error
interpreter.WithUUIDHandler(func() (uuid uint64, err error) {
wrapPanic(func() {
uuid, err = runtimeInterface.GenerateUUID()
})
if err != nil {
panic(err)
}
return
}),
interpreter.WithContractValueHandler(
Expand Down Expand Up @@ -923,7 +919,7 @@ func (r *interpreterRuntime) emitEvent(
runtimeInterface Interface,
event *interpreter.CompositeValue,
eventType *sema.CompositeType,
) {
) error {
fields := make([]exportableValue, len(eventType.ConstructorParameters))

for i, parameter := range eventType.ConstructorParameters {
Expand All @@ -940,9 +936,7 @@ func (r *interpreterRuntime) emitEvent(
wrapPanic(func() {
err = runtimeInterface.EmitEvent(exportedEvent)
})
if err != nil {
panic(err)
}
return err
}

func (r *interpreterRuntime) emitAccountEvent(
Expand Down
11 changes: 7 additions & 4 deletions runtime/sema/check_import_declaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ func (checker *Checker) declareImportDeclaration(declaration *ast.ImportDeclarat
EndPos: declaration.LocationPos,
}

resolvedLocations := checker.resolveLocation(declaration.Identifiers, declaration.Location)
resolvedLocations, err := checker.resolveLocation(declaration.Identifiers, declaration.Location)
if err != nil {
checker.report(err)
return nil
}

checker.Elaboration.ImportDeclarationsResolvedLocations[declaration] = resolvedLocations

Expand All @@ -61,7 +65,7 @@ func (checker *Checker) declareImportDeclaration(declaration *ast.ImportDeclarat
return nil
}

func (checker *Checker) resolveLocation(identifiers []ast.Identifier, location ast.Location) []ResolvedLocation {
func (checker *Checker) resolveLocation(identifiers []ast.Identifier, location ast.Location) ([]ResolvedLocation, error) {

// If no location handler is available,
// default to resolving to a single location that declares all identifiers
Expand All @@ -72,12 +76,11 @@ func (checker *Checker) resolveLocation(identifiers []ast.Identifier, location a
Location: location,
Identifiers: identifiers,
},
}
}, nil
}

// A location handler is available,
// use it to resolve the location / identifiers

return checker.locationHandler(identifiers, location)
}

Expand Down
2 changes: 1 addition & 1 deletion runtime/sema/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ type ResolvedLocation struct {
Identifiers []ast.Identifier
}

type LocationHandlerFunc func(identifiers []ast.Identifier, location ast.Location) []ResolvedLocation
type LocationHandlerFunc func(identifiers []ast.Identifier, location ast.Location) ([]ResolvedLocation, error)

type ImportHandlerFunc func(checker *Checker, location ast.Location) (Import, *CheckerError)

Expand Down
4 changes: 2 additions & 2 deletions runtime/tests/checker/import_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func TestCheckRepeatedImportResolution(t *testing.T) {
ParseAndCheckOptions{
Options: []sema.Option{
sema.WithLocationHandler(
func(identifiers []ast.Identifier, location ast.Location) (result []sema.ResolvedLocation) {
func(identifiers []ast.Identifier, location ast.Location) (result []sema.ResolvedLocation, err error) {
for _, identifier := range identifiers {
result = append(result, sema.ResolvedLocation{
Location: ast.AddressLocation{
Expand Down Expand Up @@ -253,7 +253,7 @@ func TestCheckImportResolutionSplit(t *testing.T) {
ParseAndCheckOptions{
Options: []sema.Option{
sema.WithLocationHandler(
func(identifiers []ast.Identifier, location ast.Location) (result []sema.ResolvedLocation) {
func(identifiers []ast.Identifier, location ast.Location) (result []sema.ResolvedLocation, err error) {
for _, identifier := range identifiers {
result = append(result, sema.ResolvedLocation{
Location: ast.AddressLocation{
Expand Down
2 changes: 1 addition & 1 deletion runtime/tests/interpreter/import_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ func TestInterpretImportMultipleProgramsFromLocation(t *testing.T) {
checker.ParseAndCheckOptions{
Options: []sema.Option{
sema.WithLocationHandler(
func(identifiers []ast.Identifier, location ast.Location) (result []sema.ResolvedLocation) {
func(identifiers []ast.Identifier, location ast.Location) (result []sema.ResolvedLocation, err error) {

require.Equal(t,
ast.AddressLocation{
Expand Down

0 comments on commit d37c9f3

Please sign in to comment.