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:
James Shubin
2018-02-25 19:09:21 -05:00
parent 6370f0cb95
commit df1e50e599
8 changed files with 98 additions and 29 deletions

View File

@@ -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
View 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
View 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
View File

@@ -0,0 +1,3 @@
pkg "cowsay" {
state => "installed",
}

View 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
}

View File

@@ -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)

View File

@@ -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'

View File

@@ -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}")/..