lang/funcs: parseint function
This commit is contained in:
parent
230acc1646
commit
bcc69c05bb
|
@ -2,6 +2,7 @@ package funcs
|
|||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"github.com/zclconf/go-cty/cty/function"
|
||||
|
@ -128,6 +129,62 @@ var SignumFunc = function.New(&function.Spec{
|
|||
},
|
||||
})
|
||||
|
||||
// ParseIntFunc contructs a function that parses a string argument and returns an integer of the specified base.
|
||||
var ParseIntFunc = function.New(&function.Spec{
|
||||
Params: []function.Parameter{
|
||||
{
|
||||
Name: "number",
|
||||
Type: cty.DynamicPseudoType,
|
||||
},
|
||||
{
|
||||
Name: "base",
|
||||
Type: cty.Number,
|
||||
},
|
||||
},
|
||||
|
||||
Type: func(args []cty.Value) (cty.Type, error) {
|
||||
if !args[0].Type().Equals(cty.String) {
|
||||
return cty.Number, function.NewArgErrorf(0, "first argument must be a string, not %s", args[0].Type().FriendlyName())
|
||||
}
|
||||
return cty.Number, nil
|
||||
},
|
||||
|
||||
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
|
||||
var numstr string
|
||||
var base int
|
||||
var err error
|
||||
|
||||
if err = gocty.FromCtyValue(args[0], &numstr); err != nil {
|
||||
return cty.UnknownVal(cty.String), function.NewArgError(0, err)
|
||||
}
|
||||
|
||||
if err = gocty.FromCtyValue(args[1], &base); err != nil {
|
||||
return cty.UnknownVal(cty.Number), function.NewArgError(1, err)
|
||||
}
|
||||
|
||||
if base < 2 || base > 62 {
|
||||
return cty.UnknownVal(cty.Number), function.NewArgErrorf(
|
||||
1,
|
||||
"base must be a whole number between 2 and 62 inclusive",
|
||||
)
|
||||
}
|
||||
|
||||
num, ok := (&big.Int{}).SetString(numstr, base)
|
||||
if !ok {
|
||||
return cty.UnknownVal(cty.Number), function.NewArgErrorf(
|
||||
0,
|
||||
"cannot parse %q as a base %d integer",
|
||||
numstr,
|
||||
base,
|
||||
)
|
||||
}
|
||||
|
||||
parsedNum := cty.NumberVal((&big.Float{}).SetInt(num))
|
||||
|
||||
return parsedNum, nil
|
||||
},
|
||||
})
|
||||
|
||||
// Ceil returns the closest whole number greater than or equal to the given value.
|
||||
func Ceil(num cty.Value) (cty.Value, error) {
|
||||
return CeilFunc.Call([]cty.Value{num})
|
||||
|
@ -153,3 +210,8 @@ func Pow(num, power cty.Value) (cty.Value, error) {
|
|||
func Signum(num cty.Value) (cty.Value, error) {
|
||||
return SignumFunc.Call([]cty.Value{num})
|
||||
}
|
||||
|
||||
// ParseInt parses a string argument and returns an integer of the specified base.
|
||||
func ParseInt(num cty.Value, base cty.Value) (cty.Value, error) {
|
||||
return ParseIntFunc.Call([]cty.Value{num, base})
|
||||
}
|
||||
|
|
|
@ -257,3 +257,164 @@ func TestSignum(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseInt(t *testing.T) {
|
||||
tests := []struct {
|
||||
Num cty.Value
|
||||
Base cty.Value
|
||||
Want cty.Value
|
||||
Err bool
|
||||
}{
|
||||
{
|
||||
cty.StringVal("128"),
|
||||
cty.NumberIntVal(10),
|
||||
cty.NumberIntVal(128),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal("-128"),
|
||||
cty.NumberIntVal(10),
|
||||
cty.NumberIntVal(-128),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal("00128"),
|
||||
cty.NumberIntVal(10),
|
||||
cty.NumberIntVal(128),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal("-00128"),
|
||||
cty.NumberIntVal(10),
|
||||
cty.NumberIntVal(-128),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal("FF00"),
|
||||
cty.NumberIntVal(16),
|
||||
cty.NumberIntVal(65280),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal("ff00"),
|
||||
cty.NumberIntVal(16),
|
||||
cty.NumberIntVal(65280),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal("-FF00"),
|
||||
cty.NumberIntVal(16),
|
||||
cty.NumberIntVal(-65280),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal("00FF00"),
|
||||
cty.NumberIntVal(16),
|
||||
cty.NumberIntVal(65280),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal("-00FF00"),
|
||||
cty.NumberIntVal(16),
|
||||
cty.NumberIntVal(-65280),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal("1011111011101111"),
|
||||
cty.NumberIntVal(2),
|
||||
cty.NumberIntVal(48879),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal("aA"),
|
||||
cty.NumberIntVal(62),
|
||||
cty.NumberIntVal(656),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal("Aa"),
|
||||
cty.NumberIntVal(62),
|
||||
cty.NumberIntVal(2242),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal("999999999999999999999999999999999999999999999999999999999999"),
|
||||
cty.NumberIntVal(10),
|
||||
cty.MustParseNumberVal("999999999999999999999999999999999999999999999999999999999999"),
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal("FF"),
|
||||
cty.NumberIntVal(10),
|
||||
cty.UnknownVal(cty.Number),
|
||||
true,
|
||||
},
|
||||
{
|
||||
cty.StringVal("00FF"),
|
||||
cty.NumberIntVal(10),
|
||||
cty.UnknownVal(cty.Number),
|
||||
true,
|
||||
},
|
||||
{
|
||||
cty.StringVal("-00FF"),
|
||||
cty.NumberIntVal(10),
|
||||
cty.UnknownVal(cty.Number),
|
||||
true,
|
||||
},
|
||||
{
|
||||
cty.NumberIntVal(2),
|
||||
cty.NumberIntVal(10),
|
||||
cty.UnknownVal(cty.Number),
|
||||
true,
|
||||
},
|
||||
{
|
||||
cty.StringVal("1"),
|
||||
cty.NumberIntVal(63),
|
||||
cty.UnknownVal(cty.Number),
|
||||
true,
|
||||
},
|
||||
{
|
||||
cty.StringVal("1"),
|
||||
cty.NumberIntVal(-1),
|
||||
cty.UnknownVal(cty.Number),
|
||||
true,
|
||||
},
|
||||
{
|
||||
cty.StringVal("1"),
|
||||
cty.NumberIntVal(1),
|
||||
cty.UnknownVal(cty.Number),
|
||||
true,
|
||||
},
|
||||
{
|
||||
cty.StringVal("1"),
|
||||
cty.NumberIntVal(0),
|
||||
cty.UnknownVal(cty.Number),
|
||||
true,
|
||||
},
|
||||
{
|
||||
cty.StringVal("1.2"),
|
||||
cty.NumberIntVal(10),
|
||||
cty.UnknownVal(cty.Number),
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(fmt.Sprintf("parseint(%#v, %#v)", test.Num, test.Base), func(t *testing.T) {
|
||||
got, err := ParseInt(test.Num, test.Base)
|
||||
|
||||
if test.Err {
|
||||
if err == nil {
|
||||
t.Fatal("succeeded; want error")
|
||||
}
|
||||
return
|
||||
} else if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
if !got.RawEquals(test.Want) {
|
||||
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,6 +86,7 @@ func (s *Scope) Functions() map[string]function.Function {
|
|||
"md5": funcs.Md5Func,
|
||||
"merge": funcs.MergeFunc,
|
||||
"min": stdlib.MinFunc,
|
||||
"parseint": funcs.ParseIntFunc,
|
||||
"pathexpand": funcs.PathExpandFunc,
|
||||
"pow": funcs.PowFunc,
|
||||
"range": stdlib.RangeFunc,
|
||||
|
|
|
@ -544,6 +544,13 @@ func TestFunctions(t *testing.T) {
|
|||
},
|
||||
},
|
||||
|
||||
"parseint": {
|
||||
{
|
||||
`parseint("100", 10)`,
|
||||
cty.NumberIntVal(100),
|
||||
},
|
||||
},
|
||||
|
||||
"pathexpand": {
|
||||
{
|
||||
`pathexpand("~/test-file")`,
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
layout: "functions"
|
||||
page_title: "parseint - Functions - Configuration Language"
|
||||
sidebar_current: "docs-funcs-numeric-parseint"
|
||||
description: |-
|
||||
The parseint function parses the given string as a representation of an integer.
|
||||
---
|
||||
|
||||
# `parseint` Function
|
||||
|
||||
-> **Note:** This page is about Terraform 0.12 and later. For Terraform 0.11 and
|
||||
earlier, see
|
||||
[0.11 Configuration Language: Interpolation Syntax](../../configuration-0-11/interpolation.html).
|
||||
|
||||
`parseint` parses the given string as a representation of an integer in
|
||||
the specified base and returns the resulting number. The base must be between 2
|
||||
and 62 inclusive.
|
||||
|
||||
All bases use the arabic numerals 0 through 9 first. Bases between 11 and 36
|
||||
inclusive use case-insensitive latin letters to represent higher unit values.
|
||||
Bases 37 and higher use lowercase latin letters and then uppercase latin
|
||||
letters.
|
||||
|
||||
If the given string contains any non-digit characters or digit characters that
|
||||
are too large for the given base then `parseint` will produce an error.
|
||||
|
||||
## Examples
|
||||
|
||||
```
|
||||
> parseint("100", 10)
|
||||
100
|
||||
|
||||
> parseint("FF", 16)
|
||||
255
|
||||
|
||||
> parseint("-10", 16)
|
||||
-16
|
||||
|
||||
> parseint("1011111011101111", 2)
|
||||
48879
|
||||
|
||||
> parseint("aA", 62)
|
||||
656
|
||||
|
||||
> parseint("12", 2)
|
||||
|
||||
Error: Invalid function argument
|
||||
|
||||
Invalid value for "number" parameter: cannot parse "12" as a base 2 integer.
|
||||
```
|
||||
|
||||
## Related Functions
|
||||
|
||||
* [`format`](./format.html) can format numbers and other values into strings,
|
||||
with optional zero padding, alignment, etc.
|
|
@ -40,6 +40,10 @@
|
|||
<a href="/docs/configuration/functions/min.html">min</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/functions/parseint.html">parseint</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/functions/pow.html">pow</a>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue