-
Notifications
You must be signed in to change notification settings - Fork 149
Add comparison functions #4430
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
Merged
Merged
Add comparison functions #4430
Changes from 1 commit
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
4bedb5a
add min and max functions
turbolent 5e12934
rename min/max to minOf/maxOf
turbolent 4b87ffe
assert return types
turbolent f7475c7
Merge branch 'master' into bastian/min-max-functions
turbolent f1a5561
rename to min/max, define in Comparison location
turbolent e9ae4a8
add clamp function
turbolent 3089b79
remove unnecessary cast
turbolent b78b250
Merge branch 'master' into bastian/min-max-functions
turbolent 15fe578
add docstrings
turbolent 3d2aac8
Merge branch 'master' into bastian/min-max-functions
turbolent File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,250 @@ | ||
| /* | ||
| * Cadence - The resource-oriented smart contract programming language | ||
| * | ||
| * Copyright Flow Foundation | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package stdlib | ||
|
|
||
| import ( | ||
| "fmt" | ||
|
|
||
| "github.com/onflow/cadence/ast" | ||
| "github.com/onflow/cadence/common" | ||
| "github.com/onflow/cadence/interpreter" | ||
| "github.com/onflow/cadence/sema" | ||
| ) | ||
|
|
||
| // MinFunction | ||
|
|
||
| const minFunctionName = "min" | ||
|
|
||
| const minFunctionDocString = ` | ||
| Returns the minimum of the two given values. | ||
| The arguments must be of the same comparable type. | ||
| ` | ||
|
|
||
| var minFunctionType = func() *sema.FunctionType { | ||
| typeParameter := &sema.TypeParameter{ | ||
| Name: "T", | ||
| // No TypeBound - we check comparability in TypeArgumentsCheck | ||
| } | ||
|
|
||
| typeAnnotation := sema.NewTypeAnnotation( | ||
| &sema.GenericType{ | ||
| TypeParameter: typeParameter, | ||
| }, | ||
| ) | ||
|
|
||
| return &sema.FunctionType{ | ||
| Purity: sema.FunctionPurityView, | ||
| TypeParameters: []*sema.TypeParameter{ | ||
| typeParameter, | ||
| }, | ||
| Parameters: []sema.Parameter{ | ||
| { | ||
| Label: sema.ArgumentLabelNotRequired, | ||
| Identifier: "a", | ||
| TypeAnnotation: typeAnnotation, | ||
| }, | ||
| { | ||
| Label: sema.ArgumentLabelNotRequired, | ||
| Identifier: "b", | ||
| TypeAnnotation: typeAnnotation, | ||
| }, | ||
| }, | ||
| ReturnTypeAnnotation: typeAnnotation, | ||
| TypeArgumentsCheck: func( | ||
| memoryGauge common.MemoryGauge, | ||
| typeArguments *sema.TypeParameterTypeOrderedMap, | ||
| _ []*ast.TypeAnnotation, | ||
| invocationRange ast.HasPosition, | ||
| report func(err error), | ||
| ) { | ||
| typeArg, ok := typeArguments.Get(typeParameter) | ||
| if !ok || typeArg == nil { | ||
| // Invalid, already reported by checker | ||
| return | ||
| } | ||
|
|
||
| if !typeArg.IsComparable() { | ||
| report(&sema.InvalidTypeArgumentError{ | ||
| TypeArgumentName: typeParameter.Name, | ||
| Range: ast.NewRangeFromPositioned(memoryGauge, invocationRange), | ||
| Details: fmt.Sprintf( | ||
| "Type argument for `%s` must be a comparable type, got `%s`", | ||
| minFunctionName, | ||
| typeArg, | ||
| ), | ||
| }) | ||
| } | ||
| }, | ||
| } | ||
| }() | ||
|
|
||
| var NativeMinFunction = interpreter.NativeFunction( | ||
| func( | ||
| context interpreter.NativeFunctionContext, | ||
| _ interpreter.TypeArgumentsIterator, | ||
| _ interpreter.ArgumentTypesIterator, | ||
| _ interpreter.Value, | ||
| args []interpreter.Value, | ||
| ) interpreter.Value { | ||
| a := args[0] | ||
| b := args[1] | ||
|
|
||
| comparableA, ok := a.(interpreter.ComparableValue) | ||
| if !ok { | ||
| panic(fmt.Sprintf("min: first argument is not comparable: %T", a)) | ||
| } | ||
|
|
||
| comparableB, ok := b.(interpreter.ComparableValue) | ||
| if !ok { | ||
| panic(fmt.Sprintf("min: second argument is not comparable: %T", b)) | ||
| } | ||
|
|
||
| if bool(comparableA.Less(context, comparableB)) { | ||
| return a | ||
| } | ||
| return b | ||
| }, | ||
| ) | ||
|
|
||
| var InterpreterMinFunction = NewNativeStandardLibraryStaticFunction( | ||
| minFunctionName, | ||
| minFunctionType, | ||
| minFunctionDocString, | ||
| NativeMinFunction, | ||
| false, | ||
| ) | ||
|
|
||
| var VMMinFunction = NewNativeStandardLibraryStaticFunction( | ||
| minFunctionName, | ||
| minFunctionType, | ||
| minFunctionDocString, | ||
| NativeMinFunction, | ||
| true, | ||
| ) | ||
|
|
||
| // MaxFunction | ||
|
|
||
| const maxFunctionName = "max" | ||
|
|
||
| const maxFunctionDocString = ` | ||
| Returns the maximum of the two given values. | ||
| The arguments must be of the same comparable type. | ||
| ` | ||
|
|
||
| var maxFunctionType = func() *sema.FunctionType { | ||
| typeParameter := &sema.TypeParameter{ | ||
| Name: "T", | ||
| // No TypeBound - we check comparability in TypeArgumentsCheck | ||
| } | ||
|
|
||
| typeAnnotation := sema.NewTypeAnnotation( | ||
| &sema.GenericType{ | ||
| TypeParameter: typeParameter, | ||
| }, | ||
| ) | ||
|
|
||
| return &sema.FunctionType{ | ||
| Purity: sema.FunctionPurityView, | ||
| TypeParameters: []*sema.TypeParameter{ | ||
| typeParameter, | ||
| }, | ||
| Parameters: []sema.Parameter{ | ||
| { | ||
| Label: sema.ArgumentLabelNotRequired, | ||
| Identifier: "a", | ||
| TypeAnnotation: typeAnnotation, | ||
| }, | ||
| { | ||
| Label: sema.ArgumentLabelNotRequired, | ||
| Identifier: "b", | ||
| TypeAnnotation: typeAnnotation, | ||
| }, | ||
| }, | ||
| ReturnTypeAnnotation: typeAnnotation, | ||
| TypeArgumentsCheck: func( | ||
| memoryGauge common.MemoryGauge, | ||
| typeArguments *sema.TypeParameterTypeOrderedMap, | ||
| _ []*ast.TypeAnnotation, | ||
| invocationRange ast.HasPosition, | ||
| report func(err error), | ||
| ) { | ||
| typeArg, ok := typeArguments.Get(typeParameter) | ||
| if !ok || typeArg == nil { | ||
| // Invalid, already reported by checker | ||
| return | ||
| } | ||
|
|
||
| if !typeArg.IsComparable() { | ||
| report(&sema.InvalidTypeArgumentError{ | ||
| TypeArgumentName: typeParameter.Name, | ||
| Range: ast.NewRangeFromPositioned(memoryGauge, invocationRange), | ||
| Details: fmt.Sprintf( | ||
| "Type argument for `%s` must be a comparable type, got `%s`", | ||
| maxFunctionName, | ||
| typeArg, | ||
| ), | ||
| }) | ||
| } | ||
| }, | ||
| } | ||
| }() | ||
|
|
||
| var NativeMaxFunction = interpreter.NativeFunction( | ||
| func( | ||
| context interpreter.NativeFunctionContext, | ||
| _ interpreter.TypeArgumentsIterator, | ||
| _ interpreter.ArgumentTypesIterator, | ||
| _ interpreter.Value, | ||
| args []interpreter.Value, | ||
| ) interpreter.Value { | ||
| a := args[0] | ||
| b := args[1] | ||
|
|
||
| comparableA, ok := a.(interpreter.ComparableValue) | ||
| if !ok { | ||
| panic(fmt.Sprintf("max: first argument is not comparable: %T", a)) | ||
| } | ||
|
|
||
| comparableB, ok := b.(interpreter.ComparableValue) | ||
| if !ok { | ||
| panic(fmt.Sprintf("max: second argument is not comparable: %T", b)) | ||
| } | ||
|
|
||
| if bool(comparableA.Greater(context, comparableB)) { | ||
|
turbolent marked this conversation as resolved.
Outdated
|
||
| return a | ||
| } | ||
| return b | ||
| }, | ||
| ) | ||
|
|
||
| var InterpreterMaxFunction = NewNativeStandardLibraryStaticFunction( | ||
| maxFunctionName, | ||
| maxFunctionType, | ||
| maxFunctionDocString, | ||
| NativeMaxFunction, | ||
| false, | ||
| ) | ||
|
|
||
| var VMMaxFunction = NewNativeStandardLibraryStaticFunction( | ||
| maxFunctionName, | ||
| maxFunctionType, | ||
| maxFunctionDocString, | ||
| NativeMaxFunction, | ||
| true, | ||
| ) | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.