From b3d1ed9e659c233c2c66338fd54d77889513d1b4 Mon Sep 17 00:00:00 2001 From: James Shubin Date: Wed, 12 May 2021 03:28:19 -0400 Subject: [PATCH] lang: funcs: core: math: Add a fortytwo function This is mainly meant as a useful test case, but might as well have it be fun too. As an aside, it taught me a surprising result about the %v verb in printf, and we'll have to decide if it's an issue we care about. https://github.com/golang/go/issues/46118 The interesting thing about this method is that it uses the simplepoly API but has no input args-- only the output types are different. If it had identical types in the input args, that might also have been interesting, but it's more rare to have none. Hopefully this exercises our type unification logic. --- lang/funcs/core/fmt/printf_func.go | 8 +++ lang/funcs/core/math/fortytwo_func.go | 69 +++++++++++++++++++ .../TestAstFunc2/fortytwo.output | 2 + .../TestAstFunc2/fortytwo/main.mcl | 6 ++ lang/types/value.go | 1 + 5 files changed, 86 insertions(+) create mode 100644 lang/funcs/core/math/fortytwo_func.go create mode 100644 lang/interpret_test/TestAstFunc2/fortytwo.output create mode 100644 lang/interpret_test/TestAstFunc2/fortytwo/main.mcl diff --git a/lang/funcs/core/fmt/printf_func.go b/lang/funcs/core/fmt/printf_func.go index 34326212..4057cc83 100644 --- a/lang/funcs/core/fmt/printf_func.go +++ b/lang/funcs/core/fmt/printf_func.go @@ -379,6 +379,14 @@ func (obj *PrintfFunc) Close() error { // valueToString prints our values how we expect for printf. // FIXME: if this turns out to be useful, add it to the types package. func valueToString(value types.Value) string { + switch x := value.Type().Kind; x { + // FIXME: floats don't print nicely: https://github.com/golang/go/issues/46118 + case types.KindFloat: + // TODO: use formatting flags ? + // FIXME: Our String() method in FloatValue doesn't print nicely + return value.String() + } + // FIXME: this is just an "easy-out" implementation for now... return fmt.Sprintf("%v", value.Value()) diff --git a/lang/funcs/core/math/fortytwo_func.go b/lang/funcs/core/math/fortytwo_func.go new file mode 100644 index 00000000..02bd268e --- /dev/null +++ b/lang/funcs/core/math/fortytwo_func.go @@ -0,0 +1,69 @@ +// Mgmt +// Copyright (C) 2013-2021+ James Shubin and the project contributors +// Written by James Shubin 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 . + +package coremath + +import ( + "fmt" + + "github.com/purpleidea/mgmt/lang/funcs/simplepoly" + "github.com/purpleidea/mgmt/lang/types" +) + +func init() { + typInt := types.NewType("func() int") + typFloat := types.NewType("func() float") + simplepoly.ModuleRegister(ModuleName, "fortytwo", []*types.FuncValue{ + { + T: typInt, + V: fortyTwo(typInt), // generate the correct function here + }, + { + T: typFloat, + V: fortyTwo(typFloat), + }, + }) +} + +// fortyTwo is a helper function to build the correct function for the desired +// signature, because the simplepoly API doesn't tell the implementing function +// what its signature should be! In the next version of this API, we could pass +// in a sig field, like how we demonstrate in the implementation of FortyTwo. If +// the API doesn't change, then this is an example of how to build this as a +// wrapper. +func fortyTwo(sig *types.Type) func([]types.Value) (types.Value, error) { + return func(input []types.Value) (types.Value, error) { + return FortyTwo(sig, input) + } +} + +// FortyTwo returns 42 as either an int or a float. This is not especially +// useful, but was built for a fun test case of a simple poly function with two +// different return types, but no input args. +func FortyTwo(sig *types.Type, input []types.Value) (types.Value, error) { + if sig.Out.Kind == types.KindInt { + return &types.IntValue{ + V: 42, + }, nil + } + if sig.Out.Kind == types.KindFloat { + return &types.FloatValue{ + V: 42.0, + }, nil + } + return nil, fmt.Errorf("unknown output type: %+v", sig.Out) +} diff --git a/lang/interpret_test/TestAstFunc2/fortytwo.output b/lang/interpret_test/TestAstFunc2/fortytwo.output new file mode 100644 index 00000000..a8afdb37 --- /dev/null +++ b/lang/interpret_test/TestAstFunc2/fortytwo.output @@ -0,0 +1,2 @@ +Vertex: test[float: 42] +Vertex: test[int: 42] diff --git a/lang/interpret_test/TestAstFunc2/fortytwo/main.mcl b/lang/interpret_test/TestAstFunc2/fortytwo/main.mcl new file mode 100644 index 00000000..3e888213 --- /dev/null +++ b/lang/interpret_test/TestAstFunc2/fortytwo/main.mcl @@ -0,0 +1,6 @@ +import "fmt" +import "math" +# FIXME: floats don't print nicely: https://github.com/golang/go/issues/46118 +# FIXME: This means that we see "42" for both, instead of 42.0 ... +test fmt.printf("int: %d", math.fortytwo()) {} +test fmt.printf("float: %f", math.fortytwo()) {} diff --git a/lang/types/value.go b/lang/types/value.go index f428d164..7022c0d5 100644 --- a/lang/types/value.go +++ b/lang/types/value.go @@ -708,6 +708,7 @@ func NewFloat() *FloatValue { return &FloatValue{} } // String returns a visual representation of this value. func (obj *FloatValue) String() string { // TODO: is this the right display mode? + // FIXME: floats don't print nicely: https://github.com/golang/go/issues/46118 return strconv.FormatFloat(obj.V, 'f', -1, 64) // -1 for exact precision }