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

Add optional second base argument to int DSL function #1244

Merged
merged 4 commits into from
Mar 24, 2023
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
12 changes: 10 additions & 2 deletions docs/src/manpage.md
Original file line number Diff line number Diff line change
Expand Up @@ -2388,7 +2388,15 @@ MILLER(1) MILLER(1)
(class=system #args=0) Returns the hostname as a string.

1mint0m
(class=conversion #args=1) Convert int/float/bool/string to int.
(class=conversion #args=1,2) Convert int/float/bool/string to int. If the second argument is omitted and the first argument is a string, base is inferred from the first argument's prefix. If the second argument is provided and the first argument is a string, the second argument is used as the base. If the second argument is provided and the first argument is not a string, the second argument is ignored.
Examples:
int("345") gives decimal 345 (base-10/decimal input is inferred)
int("0xff") gives decimal 255 (base-16/hexadecimal input is inferred)
int("0377") gives decimal 255 (base-8/octal input is inferred)
int("0b11010011") gives decimal 211 which is hexadecimal 0xd3 (base-2/binary input is inferred)
int("0377", 10) gives decimal 377
int(345, 16) gives decimal 345
int(string(345), 16) gives decimal 837

1minvqnorm0m
(class=math #args=1) Inverse of normal cumulative distribution function. Note that invqorm(urand()) is normally distributed.
Expand Down Expand Up @@ -3338,5 +3346,5 @@ MILLER(1) MILLER(1)



2023-03-12 MILLER(1)
2023-03-24 MILLER(1)
</pre>
12 changes: 10 additions & 2 deletions docs/src/manpage.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2367,7 +2367,15 @@ MILLER(1) MILLER(1)
(class=system #args=0) Returns the hostname as a string.

1mint0m
(class=conversion #args=1) Convert int/float/bool/string to int.
(class=conversion #args=1,2) Convert int/float/bool/string to int. If the second argument is omitted and the first argument is a string, base is inferred from the first argument's prefix. If the second argument is provided and the first argument is a string, the second argument is used as the base. If the second argument is provided and the first argument is not a string, the second argument is ignored.
Examples:
int("345") gives decimal 345 (base-10/decimal input is inferred)
int("0xff") gives decimal 255 (base-16/hexadecimal input is inferred)
int("0377") gives decimal 255 (base-8/octal input is inferred)
int("0b11010011") gives decimal 211 which is hexadecimal 0xd3 (base-2/binary input is inferred)
int("0377", 10) gives decimal 377
int(345, 16) gives decimal 345
int(string(345), 16) gives decimal 837

1minvqnorm0m
(class=math #args=1) Inverse of normal cumulative distribution function. Note that invqorm(urand()) is normally distributed.
Expand Down Expand Up @@ -3317,4 +3325,4 @@ MILLER(1) MILLER(1)



2023-03-12 MILLER(1)
2023-03-24 MILLER(1)
10 changes: 9 additions & 1 deletion docs/src/reference-dsl-builtin-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,15 @@ hexfmt (class=conversion #args=1) Convert int to hex string, e.g. 255 to "0xff"

### int
<pre class="pre-non-highlight-non-pair">
int (class=conversion #args=1) Convert int/float/bool/string to int.
int (class=conversion #args=1,2) Convert int/float/bool/string to int. If the second argument is omitted and the first argument is a string, base is inferred from the first argument's prefix. If the second argument is provided and the first argument is a string, the second argument is used as the base. If the second argument is provided and the first argument is not a string, the second argument is ignored.
Examples:
int("345") gives decimal 345 (base-10/decimal input is inferred)
int("0xff") gives decimal 255 (base-16/hexadecimal input is inferred)
int("0377") gives decimal 255 (base-8/octal input is inferred)
int("0b11010011") gives decimal 211 which is hexadecimal 0xd3 (base-2/binary input is inferred)
int("0377", 10) gives decimal 377
int(345, 16) gives decimal 345
int(string(345), 16) gives decimal 837
</pre>


Expand Down
47 changes: 47 additions & 0 deletions internal/pkg/bifs/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,53 @@ func BIF_int(input1 *mlrval.Mlrval) *mlrval.Mlrval {
return to_int_dispositions[input1.Type()](input1)
}

// ----------------------------------------------------------------
func string_to_int_with_base(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
i, ok := lib.TryIntFromStringWithBase(input1.AcquireStringValue(), input2.AcquireIntValue())
if ok {
return mlrval.FromInt(i)
} else {
return mlrval.ERROR
}
}

func int_to_int_with_base(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(int64(input1.AcquireIntValue()))
}

func float_to_int_with_base(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
return mlrval.FromInt(int64(input1.AcquireFloatValue()))
}

func bool_to_int_with_base(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if input1.AcquireBoolValue() == true {
return mlrval.FromInt(1)
} else {
return mlrval.FromInt(0)
}
}

var to_int_with_base_dispositions = [mlrval.MT_DIM]BinaryFunc{
/*INT */ int_to_int_with_base,
/*FLOAT */ float_to_int_with_base,
/*BOOL */ bool_to_int_with_base,
/*VOID */ _void,
/*STRING */ string_to_int_with_base,
/*ARRAY */ _erro,
/*MAP */ _erro,
/*FUNC */ _erro,
/*ERROR */ _erro,
/*NULL */ _null,
/*ABSENT */ _absn,
}

func BIF_int_with_base(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
if !input2.IsInt() {
return mlrval.ERROR
}
return to_int_with_base_dispositions[input1.Type()](input1, input2)
}

// ----------------------------------------------------------------
func string_to_float(input1 *mlrval.Mlrval) *mlrval.Mlrval {
f, ok := lib.TryFloatFromString(input1.AcquireStringValue())
Expand Down
23 changes: 19 additions & 4 deletions internal/pkg/dsl/cst/builtin_function_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -1529,10 +1529,25 @@ Note that NaN has the property that NaN != NaN, so you need 'is_nan(x)' rather t
},

{
name: "int",
class: FUNC_CLASS_CONVERSION,
help: "Convert int/float/bool/string to int.",
unaryFunc: bifs.BIF_int,
name: "int",
class: FUNC_CLASS_CONVERSION,
help: `Convert int/float/bool/string to int.
If the second argument is omitted and the first argument is a string, base is inferred from the first argument's prefix.
If the second argument is provided and the first argument is a string, the second argument is used as the base.
If the second argument is provided and the first argument is not a string, the second argument is ignored.`,

unaryFunc: bifs.BIF_int,
binaryFunc: bifs.BIF_int_with_base,
hasMultipleArities: true,
examples: []string{
`int("345") gives decimal 345 (base-10/decimal input is inferred)`,
`int("0xff") gives decimal 255 (base-16/hexadecimal input is inferred)`,
`int("0377") gives decimal 255 (base-8/octal input is inferred)`,
`int("0b11010011") gives decimal 211 which is hexadecimal 0xd3 (base-2/binary input is inferred)`,
`int("0377", 10) gives decimal 377`,
`int(345, 16) gives decimal 345`,
`int(string(345), 16) gives decimal 837`,
},
},

{
Expand Down
21 changes: 21 additions & 0 deletions internal/pkg/lib/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,27 @@ func TryIntFromString(input string) (int64, bool) {
return 0, false
}

// TryIntFromStringWithBase allows the user to choose the base that's used,
// rather than inferring from 0x prefix, etc as TryIntFromString does.
func TryIntFromStringWithBase(input string, base int64) (int64, bool) {
// Go's strconv parses "1_2" as 12; not OK for Miller syntax. (Also not valid JSON.)
for i := 0; i < len(input); i++ {
if input[i] == '_' {
return 0, false
}
}

i64, ierr := strconv.ParseInt(input, int(base), 64)
if ierr == nil {
return i64, true
}
u64, uerr := strconv.ParseUint(input, int(base), 64)
if uerr == nil {
return int64(u64), true
}
return 0, false
}

func TryFloatFromString(input string) (float64, bool) {
// Go's strconv parses "1_2.3_4" as 12.34; not OK for Miller syntax. (Also not valid JSON.)
for i := 0; i < len(input); i++ {
Expand Down
12 changes: 10 additions & 2 deletions man/manpage.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2367,7 +2367,15 @@ MILLER(1) MILLER(1)
(class=system #args=0) Returns the hostname as a string.

1mint0m
(class=conversion #args=1) Convert int/float/bool/string to int.
(class=conversion #args=1,2) Convert int/float/bool/string to int. If the second argument is omitted and the first argument is a string, base is inferred from the first argument's prefix. If the second argument is provided and the first argument is a string, the second argument is used as the base. If the second argument is provided and the first argument is not a string, the second argument is ignored.
Examples:
int("345") gives decimal 345 (base-10/decimal input is inferred)
int("0xff") gives decimal 255 (base-16/hexadecimal input is inferred)
int("0377") gives decimal 255 (base-8/octal input is inferred)
int("0b11010011") gives decimal 211 which is hexadecimal 0xd3 (base-2/binary input is inferred)
int("0377", 10) gives decimal 377
int(345, 16) gives decimal 345
int(string(345), 16) gives decimal 837

1minvqnorm0m
(class=math #args=1) Inverse of normal cumulative distribution function. Note that invqorm(urand()) is normally distributed.
Expand Down Expand Up @@ -3317,4 +3325,4 @@ MILLER(1) MILLER(1)



2023-03-12 MILLER(1)
2023-03-24 MILLER(1)
14 changes: 11 additions & 3 deletions man/mlr.1
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
.\" Title: mlr
.\" Author: [see the "AUTHOR" section]
.\" Generator: ./mkman.rb
.\" Date: 2023-03-12
.\" Date: 2023-03-24
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
.TH "MILLER" "1" "2023-03-12" "\ \&" "\ \&"
.TH "MILLER" "1" "2023-03-24" "\ \&" "\ \&"
.\" -----------------------------------------------------------------
.\" * Portability definitions
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -3362,7 +3362,15 @@ gsub("prefix4529:suffix8567", "(....ix)([0-9]+)", "[\e1 : \e2]") gives "[prefix
.RS 0
.\}
.nf
(class=conversion #args=1) Convert int/float/bool/string to int.
(class=conversion #args=1,2) Convert int/float/bool/string to int. If the second argument is omitted and the first argument is a string, base is inferred from the first argument's prefix. If the second argument is provided and the first argument is a string, the second argument is used as the base. If the second argument is provided and the first argument is not a string, the second argument is ignored.
Examples:
int("345") gives decimal 345 (base-10/decimal input is inferred)
int("0xff") gives decimal 255 (base-16/hexadecimal input is inferred)
int("0377") gives decimal 255 (base-8/octal input is inferred)
int("0b11010011") gives decimal 211 which is hexadecimal 0xd3 (base-2/binary input is inferred)
int("0377", 10) gives decimal 377
int(345, 16) gives decimal 345
int(string(345), 16) gives decimal 837
.fi
.if n \{\
.RE
Expand Down
1 change: 1 addition & 0 deletions test/cases/dsl-int-function/0001/cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mlr --nidx --from ${CASEDIR}/input -S put -f ${CASEDIR}/mlr
Empty file.
4 changes: 4 additions & 0 deletions test/cases/dsl-int-function/0001/expout
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
345 345
0xff 255
0377 255
0b11010011 211
4 changes: 4 additions & 0 deletions test/cases/dsl-int-function/0001/input
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
345
0xff
0377
0b11010011
1 change: 1 addition & 0 deletions test/cases/dsl-int-function/0001/mlr
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$2 = int($1) + 0
1 change: 1 addition & 0 deletions test/cases/dsl-int-function/0002/cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mlr --nidx --from ${CASEDIR}/input -S put -f ${CASEDIR}/mlr
Empty file.
4 changes: 4 additions & 0 deletions test/cases/dsl-int-function/0002/expout
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
345 345
ff (error)
0377 377
11010011 11010011
4 changes: 4 additions & 0 deletions test/cases/dsl-int-function/0002/input
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
345
ff
0377
11010011
1 change: 1 addition & 0 deletions test/cases/dsl-int-function/0002/mlr
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$2 = int($1, 10) + 0
1 change: 1 addition & 0 deletions test/cases/dsl-int-function/0003/cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mlr --nidx --from ${CASEDIR}/input -S put -f ${CASEDIR}/mlr
Empty file.
4 changes: 4 additions & 0 deletions test/cases/dsl-int-function/0003/expout
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
345 837
ff 255
0377 887
11010011 285278225
4 changes: 4 additions & 0 deletions test/cases/dsl-int-function/0003/input
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
345
ff
0377
11010011
1 change: 1 addition & 0 deletions test/cases/dsl-int-function/0003/mlr
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$2 = int($1, 16) + 0
1 change: 1 addition & 0 deletions test/cases/dsl-int-function/0004/cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mlr --nidx --from ${CASEDIR}/input -S put -f ${CASEDIR}/mlr
Empty file.
4 changes: 4 additions & 0 deletions test/cases/dsl-int-function/0004/expout
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
345 229
ff (error)
0377 255
11010011 2363401
4 changes: 4 additions & 0 deletions test/cases/dsl-int-function/0004/input
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
345
ff
0377
11010011
1 change: 1 addition & 0 deletions test/cases/dsl-int-function/0004/mlr
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$2 = int($1, 8) + 0
1 change: 1 addition & 0 deletions test/cases/dsl-int-function/0005/cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mlr --nidx --from ${CASEDIR}/input -S put -f ${CASEDIR}/mlr
Empty file.
4 changes: 4 additions & 0 deletions test/cases/dsl-int-function/0005/expout
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
345 (error)
ff (error)
0377 (error)
11010011 211
4 changes: 4 additions & 0 deletions test/cases/dsl-int-function/0005/input
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
345
ff
0377
11010011
1 change: 1 addition & 0 deletions test/cases/dsl-int-function/0005/mlr
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$2 = int($1, 2) + 0
1 change: 1 addition & 0 deletions test/cases/dsl-int-function/0006/cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mlr --nidx --from ${CASEDIR}/input put -f ${CASEDIR}/mlr
Empty file.
4 changes: 4 additions & 0 deletions test/cases/dsl-int-function/0006/expout
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
345 345
ff (error)
0377 255
11010011 11010011
4 changes: 4 additions & 0 deletions test/cases/dsl-int-function/0006/input
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
345
ff
0377
11010011
1 change: 1 addition & 0 deletions test/cases/dsl-int-function/0006/mlr
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$2 = int($1, 8) + 0