lang: funcs: Add math pow function and a few examples
Just a few small things I think should be committed.
This commit is contained in:
@@ -291,7 +291,7 @@ If you'd like to create a built-in, core function, you'll need to implement the
|
|||||||
function API interface named `Func`. It can be found in
|
function API interface named `Func`. It can be found in
|
||||||
[lang/interfaces/func.go](https://github.com/purpleidea/mgmt/tree/master/lang/interfaces/func.go).
|
[lang/interfaces/func.go](https://github.com/purpleidea/mgmt/tree/master/lang/interfaces/func.go).
|
||||||
Your function must have a specific type. For example, a simple math function
|
Your function must have a specific type. For example, a simple math function
|
||||||
might have a signature of `func(x int, x int) int`. As you can see, all the
|
might have a signature of `func(x int, y int) int`. As you can see, all the
|
||||||
types are known _before_ compile time.
|
types are known _before_ compile time.
|
||||||
|
|
||||||
A separate discussion on this matter can be found in the [function guide](function-guide.md).
|
A separate discussion on this matter can be found in the [function guide](function-guide.md).
|
||||||
|
|||||||
10
examples/lang/env1.mcl
Normal file
10
examples/lang/env1.mcl
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
$env = env()
|
||||||
|
$m = maplookup($env, "GOPATH", "")
|
||||||
|
|
||||||
|
print "print0" {
|
||||||
|
msg => if hasenv("GOPATH") {
|
||||||
|
printf("GOPATH is: %s", $m)
|
||||||
|
} else {
|
||||||
|
"GOPATH is missing!"
|
||||||
|
},
|
||||||
|
}
|
||||||
3
examples/lang/math2.mcl
Normal file
3
examples/lang/math2.mcl
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
print "print0" {
|
||||||
|
msg => printf("13.0 ^ 4.2 is: %f", pow(13.0, 4.2)),
|
||||||
|
}
|
||||||
3
examples/lang/pkg1.mcl
Normal file
3
examples/lang/pkg1.mcl
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pkg "cowsay" {
|
||||||
|
state => "installed",
|
||||||
|
}
|
||||||
53
lang/funcs/simple/math_func.go
Normal file
53
lang/funcs/simple/math_func.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// Mgmt
|
||||||
|
// Copyright (C) 2013-2018+ James Shubin and the project contributors
|
||||||
|
// Written by James Shubin <james@shubin.ca> and the project contributors
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package simple // TODO: should this be in its own individual package?
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"github.com/purpleidea/mgmt/lang/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Register("pow", &types.FuncValue{
|
||||||
|
T: types.NewType("func(x float, y float) float"),
|
||||||
|
V: Pow,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pow returns x ^ y, the base-x exponential of y.
|
||||||
|
func Pow(input []types.Value) (types.Value, error) {
|
||||||
|
x, y := input[0].Float(), input[1].Float()
|
||||||
|
// FIXME: check for overflow
|
||||||
|
z := math.Pow(x, y)
|
||||||
|
if math.IsNaN(z) {
|
||||||
|
return nil, fmt.Errorf("result is not a number")
|
||||||
|
}
|
||||||
|
if math.IsInf(z, 1) {
|
||||||
|
return nil, fmt.Errorf("result is positive infinity")
|
||||||
|
}
|
||||||
|
if math.IsInf(z, -1) {
|
||||||
|
return nil, fmt.Errorf("result is negative infinity")
|
||||||
|
}
|
||||||
|
// TODO: consider only returning floats, and adding isinf and
|
||||||
|
// isnan functions so that users can decide for themselves...
|
||||||
|
return &types.FloatValue{
|
||||||
|
V: z,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -80,7 +80,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
values = append(values, test{
|
values = append(values, test{
|
||||||
name: "bad escaping",
|
name: "bad escaping",
|
||||||
code: `
|
code: `
|
||||||
test "n1" {
|
test "t1" {
|
||||||
str => "he\ llo", # incorrect escaping
|
str => "he\ llo", # incorrect escaping
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -91,7 +91,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
values = append(values, test{
|
values = append(values, test{
|
||||||
name: "int overflow",
|
name: "int overflow",
|
||||||
code: `
|
code: `
|
||||||
test "n1" {
|
test "t1" {
|
||||||
int => 888888888888888888888888, # overflows
|
int => 888888888888888888888888, # overflows
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -102,7 +102,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
values = append(values, test{
|
values = append(values, test{
|
||||||
name: "overflow after lexer",
|
name: "overflow after lexer",
|
||||||
code: `
|
code: `
|
||||||
test "n1" {
|
test "t1" {
|
||||||
uint8 => 128, # does not overflow at lexer stage
|
uint8 => 128, # does not overflow at lexer stage
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -114,7 +114,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
values = append(values, test{
|
values = append(values, test{
|
||||||
name: "one res",
|
name: "one res",
|
||||||
code: `
|
code: `
|
||||||
test "n1" {
|
test "t1" {
|
||||||
int16 => 01134, # some comment
|
int16 => 01134, # some comment
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -262,7 +262,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
values = append(values, test{
|
values = append(values, test{
|
||||||
name: "res with floats",
|
name: "res with floats",
|
||||||
code: `
|
code: `
|
||||||
test "n1" {
|
test "t1" {
|
||||||
float32 => -25.38789, # some float
|
float32 => -25.38789, # some float
|
||||||
float64 => 53.393908945, # some float
|
float64 => 53.393908945, # some float
|
||||||
}
|
}
|
||||||
@@ -279,7 +279,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
// values = append(values, test{
|
// values = append(values, test{
|
||||||
// name: "overflowing float",
|
// name: "overflowing float",
|
||||||
// code: `
|
// code: `
|
||||||
// test "n1" {
|
// test "t1" {
|
||||||
// float32 => -457643875645764387564578645457864525457643875645764387564578645457864525.457643875645764387564578645457864525387899898753459879587574928798759863965, # overflow
|
// float32 => -457643875645764387564578645457864525457643875645764387564578645457864525.457643875645764387564578645457864525387899898753459879587574928798759863965, # overflow
|
||||||
// }
|
// }
|
||||||
// `,
|
// `,
|
||||||
@@ -290,7 +290,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
values = append(values, test{
|
values = append(values, test{
|
||||||
name: "res and addition",
|
name: "res and addition",
|
||||||
code: `
|
code: `
|
||||||
test "n1" {
|
test "t1" {
|
||||||
float32 => -25.38789 + 32.6,
|
float32 => -25.38789 + 32.6,
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -304,7 +304,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
&StmtRes{
|
&StmtRes{
|
||||||
Kind: "test",
|
Kind: "test",
|
||||||
Name: &ExprStr{
|
Name: &ExprStr{
|
||||||
V: "n1",
|
V: "t1",
|
||||||
},
|
},
|
||||||
Fields: []*StmtResField{
|
Fields: []*StmtResField{
|
||||||
{
|
{
|
||||||
@@ -331,7 +331,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
values = append(values, test{
|
values = append(values, test{
|
||||||
name: "addition",
|
name: "addition",
|
||||||
code: `
|
code: `
|
||||||
test "n1" {
|
test "t1" {
|
||||||
int64ptr => 13 + 42,
|
int64ptr => 13 + 42,
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -345,7 +345,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
&StmtRes{
|
&StmtRes{
|
||||||
Kind: "test",
|
Kind: "test",
|
||||||
Name: &ExprStr{
|
Name: &ExprStr{
|
||||||
V: "n1",
|
V: "t1",
|
||||||
},
|
},
|
||||||
Fields: []*StmtResField{
|
Fields: []*StmtResField{
|
||||||
{
|
{
|
||||||
@@ -383,7 +383,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
values = append(values, test{
|
values = append(values, test{
|
||||||
name: "multiple float addition",
|
name: "multiple float addition",
|
||||||
code: `
|
code: `
|
||||||
test "n1" {
|
test "t1" {
|
||||||
float32 => -25.38789 + 32.6 + 13.7,
|
float32 => -25.38789 + 32.6 + 13.7,
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -397,7 +397,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
&StmtRes{
|
&StmtRes{
|
||||||
Kind: "test",
|
Kind: "test",
|
||||||
Name: &ExprStr{
|
Name: &ExprStr{
|
||||||
V: "n1",
|
V: "t1",
|
||||||
},
|
},
|
||||||
Fields: []*StmtResField{
|
Fields: []*StmtResField{
|
||||||
{
|
{
|
||||||
@@ -435,7 +435,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
values = append(values, test{
|
values = append(values, test{
|
||||||
name: "order of operations lucky",
|
name: "order of operations lucky",
|
||||||
code: `
|
code: `
|
||||||
test "n1" {
|
test "t1" {
|
||||||
int64ptr => 4 + 3 * 12, # 40, not 84
|
int64ptr => 4 + 3 * 12, # 40, not 84
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -449,7 +449,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
&StmtRes{
|
&StmtRes{
|
||||||
Kind: "test",
|
Kind: "test",
|
||||||
Name: &ExprStr{
|
Name: &ExprStr{
|
||||||
V: "n1",
|
V: "t1",
|
||||||
},
|
},
|
||||||
Fields: []*StmtResField{
|
Fields: []*StmtResField{
|
||||||
{
|
{
|
||||||
@@ -487,7 +487,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
values = append(values, test{
|
values = append(values, test{
|
||||||
name: "order of operations needs left precedence",
|
name: "order of operations needs left precedence",
|
||||||
code: `
|
code: `
|
||||||
test "n1" {
|
test "t1" {
|
||||||
int64ptr => 3 * 12 + 4, # 40, not 48
|
int64ptr => 3 * 12 + 4, # 40, not 48
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -501,7 +501,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
&StmtRes{
|
&StmtRes{
|
||||||
Kind: "test",
|
Kind: "test",
|
||||||
Name: &ExprStr{
|
Name: &ExprStr{
|
||||||
V: "n1",
|
V: "t1",
|
||||||
},
|
},
|
||||||
Fields: []*StmtResField{
|
Fields: []*StmtResField{
|
||||||
{
|
{
|
||||||
@@ -539,7 +539,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
values = append(values, test{
|
values = append(values, test{
|
||||||
name: "order of operations parens",
|
name: "order of operations parens",
|
||||||
code: `
|
code: `
|
||||||
test "n1" {
|
test "t1" {
|
||||||
int64ptr => 3 * (12 + 4), # 48, not 40
|
int64ptr => 3 * (12 + 4), # 48, not 40
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -553,7 +553,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
&StmtRes{
|
&StmtRes{
|
||||||
Kind: "test",
|
Kind: "test",
|
||||||
Name: &ExprStr{
|
Name: &ExprStr{
|
||||||
V: "n1",
|
V: "t1",
|
||||||
},
|
},
|
||||||
Fields: []*StmtResField{
|
Fields: []*StmtResField{
|
||||||
{
|
{
|
||||||
@@ -591,7 +591,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
values = append(values, test{
|
values = append(values, test{
|
||||||
name: "order of operations bools",
|
name: "order of operations bools",
|
||||||
code: `
|
code: `
|
||||||
test "n1" {
|
test "t1" {
|
||||||
boolptr => 3 + 4 > 5, # should be true
|
boolptr => 3 + 4 > 5, # should be true
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -605,7 +605,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
&StmtRes{
|
&StmtRes{
|
||||||
Kind: "test",
|
Kind: "test",
|
||||||
Name: &ExprStr{
|
Name: &ExprStr{
|
||||||
V: "n1",
|
V: "t1",
|
||||||
},
|
},
|
||||||
Fields: []*StmtResField{
|
Fields: []*StmtResField{
|
||||||
{
|
{
|
||||||
@@ -643,7 +643,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
values = append(values, test{
|
values = append(values, test{
|
||||||
name: "order of operations bools reversed",
|
name: "order of operations bools reversed",
|
||||||
code: `
|
code: `
|
||||||
test "n1" {
|
test "t1" {
|
||||||
boolptr => 3 > 4 + 5, # should be false
|
boolptr => 3 > 4 + 5, # should be false
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -657,7 +657,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
&StmtRes{
|
&StmtRes{
|
||||||
Kind: "test",
|
Kind: "test",
|
||||||
Name: &ExprStr{
|
Name: &ExprStr{
|
||||||
V: "n1",
|
V: "t1",
|
||||||
},
|
},
|
||||||
Fields: []*StmtResField{
|
Fields: []*StmtResField{
|
||||||
{
|
{
|
||||||
@@ -692,7 +692,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
values = append(values, test{
|
values = append(values, test{
|
||||||
name: "order of operations with not",
|
name: "order of operations with not",
|
||||||
code: `
|
code: `
|
||||||
test "n1" {
|
test "t1" {
|
||||||
boolptr => ! 3 > 4, # should parse, but not compile
|
boolptr => ! 3 > 4, # should parse, but not compile
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -706,7 +706,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
&StmtRes{
|
&StmtRes{
|
||||||
Kind: "test",
|
Kind: "test",
|
||||||
Name: &ExprStr{
|
Name: &ExprStr{
|
||||||
V: "n1",
|
V: "t1",
|
||||||
},
|
},
|
||||||
Fields: []*StmtResField{
|
Fields: []*StmtResField{
|
||||||
{
|
{
|
||||||
@@ -744,7 +744,7 @@ func TestLexParse0(t *testing.T) {
|
|||||||
values = append(values, test{
|
values = append(values, test{
|
||||||
name: "order of operations logical",
|
name: "order of operations logical",
|
||||||
code: `
|
code: `
|
||||||
test "n1" {
|
test "t1" {
|
||||||
boolptr => 7 < 4 && true, # should be false
|
boolptr => 7 < 4 && true, # should be false
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -879,7 +879,7 @@ func TestLexParse1(t *testing.T) {
|
|||||||
}
|
}
|
||||||
# hello
|
# hello
|
||||||
# world
|
# world
|
||||||
test "n1" {}
|
test "t1" {}
|
||||||
` // error
|
` // error
|
||||||
str := strings.NewReader(code)
|
str := strings.NewReader(code)
|
||||||
_, err := LexParse(str)
|
_, err := LexParse(str)
|
||||||
|
|||||||
2
test.sh
2
test.sh
@@ -89,7 +89,7 @@ if [[ -n "$failures" ]]; then
|
|||||||
echo
|
echo
|
||||||
echo 'You can rerun a single suite like so:'
|
echo 'You can rerun a single suite like so:'
|
||||||
echo
|
echo
|
||||||
echo 'make test-gofmt'
|
echo '`make test-gofmt` or `make test-shell-<testname>`'
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo 'ALL PASSED'
|
echo 'ALL PASSED'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
echo "running test-gotest.sh $1"
|
echo running "$0" "$@"
|
||||||
|
|
||||||
#ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )" # dir!
|
#ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )" # dir!
|
||||||
ROOT=$(dirname "${BASH_SOURCE}")/..
|
ROOT=$(dirname "${BASH_SOURCE}")/..
|
||||||
|
|||||||
Reference in New Issue
Block a user