From 21ac8dbf42bc492eadf28f68a2d03a0fdc03356f Mon Sep 17 00:00:00 2001 From: Angus Lees Date: Fri, 12 May 2017 17:28:23 +1000 Subject: [PATCH] Initial version. Implements 'show' Basic skeleton. Can evaluate jsonnet and show the output as yaml or json .. and that's about it. --- .gitignore | 2 + Makefile | 17 + cmd/root.go | 69 + cmd/show.go | 63 + cmd/show_test.go | 71 + cmd/version.go | 25 + cmd/version_test.go | 15 + main.go | 21 + testdata/lib/test.libsonnet | 10 + testdata/test.jsonnet | 5 + vendor/github.com/golang/glog/LICENSE | 191 ++ vendor/github.com/golang/glog/README | 44 + vendor/github.com/golang/glog/glog.go | 1180 +++++++ vendor/github.com/golang/glog/glog_file.go | 124 + .../inconshreveable/mousetrap/LICENSE | 13 + .../inconshreveable/mousetrap/README.md | 23 + .../inconshreveable/mousetrap/trap_others.go | 15 + .../inconshreveable/mousetrap/trap_windows.go | 98 + .../mousetrap/trap_windows_1.4.go | 46 + vendor/github.com/spf13/cobra/LICENSE.txt | 174 ++ vendor/github.com/spf13/cobra/README.md | 887 ++++++ .../spf13/cobra/bash_completions.go | 645 ++++ .../spf13/cobra/bash_completions.md | 206 ++ vendor/github.com/spf13/cobra/cobra.go | 181 ++ vendor/github.com/spf13/cobra/command.go | 1298 ++++++++ .../github.com/spf13/cobra/command_notwin.go | 5 + vendor/github.com/spf13/cobra/command_win.go | 26 + vendor/github.com/spf13/pflag/LICENSE | 28 + vendor/github.com/spf13/pflag/README.md | 296 ++ vendor/github.com/spf13/pflag/bool.go | 94 + vendor/github.com/spf13/pflag/bool_slice.go | 147 + vendor/github.com/spf13/pflag/count.go | 96 + vendor/github.com/spf13/pflag/duration.go | 86 + vendor/github.com/spf13/pflag/flag.go | 1128 +++++++ vendor/github.com/spf13/pflag/float32.go | 88 + vendor/github.com/spf13/pflag/float64.go | 84 + vendor/github.com/spf13/pflag/golangflag.go | 101 + vendor/github.com/spf13/pflag/int.go | 84 + vendor/github.com/spf13/pflag/int32.go | 88 + vendor/github.com/spf13/pflag/int64.go | 84 + vendor/github.com/spf13/pflag/int8.go | 88 + vendor/github.com/spf13/pflag/int_slice.go | 128 + vendor/github.com/spf13/pflag/ip.go | 94 + vendor/github.com/spf13/pflag/ip_slice.go | 148 + vendor/github.com/spf13/pflag/ipmask.go | 122 + vendor/github.com/spf13/pflag/ipnet.go | 98 + vendor/github.com/spf13/pflag/string.go | 80 + vendor/github.com/spf13/pflag/string_array.go | 103 + vendor/github.com/spf13/pflag/string_slice.go | 129 + vendor/github.com/spf13/pflag/uint.go | 88 + vendor/github.com/spf13/pflag/uint16.go | 88 + vendor/github.com/spf13/pflag/uint32.go | 88 + vendor/github.com/spf13/pflag/uint64.go | 88 + vendor/github.com/spf13/pflag/uint8.go | 88 + vendor/github.com/spf13/pflag/uint_slice.go | 126 + .../strickyak/jsonnet_cgo/COMPARE-jsonnet.sh | 73 + .../github.com/strickyak/jsonnet_cgo/LICENSE | 22 + .../strickyak/jsonnet_cgo/LICENSE.jsonnet | 202 ++ .../strickyak/jsonnet_cgo/LICENSE.md5 | 29 + .../strickyak/jsonnet_cgo/README.md | 25 + vendor/github.com/strickyak/jsonnet_cgo/ast.h | 879 ++++++ .../github.com/strickyak/jsonnet_cgo/bridge.c | 19 + .../github.com/strickyak/jsonnet_cgo/bridge.h | 13 + .../strickyak/jsonnet_cgo/desugarer.cpp | 906 ++++++ .../strickyak/jsonnet_cgo/desugarer.h | 34 + .../strickyak/jsonnet_cgo/formatter.cpp | 1747 +++++++++++ .../strickyak/jsonnet_cgo/formatter.h | 51 + .../github.com/strickyak/jsonnet_cgo/json.h | 42 + .../strickyak/jsonnet_cgo/jsonnet.go | 149 + .../strickyak/jsonnet_cgo/lexer.cpp | 810 +++++ .../github.com/strickyak/jsonnet_cgo/lexer.h | 250 ++ .../strickyak/jsonnet_cgo/libjsonnet.cpp | 672 ++++ .../strickyak/jsonnet_cgo/libjsonnet.h | 365 +++ .../github.com/strickyak/jsonnet_cgo/md5.cpp | 363 +++ vendor/github.com/strickyak/jsonnet_cgo/md5.h | 93 + .../strickyak/jsonnet_cgo/parser.cpp | 984 ++++++ .../github.com/strickyak/jsonnet_cgo/parser.h | 44 + .../github.com/strickyak/jsonnet_cgo/pass.cpp | 426 +++ .../github.com/strickyak/jsonnet_cgo/pass.h | 115 + .../github.com/strickyak/jsonnet_cgo/state.h | 444 +++ .../strickyak/jsonnet_cgo/static_analysis.cpp | 178 ++ .../strickyak/jsonnet_cgo/static_analysis.h | 27 + .../strickyak/jsonnet_cgo/static_error.h | 115 + .../strickyak/jsonnet_cgo/std.jsonnet.h | 2 + .../strickyak/jsonnet_cgo/string_utils.cpp | 162 + .../strickyak/jsonnet_cgo/string_utils.h | 31 + .../github.com/strickyak/jsonnet_cgo/test1.j | 4 + .../github.com/strickyak/jsonnet_cgo/test2.j | 5 + .../strickyak/jsonnet_cgo/unicode.h | 166 + .../github.com/strickyak/jsonnet_cgo/vm.cpp | 2750 +++++++++++++++++ vendor/github.com/strickyak/jsonnet_cgo/vm.h | 148 + vendor/vendor.json | 37 + 92 files changed, 21796 insertions(+) create mode 100644 Makefile create mode 100644 cmd/root.go create mode 100644 cmd/show.go create mode 100644 cmd/show_test.go create mode 100644 cmd/version.go create mode 100644 cmd/version_test.go create mode 100644 main.go create mode 100644 testdata/lib/test.libsonnet create mode 100644 testdata/test.jsonnet create mode 100644 vendor/github.com/golang/glog/LICENSE create mode 100644 vendor/github.com/golang/glog/README create mode 100644 vendor/github.com/golang/glog/glog.go create mode 100644 vendor/github.com/golang/glog/glog_file.go create mode 100644 vendor/github.com/inconshreveable/mousetrap/LICENSE create mode 100644 vendor/github.com/inconshreveable/mousetrap/README.md create mode 100644 vendor/github.com/inconshreveable/mousetrap/trap_others.go create mode 100644 vendor/github.com/inconshreveable/mousetrap/trap_windows.go create mode 100644 vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go create mode 100644 vendor/github.com/spf13/cobra/LICENSE.txt create mode 100644 vendor/github.com/spf13/cobra/README.md create mode 100644 vendor/github.com/spf13/cobra/bash_completions.go create mode 100644 vendor/github.com/spf13/cobra/bash_completions.md create mode 100644 vendor/github.com/spf13/cobra/cobra.go create mode 100644 vendor/github.com/spf13/cobra/command.go create mode 100644 vendor/github.com/spf13/cobra/command_notwin.go create mode 100644 vendor/github.com/spf13/cobra/command_win.go create mode 100644 vendor/github.com/spf13/pflag/LICENSE create mode 100644 vendor/github.com/spf13/pflag/README.md create mode 100644 vendor/github.com/spf13/pflag/bool.go create mode 100644 vendor/github.com/spf13/pflag/bool_slice.go create mode 100644 vendor/github.com/spf13/pflag/count.go create mode 100644 vendor/github.com/spf13/pflag/duration.go create mode 100644 vendor/github.com/spf13/pflag/flag.go create mode 100644 vendor/github.com/spf13/pflag/float32.go create mode 100644 vendor/github.com/spf13/pflag/float64.go create mode 100644 vendor/github.com/spf13/pflag/golangflag.go create mode 100644 vendor/github.com/spf13/pflag/int.go create mode 100644 vendor/github.com/spf13/pflag/int32.go create mode 100644 vendor/github.com/spf13/pflag/int64.go create mode 100644 vendor/github.com/spf13/pflag/int8.go create mode 100644 vendor/github.com/spf13/pflag/int_slice.go create mode 100644 vendor/github.com/spf13/pflag/ip.go create mode 100644 vendor/github.com/spf13/pflag/ip_slice.go create mode 100644 vendor/github.com/spf13/pflag/ipmask.go create mode 100644 vendor/github.com/spf13/pflag/ipnet.go create mode 100644 vendor/github.com/spf13/pflag/string.go create mode 100644 vendor/github.com/spf13/pflag/string_array.go create mode 100644 vendor/github.com/spf13/pflag/string_slice.go create mode 100644 vendor/github.com/spf13/pflag/uint.go create mode 100644 vendor/github.com/spf13/pflag/uint16.go create mode 100644 vendor/github.com/spf13/pflag/uint32.go create mode 100644 vendor/github.com/spf13/pflag/uint64.go create mode 100644 vendor/github.com/spf13/pflag/uint8.go create mode 100644 vendor/github.com/spf13/pflag/uint_slice.go create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/COMPARE-jsonnet.sh create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/LICENSE create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/LICENSE.jsonnet create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/LICENSE.md5 create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/README.md create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/ast.h create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/bridge.c create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/bridge.h create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/desugarer.cpp create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/desugarer.h create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/formatter.cpp create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/formatter.h create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/json.h create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/jsonnet.go create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/lexer.cpp create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/lexer.h create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/libjsonnet.cpp create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/libjsonnet.h create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/md5.cpp create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/md5.h create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/parser.cpp create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/parser.h create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/pass.cpp create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/pass.h create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/state.h create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/static_analysis.cpp create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/static_analysis.h create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/static_error.h create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/std.jsonnet.h create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/string_utils.cpp create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/string_utils.h create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/test1.j create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/test2.j create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/unicode.h create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/vm.cpp create mode 100644 vendor/github.com/strickyak/jsonnet_cgo/vm.h create mode 100644 vendor/vendor.json diff --git a/.gitignore b/.gitignore index daf913b1..838d15b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +/kubecfg + # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..593eef84 --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ +VERSION = dev-$(shell date +%FT%T%z) + +GO = go +GO_FLAGS = -ldflags="-X main.version=$(VERSION)" + +all: kubecfg + +kubecfg: + $(GO) build $(GO_FLAGS) . + +test: + $(GO) test ./cmd/... + +clean: + $(RM) ./kubecfg + +.PHONY: all test clean kubecfg diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 00000000..fa60984f --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,69 @@ +package cmd + +import ( + "encoding/json" + goflag "flag" + "path/filepath" + + "github.com/golang/glog" + "github.com/spf13/cobra" + jsonnet "github.com/strickyak/jsonnet_cgo" +) + +func init() { + RootCmd.PersistentFlags().String("context", "", "The name of the kubeconfig context to use") + RootCmd.PersistentFlags().StringP("jpath", "J", "", "Additional jsonnet library search path") + RootCmd.PersistentFlags().AddGoFlagSet(goflag.CommandLine) + RootCmd.PersistentFlags().Set("logtostderr", "true") +} + +// RootCmd is the root of cobra subcommand tree +var RootCmd = &cobra.Command{ + Use: "kubecfg", + Short: "Synchronise Kubernetes resources with config files", + SilenceErrors: true, + SilenceUsage: true, + PersistentPreRun: func(cmd *cobra.Command, args []string) { + goflag.CommandLine.Parse([]string{}) + glog.CopyStandardLogTo("INFO") + }, +} + +// JsonnetVM constructs a new jsonnet.VM, according to command line +// flags +func JsonnetVM(cmd *cobra.Command) (*jsonnet.VM, error) { + vm := jsonnet.Make() + flags := cmd.Flags() + + jpath, err := flags.GetString("jpath") + if err != nil { + return nil, err + } + for _, p := range filepath.SplitList(jpath) { + glog.V(2).Infoln("Adding jsonnet path", p) + vm.JpathAdd(p) + } + + return vm, nil +} + +func evalFile(vm *jsonnet.VM, file string) (interface{}, error) { + var err error + jsonstr := "" + if file != "" { + jsonstr, err = vm.EvaluateFile(file) + if err != nil { + return nil, err + } + } + + glog.V(4).Infof("jsonnet result is: %s\n", jsonstr) + + var jsobj interface{} + err = json.Unmarshal([]byte(jsonstr), &jsobj) + if err != nil { + return nil, err + } + + return jsobj, nil +} diff --git a/cmd/show.go b/cmd/show.go new file mode 100644 index 00000000..82f8c0ef --- /dev/null +++ b/cmd/show.go @@ -0,0 +1,63 @@ +package cmd + +import ( + "encoding/json" + "fmt" + + "github.com/spf13/cobra" + "gopkg.in/yaml.v2" +) + +func init() { + RootCmd.AddCommand(showCmd) + showCmd.PersistentFlags().StringP("file", "f", "", "Input jsonnet file") + showCmd.MarkFlagFilename("file", "jsonnet", "libsonnet") + showCmd.PersistentFlags().StringP("format", "o", "yaml", "Output format. Supported values are: json, yaml") +} + +var showCmd = &cobra.Command{ + Use: "show", + Short: "Show expanded resource definitions", + RunE: func(cmd *cobra.Command, args []string) error { + flags := cmd.Flags() + out := cmd.OutOrStdout() + + vm, err := JsonnetVM(cmd) + if err != nil { + return err + } + defer vm.Destroy() + + file, err := flags.GetString("file") + if err != nil { + return err + } + jsobj, err := evalFile(vm, file) + if err != nil { + return err + } + + format, err := flags.GetString("format") + if err != nil { + return err + } + switch format { + case "yaml": + buf, err := yaml.Marshal(jsobj) + if err != nil { + return err + } + out.Write(buf) + case "json": + enc := json.NewEncoder(out) + enc.SetIndent("", " ") + if err := enc.Encode(&jsobj); err != nil { + return err + } + default: + return fmt.Errorf("Unknown --format: %s", format) + } + + return nil + }, +} diff --git a/cmd/show_test.go b/cmd/show_test.go new file mode 100644 index 00000000..7ce55fb7 --- /dev/null +++ b/cmd/show_test.go @@ -0,0 +1,71 @@ +package cmd + +import ( + "bytes" + "encoding/json" + "path/filepath" + "reflect" + "testing" + + "gopkg.in/yaml.v2" +) + +func cmdOutput(t *testing.T, args []string) string { + var buf bytes.Buffer + RootCmd.SetOutput(&buf) + defer RootCmd.SetOutput(nil) + + t.Log("Running args", args) + RootCmd.SetArgs(args) + if err := RootCmd.Execute(); err != nil { + t.Fatal("command failed:", err) + } + + return buf.String() +} + +func TestShow(t *testing.T) { + formats := map[string]func(string) (interface{}, error){ + "json": func(text string) (ret interface{}, err error) { + err = json.Unmarshal([]byte(text), &ret) + return + }, + "yaml": func(text string) (ret interface{}, err error) { + err = yaml.Unmarshal([]byte(text), &ret) + return + }, + } + + // Use the fact that JSON is also valid YAML .. + expected := ` +{ + "nil": null, + "bool": true, + "number": 42, + "string": "bar", + "array": ["one", 2, [3]], + "object": {"foo": "bar"} +} +` + + for format, parser := range formats { + expected, err := parser(expected) + if err != nil { + t.Errorf("error parsing *expected* value: %s", err) + } + + output := cmdOutput(t, []string{"show", + "-J", filepath.FromSlash("../testdata/lib"), + "-f", filepath.FromSlash("../testdata/test.jsonnet"), + "-o", format, + }) + + t.Log("output is", output) + actual, err := parser(output) + if err != nil { + t.Errorf("error parsing output of format %s: %s", format, err) + } else if !reflect.DeepEqual(expected, actual) { + t.Errorf("format %s expected != actual: %s != %s", format, expected, actual) + } + } +} diff --git a/cmd/version.go b/cmd/version.go new file mode 100644 index 00000000..cd700e2e --- /dev/null +++ b/cmd/version.go @@ -0,0 +1,25 @@ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" + jsonnet "github.com/strickyak/jsonnet_cgo" +) + +func init() { + RootCmd.AddCommand(versionCmd) +} + +// Version is overridden by main +var Version = "(dev build)" + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Print version information", + Run: func(cmd *cobra.Command, args []string) { + out := cmd.OutOrStdout() + fmt.Fprintln(out, "kubecfg version:", Version) + fmt.Fprintln(out, "jsonnet version:", jsonnet.Version()) + }, +} diff --git a/cmd/version_test.go b/cmd/version_test.go new file mode 100644 index 00000000..10ce2ed5 --- /dev/null +++ b/cmd/version_test.go @@ -0,0 +1,15 @@ +package cmd + +import ( + "regexp" + "testing" +) + +func TestVersion(t *testing.T) { + output := cmdOutput(t, []string{"version"}) + + // Also a good smoke-test that libjsonnet linked successfully + if !regexp.MustCompile(`jsonnet version: v[\d.]+`).MatchString(output) { + t.Error("Failed to find jsonnet version in:", output) + } +} diff --git a/main.go b/main.go new file mode 100644 index 00000000..9284ca18 --- /dev/null +++ b/main.go @@ -0,0 +1,21 @@ +package main + +import ( + "fmt" + "os" + + "github.com/anguslees/kubecfg/cmd" +) + +// Version is overridden using `-X main.version` during release builds +var version = "(dev build)" + +func main() { + cmd.Version = version + + if err := cmd.RootCmd.Execute(); err != nil { + fmt.Println("got error") + fmt.Println("Error:", err) + os.Exit(1) + } +} diff --git a/testdata/lib/test.libsonnet b/testdata/lib/test.libsonnet new file mode 100644 index 00000000..6dd03fe6 --- /dev/null +++ b/testdata/lib/test.libsonnet @@ -0,0 +1,10 @@ +{ + nil: null, + bool: true, + number: 42, + string: "foo", + array: ["one", 2, [3]], + object: { + foo: "bar", + }, +} diff --git a/testdata/test.jsonnet b/testdata/test.jsonnet new file mode 100644 index 00000000..935c6df1 --- /dev/null +++ b/testdata/test.jsonnet @@ -0,0 +1,5 @@ +local test = import "test.libsonnet"; + +test { + string: "bar", +} diff --git a/vendor/github.com/golang/glog/LICENSE b/vendor/github.com/golang/glog/LICENSE new file mode 100644 index 00000000..37ec93a1 --- /dev/null +++ b/vendor/github.com/golang/glog/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/golang/glog/README b/vendor/github.com/golang/glog/README new file mode 100644 index 00000000..387b4eb6 --- /dev/null +++ b/vendor/github.com/golang/glog/README @@ -0,0 +1,44 @@ +glog +==== + +Leveled execution logs for Go. + +This is an efficient pure Go implementation of leveled logs in the +manner of the open source C++ package + https://github.com/google/glog + +By binding methods to booleans it is possible to use the log package +without paying the expense of evaluating the arguments to the log. +Through the -vmodule flag, the package also provides fine-grained +control over logging at the file level. + +The comment from glog.go introduces the ideas: + + Package glog implements logging analogous to the Google-internal + C++ INFO/ERROR/V setup. It provides functions Info, Warning, + Error, Fatal, plus formatting variants such as Infof. It + also provides V-style logging controlled by the -v and + -vmodule=file=2 flags. + + Basic examples: + + glog.Info("Prepare to repel boarders") + + glog.Fatalf("Initialization failed: %s", err) + + See the documentation for the V function for an explanation + of these examples: + + if glog.V(2) { + glog.Info("Starting transaction...") + } + + glog.V(2).Infoln("Processed", nItems, "elements") + + +The repository contains an open source version of the log package +used inside Google. The master copy of the source lives inside +Google, not here. The code in this repo is for export only and is not itself +under development. Feature requests will be ignored. + +Send bug reports to golang-nuts@googlegroups.com. diff --git a/vendor/github.com/golang/glog/glog.go b/vendor/github.com/golang/glog/glog.go new file mode 100644 index 00000000..54bd7afd --- /dev/null +++ b/vendor/github.com/golang/glog/glog.go @@ -0,0 +1,1180 @@ +// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/ +// +// Copyright 2013 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package glog implements logging analogous to the Google-internal C++ INFO/ERROR/V setup. +// It provides functions Info, Warning, Error, Fatal, plus formatting variants such as +// Infof. It also provides V-style logging controlled by the -v and -vmodule=file=2 flags. +// +// Basic examples: +// +// glog.Info("Prepare to repel boarders") +// +// glog.Fatalf("Initialization failed: %s", err) +// +// See the documentation for the V function for an explanation of these examples: +// +// if glog.V(2) { +// glog.Info("Starting transaction...") +// } +// +// glog.V(2).Infoln("Processed", nItems, "elements") +// +// Log output is buffered and written periodically using Flush. Programs +// should call Flush before exiting to guarantee all log output is written. +// +// By default, all log statements write to files in a temporary directory. +// This package provides several flags that modify this behavior. +// As a result, flag.Parse must be called before any logging is done. +// +// -logtostderr=false +// Logs are written to standard error instead of to files. +// -alsologtostderr=false +// Logs are written to standard error as well as to files. +// -stderrthreshold=ERROR +// Log events at or above this severity are logged to standard +// error as well as to files. +// -log_dir="" +// Log files will be written to this directory instead of the +// default temporary directory. +// +// Other flags provide aids to debugging. +// +// -log_backtrace_at="" +// When set to a file and line number holding a logging statement, +// such as +// -log_backtrace_at=gopherflakes.go:234 +// a stack trace will be written to the Info log whenever execution +// hits that statement. (Unlike with -vmodule, the ".go" must be +// present.) +// -v=0 +// Enable V-leveled logging at the specified level. +// -vmodule="" +// The syntax of the argument is a comma-separated list of pattern=N, +// where pattern is a literal file name (minus the ".go" suffix) or +// "glob" pattern and N is a V level. For instance, +// -vmodule=gopher*=3 +// sets the V level to 3 in all Go files whose names begin "gopher". +// +package glog + +import ( + "bufio" + "bytes" + "errors" + "flag" + "fmt" + "io" + stdLog "log" + "os" + "path/filepath" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" +) + +// severity identifies the sort of log: info, warning etc. It also implements +// the flag.Value interface. The -stderrthreshold flag is of type severity and +// should be modified only through the flag.Value interface. The values match +// the corresponding constants in C++. +type severity int32 // sync/atomic int32 + +// These constants identify the log levels in order of increasing severity. +// A message written to a high-severity log file is also written to each +// lower-severity log file. +const ( + infoLog severity = iota + warningLog + errorLog + fatalLog + numSeverity = 4 +) + +const severityChar = "IWEF" + +var severityName = []string{ + infoLog: "INFO", + warningLog: "WARNING", + errorLog: "ERROR", + fatalLog: "FATAL", +} + +// get returns the value of the severity. +func (s *severity) get() severity { + return severity(atomic.LoadInt32((*int32)(s))) +} + +// set sets the value of the severity. +func (s *severity) set(val severity) { + atomic.StoreInt32((*int32)(s), int32(val)) +} + +// String is part of the flag.Value interface. +func (s *severity) String() string { + return strconv.FormatInt(int64(*s), 10) +} + +// Get is part of the flag.Value interface. +func (s *severity) Get() interface{} { + return *s +} + +// Set is part of the flag.Value interface. +func (s *severity) Set(value string) error { + var threshold severity + // Is it a known name? + if v, ok := severityByName(value); ok { + threshold = v + } else { + v, err := strconv.Atoi(value) + if err != nil { + return err + } + threshold = severity(v) + } + logging.stderrThreshold.set(threshold) + return nil +} + +func severityByName(s string) (severity, bool) { + s = strings.ToUpper(s) + for i, name := range severityName { + if name == s { + return severity(i), true + } + } + return 0, false +} + +// OutputStats tracks the number of output lines and bytes written. +type OutputStats struct { + lines int64 + bytes int64 +} + +// Lines returns the number of lines written. +func (s *OutputStats) Lines() int64 { + return atomic.LoadInt64(&s.lines) +} + +// Bytes returns the number of bytes written. +func (s *OutputStats) Bytes() int64 { + return atomic.LoadInt64(&s.bytes) +} + +// Stats tracks the number of lines of output and number of bytes +// per severity level. Values must be read with atomic.LoadInt64. +var Stats struct { + Info, Warning, Error OutputStats +} + +var severityStats = [numSeverity]*OutputStats{ + infoLog: &Stats.Info, + warningLog: &Stats.Warning, + errorLog: &Stats.Error, +} + +// Level is exported because it appears in the arguments to V and is +// the type of the v flag, which can be set programmatically. +// It's a distinct type because we want to discriminate it from logType. +// Variables of type level are only changed under logging.mu. +// The -v flag is read only with atomic ops, so the state of the logging +// module is consistent. + +// Level is treated as a sync/atomic int32. + +// Level specifies a level of verbosity for V logs. *Level implements +// flag.Value; the -v flag is of type Level and should be modified +// only through the flag.Value interface. +type Level int32 + +// get returns the value of the Level. +func (l *Level) get() Level { + return Level(atomic.LoadInt32((*int32)(l))) +} + +// set sets the value of the Level. +func (l *Level) set(val Level) { + atomic.StoreInt32((*int32)(l), int32(val)) +} + +// String is part of the flag.Value interface. +func (l *Level) String() string { + return strconv.FormatInt(int64(*l), 10) +} + +// Get is part of the flag.Value interface. +func (l *Level) Get() interface{} { + return *l +} + +// Set is part of the flag.Value interface. +func (l *Level) Set(value string) error { + v, err := strconv.Atoi(value) + if err != nil { + return err + } + logging.mu.Lock() + defer logging.mu.Unlock() + logging.setVState(Level(v), logging.vmodule.filter, false) + return nil +} + +// moduleSpec represents the setting of the -vmodule flag. +type moduleSpec struct { + filter []modulePat +} + +// modulePat contains a filter for the -vmodule flag. +// It holds a verbosity level and a file pattern to match. +type modulePat struct { + pattern string + literal bool // The pattern is a literal string + level Level +} + +// match reports whether the file matches the pattern. It uses a string +// comparison if the pattern contains no metacharacters. +func (m *modulePat) match(file string) bool { + if m.literal { + return file == m.pattern + } + match, _ := filepath.Match(m.pattern, file) + return match +} + +func (m *moduleSpec) String() string { + // Lock because the type is not atomic. TODO: clean this up. + logging.mu.Lock() + defer logging.mu.Unlock() + var b bytes.Buffer + for i, f := range m.filter { + if i > 0 { + b.WriteRune(',') + } + fmt.Fprintf(&b, "%s=%d", f.pattern, f.level) + } + return b.String() +} + +// Get is part of the (Go 1.2) flag.Getter interface. It always returns nil for this flag type since the +// struct is not exported. +func (m *moduleSpec) Get() interface{} { + return nil +} + +var errVmoduleSyntax = errors.New("syntax error: expect comma-separated list of filename=N") + +// Syntax: -vmodule=recordio=2,file=1,gfs*=3 +func (m *moduleSpec) Set(value string) error { + var filter []modulePat + for _, pat := range strings.Split(value, ",") { + if len(pat) == 0 { + // Empty strings such as from a trailing comma can be ignored. + continue + } + patLev := strings.Split(pat, "=") + if len(patLev) != 2 || len(patLev[0]) == 0 || len(patLev[1]) == 0 { + return errVmoduleSyntax + } + pattern := patLev[0] + v, err := strconv.Atoi(patLev[1]) + if err != nil { + return errors.New("syntax error: expect comma-separated list of filename=N") + } + if v < 0 { + return errors.New("negative value for vmodule level") + } + if v == 0 { + continue // Ignore. It's harmless but no point in paying the overhead. + } + // TODO: check syntax of filter? + filter = append(filter, modulePat{pattern, isLiteral(pattern), Level(v)}) + } + logging.mu.Lock() + defer logging.mu.Unlock() + logging.setVState(logging.verbosity, filter, true) + return nil +} + +// isLiteral reports whether the pattern is a literal string, that is, has no metacharacters +// that require filepath.Match to be called to match the pattern. +func isLiteral(pattern string) bool { + return !strings.ContainsAny(pattern, `\*?[]`) +} + +// traceLocation represents the setting of the -log_backtrace_at flag. +type traceLocation struct { + file string + line int +} + +// isSet reports whether the trace location has been specified. +// logging.mu is held. +func (t *traceLocation) isSet() bool { + return t.line > 0 +} + +// match reports whether the specified file and line matches the trace location. +// The argument file name is the full path, not the basename specified in the flag. +// logging.mu is held. +func (t *traceLocation) match(file string, line int) bool { + if t.line != line { + return false + } + if i := strings.LastIndex(file, "/"); i >= 0 { + file = file[i+1:] + } + return t.file == file +} + +func (t *traceLocation) String() string { + // Lock because the type is not atomic. TODO: clean this up. + logging.mu.Lock() + defer logging.mu.Unlock() + return fmt.Sprintf("%s:%d", t.file, t.line) +} + +// Get is part of the (Go 1.2) flag.Getter interface. It always returns nil for this flag type since the +// struct is not exported +func (t *traceLocation) Get() interface{} { + return nil +} + +var errTraceSyntax = errors.New("syntax error: expect file.go:234") + +// Syntax: -log_backtrace_at=gopherflakes.go:234 +// Note that unlike vmodule the file extension is included here. +func (t *traceLocation) Set(value string) error { + if value == "" { + // Unset. + t.line = 0 + t.file = "" + } + fields := strings.Split(value, ":") + if len(fields) != 2 { + return errTraceSyntax + } + file, line := fields[0], fields[1] + if !strings.Contains(file, ".") { + return errTraceSyntax + } + v, err := strconv.Atoi(line) + if err != nil { + return errTraceSyntax + } + if v <= 0 { + return errors.New("negative or zero value for level") + } + logging.mu.Lock() + defer logging.mu.Unlock() + t.line = v + t.file = file + return nil +} + +// flushSyncWriter is the interface satisfied by logging destinations. +type flushSyncWriter interface { + Flush() error + Sync() error + io.Writer +} + +func init() { + flag.BoolVar(&logging.toStderr, "logtostderr", false, "log to standard error instead of files") + flag.BoolVar(&logging.alsoToStderr, "alsologtostderr", false, "log to standard error as well as files") + flag.Var(&logging.verbosity, "v", "log level for V logs") + flag.Var(&logging.stderrThreshold, "stderrthreshold", "logs at or above this threshold go to stderr") + flag.Var(&logging.vmodule, "vmodule", "comma-separated list of pattern=N settings for file-filtered logging") + flag.Var(&logging.traceLocation, "log_backtrace_at", "when logging hits line file:N, emit a stack trace") + + // Default stderrThreshold is ERROR. + logging.stderrThreshold = errorLog + + logging.setVState(0, nil, false) + go logging.flushDaemon() +} + +// Flush flushes all pending log I/O. +func Flush() { + logging.lockAndFlushAll() +} + +// loggingT collects all the global state of the logging setup. +type loggingT struct { + // Boolean flags. Not handled atomically because the flag.Value interface + // does not let us avoid the =true, and that shorthand is necessary for + // compatibility. TODO: does this matter enough to fix? Seems unlikely. + toStderr bool // The -logtostderr flag. + alsoToStderr bool // The -alsologtostderr flag. + + // Level flag. Handled atomically. + stderrThreshold severity // The -stderrthreshold flag. + + // freeList is a list of byte buffers, maintained under freeListMu. + freeList *buffer + // freeListMu maintains the free list. It is separate from the main mutex + // so buffers can be grabbed and printed to without holding the main lock, + // for better parallelization. + freeListMu sync.Mutex + + // mu protects the remaining elements of this structure and is + // used to synchronize logging. + mu sync.Mutex + // file holds writer for each of the log types. + file [numSeverity]flushSyncWriter + // pcs is used in V to avoid an allocation when computing the caller's PC. + pcs [1]uintptr + // vmap is a cache of the V Level for each V() call site, identified by PC. + // It is wiped whenever the vmodule flag changes state. + vmap map[uintptr]Level + // filterLength stores the length of the vmodule filter chain. If greater + // than zero, it means vmodule is enabled. It may be read safely + // using sync.LoadInt32, but is only modified under mu. + filterLength int32 + // traceLocation is the state of the -log_backtrace_at flag. + traceLocation traceLocation + // These flags are modified only under lock, although verbosity may be fetched + // safely using atomic.LoadInt32. + vmodule moduleSpec // The state of the -vmodule flag. + verbosity Level // V logging level, the value of the -v flag/ +} + +// buffer holds a byte Buffer for reuse. The zero value is ready for use. +type buffer struct { + bytes.Buffer + tmp [64]byte // temporary byte array for creating headers. + next *buffer +} + +var logging loggingT + +// setVState sets a consistent state for V logging. +// l.mu is held. +func (l *loggingT) setVState(verbosity Level, filter []modulePat, setFilter bool) { + // Turn verbosity off so V will not fire while we are in transition. + logging.verbosity.set(0) + // Ditto for filter length. + atomic.StoreInt32(&logging.filterLength, 0) + + // Set the new filters and wipe the pc->Level map if the filter has changed. + if setFilter { + logging.vmodule.filter = filter + logging.vmap = make(map[uintptr]Level) + } + + // Things are consistent now, so enable filtering and verbosity. + // They are enabled in order opposite to that in V. + atomic.StoreInt32(&logging.filterLength, int32(len(filter))) + logging.verbosity.set(verbosity) +} + +// getBuffer returns a new, ready-to-use buffer. +func (l *loggingT) getBuffer() *buffer { + l.freeListMu.Lock() + b := l.freeList + if b != nil { + l.freeList = b.next + } + l.freeListMu.Unlock() + if b == nil { + b = new(buffer) + } else { + b.next = nil + b.Reset() + } + return b +} + +// putBuffer returns a buffer to the free list. +func (l *loggingT) putBuffer(b *buffer) { + if b.Len() >= 256 { + // Let big buffers die a natural death. + return + } + l.freeListMu.Lock() + b.next = l.freeList + l.freeList = b + l.freeListMu.Unlock() +} + +var timeNow = time.Now // Stubbed out for testing. + +/* +header formats a log header as defined by the C++ implementation. +It returns a buffer containing the formatted header and the user's file and line number. +The depth specifies how many stack frames above lives the source line to be identified in the log message. + +Log lines have this form: + Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg... +where the fields are defined as follows: + L A single character, representing the log level (eg 'I' for INFO) + mm The month (zero padded; ie May is '05') + dd The day (zero padded) + hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds + threadid The space-padded thread ID as returned by GetTID() + file The file name + line The line number + msg The user-supplied message +*/ +func (l *loggingT) header(s severity, depth int) (*buffer, string, int) { + _, file, line, ok := runtime.Caller(3 + depth) + if !ok { + file = "???" + line = 1 + } else { + slash := strings.LastIndex(file, "/") + if slash >= 0 { + file = file[slash+1:] + } + } + return l.formatHeader(s, file, line), file, line +} + +// formatHeader formats a log header using the provided file name and line number. +func (l *loggingT) formatHeader(s severity, file string, line int) *buffer { + now := timeNow() + if line < 0 { + line = 0 // not a real line number, but acceptable to someDigits + } + if s > fatalLog { + s = infoLog // for safety. + } + buf := l.getBuffer() + + // Avoid Fprintf, for speed. The format is so simple that we can do it quickly by hand. + // It's worth about 3X. Fprintf is hard. + _, month, day := now.Date() + hour, minute, second := now.Clock() + // Lmmdd hh:mm:ss.uuuuuu threadid file:line] + buf.tmp[0] = severityChar[s] + buf.twoDigits(1, int(month)) + buf.twoDigits(3, day) + buf.tmp[5] = ' ' + buf.twoDigits(6, hour) + buf.tmp[8] = ':' + buf.twoDigits(9, minute) + buf.tmp[11] = ':' + buf.twoDigits(12, second) + buf.tmp[14] = '.' + buf.nDigits(6, 15, now.Nanosecond()/1000, '0') + buf.tmp[21] = ' ' + buf.nDigits(7, 22, pid, ' ') // TODO: should be TID + buf.tmp[29] = ' ' + buf.Write(buf.tmp[:30]) + buf.WriteString(file) + buf.tmp[0] = ':' + n := buf.someDigits(1, line) + buf.tmp[n+1] = ']' + buf.tmp[n+2] = ' ' + buf.Write(buf.tmp[:n+3]) + return buf +} + +// Some custom tiny helper functions to print the log header efficiently. + +const digits = "0123456789" + +// twoDigits formats a zero-prefixed two-digit integer at buf.tmp[i]. +func (buf *buffer) twoDigits(i, d int) { + buf.tmp[i+1] = digits[d%10] + d /= 10 + buf.tmp[i] = digits[d%10] +} + +// nDigits formats an n-digit integer at buf.tmp[i], +// padding with pad on the left. +// It assumes d >= 0. +func (buf *buffer) nDigits(n, i, d int, pad byte) { + j := n - 1 + for ; j >= 0 && d > 0; j-- { + buf.tmp[i+j] = digits[d%10] + d /= 10 + } + for ; j >= 0; j-- { + buf.tmp[i+j] = pad + } +} + +// someDigits formats a zero-prefixed variable-width integer at buf.tmp[i]. +func (buf *buffer) someDigits(i, d int) int { + // Print into the top, then copy down. We know there's space for at least + // a 10-digit number. + j := len(buf.tmp) + for { + j-- + buf.tmp[j] = digits[d%10] + d /= 10 + if d == 0 { + break + } + } + return copy(buf.tmp[i:], buf.tmp[j:]) +} + +func (l *loggingT) println(s severity, args ...interface{}) { + buf, file, line := l.header(s, 0) + fmt.Fprintln(buf, args...) + l.output(s, buf, file, line, false) +} + +func (l *loggingT) print(s severity, args ...interface{}) { + l.printDepth(s, 1, args...) +} + +func (l *loggingT) printDepth(s severity, depth int, args ...interface{}) { + buf, file, line := l.header(s, depth) + fmt.Fprint(buf, args...) + if buf.Bytes()[buf.Len()-1] != '\n' { + buf.WriteByte('\n') + } + l.output(s, buf, file, line, false) +} + +func (l *loggingT) printf(s severity, format string, args ...interface{}) { + buf, file, line := l.header(s, 0) + fmt.Fprintf(buf, format, args...) + if buf.Bytes()[buf.Len()-1] != '\n' { + buf.WriteByte('\n') + } + l.output(s, buf, file, line, false) +} + +// printWithFileLine behaves like print but uses the provided file and line number. If +// alsoLogToStderr is true, the log message always appears on standard error; it +// will also appear in the log file unless --logtostderr is set. +func (l *loggingT) printWithFileLine(s severity, file string, line int, alsoToStderr bool, args ...interface{}) { + buf := l.formatHeader(s, file, line) + fmt.Fprint(buf, args...) + if buf.Bytes()[buf.Len()-1] != '\n' { + buf.WriteByte('\n') + } + l.output(s, buf, file, line, alsoToStderr) +} + +// output writes the data to the log files and releases the buffer. +func (l *loggingT) output(s severity, buf *buffer, file string, line int, alsoToStderr bool) { + l.mu.Lock() + if l.traceLocation.isSet() { + if l.traceLocation.match(file, line) { + buf.Write(stacks(false)) + } + } + data := buf.Bytes() + if !flag.Parsed() { + os.Stderr.Write([]byte("ERROR: logging before flag.Parse: ")) + os.Stderr.Write(data) + } else if l.toStderr { + os.Stderr.Write(data) + } else { + if alsoToStderr || l.alsoToStderr || s >= l.stderrThreshold.get() { + os.Stderr.Write(data) + } + if l.file[s] == nil { + if err := l.createFiles(s); err != nil { + os.Stderr.Write(data) // Make sure the message appears somewhere. + l.exit(err) + } + } + switch s { + case fatalLog: + l.file[fatalLog].Write(data) + fallthrough + case errorLog: + l.file[errorLog].Write(data) + fallthrough + case warningLog: + l.file[warningLog].Write(data) + fallthrough + case infoLog: + l.file[infoLog].Write(data) + } + } + if s == fatalLog { + // If we got here via Exit rather than Fatal, print no stacks. + if atomic.LoadUint32(&fatalNoStacks) > 0 { + l.mu.Unlock() + timeoutFlush(10 * time.Second) + os.Exit(1) + } + // Dump all goroutine stacks before exiting. + // First, make sure we see the trace for the current goroutine on standard error. + // If -logtostderr has been specified, the loop below will do that anyway + // as the first stack in the full dump. + if !l.toStderr { + os.Stderr.Write(stacks(false)) + } + // Write the stack trace for all goroutines to the files. + trace := stacks(true) + logExitFunc = func(error) {} // If we get a write error, we'll still exit below. + for log := fatalLog; log >= infoLog; log-- { + if f := l.file[log]; f != nil { // Can be nil if -logtostderr is set. + f.Write(trace) + } + } + l.mu.Unlock() + timeoutFlush(10 * time.Second) + os.Exit(255) // C++ uses -1, which is silly because it's anded with 255 anyway. + } + l.putBuffer(buf) + l.mu.Unlock() + if stats := severityStats[s]; stats != nil { + atomic.AddInt64(&stats.lines, 1) + atomic.AddInt64(&stats.bytes, int64(len(data))) + } +} + +// timeoutFlush calls Flush and returns when it completes or after timeout +// elapses, whichever happens first. This is needed because the hooks invoked +// by Flush may deadlock when glog.Fatal is called from a hook that holds +// a lock. +func timeoutFlush(timeout time.Duration) { + done := make(chan bool, 1) + go func() { + Flush() // calls logging.lockAndFlushAll() + done <- true + }() + select { + case <-done: + case <-time.After(timeout): + fmt.Fprintln(os.Stderr, "glog: Flush took longer than", timeout) + } +} + +// stacks is a wrapper for runtime.Stack that attempts to recover the data for all goroutines. +func stacks(all bool) []byte { + // We don't know how big the traces are, so grow a few times if they don't fit. Start large, though. + n := 10000 + if all { + n = 100000 + } + var trace []byte + for i := 0; i < 5; i++ { + trace = make([]byte, n) + nbytes := runtime.Stack(trace, all) + if nbytes < len(trace) { + return trace[:nbytes] + } + n *= 2 + } + return trace +} + +// logExitFunc provides a simple mechanism to override the default behavior +// of exiting on error. Used in testing and to guarantee we reach a required exit +// for fatal logs. Instead, exit could be a function rather than a method but that +// would make its use clumsier. +var logExitFunc func(error) + +// exit is called if there is trouble creating or writing log files. +// It flushes the logs and exits the program; there's no point in hanging around. +// l.mu is held. +func (l *loggingT) exit(err error) { + fmt.Fprintf(os.Stderr, "log: exiting because of error: %s\n", err) + // If logExitFunc is set, we do that instead of exiting. + if logExitFunc != nil { + logExitFunc(err) + return + } + l.flushAll() + os.Exit(2) +} + +// syncBuffer joins a bufio.Writer to its underlying file, providing access to the +// file's Sync method and providing a wrapper for the Write method that provides log +// file rotation. There are conflicting methods, so the file cannot be embedded. +// l.mu is held for all its methods. +type syncBuffer struct { + logger *loggingT + *bufio.Writer + file *os.File + sev severity + nbytes uint64 // The number of bytes written to this file +} + +func (sb *syncBuffer) Sync() error { + return sb.file.Sync() +} + +func (sb *syncBuffer) Write(p []byte) (n int, err error) { + if sb.nbytes+uint64(len(p)) >= MaxSize { + if err := sb.rotateFile(time.Now()); err != nil { + sb.logger.exit(err) + } + } + n, err = sb.Writer.Write(p) + sb.nbytes += uint64(n) + if err != nil { + sb.logger.exit(err) + } + return +} + +// rotateFile closes the syncBuffer's file and starts a new one. +func (sb *syncBuffer) rotateFile(now time.Time) error { + if sb.file != nil { + sb.Flush() + sb.file.Close() + } + var err error + sb.file, _, err = create(severityName[sb.sev], now) + sb.nbytes = 0 + if err != nil { + return err + } + + sb.Writer = bufio.NewWriterSize(sb.file, bufferSize) + + // Write header. + var buf bytes.Buffer + fmt.Fprintf(&buf, "Log file created at: %s\n", now.Format("2006/01/02 15:04:05")) + fmt.Fprintf(&buf, "Running on machine: %s\n", host) + fmt.Fprintf(&buf, "Binary: Built with %s %s for %s/%s\n", runtime.Compiler, runtime.Version(), runtime.GOOS, runtime.GOARCH) + fmt.Fprintf(&buf, "Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg\n") + n, err := sb.file.Write(buf.Bytes()) + sb.nbytes += uint64(n) + return err +} + +// bufferSize sizes the buffer associated with each log file. It's large +// so that log records can accumulate without the logging thread blocking +// on disk I/O. The flushDaemon will block instead. +const bufferSize = 256 * 1024 + +// createFiles creates all the log files for severity from sev down to infoLog. +// l.mu is held. +func (l *loggingT) createFiles(sev severity) error { + now := time.Now() + // Files are created in decreasing severity order, so as soon as we find one + // has already been created, we can stop. + for s := sev; s >= infoLog && l.file[s] == nil; s-- { + sb := &syncBuffer{ + logger: l, + sev: s, + } + if err := sb.rotateFile(now); err != nil { + return err + } + l.file[s] = sb + } + return nil +} + +const flushInterval = 30 * time.Second + +// flushDaemon periodically flushes the log file buffers. +func (l *loggingT) flushDaemon() { + for _ = range time.NewTicker(flushInterval).C { + l.lockAndFlushAll() + } +} + +// lockAndFlushAll is like flushAll but locks l.mu first. +func (l *loggingT) lockAndFlushAll() { + l.mu.Lock() + l.flushAll() + l.mu.Unlock() +} + +// flushAll flushes all the logs and attempts to "sync" their data to disk. +// l.mu is held. +func (l *loggingT) flushAll() { + // Flush from fatal down, in case there's trouble flushing. + for s := fatalLog; s >= infoLog; s-- { + file := l.file[s] + if file != nil { + file.Flush() // ignore error + file.Sync() // ignore error + } + } +} + +// CopyStandardLogTo arranges for messages written to the Go "log" package's +// default logs to also appear in the Google logs for the named and lower +// severities. Subsequent changes to the standard log's default output location +// or format may break this behavior. +// +// Valid names are "INFO", "WARNING", "ERROR", and "FATAL". If the name is not +// recognized, CopyStandardLogTo panics. +func CopyStandardLogTo(name string) { + sev, ok := severityByName(name) + if !ok { + panic(fmt.Sprintf("log.CopyStandardLogTo(%q): unrecognized severity name", name)) + } + // Set a log format that captures the user's file and line: + // d.go:23: message + stdLog.SetFlags(stdLog.Lshortfile) + stdLog.SetOutput(logBridge(sev)) +} + +// logBridge provides the Write method that enables CopyStandardLogTo to connect +// Go's standard logs to the logs provided by this package. +type logBridge severity + +// Write parses the standard logging line and passes its components to the +// logger for severity(lb). +func (lb logBridge) Write(b []byte) (n int, err error) { + var ( + file = "???" + line = 1 + text string + ) + // Split "d.go:23: message" into "d.go", "23", and "message". + if parts := bytes.SplitN(b, []byte{':'}, 3); len(parts) != 3 || len(parts[0]) < 1 || len(parts[2]) < 1 { + text = fmt.Sprintf("bad log format: %s", b) + } else { + file = string(parts[0]) + text = string(parts[2][1:]) // skip leading space + line, err = strconv.Atoi(string(parts[1])) + if err != nil { + text = fmt.Sprintf("bad line number: %s", b) + line = 1 + } + } + // printWithFileLine with alsoToStderr=true, so standard log messages + // always appear on standard error. + logging.printWithFileLine(severity(lb), file, line, true, text) + return len(b), nil +} + +// setV computes and remembers the V level for a given PC +// when vmodule is enabled. +// File pattern matching takes the basename of the file, stripped +// of its .go suffix, and uses filepath.Match, which is a little more +// general than the *? matching used in C++. +// l.mu is held. +func (l *loggingT) setV(pc uintptr) Level { + fn := runtime.FuncForPC(pc) + file, _ := fn.FileLine(pc) + // The file is something like /a/b/c/d.go. We want just the d. + if strings.HasSuffix(file, ".go") { + file = file[:len(file)-3] + } + if slash := strings.LastIndex(file, "/"); slash >= 0 { + file = file[slash+1:] + } + for _, filter := range l.vmodule.filter { + if filter.match(file) { + l.vmap[pc] = filter.level + return filter.level + } + } + l.vmap[pc] = 0 + return 0 +} + +// Verbose is a boolean type that implements Infof (like Printf) etc. +// See the documentation of V for more information. +type Verbose bool + +// V reports whether verbosity at the call site is at least the requested level. +// The returned value is a boolean of type Verbose, which implements Info, Infoln +// and Infof. These methods will write to the Info log if called. +// Thus, one may write either +// if glog.V(2) { glog.Info("log this") } +// or +// glog.V(2).Info("log this") +// The second form is shorter but the first is cheaper if logging is off because it does +// not evaluate its arguments. +// +// Whether an individual call to V generates a log record depends on the setting of +// the -v and --vmodule flags; both are off by default. If the level in the call to +// V is at least the value of -v, or of -vmodule for the source file containing the +// call, the V call will log. +func V(level Level) Verbose { + // This function tries hard to be cheap unless there's work to do. + // The fast path is two atomic loads and compares. + + // Here is a cheap but safe test to see if V logging is enabled globally. + if logging.verbosity.get() >= level { + return Verbose(true) + } + + // It's off globally but it vmodule may still be set. + // Here is another cheap but safe test to see if vmodule is enabled. + if atomic.LoadInt32(&logging.filterLength) > 0 { + // Now we need a proper lock to use the logging structure. The pcs field + // is shared so we must lock before accessing it. This is fairly expensive, + // but if V logging is enabled we're slow anyway. + logging.mu.Lock() + defer logging.mu.Unlock() + if runtime.Callers(2, logging.pcs[:]) == 0 { + return Verbose(false) + } + v, ok := logging.vmap[logging.pcs[0]] + if !ok { + v = logging.setV(logging.pcs[0]) + } + return Verbose(v >= level) + } + return Verbose(false) +} + +// Info is equivalent to the global Info function, guarded by the value of v. +// See the documentation of V for usage. +func (v Verbose) Info(args ...interface{}) { + if v { + logging.print(infoLog, args...) + } +} + +// Infoln is equivalent to the global Infoln function, guarded by the value of v. +// See the documentation of V for usage. +func (v Verbose) Infoln(args ...interface{}) { + if v { + logging.println(infoLog, args...) + } +} + +// Infof is equivalent to the global Infof function, guarded by the value of v. +// See the documentation of V for usage. +func (v Verbose) Infof(format string, args ...interface{}) { + if v { + logging.printf(infoLog, format, args...) + } +} + +// Info logs to the INFO log. +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Info(args ...interface{}) { + logging.print(infoLog, args...) +} + +// InfoDepth acts as Info but uses depth to determine which call frame to log. +// InfoDepth(0, "msg") is the same as Info("msg"). +func InfoDepth(depth int, args ...interface{}) { + logging.printDepth(infoLog, depth, args...) +} + +// Infoln logs to the INFO log. +// Arguments are handled in the manner of fmt.Println; a newline is appended if missing. +func Infoln(args ...interface{}) { + logging.println(infoLog, args...) +} + +// Infof logs to the INFO log. +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Infof(format string, args ...interface{}) { + logging.printf(infoLog, format, args...) +} + +// Warning logs to the WARNING and INFO logs. +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Warning(args ...interface{}) { + logging.print(warningLog, args...) +} + +// WarningDepth acts as Warning but uses depth to determine which call frame to log. +// WarningDepth(0, "msg") is the same as Warning("msg"). +func WarningDepth(depth int, args ...interface{}) { + logging.printDepth(warningLog, depth, args...) +} + +// Warningln logs to the WARNING and INFO logs. +// Arguments are handled in the manner of fmt.Println; a newline is appended if missing. +func Warningln(args ...interface{}) { + logging.println(warningLog, args...) +} + +// Warningf logs to the WARNING and INFO logs. +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Warningf(format string, args ...interface{}) { + logging.printf(warningLog, format, args...) +} + +// Error logs to the ERROR, WARNING, and INFO logs. +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Error(args ...interface{}) { + logging.print(errorLog, args...) +} + +// ErrorDepth acts as Error but uses depth to determine which call frame to log. +// ErrorDepth(0, "msg") is the same as Error("msg"). +func ErrorDepth(depth int, args ...interface{}) { + logging.printDepth(errorLog, depth, args...) +} + +// Errorln logs to the ERROR, WARNING, and INFO logs. +// Arguments are handled in the manner of fmt.Println; a newline is appended if missing. +func Errorln(args ...interface{}) { + logging.println(errorLog, args...) +} + +// Errorf logs to the ERROR, WARNING, and INFO logs. +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Errorf(format string, args ...interface{}) { + logging.printf(errorLog, format, args...) +} + +// Fatal logs to the FATAL, ERROR, WARNING, and INFO logs, +// including a stack trace of all running goroutines, then calls os.Exit(255). +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Fatal(args ...interface{}) { + logging.print(fatalLog, args...) +} + +// FatalDepth acts as Fatal but uses depth to determine which call frame to log. +// FatalDepth(0, "msg") is the same as Fatal("msg"). +func FatalDepth(depth int, args ...interface{}) { + logging.printDepth(fatalLog, depth, args...) +} + +// Fatalln logs to the FATAL, ERROR, WARNING, and INFO logs, +// including a stack trace of all running goroutines, then calls os.Exit(255). +// Arguments are handled in the manner of fmt.Println; a newline is appended if missing. +func Fatalln(args ...interface{}) { + logging.println(fatalLog, args...) +} + +// Fatalf logs to the FATAL, ERROR, WARNING, and INFO logs, +// including a stack trace of all running goroutines, then calls os.Exit(255). +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Fatalf(format string, args ...interface{}) { + logging.printf(fatalLog, format, args...) +} + +// fatalNoStacks is non-zero if we are to exit without dumping goroutine stacks. +// It allows Exit and relatives to use the Fatal logs. +var fatalNoStacks uint32 + +// Exit logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1). +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Exit(args ...interface{}) { + atomic.StoreUint32(&fatalNoStacks, 1) + logging.print(fatalLog, args...) +} + +// ExitDepth acts as Exit but uses depth to determine which call frame to log. +// ExitDepth(0, "msg") is the same as Exit("msg"). +func ExitDepth(depth int, args ...interface{}) { + atomic.StoreUint32(&fatalNoStacks, 1) + logging.printDepth(fatalLog, depth, args...) +} + +// Exitln logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1). +func Exitln(args ...interface{}) { + atomic.StoreUint32(&fatalNoStacks, 1) + logging.println(fatalLog, args...) +} + +// Exitf logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1). +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Exitf(format string, args ...interface{}) { + atomic.StoreUint32(&fatalNoStacks, 1) + logging.printf(fatalLog, format, args...) +} diff --git a/vendor/github.com/golang/glog/glog_file.go b/vendor/github.com/golang/glog/glog_file.go new file mode 100644 index 00000000..65075d28 --- /dev/null +++ b/vendor/github.com/golang/glog/glog_file.go @@ -0,0 +1,124 @@ +// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/ +// +// Copyright 2013 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// File I/O for logs. + +package glog + +import ( + "errors" + "flag" + "fmt" + "os" + "os/user" + "path/filepath" + "strings" + "sync" + "time" +) + +// MaxSize is the maximum size of a log file in bytes. +var MaxSize uint64 = 1024 * 1024 * 1800 + +// logDirs lists the candidate directories for new log files. +var logDirs []string + +// If non-empty, overrides the choice of directory in which to write logs. +// See createLogDirs for the full list of possible destinations. +var logDir = flag.String("log_dir", "", "If non-empty, write log files in this directory") + +func createLogDirs() { + if *logDir != "" { + logDirs = append(logDirs, *logDir) + } + logDirs = append(logDirs, os.TempDir()) +} + +var ( + pid = os.Getpid() + program = filepath.Base(os.Args[0]) + host = "unknownhost" + userName = "unknownuser" +) + +func init() { + h, err := os.Hostname() + if err == nil { + host = shortHostname(h) + } + + current, err := user.Current() + if err == nil { + userName = current.Username + } + + // Sanitize userName since it may contain filepath separators on Windows. + userName = strings.Replace(userName, `\`, "_", -1) +} + +// shortHostname returns its argument, truncating at the first period. +// For instance, given "www.google.com" it returns "www". +func shortHostname(hostname string) string { + if i := strings.Index(hostname, "."); i >= 0 { + return hostname[:i] + } + return hostname +} + +// logName returns a new log file name containing tag, with start time t, and +// the name for the symlink for tag. +func logName(tag string, t time.Time) (name, link string) { + name = fmt.Sprintf("%s.%s.%s.log.%s.%04d%02d%02d-%02d%02d%02d.%d", + program, + host, + userName, + tag, + t.Year(), + t.Month(), + t.Day(), + t.Hour(), + t.Minute(), + t.Second(), + pid) + return name, program + "." + tag +} + +var onceLogDirs sync.Once + +// create creates a new log file and returns the file and its filename, which +// contains tag ("INFO", "FATAL", etc.) and t. If the file is created +// successfully, create also attempts to update the symlink for that tag, ignoring +// errors. +func create(tag string, t time.Time) (f *os.File, filename string, err error) { + onceLogDirs.Do(createLogDirs) + if len(logDirs) == 0 { + return nil, "", errors.New("log: no log dirs") + } + name, link := logName(tag, t) + var lastErr error + for _, dir := range logDirs { + fname := filepath.Join(dir, name) + f, err := os.Create(fname) + if err == nil { + symlink := filepath.Join(dir, link) + os.Remove(symlink) // ignore err + os.Symlink(name, symlink) // ignore err + return f, fname, nil + } + lastErr = err + } + return nil, "", fmt.Errorf("log: cannot create log: %v", lastErr) +} diff --git a/vendor/github.com/inconshreveable/mousetrap/LICENSE b/vendor/github.com/inconshreveable/mousetrap/LICENSE new file mode 100644 index 00000000..5f0d1fb6 --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/LICENSE @@ -0,0 +1,13 @@ +Copyright 2014 Alan Shreve + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/github.com/inconshreveable/mousetrap/README.md b/vendor/github.com/inconshreveable/mousetrap/README.md new file mode 100644 index 00000000..7a950d17 --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/README.md @@ -0,0 +1,23 @@ +# mousetrap + +mousetrap is a tiny library that answers a single question. + +On a Windows machine, was the process invoked by someone double clicking on +the executable file while browsing in explorer? + +### Motivation + +Windows developers unfamiliar with command line tools will often "double-click" +the executable for a tool. Because most CLI tools print the help and then exit +when invoked without arguments, this is often very frustrating for those users. + +mousetrap provides a way to detect these invocations so that you can provide +more helpful behavior and instructions on how to run the CLI tool. To see what +this looks like, both from an organizational and a technical perspective, see +https://inconshreveable.com/09-09-2014/sweat-the-small-stuff/ + +### The interface + +The library exposes a single interface: + + func StartedByExplorer() (bool) diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_others.go b/vendor/github.com/inconshreveable/mousetrap/trap_others.go new file mode 100644 index 00000000..9d2d8a4b --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/trap_others.go @@ -0,0 +1,15 @@ +// +build !windows + +package mousetrap + +// StartedByExplorer returns true if the program was invoked by the user +// double-clicking on the executable from explorer.exe +// +// It is conservative and returns false if any of the internal calls fail. +// It does not guarantee that the program was run from a terminal. It only can tell you +// whether it was launched from explorer.exe +// +// On non-Windows platforms, it always returns false. +func StartedByExplorer() bool { + return false +} diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_windows.go b/vendor/github.com/inconshreveable/mousetrap/trap_windows.go new file mode 100644 index 00000000..336142a5 --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/trap_windows.go @@ -0,0 +1,98 @@ +// +build windows +// +build !go1.4 + +package mousetrap + +import ( + "fmt" + "os" + "syscall" + "unsafe" +) + +const ( + // defined by the Win32 API + th32cs_snapprocess uintptr = 0x2 +) + +var ( + kernel = syscall.MustLoadDLL("kernel32.dll") + CreateToolhelp32Snapshot = kernel.MustFindProc("CreateToolhelp32Snapshot") + Process32First = kernel.MustFindProc("Process32FirstW") + Process32Next = kernel.MustFindProc("Process32NextW") +) + +// ProcessEntry32 structure defined by the Win32 API +type processEntry32 struct { + dwSize uint32 + cntUsage uint32 + th32ProcessID uint32 + th32DefaultHeapID int + th32ModuleID uint32 + cntThreads uint32 + th32ParentProcessID uint32 + pcPriClassBase int32 + dwFlags uint32 + szExeFile [syscall.MAX_PATH]uint16 +} + +func getProcessEntry(pid int) (pe *processEntry32, err error) { + snapshot, _, e1 := CreateToolhelp32Snapshot.Call(th32cs_snapprocess, uintptr(0)) + if snapshot == uintptr(syscall.InvalidHandle) { + err = fmt.Errorf("CreateToolhelp32Snapshot: %v", e1) + return + } + defer syscall.CloseHandle(syscall.Handle(snapshot)) + + var processEntry processEntry32 + processEntry.dwSize = uint32(unsafe.Sizeof(processEntry)) + ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) + if ok == 0 { + err = fmt.Errorf("Process32First: %v", e1) + return + } + + for { + if processEntry.th32ProcessID == uint32(pid) { + pe = &processEntry + return + } + + ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) + if ok == 0 { + err = fmt.Errorf("Process32Next: %v", e1) + return + } + } +} + +func getppid() (pid int, err error) { + pe, err := getProcessEntry(os.Getpid()) + if err != nil { + return + } + + pid = int(pe.th32ParentProcessID) + return +} + +// StartedByExplorer returns true if the program was invoked by the user double-clicking +// on the executable from explorer.exe +// +// It is conservative and returns false if any of the internal calls fail. +// It does not guarantee that the program was run from a terminal. It only can tell you +// whether it was launched from explorer.exe +func StartedByExplorer() bool { + ppid, err := getppid() + if err != nil { + return false + } + + pe, err := getProcessEntry(ppid) + if err != nil { + return false + } + + name := syscall.UTF16ToString(pe.szExeFile[:]) + return name == "explorer.exe" +} diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go b/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go new file mode 100644 index 00000000..9a28e57c --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go @@ -0,0 +1,46 @@ +// +build windows +// +build go1.4 + +package mousetrap + +import ( + "os" + "syscall" + "unsafe" +) + +func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) { + snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0) + if err != nil { + return nil, err + } + defer syscall.CloseHandle(snapshot) + var procEntry syscall.ProcessEntry32 + procEntry.Size = uint32(unsafe.Sizeof(procEntry)) + if err = syscall.Process32First(snapshot, &procEntry); err != nil { + return nil, err + } + for { + if procEntry.ProcessID == uint32(pid) { + return &procEntry, nil + } + err = syscall.Process32Next(snapshot, &procEntry) + if err != nil { + return nil, err + } + } +} + +// StartedByExplorer returns true if the program was invoked by the user double-clicking +// on the executable from explorer.exe +// +// It is conservative and returns false if any of the internal calls fail. +// It does not guarantee that the program was run from a terminal. It only can tell you +// whether it was launched from explorer.exe +func StartedByExplorer() bool { + pe, err := getProcessEntry(os.Getppid()) + if err != nil { + return false + } + return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:]) +} diff --git a/vendor/github.com/spf13/cobra/LICENSE.txt b/vendor/github.com/spf13/cobra/LICENSE.txt new file mode 100644 index 00000000..298f0e26 --- /dev/null +++ b/vendor/github.com/spf13/cobra/LICENSE.txt @@ -0,0 +1,174 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. diff --git a/vendor/github.com/spf13/cobra/README.md b/vendor/github.com/spf13/cobra/README.md new file mode 100644 index 00000000..b45f401e --- /dev/null +++ b/vendor/github.com/spf13/cobra/README.md @@ -0,0 +1,887 @@ +![cobra logo](https://cloud.githubusercontent.com/assets/173412/10886352/ad566232-814f-11e5-9cd0-aa101788c117.png) + +Cobra is both a library for creating powerful modern CLI applications as well as a program to generate applications and command files. + +Many of the most widely used Go projects are built using Cobra including: + +* [Kubernetes](http://kubernetes.io/) +* [Hugo](http://gohugo.io) +* [rkt](https://github.com/coreos/rkt) +* [etcd](https://github.com/coreos/etcd) +* [Moby (former Docker)](https://github.com/moby/moby) +* [Docker (distribution)](https://github.com/docker/distribution) +* [OpenShift](https://www.openshift.com/) +* [Delve](https://github.com/derekparker/delve) +* [GopherJS](http://www.gopherjs.org/) +* [CockroachDB](http://www.cockroachlabs.com/) +* [Bleve](http://www.blevesearch.com/) +* [ProjectAtomic (enterprise)](http://www.projectatomic.io/) +* [GiantSwarm's swarm](https://github.com/giantswarm/cli) +* [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack) +* [rclone](http://rclone.org/) + + +[![Build Status](https://travis-ci.org/spf13/cobra.svg "Travis CI status")](https://travis-ci.org/spf13/cobra) +[![CircleCI status](https://circleci.com/gh/spf13/cobra.png?circle-token=:circle-token "CircleCI status")](https://circleci.com/gh/spf13/cobra) +[![GoDoc](https://godoc.org/github.com/spf13/cobra?status.svg)](https://godoc.org/github.com/spf13/cobra) + +![cobra](https://cloud.githubusercontent.com/assets/173412/10911369/84832a8e-8212-11e5-9f82-cc96660a4794.gif) + +# Overview + +Cobra is a library providing a simple interface to create powerful modern CLI +interfaces similar to git & go tools. + +Cobra is also an application that will generate your application scaffolding to rapidly +develop a Cobra-based application. + +Cobra provides: +* Easy subcommand-based CLIs: `app server`, `app fetch`, etc. +* Fully POSIX-compliant flags (including short & long versions) +* Nested subcommands +* Global, local and cascading flags +* Easy generation of applications & commands with `cobra init appname` & `cobra add cmdname` +* Intelligent suggestions (`app srver`... did you mean `app server`?) +* Automatic help generation for commands and flags +* Automatic detailed help for `app help [command]` +* Automatic help flag recognition of `-h`, `--help`, etc. +* Automatically generated bash autocomplete for your application +* Automatically generated man pages for your application +* Command aliases so you can change things without breaking them +* The flexibility to define your own help, usage, etc. +* Optional tight integration with [viper](http://github.com/spf13/viper) for 12-factor apps + +Cobra has an exceptionally clean interface and simple design without needless +constructors or initialization methods. + +Applications built with Cobra commands are designed to be as user-friendly as +possible. Flags can be placed before or after the command (as long as a +confusing space isn’t provided). Both short and long flags can be used. A +command need not even be fully typed. Help is automatically generated and +available for the application or for a specific command using either the help +command or the `--help` flag. + +# Concepts + +Cobra is built on a structure of commands, arguments & flags. + +**Commands** represent actions, **Args** are things and **Flags** are modifiers for those actions. + +The best applications will read like sentences when used. Users will know how +to use the application because they will natively understand how to use it. + +The pattern to follow is +`APPNAME VERB NOUN --ADJECTIVE.` + or +`APPNAME COMMAND ARG --FLAG` + +A few good real world examples may better illustrate this point. + +In the following example, 'server' is a command, and 'port' is a flag: + + hugo server --port=1313 + +In this command we are telling Git to clone the url bare. + + git clone URL --bare + +## Commands + +Command is the central point of the application. Each interaction that +the application supports will be contained in a Command. A command can +have children commands and optionally run an action. + +In the example above, 'server' is the command. + +A Command has the following structure: + +```go +type Command struct { + Use string // The one-line usage message. + Short string // The short description shown in the 'help' output. + Long string // The long message shown in the 'help ' output. + Run func(cmd *Command, args []string) // Run runs the command. +} +``` + +## Flags + +A Flag is a way to modify the behavior of a command. Cobra supports +fully POSIX-compliant flags as well as the Go [flag package](https://golang.org/pkg/flag/). +A Cobra command can define flags that persist through to children commands +and flags that are only available to that command. + +In the example above, 'port' is the flag. + +Flag functionality is provided by the [pflag +library](https://github.com/ogier/pflag), a fork of the flag standard library +which maintains the same interface while adding POSIX compliance. + +## Usage + +Cobra works by creating a set of commands and then organizing them into a tree. +The tree defines the structure of the application. + +Once each command is defined with its corresponding flags, then the +tree is assigned to the commander which is finally executed. + +# Installing +Using Cobra is easy. First, use `go get` to install the latest version +of the library. This command will install the `cobra` generator executible +along with the library: + + go get -v github.com/spf13/cobra/cobra + +Next, include Cobra in your application: + +```go +import "github.com/spf13/cobra" +``` + +# Getting Started + +While you are welcome to provide your own organization, typically a Cobra based +application will follow the following organizational structure. + +``` + â–¾ appName/ + â–¾ cmd/ + add.go + your.go + commands.go + here.go + main.go +``` + +In a Cobra app, typically the main.go file is very bare. It serves, one purpose, to initialize Cobra. + +```go +package main + +import ( + "fmt" + "os" + + "{pathToYourApp}/cmd" +) + +func main() { + if err := cmd.RootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} +``` + +## Using the Cobra Generator + +Cobra provides its own program that will create your application and add any +commands you want. It's the easiest way to incorporate Cobra into your application. + +In order to use the cobra command, compile it using the following command: + + go get github.com/spf13/cobra/cobra + +This will create the cobra executable under your `$GOPATH/bin` directory. + +### cobra init + +The `cobra init [yourApp]` command will create your initial application code +for you. It is a very powerful application that will populate your program with +the right structure so you can immediately enjoy all the benefits of Cobra. It +will also automatically apply the license you specify to your application. + +Cobra init is pretty smart. You can provide it a full path, or simply a path +similar to what is expected in the import. + +``` +cobra init github.com/spf13/newAppName +``` + +### cobra add + +Once an application is initialized Cobra can create additional commands for you. +Let's say you created an app and you wanted the following commands for it: + +* app serve +* app config +* app config create + +In your project directory (where your main.go file is) you would run the following: + +``` +cobra add serve +cobra add config +cobra add create -p 'configCmd' +``` + +*Note: Use camelCase (not snake_case/snake-case) for command names. +Otherwise, you will become unexpected errors. +For example, `cobra add add-user` is incorrect, but `cobra add addUser` is valid.* + +Once you have run these three commands you would have an app structure that would look like: + +``` + â–¾ app/ + â–¾ cmd/ + serve.go + config.go + create.go + main.go +``` + +at this point you can run `go run main.go` and it would run your app. `go run +main.go serve`, `go run main.go config`, `go run main.go config create` along +with `go run main.go help serve`, etc would all work. + +Obviously you haven't added your own code to these yet, the commands are ready +for you to give them their tasks. Have fun. + +### Configuring the cobra generator + +The cobra generator will be easier to use if you provide a simple configuration +file which will help you eliminate providing a bunch of repeated information in +flags over and over. + +An example ~/.cobra.yaml file: + +```yaml +author: Steve Francia +license: MIT +``` + +You can specify no license by setting `license` to `none` or you can specify +a custom license: + +```yaml +license: + header: This file is part of {{ .appName }}. + text: | + {{ .copyright }} + + This is my license. There are many like it, but this one is mine. + My license is my best friend. It is my life. I must master it as I must + master my life. +``` + +You can also use built-in licenses. For example, **GPLv2**, **GPLv3**, **LGPL**, +**AGPL**, **MIT**, **2-Clause BSD** or **3-Clause BSD**. + +## Manually implementing Cobra + +To manually implement cobra you need to create a bare main.go file and a RootCmd file. +You will optionally provide additional commands as you see fit. + +### Create the root command + +The root command represents your binary itself. + + +#### Manually create rootCmd + +Cobra doesn't require any special constructors. Simply create your commands. + +Ideally you place this in app/cmd/root.go: + +```go +var RootCmd = &cobra.Command{ + Use: "hugo", + Short: "Hugo is a very fast static site generator", + Long: `A Fast and Flexible Static Site Generator built with + love by spf13 and friends in Go. + Complete documentation is available at http://hugo.spf13.com`, + Run: func(cmd *cobra.Command, args []string) { + // Do Stuff Here + }, +} +``` + +You will additionally define flags and handle configuration in your init() function. + +for example cmd/root.go: + +```go +func init() { + cobra.OnInitialize(initConfig) + RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") + RootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory eg. github.com/spf13/") + RootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution") + RootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `licensetext` in config)") + RootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration") + viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author")) + viper.BindPFlag("projectbase", RootCmd.PersistentFlags().Lookup("projectbase")) + viper.BindPFlag("useViper", RootCmd.PersistentFlags().Lookup("viper")) + viper.SetDefault("author", "NAME HERE ") + viper.SetDefault("license", "apache") +} +``` + +### Create your main.go + +With the root command you need to have your main function execute it. +Execute should be run on the root for clarity, though it can be called on any command. + +In a Cobra app, typically the main.go file is very bare. It serves, one purpose, to initialize Cobra. + +```go +package main + +import ( + "fmt" + "os" + + "{pathToYourApp}/cmd" +) + +func main() { + if err := cmd.RootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} +``` + + +### Create additional commands + +Additional commands can be defined and typically are each given their own file +inside of the cmd/ directory. + +If you wanted to create a version command you would create cmd/version.go and +populate it with the following: + +```go +package cmd + +import ( + "github.com/spf13/cobra" + "fmt" +) + +func init() { + RootCmd.AddCommand(versionCmd) +} + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Print the version number of Hugo", + Long: `All software has versions. This is Hugo's`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Hugo Static Site Generator v0.9 -- HEAD") + }, +} +``` + +### Attach command to its parent + + +If you notice in the above example we attach the command to its parent. In +this case the parent is the rootCmd. In this example we are attaching it to the +root, but commands can be attached at any level. + +```go +RootCmd.AddCommand(versionCmd) +``` + +### Remove a command from its parent + +Removing a command is not a common action in simple programs, but it allows 3rd +parties to customize an existing command tree. + +In this example, we remove the existing `VersionCmd` command of an existing +root command, and we replace it with our own version: + +```go +mainlib.RootCmd.RemoveCommand(mainlib.VersionCmd) +mainlib.RootCmd.AddCommand(versionCmd) +``` + +## Working with Flags + +Flags provide modifiers to control how the action command operates. + +### Assign flags to a command + +Since the flags are defined and used in different locations, we need to +define a variable outside with the correct scope to assign the flag to +work with. + +```go +var Verbose bool +var Source string +``` + +There are two different approaches to assign a flag. + +### Persistent Flags + +A flag can be 'persistent' meaning that this flag will be available to the +command it's assigned to as well as every command under that command. For +global flags, assign a flag as a persistent flag on the root. + +```go +RootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") +``` + +### Local Flags + +A flag can also be assigned locally which will only apply to that specific command. + +```go +RootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") +``` + + +## Example + +In the example below, we have defined three commands. Two are at the top level +and one (cmdTimes) is a child of one of the top commands. In this case the root +is not executable meaning that a subcommand is required. This is accomplished +by not providing a 'Run' for the 'rootCmd'. + +We have only defined one flag for a single command. + +More documentation about flags is available at https://github.com/spf13/pflag + +```go +package main + +import ( + "fmt" + "strings" + + "github.com/spf13/cobra" +) + +func main() { + + var echoTimes int + + var cmdPrint = &cobra.Command{ + Use: "print [string to print]", + Short: "Print anything to the screen", + Long: `print is for printing anything back to the screen. + For many years people have printed back to the screen. + `, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Print: " + strings.Join(args, " ")) + }, + } + + var cmdEcho = &cobra.Command{ + Use: "echo [string to echo]", + Short: "Echo anything to the screen", + Long: `echo is for echoing anything back. + Echo works a lot like print, except it has a child command. + `, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Print: " + strings.Join(args, " ")) + }, + } + + var cmdTimes = &cobra.Command{ + Use: "times [# times] [string to echo]", + Short: "Echo anything to the screen more times", + Long: `echo things multiple times back to the user by providing + a count and a string.`, + Run: func(cmd *cobra.Command, args []string) { + for i := 0; i < echoTimes; i++ { + fmt.Println("Echo: " + strings.Join(args, " ")) + } + }, + } + + cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input") + + var rootCmd = &cobra.Command{Use: "app"} + rootCmd.AddCommand(cmdPrint, cmdEcho) + cmdEcho.AddCommand(cmdTimes) + rootCmd.Execute() +} +``` + +For a more complete example of a larger application, please checkout [Hugo](http://gohugo.io/). + +## The Help Command + +Cobra automatically adds a help command to your application when you have subcommands. +This will be called when a user runs 'app help'. Additionally, help will also +support all other commands as input. Say, for instance, you have a command called +'create' without any additional configuration; Cobra will work when 'app help +create' is called. Every command will automatically have the '--help' flag added. + +### Example + +The following output is automatically generated by Cobra. Nothing beyond the +command and flag definitions are needed. + + > hugo help + + hugo is the main command, used to build your Hugo site. + + Hugo is a Fast and Flexible Static Site Generator + built with love by spf13 and friends in Go. + + Complete documentation is available at http://gohugo.io/. + + Usage: + hugo [flags] + hugo [command] + + Available Commands: + server Hugo runs its own webserver to render the files + version Print the version number of Hugo + config Print the site configuration + check Check content in the source directory + benchmark Benchmark hugo by building a site a number of times. + convert Convert your content to different formats + new Create new content for your site + list Listing out various types of content + undraft Undraft changes the content's draft status from 'True' to 'False' + genautocomplete Generate shell autocompletion script for Hugo + gendoc Generate Markdown documentation for the Hugo CLI. + genman Generate man page for Hugo + import Import your site from others. + + Flags: + -b, --baseURL="": hostname (and path) to the root, e.g. http://spf13.com/ + -D, --buildDrafts[=false]: include content marked as draft + -F, --buildFuture[=false]: include content with publishdate in the future + --cacheDir="": filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/ + --canonifyURLs[=false]: if true, all relative URLs will be canonicalized using baseURL + --config="": config file (default is path/config.yaml|json|toml) + -d, --destination="": filesystem path to write files to + --disableRSS[=false]: Do not build RSS files + --disableSitemap[=false]: Do not build Sitemap file + --editor="": edit new content with this editor, if provided + --ignoreCache[=false]: Ignores the cache directory for reading but still writes to it + --log[=false]: Enable Logging + --logFile="": Log File path (if set, logging enabled automatically) + --noTimes[=false]: Don't sync modification time of files + --pluralizeListTitles[=true]: Pluralize titles in lists using inflect + --preserveTaxonomyNames[=false]: Preserve taxonomy names as written ("Gérard Depardieu" vs "gerard-depardieu") + -s, --source="": filesystem path to read files relative from + --stepAnalysis[=false]: display memory and timing of different steps of the program + -t, --theme="": theme to use (located in /themes/THEMENAME/) + --uglyURLs[=false]: if true, use /filename.html instead of /filename/ + -v, --verbose[=false]: verbose output + --verboseLog[=false]: verbose logging + -w, --watch[=false]: watch filesystem for changes and recreate as needed + + Use "hugo [command] --help" for more information about a command. + + +Help is just a command like any other. There is no special logic or behavior +around it. In fact, you can provide your own if you want. + +### Defining your own help + +You can provide your own Help command or your own template for the default command to use. + +The default help command is + +```go +func (c *Command) initHelp() { + if c.helpCommand == nil { + c.helpCommand = &Command{ + Use: "help [command]", + Short: "Help about any command", + Long: `Help provides help for any command in the application. + Simply type ` + c.Name() + ` help [path to command] for full details.`, + Run: c.HelpFunc(), + } + } + c.AddCommand(c.helpCommand) +} +``` + +You can provide your own command, function or template through the following methods: + +```go +command.SetHelpCommand(cmd *Command) + +command.SetHelpFunc(f func(*Command, []string)) + +command.SetHelpTemplate(s string) +``` + +The latter two will also apply to any children commands. + +## Usage + +When the user provides an invalid flag or invalid command, Cobra responds by +showing the user the 'usage'. + +### Example +You may recognize this from the help above. That's because the default help +embeds the usage as part of its output. + + Usage: + hugo [flags] + hugo [command] + + Available Commands: + server Hugo runs its own webserver to render the files + version Print the version number of Hugo + config Print the site configuration + check Check content in the source directory + benchmark Benchmark hugo by building a site a number of times. + convert Convert your content to different formats + new Create new content for your site + list Listing out various types of content + undraft Undraft changes the content's draft status from 'True' to 'False' + genautocomplete Generate shell autocompletion script for Hugo + gendoc Generate Markdown documentation for the Hugo CLI. + genman Generate man page for Hugo + import Import your site from others. + + Flags: + -b, --baseURL="": hostname (and path) to the root, e.g. http://spf13.com/ + -D, --buildDrafts[=false]: include content marked as draft + -F, --buildFuture[=false]: include content with publishdate in the future + --cacheDir="": filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/ + --canonifyURLs[=false]: if true, all relative URLs will be canonicalized using baseURL + --config="": config file (default is path/config.yaml|json|toml) + -d, --destination="": filesystem path to write files to + --disableRSS[=false]: Do not build RSS files + --disableSitemap[=false]: Do not build Sitemap file + --editor="": edit new content with this editor, if provided + --ignoreCache[=false]: Ignores the cache directory for reading but still writes to it + --log[=false]: Enable Logging + --logFile="": Log File path (if set, logging enabled automatically) + --noTimes[=false]: Don't sync modification time of files + --pluralizeListTitles[=true]: Pluralize titles in lists using inflect + --preserveTaxonomyNames[=false]: Preserve taxonomy names as written ("Gérard Depardieu" vs "gerard-depardieu") + -s, --source="": filesystem path to read files relative from + --stepAnalysis[=false]: display memory and timing of different steps of the program + -t, --theme="": theme to use (located in /themes/THEMENAME/) + --uglyURLs[=false]: if true, use /filename.html instead of /filename/ + -v, --verbose[=false]: verbose output + --verboseLog[=false]: verbose logging + -w, --watch[=false]: watch filesystem for changes and recreate as needed + +### Defining your own usage +You can provide your own usage function or template for Cobra to use. + +The default usage function is: + +```go +return func(c *Command) error { + err := tmpl(c.Out(), c.UsageTemplate(), c) + return err +} +``` + +Like help, the function and template are overridable through public methods: + +```go +command.SetUsageFunc(f func(*Command) error) + +command.SetUsageTemplate(s string) +``` + +## PreRun or PostRun Hooks + +It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order: + +- `PersistentPreRun` +- `PreRun` +- `Run` +- `PostRun` +- `PersistentPostRun` + +An example of two commands which use all of these features is below. When the subcommand is executed, it will run the root command's `PersistentPreRun` but not the root command's `PersistentPostRun`: + +```go +package main + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +func main() { + + var rootCmd = &cobra.Command{ + Use: "root [sub]", + Short: "My root command", + PersistentPreRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args) + }, + PreRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd PreRun with args: %v\n", args) + }, + Run: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd Run with args: %v\n", args) + }, + PostRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd PostRun with args: %v\n", args) + }, + PersistentPostRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args) + }, + } + + var subCmd = &cobra.Command{ + Use: "sub [no options!]", + Short: "My subcommand", + PreRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside subCmd PreRun with args: %v\n", args) + }, + Run: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside subCmd Run with args: %v\n", args) + }, + PostRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside subCmd PostRun with args: %v\n", args) + }, + PersistentPostRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args) + }, + } + + rootCmd.AddCommand(subCmd) + + rootCmd.SetArgs([]string{""}) + _ = rootCmd.Execute() + fmt.Print("\n") + rootCmd.SetArgs([]string{"sub", "arg1", "arg2"}) + _ = rootCmd.Execute() +} +``` + + +## Alternative Error Handling + +Cobra also has functions where the return signature is an error. This allows for errors to bubble up to the top, +providing a way to handle the errors in one location. The current list of functions that return an error is: + +* PersistentPreRunE +* PreRunE +* RunE +* PostRunE +* PersistentPostRunE + +If you would like to silence the default `error` and `usage` output in favor of your own, you can set `SilenceUsage` +and `SilenceErrors` to `true` on the command. A child command respects these flags if they are set on the parent +command. + +**Example Usage using RunE:** + +```go +package main + +import ( + "errors" + "log" + + "github.com/spf13/cobra" +) + +func main() { + var rootCmd = &cobra.Command{ + Use: "hugo", + Short: "Hugo is a very fast static site generator", + Long: `A Fast and Flexible Static Site Generator built with + love by spf13 and friends in Go. + Complete documentation is available at http://hugo.spf13.com`, + RunE: func(cmd *cobra.Command, args []string) error { + // Do Stuff Here + return errors.New("some random error") + }, + } + + if err := rootCmd.Execute(); err != nil { + log.Fatal(err) + } +} +``` + +## Suggestions when "unknown command" happens + +Cobra will print automatic suggestions when "unknown command" errors happen. This allows Cobra to behave similarly to the `git` command when a typo happens. For example: + +``` +$ hugo srever +Error: unknown command "srever" for "hugo" + +Did you mean this? + server + +Run 'hugo --help' for usage. +``` + +Suggestions are automatic based on every subcommand registered and use an implementation of [Levenshtein distance](http://en.wikipedia.org/wiki/Levenshtein_distance). Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion. + +If you need to disable suggestions or tweak the string distance in your command, use: + +```go +command.DisableSuggestions = true +``` + +or + +```go +command.SuggestionsMinimumDistance = 1 +``` + +You can also explicitly set names for which a given command will be suggested using the `SuggestFor` attribute. This allows suggestions for strings that are not close in terms of string distance, but makes sense in your set of commands and for some which you don't want aliases. Example: + +``` +$ kubectl remove +Error: unknown command "remove" for "kubectl" + +Did you mean this? + delete + +Run 'kubectl help' for usage. +``` + +## Generating Markdown-formatted documentation for your command + +Cobra can generate a Markdown-formatted document based on the subcommands, flags, etc. A simple example of how to do this for your command can be found in [Markdown Docs](doc/md_docs.md). + +## Generating man pages for your command + +Cobra can generate a man page based on the subcommands, flags, etc. A simple example of how to do this for your command can be found in [Man Docs](doc/man_docs.md). + +## Generating bash completions for your command + +Cobra can generate a bash-completion file. If you add more information to your command, these completions can be amazingly powerful and flexible. Read more about it in [Bash Completions](bash_completions.md). + +## Debugging + +Cobra provides a ‘DebugFlags’ method on a command which, when called, will print +out everything Cobra knows about the flags for each command. + +### Example + +```go +command.DebugFlags() +``` + +## Extensions + +Libraries for extending Cobra: + +* [cmdns](https://github.com/gosuri/cmdns): Enables name spacing a command's immediate children. It provides an alternative way to structure subcommands, similar to `heroku apps:create` and `ovrclk clusters:launch`. + +## Contributing + +1. Fork it +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Commit your changes (`git commit -am 'Add some feature'`) +4. Push to the branch (`git push origin my-new-feature`) +5. Create new Pull Request + +## Contributors + +Names in no particular order: + +* [spf13](https://github.com/spf13), +[eparis](https://github.com/eparis), +[bep](https://github.com/bep), and many more! + +## License + +Cobra is released under the Apache 2.0 license. See [LICENSE.txt](https://github.com/spf13/cobra/blob/master/LICENSE.txt) diff --git a/vendor/github.com/spf13/cobra/bash_completions.go b/vendor/github.com/spf13/cobra/bash_completions.go new file mode 100644 index 00000000..a0d04027 --- /dev/null +++ b/vendor/github.com/spf13/cobra/bash_completions.go @@ -0,0 +1,645 @@ +package cobra + +import ( + "fmt" + "io" + "os" + "sort" + "strings" + + "github.com/spf13/pflag" +) + +// Annotations for Bash completion. +const ( + BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extensions" + BashCompCustom = "cobra_annotation_bash_completion_custom" + BashCompOneRequiredFlag = "cobra_annotation_bash_completion_one_required_flag" + BashCompSubdirsInDir = "cobra_annotation_bash_completion_subdirs_in_dir" +) + +func preamble(out io.Writer, name string) error { + _, err := fmt.Fprintf(out, "# bash completion for %-36s -*- shell-script -*-\n", name) + if err != nil { + return err + } + preamStr := ` +__debug() +{ + if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then + echo "$*" >> "${BASH_COMP_DEBUG_FILE}" + fi +} + +# Homebrew on Macs have version 1.3 of bash-completion which doesn't include +# _init_completion. This is a very minimal version of that function. +__my_init_completion() +{ + COMPREPLY=() + _get_comp_words_by_ref "$@" cur prev words cword +} + +__index_of_word() +{ + local w word=$1 + shift + index=0 + for w in "$@"; do + [[ $w = "$word" ]] && return + index=$((index+1)) + done + index=-1 +} + +__contains_word() +{ + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done + return 1 +} + +__handle_reply() +{ + __debug "${FUNCNAME[0]}" + case $cur in + -*) + if [[ $(type -t compopt) = "builtin" ]]; then + compopt -o nospace + fi + local allflags + if [ ${#must_have_one_flag[@]} -ne 0 ]; then + allflags=("${must_have_one_flag[@]}") + else + allflags=("${flags[*]} ${two_word_flags[*]}") + fi + COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") ) + if [[ $(type -t compopt) = "builtin" ]]; then + [[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace + fi + + # complete after --flag=abc + if [[ $cur == *=* ]]; then + if [[ $(type -t compopt) = "builtin" ]]; then + compopt +o nospace + fi + + local index flag + flag="${cur%%=*}" + __index_of_word "${flag}" "${flags_with_completion[@]}" + COMPREPLY=() + if [[ ${index} -ge 0 ]]; then + PREFIX="" + cur="${cur#*=}" + ${flags_completion[${index}]} + if [ -n "${ZSH_VERSION}" ]; then + # zfs completion needs --flag= prefix + eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )" + fi + fi + fi + return 0; + ;; + esac + + # check if we are handling a flag with special work handling + local index + __index_of_word "${prev}" "${flags_with_completion[@]}" + if [[ ${index} -ge 0 ]]; then + ${flags_completion[${index}]} + return + fi + + # we are parsing a flag and don't have a special handler, no completion + if [[ ${cur} != "${words[cword]}" ]]; then + return + fi + + local completions + completions=("${commands[@]}") + if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then + completions=("${must_have_one_noun[@]}") + fi + if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then + completions+=("${must_have_one_flag[@]}") + fi + COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") ) + + if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then + COMPREPLY=( $(compgen -W "${noun_aliases[*]}" -- "$cur") ) + fi + + if [[ ${#COMPREPLY[@]} -eq 0 ]]; then + declare -F __custom_func >/dev/null && __custom_func + fi + + __ltrim_colon_completions "$cur" +} + +# The arguments should be in the form "ext1|ext2|extn" +__handle_filename_extension_flag() +{ + local ext="$1" + _filedir "@(${ext})" +} + +__handle_subdirs_in_dir_flag() +{ + local dir="$1" + pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 +} + +__handle_flag() +{ + __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + + # if a command required a flag, and we found it, unset must_have_one_flag() + local flagname=${words[c]} + local flagvalue + # if the word contained an = + if [[ ${words[c]} == *"="* ]]; then + flagvalue=${flagname#*=} # take in as flagvalue after the = + flagname=${flagname%%=*} # strip everything after the = + flagname="${flagname}=" # but put the = back + fi + __debug "${FUNCNAME[0]}: looking for ${flagname}" + if __contains_word "${flagname}" "${must_have_one_flag[@]}"; then + must_have_one_flag=() + fi + + # if you set a flag which only applies to this command, don't show subcommands + if __contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then + commands=() + fi + + # keep flag value with flagname as flaghash + if [ -n "${flagvalue}" ] ; then + flaghash[${flagname}]=${flagvalue} + elif [ -n "${words[ $((c+1)) ]}" ] ; then + flaghash[${flagname}]=${words[ $((c+1)) ]} + else + flaghash[${flagname}]="true" # pad "true" for bool flag + fi + + # skip the argument to a two word flag + if __contains_word "${words[c]}" "${two_word_flags[@]}"; then + c=$((c+1)) + # if we are looking for a flags value, don't show commands + if [[ $c -eq $cword ]]; then + commands=() + fi + fi + + c=$((c+1)) + +} + +__handle_noun() +{ + __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + + if __contains_word "${words[c]}" "${must_have_one_noun[@]}"; then + must_have_one_noun=() + elif __contains_word "${words[c]}" "${noun_aliases[@]}"; then + must_have_one_noun=() + fi + + nouns+=("${words[c]}") + c=$((c+1)) +} + +__handle_command() +{ + __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + + local next_command + if [[ -n ${last_command} ]]; then + next_command="_${last_command}_${words[c]//:/__}" + else + if [[ $c -eq 0 ]]; then + next_command="_$(basename "${words[c]//:/__}")" + else + next_command="_${words[c]//:/__}" + fi + fi + c=$((c+1)) + __debug "${FUNCNAME[0]}: looking for ${next_command}" + declare -F "$next_command" >/dev/null && $next_command +} + +__handle_word() +{ + if [[ $c -ge $cword ]]; then + __handle_reply + return + fi + __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + if [[ "${words[c]}" == -* ]]; then + __handle_flag + elif __contains_word "${words[c]}" "${commands[@]}"; then + __handle_command + elif [[ $c -eq 0 ]] && __contains_word "$(basename "${words[c]}")" "${commands[@]}"; then + __handle_command + else + __handle_noun + fi + __handle_word +} + +` + _, err = fmt.Fprint(out, preamStr) + return err +} + +func postscript(w io.Writer, name string) error { + name = strings.Replace(name, ":", "__", -1) + _, err := fmt.Fprintf(w, "__start_%s()\n", name) + if err != nil { + return err + } + _, err = fmt.Fprintf(w, `{ + local cur prev words cword + declare -A flaghash 2>/dev/null || : + if declare -F _init_completion >/dev/null 2>&1; then + _init_completion -s || return + else + __my_init_completion -n "=" || return + fi + + local c=0 + local flags=() + local two_word_flags=() + local local_nonpersistent_flags=() + local flags_with_completion=() + local flags_completion=() + local commands=("%s") + local must_have_one_flag=() + local must_have_one_noun=() + local last_command + local nouns=() + + __handle_word +} + +`, name) + if err != nil { + return err + } + _, err = fmt.Fprintf(w, `if [[ $(type -t compopt) = "builtin" ]]; then + complete -o default -F __start_%s %s +else + complete -o default -o nospace -F __start_%s %s +fi + +`, name, name, name, name) + if err != nil { + return err + } + _, err = fmt.Fprintf(w, "# ex: ts=4 sw=4 et filetype=sh\n") + return err +} + +func writeCommands(cmd *Command, w io.Writer) error { + if _, err := fmt.Fprintf(w, " commands=()\n"); err != nil { + return err + } + for _, c := range cmd.Commands() { + if !c.IsAvailableCommand() || c == cmd.helpCommand { + continue + } + if _, err := fmt.Fprintf(w, " commands+=(%q)\n", c.Name()); err != nil { + return err + } + } + _, err := fmt.Fprintf(w, "\n") + return err +} + +func writeFlagHandler(name string, annotations map[string][]string, w io.Writer) error { + for key, value := range annotations { + switch key { + case BashCompFilenameExt: + _, err := fmt.Fprintf(w, " flags_with_completion+=(%q)\n", name) + if err != nil { + return err + } + + if len(value) > 0 { + ext := "__handle_filename_extension_flag " + strings.Join(value, "|") + _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext) + } else { + ext := "_filedir" + _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext) + } + if err != nil { + return err + } + case BashCompCustom: + _, err := fmt.Fprintf(w, " flags_with_completion+=(%q)\n", name) + if err != nil { + return err + } + if len(value) > 0 { + handlers := strings.Join(value, "; ") + _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", handlers) + } else { + _, err = fmt.Fprintf(w, " flags_completion+=(:)\n") + } + if err != nil { + return err + } + case BashCompSubdirsInDir: + _, err := fmt.Fprintf(w, " flags_with_completion+=(%q)\n", name) + + if len(value) == 1 { + ext := "__handle_subdirs_in_dir_flag " + value[0] + _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext) + } else { + ext := "_filedir -d" + _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext) + } + if err != nil { + return err + } + } + } + return nil +} + +func writeShortFlag(flag *pflag.Flag, w io.Writer) error { + b := (len(flag.NoOptDefVal) > 0) + name := flag.Shorthand + format := " " + if !b { + format += "two_word_" + } + format += "flags+=(\"-%s\")\n" + if _, err := fmt.Fprintf(w, format, name); err != nil { + return err + } + return writeFlagHandler("-"+name, flag.Annotations, w) +} + +func writeFlag(flag *pflag.Flag, w io.Writer) error { + b := (len(flag.NoOptDefVal) > 0) + name := flag.Name + format := " flags+=(\"--%s" + if !b { + format += "=" + } + format += "\")\n" + if _, err := fmt.Fprintf(w, format, name); err != nil { + return err + } + return writeFlagHandler("--"+name, flag.Annotations, w) +} + +func writeLocalNonPersistentFlag(flag *pflag.Flag, w io.Writer) error { + b := (len(flag.NoOptDefVal) > 0) + name := flag.Name + format := " local_nonpersistent_flags+=(\"--%s" + if !b { + format += "=" + } + format += "\")\n" + _, err := fmt.Fprintf(w, format, name) + return err +} + +func writeFlags(cmd *Command, w io.Writer) error { + _, err := fmt.Fprintf(w, ` flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + +`) + if err != nil { + return err + } + localNonPersistentFlags := cmd.LocalNonPersistentFlags() + var visitErr error + cmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) { + if nonCompletableFlag(flag) { + return + } + if err := writeFlag(flag, w); err != nil { + visitErr = err + return + } + if len(flag.Shorthand) > 0 { + if err := writeShortFlag(flag, w); err != nil { + visitErr = err + return + } + } + if localNonPersistentFlags.Lookup(flag.Name) != nil { + if err := writeLocalNonPersistentFlag(flag, w); err != nil { + visitErr = err + return + } + } + }) + if visitErr != nil { + return visitErr + } + cmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) { + if nonCompletableFlag(flag) { + return + } + if err := writeFlag(flag, w); err != nil { + visitErr = err + return + } + if len(flag.Shorthand) > 0 { + if err := writeShortFlag(flag, w); err != nil { + visitErr = err + return + } + } + }) + if visitErr != nil { + return visitErr + } + + _, err = fmt.Fprintf(w, "\n") + return err +} + +func writeRequiredFlag(cmd *Command, w io.Writer) error { + if _, err := fmt.Fprintf(w, " must_have_one_flag=()\n"); err != nil { + return err + } + flags := cmd.NonInheritedFlags() + var visitErr error + flags.VisitAll(func(flag *pflag.Flag) { + if nonCompletableFlag(flag) { + return + } + for key := range flag.Annotations { + switch key { + case BashCompOneRequiredFlag: + format := " must_have_one_flag+=(\"--%s" + b := (flag.Value.Type() == "bool") + if !b { + format += "=" + } + format += "\")\n" + if _, err := fmt.Fprintf(w, format, flag.Name); err != nil { + visitErr = err + return + } + + if len(flag.Shorthand) > 0 { + if _, err := fmt.Fprintf(w, " must_have_one_flag+=(\"-%s\")\n", flag.Shorthand); err != nil { + visitErr = err + return + } + } + } + } + }) + return visitErr +} + +func writeRequiredNouns(cmd *Command, w io.Writer) error { + if _, err := fmt.Fprintf(w, " must_have_one_noun=()\n"); err != nil { + return err + } + sort.Sort(sort.StringSlice(cmd.ValidArgs)) + for _, value := range cmd.ValidArgs { + if _, err := fmt.Fprintf(w, " must_have_one_noun+=(%q)\n", value); err != nil { + return err + } + } + return nil +} + +func writeArgAliases(cmd *Command, w io.Writer) error { + if _, err := fmt.Fprintf(w, " noun_aliases=()\n"); err != nil { + return err + } + sort.Sort(sort.StringSlice(cmd.ArgAliases)) + for _, value := range cmd.ArgAliases { + if _, err := fmt.Fprintf(w, " noun_aliases+=(%q)\n", value); err != nil { + return err + } + } + return nil +} + +func gen(cmd *Command, w io.Writer) error { + for _, c := range cmd.Commands() { + if !c.IsAvailableCommand() || c == cmd.helpCommand { + continue + } + if err := gen(c, w); err != nil { + return err + } + } + commandName := cmd.CommandPath() + commandName = strings.Replace(commandName, " ", "_", -1) + commandName = strings.Replace(commandName, ":", "__", -1) + if _, err := fmt.Fprintf(w, "_%s()\n{\n", commandName); err != nil { + return err + } + if _, err := fmt.Fprintf(w, " last_command=%q\n", commandName); err != nil { + return err + } + if err := writeCommands(cmd, w); err != nil { + return err + } + if err := writeFlags(cmd, w); err != nil { + return err + } + if err := writeRequiredFlag(cmd, w); err != nil { + return err + } + if err := writeRequiredNouns(cmd, w); err != nil { + return err + } + if err := writeArgAliases(cmd, w); err != nil { + return err + } + if _, err := fmt.Fprintf(w, "}\n\n"); err != nil { + return err + } + return nil +} + +// GenBashCompletion generates bash completion file and writes to the passed writer. +func (cmd *Command) GenBashCompletion(w io.Writer) error { + if err := preamble(w, cmd.Name()); err != nil { + return err + } + if len(cmd.BashCompletionFunction) > 0 { + if _, err := fmt.Fprintf(w, "%s\n", cmd.BashCompletionFunction); err != nil { + return err + } + } + if err := gen(cmd, w); err != nil { + return err + } + return postscript(w, cmd.Name()) +} + +func nonCompletableFlag(flag *pflag.Flag) bool { + return flag.Hidden || len(flag.Deprecated) > 0 +} + +// GenBashCompletionFile generates bash completion file. +func (cmd *Command) GenBashCompletionFile(filename string) error { + outFile, err := os.Create(filename) + if err != nil { + return err + } + defer outFile.Close() + + return cmd.GenBashCompletion(outFile) +} + +// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag, if it exists. +func (cmd *Command) MarkFlagRequired(name string) error { + return MarkFlagRequired(cmd.Flags(), name) +} + +// MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag, if it exists. +func (cmd *Command) MarkPersistentFlagRequired(name string) error { + return MarkFlagRequired(cmd.PersistentFlags(), name) +} + +// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag in the flag set, if it exists. +func MarkFlagRequired(flags *pflag.FlagSet, name string) error { + return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"}) +} + +// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists. +// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. +func (cmd *Command) MarkFlagFilename(name string, extensions ...string) error { + return MarkFlagFilename(cmd.Flags(), name, extensions...) +} + +// MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists. +// Generated bash autocompletion will call the bash function f for the flag. +func (cmd *Command) MarkFlagCustom(name string, f string) error { + return MarkFlagCustom(cmd.Flags(), name, f) +} + +// MarkPersistentFlagFilename adds the BashCompFilenameExt annotation to the named persistent flag, if it exists. +// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. +func (cmd *Command) MarkPersistentFlagFilename(name string, extensions ...string) error { + return MarkFlagFilename(cmd.PersistentFlags(), name, extensions...) +} + +// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag in the flag set, if it exists. +// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. +func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error { + return flags.SetAnnotation(name, BashCompFilenameExt, extensions) +} + +// MarkFlagCustom adds the BashCompCustom annotation to the named flag in the flag set, if it exists. +// Generated bash autocompletion will call the bash function f for the flag. +func MarkFlagCustom(flags *pflag.FlagSet, name string, f string) error { + return flags.SetAnnotation(name, BashCompCustom, []string{f}) +} diff --git a/vendor/github.com/spf13/cobra/bash_completions.md b/vendor/github.com/spf13/cobra/bash_completions.md new file mode 100644 index 00000000..52bd39dd --- /dev/null +++ b/vendor/github.com/spf13/cobra/bash_completions.md @@ -0,0 +1,206 @@ +# Generating Bash Completions For Your Own cobra.Command + +Generating bash completions from a cobra command is incredibly easy. An actual program which does so for the kubernetes kubectl binary is as follows: + +```go +package main + +import ( + "io/ioutil" + "os" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd" +) + +func main() { + kubectl := cmd.NewFactory(nil).NewKubectlCommand(os.Stdin, ioutil.Discard, ioutil.Discard) + kubectl.GenBashCompletionFile("out.sh") +} +``` + +`out.sh` will get you completions of subcommands and flags. Copy it to `/etc/bash_completion.d/` as described [here](https://debian-administration.org/article/316/An_introduction_to_bash_completion_part_1) and reset your terminal to use autocompletion. If you make additional annotations to your code, you can get even more intelligent and flexible behavior. + +## Creating your own custom functions + +Some more actual code that works in kubernetes: + +```bash +const ( + bash_completion_func = `__kubectl_parse_get() +{ + local kubectl_output out + if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then + out=($(echo "${kubectl_output}" | awk '{print $1}')) + COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) ) + fi +} + +__kubectl_get_resource() +{ + if [[ ${#nouns[@]} -eq 0 ]]; then + return 1 + fi + __kubectl_parse_get ${nouns[${#nouns[@]} -1]} + if [[ $? -eq 0 ]]; then + return 0 + fi +} + +__custom_func() { + case ${last_command} in + kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop) + __kubectl_get_resource + return + ;; + *) + ;; + esac +} +`) +``` + +And then I set that in my command definition: + +```go +cmds := &cobra.Command{ + Use: "kubectl", + Short: "kubectl controls the Kubernetes cluster manager", + Long: `kubectl controls the Kubernetes cluster manager. + +Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`, + Run: runHelp, + BashCompletionFunction: bash_completion_func, +} +``` + +The `BashCompletionFunction` option is really only valid/useful on the root command. Doing the above will cause `__custom_func()` to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like `kubectl get pod [mypod]`. If you type `kubectl get pod [tab][tab]` the `__customc_func()` will run because the cobra.Command only understood "kubectl" and "get." `__custom_func()` will see that the cobra.Command is "kubectl_get" and will thus call another helper `__kubectl_get_resource()`. `__kubectl_get_resource` will look at the 'nouns' collected. In our example the only noun will be `pod`. So it will call `__kubectl_parse_get pod`. `__kubectl_parse_get` will actually call out to kubernetes and get any pods. It will then set `COMPREPLY` to valid pods! + +## Have the completions code complete your 'nouns' + +In the above example "pod" was assumed to already be typed. But if you want `kubectl get [tab][tab]` to show a list of valid "nouns" you have to set them. Simplified code from `kubectl get` looks like: + +```go +validArgs []string = { "pod", "node", "service", "replicationcontroller" } + +cmd := &cobra.Command{ + Use: "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)", + Short: "Display one or many resources", + Long: get_long, + Example: get_example, + Run: func(cmd *cobra.Command, args []string) { + err := RunGet(f, out, cmd, args) + util.CheckErr(err) + }, + ValidArgs: validArgs, +} +``` + +Notice we put the "ValidArgs" on the "get" subcommand. Doing so will give results like + +```bash +# kubectl get [tab][tab] +node pod replicationcontroller service +``` + +## Plural form and shortcuts for nouns + +If your nouns have a number of aliases, you can define them alongside `ValidArgs` using `ArgAliases`: + +```go +argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" } + +cmd := &cobra.Command{ + ... + ValidArgs: validArgs, + ArgAliases: argAliases +} +``` + +The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by +the completion algorithm if entered manually, e.g. in: + +```bash +# kubectl get rc [tab][tab] +backend frontend database +``` + +Note that without declaring `rc` as an alias, the completion algorithm would show the list of nouns +in this example again instead of the replication controllers. + +## Mark flags as required + +Most of the time completions will only show subcommands. But if a flag is required to make a subcommand work, you probably want it to show up when the user types [tab][tab]. Marking a flag as 'Required' is incredibly easy. + +```go +cmd.MarkFlagRequired("pod") +cmd.MarkFlagRequired("container") +``` + +and you'll get something like + +```bash +# kubectl exec [tab][tab][tab] +-c --container= -p --pod= +``` + +# Specify valid filename extensions for flags that take a filename + +In this example we use --filename= and expect to get a json or yaml file as the argument. To make this easier we annotate the --filename flag with valid filename extensions. + +```go + annotations := []string{"json", "yaml", "yml"} + annotation := make(map[string][]string) + annotation[cobra.BashCompFilenameExt] = annotations + + flag := &pflag.Flag{ + Name: "filename", + Shorthand: "f", + Usage: usage, + Value: value, + DefValue: value.String(), + Annotations: annotation, + } + cmd.Flags().AddFlag(flag) +``` + +Now when you run a command with this filename flag you'll get something like + +```bash +# kubectl create -f +test/ example/ rpmbuild/ +hello.yml test.json +``` + +So while there are many other files in the CWD it only shows me subdirs and those with valid extensions. + +# Specifiy custom flag completion + +Similar to the filename completion and filtering using cobra.BashCompFilenameExt, you can specifiy +a custom flag completion function with cobra.BashCompCustom: + +```go + annotation := make(map[string][]string) + annotation[cobra.BashCompFilenameExt] = []string{"__kubectl_get_namespaces"} + + flag := &pflag.Flag{ + Name: "namespace", + Usage: usage, + Annotations: annotation, + } + cmd.Flags().AddFlag(flag) +``` + +In addition add the `__handle_namespace_flag` implementation in the `BashCompletionFunction` +value, e.g.: + +```bash +__kubectl_get_namespaces() +{ + local template + template="{{ range .items }}{{ .metadata.name }} {{ end }}" + local kubectl_out + if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then + COMPREPLY=( $( compgen -W "${kubectl_out}[*]" -- "$cur" ) ) + fi +} +``` diff --git a/vendor/github.com/spf13/cobra/cobra.go b/vendor/github.com/spf13/cobra/cobra.go new file mode 100644 index 00000000..2726d19e --- /dev/null +++ b/vendor/github.com/spf13/cobra/cobra.go @@ -0,0 +1,181 @@ +// Copyright © 2013 Steve Francia . +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Commands similar to git, go tools and other modern CLI tools +// inspired by go, go-Commander, gh and subcommand + +package cobra + +import ( + "fmt" + "io" + "reflect" + "strconv" + "strings" + "text/template" + "unicode" +) + +var templateFuncs = template.FuncMap{ + "trim": strings.TrimSpace, + "trimRightSpace": trimRightSpace, + "trimTrailingWhitespaces": trimRightSpace, + "appendIfNotPresent": appendIfNotPresent, + "rpad": rpad, + "gt": Gt, + "eq": Eq, +} + +var initializers []func() + +// EnablePrefixMatching allows to set automatic prefix matching. Automatic prefix matching can be a dangerous thing +// to automatically enable in CLI tools. +// Set this to true to enable it. +var EnablePrefixMatching = false + +// EnableCommandSorting controls sorting of the slice of commands, which is turned on by default. +// To disable sorting, set it to false. +var EnableCommandSorting = true + +// AddTemplateFunc adds a template function that's available to Usage and Help +// template generation. +func AddTemplateFunc(name string, tmplFunc interface{}) { + templateFuncs[name] = tmplFunc +} + +// AddTemplateFuncs adds multiple template functions that are available to Usage and +// Help template generation. +func AddTemplateFuncs(tmplFuncs template.FuncMap) { + for k, v := range tmplFuncs { + templateFuncs[k] = v + } +} + +// OnInitialize takes a series of func() arguments and appends them to a slice of func(). +func OnInitialize(y ...func()) { + initializers = append(initializers, y...) +} + +// FIXME Gt is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra. + +// Gt takes two types and checks whether the first type is greater than the second. In case of types Arrays, Chans, +// Maps and Slices, Gt will compare their lengths. Ints are compared directly while strings are first parsed as +// ints and then compared. +func Gt(a interface{}, b interface{}) bool { + var left, right int64 + av := reflect.ValueOf(a) + + switch av.Kind() { + case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: + left = int64(av.Len()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + left = av.Int() + case reflect.String: + left, _ = strconv.ParseInt(av.String(), 10, 64) + } + + bv := reflect.ValueOf(b) + + switch bv.Kind() { + case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: + right = int64(bv.Len()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + right = bv.Int() + case reflect.String: + right, _ = strconv.ParseInt(bv.String(), 10, 64) + } + + return left > right +} + +// FIXME Eq is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra. + +// Eq takes two types and checks whether they are equal. Supported types are int and string. Unsupported types will panic. +func Eq(a interface{}, b interface{}) bool { + av := reflect.ValueOf(a) + bv := reflect.ValueOf(b) + + switch av.Kind() { + case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: + panic("Eq called on unsupported type") + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return av.Int() == bv.Int() + case reflect.String: + return av.String() == bv.String() + } + return false +} + +func trimRightSpace(s string) string { + return strings.TrimRightFunc(s, unicode.IsSpace) +} + +// FIXME appendIfNotPresent is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra. + +// appendIfNotPresent will append stringToAppend to the end of s, but only if it's not yet present in s. +func appendIfNotPresent(s, stringToAppend string) string { + if strings.Contains(s, stringToAppend) { + return s + } + return s + " " + stringToAppend +} + +// rpad adds padding to the right of a string. +func rpad(s string, padding int) string { + template := fmt.Sprintf("%%-%ds", padding) + return fmt.Sprintf(template, s) +} + +// tmpl executes the given template text on data, writing the result to w. +func tmpl(w io.Writer, text string, data interface{}) error { + t := template.New("top") + t.Funcs(templateFuncs) + template.Must(t.Parse(text)) + return t.Execute(w, data) +} + +// ld compares two strings and returns the levenshtein distance between them. +func ld(s, t string, ignoreCase bool) int { + if ignoreCase { + s = strings.ToLower(s) + t = strings.ToLower(t) + } + d := make([][]int, len(s)+1) + for i := range d { + d[i] = make([]int, len(t)+1) + } + for i := range d { + d[i][0] = i + } + for j := range d[0] { + d[0][j] = j + } + for j := 1; j <= len(t); j++ { + for i := 1; i <= len(s); i++ { + if s[i-1] == t[j-1] { + d[i][j] = d[i-1][j-1] + } else { + min := d[i-1][j] + if d[i][j-1] < min { + min = d[i][j-1] + } + if d[i-1][j-1] < min { + min = d[i-1][j-1] + } + d[i][j] = min + 1 + } + } + + } + return d[len(s)][len(t)] +} diff --git a/vendor/github.com/spf13/cobra/command.go b/vendor/github.com/spf13/cobra/command.go new file mode 100644 index 00000000..9e6bdf30 --- /dev/null +++ b/vendor/github.com/spf13/cobra/command.go @@ -0,0 +1,1298 @@ +// Copyright © 2013 Steve Francia . +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package cobra is a commander providing a simple interface to create powerful modern CLI interfaces. +// In addition to providing an interface, Cobra simultaneously provides a controller to organize your application code. +package cobra + +import ( + "bytes" + "fmt" + "io" + "os" + "path/filepath" + "sort" + "strings" + + flag "github.com/spf13/pflag" +) + +// Command is just that, a command for your application. +// E.g. 'go run ...' - 'run' is the command. Cobra requires +// you to define the usage and description as part of your command +// definition to ensure usability. +type Command struct { + // Use is the one-line usage message. + Use string + + // Aliases is an array of aliases that can be used instead of the first word in Use. + Aliases []string + + // SuggestFor is an array of command names for which this command will be suggested - + // similar to aliases but only suggests. + SuggestFor []string + + // Short is the short description shown in the 'help' output. + Short string + + // Long is the long message shown in the 'help ' output. + Long string + + // Example is examples of how to use the command. + Example string + + // ValidArgs is list of all valid non-flag arguments that are accepted in bash completions + ValidArgs []string + + // ArgAliases is List of aliases for ValidArgs. + // These are not suggested to the user in the bash completion, + // but accepted if entered manually. + ArgAliases []string + + // BashCompletionFunction is custom functions used by the bash autocompletion generator. + BashCompletionFunction string + + // Deprecated defines, if this command is deprecated and should print this string when used. + Deprecated string + + // Hidden defines, if this command is hidden and should NOT show up in the list of available commands. + Hidden bool + + // Annotations are key/value pairs that can be used by applications to identify or + // group commands. + Annotations map[string]string + + // The *Run functions are executed in the following order: + // * PersistentPreRun() + // * PreRun() + // * Run() + // * PostRun() + // * PersistentPostRun() + // All functions get the same args, the arguments after the command name. + // + // PersistentPreRun: children of this command will inherit and execute. + PersistentPreRun func(cmd *Command, args []string) + // PersistentPreRunE: PersistentPreRun but returns an error. + PersistentPreRunE func(cmd *Command, args []string) error + // PreRun: children of this command will not inherit. + PreRun func(cmd *Command, args []string) + // PreRunE: PreRun but returns an error. + PreRunE func(cmd *Command, args []string) error + // Run: Typically the actual work function. Most commands will only implement this. + Run func(cmd *Command, args []string) + // RunE: Run but returns an error. + RunE func(cmd *Command, args []string) error + // PostRun: run after the Run command. + PostRun func(cmd *Command, args []string) + // PostRunE: PostRun but returns an error. + PostRunE func(cmd *Command, args []string) error + // PersistentPostRun: children of this command will inherit and execute after PostRun. + PersistentPostRun func(cmd *Command, args []string) + // PersistentPostRunE: PersistentPostRun but returns an error. + PersistentPostRunE func(cmd *Command, args []string) error + + // SilenceErrors is an option to quiet errors down stream. + SilenceErrors bool + + // SilenceUsage is an option to silence usage when an error occurs. + SilenceUsage bool + + // DisableFlagParsing disables the flag parsing. + // If this is true all flags will be passed to the command as arguments. + DisableFlagParsing bool + + // DisableAutoGenTag defines, if gen tag ("Auto generated by spf13/cobra...") + // will be printed by generating docs for this command. + DisableAutoGenTag bool + + // DisableSuggestions disables the suggestions based on Levenshtein distance + // that go along with 'unknown command' messages. + DisableSuggestions bool + // SuggestionsMinimumDistance defines minimum levenshtein distance to display suggestions. + // Must be > 0. + SuggestionsMinimumDistance int + + // name is the command name, usually the executable's name. + name string + // commands is the list of commands supported by this program. + commands []*Command + // parent is a parent command for this command. + parent *Command + // Max lengths of commands' string lengths for use in padding. + commandsMaxUseLen int + commandsMaxCommandPathLen int + commandsMaxNameLen int + // commandsAreSorted defines, if command slice are sorted or not. + commandsAreSorted bool + + // args is actual args parsed from flags. + args []string + // flagErrorBuf contains all error messages from pflag. + flagErrorBuf *bytes.Buffer + // flags is full set of flags. + flags *flag.FlagSet + // pflags contains persistent flags. + pflags *flag.FlagSet + // lflags contains local flags. + lflags *flag.FlagSet + // iflags contains inherited flags. + iflags *flag.FlagSet + // parentsPflags is all persistent flags of cmd's parents. + parentsPflags *flag.FlagSet + // globNormFunc is the global normalization function + // that we can use on every pflag set and children commands + globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName + + // output is an output writer defined by user. + output io.Writer + // usageFunc is usage func defined by user. + usageFunc func(*Command) error + // usageTemplate is usage template defined by user. + usageTemplate string + // flagErrorFunc is func defined by user and it's called when the parsing of + // flags returns an error. + flagErrorFunc func(*Command, error) error + // helpTemplate is help template defined by user. + helpTemplate string + // helpFunc is help func defined by user. + helpFunc func(*Command, []string) + // helpCommand is command with usage 'help'. If it's not defined by user, + // cobra uses default help command. + helpCommand *Command +} + +// SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden +// particularly useful when testing. +func (c *Command) SetArgs(a []string) { + c.args = a +} + +// SetOutput sets the destination for usage and error messages. +// If output is nil, os.Stderr is used. +func (c *Command) SetOutput(output io.Writer) { + c.output = output +} + +// SetUsageFunc sets usage function. Usage can be defined by application. +func (c *Command) SetUsageFunc(f func(*Command) error) { + c.usageFunc = f +} + +// SetUsageTemplate sets usage template. Can be defined by Application. +func (c *Command) SetUsageTemplate(s string) { + c.usageTemplate = s +} + +// SetFlagErrorFunc sets a function to generate an error when flag parsing +// fails. +func (c *Command) SetFlagErrorFunc(f func(*Command, error) error) { + c.flagErrorFunc = f +} + +// SetHelpFunc sets help function. Can be defined by Application. +func (c *Command) SetHelpFunc(f func(*Command, []string)) { + c.helpFunc = f +} + +// SetHelpCommand sets help command. +func (c *Command) SetHelpCommand(cmd *Command) { + c.helpCommand = cmd +} + +// SetHelpTemplate sets help template to be used. Application can use it to set custom template. +func (c *Command) SetHelpTemplate(s string) { + c.helpTemplate = s +} + +// SetGlobalNormalizationFunc sets a normalization function to all flag sets and also to child commands. +// The user should not have a cyclic dependency on commands. +func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string) flag.NormalizedName) { + c.Flags().SetNormalizeFunc(n) + c.PersistentFlags().SetNormalizeFunc(n) + c.globNormFunc = n + + for _, command := range c.commands { + command.SetGlobalNormalizationFunc(n) + } +} + +// OutOrStdout returns output to stdout. +func (c *Command) OutOrStdout() io.Writer { + return c.getOut(os.Stdout) +} + +// OutOrStderr returns output to stderr +func (c *Command) OutOrStderr() io.Writer { + return c.getOut(os.Stderr) +} + +func (c *Command) getOut(def io.Writer) io.Writer { + if c.output != nil { + return c.output + } + if c.HasParent() { + return c.parent.getOut(def) + } + return def +} + +// UsageFunc returns either the function set by SetUsageFunc for this command +// or a parent, or it returns a default usage function. +func (c *Command) UsageFunc() (f func(*Command) error) { + if c.usageFunc != nil { + return c.usageFunc + } + if c.HasParent() { + return c.Parent().UsageFunc() + } + return func(c *Command) error { + c.mergePersistentFlags() + err := tmpl(c.OutOrStderr(), c.UsageTemplate(), c) + if err != nil { + c.Println(err) + } + return err + } +} + +// Usage puts out the usage for the command. +// Used when a user provides invalid input. +// Can be defined by user by overriding UsageFunc. +func (c *Command) Usage() error { + return c.UsageFunc()(c) +} + +// HelpFunc returns either the function set by SetHelpFunc for this command +// or a parent, or it returns a function with default help behavior. +func (c *Command) HelpFunc() func(*Command, []string) { + if c.helpFunc != nil { + return c.helpFunc + } + if c.HasParent() { + return c.Parent().HelpFunc() + } + return func(c *Command, a []string) { + c.mergePersistentFlags() + err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c) + if err != nil { + c.Println(err) + } + } +} + +// Help puts out the help for the command. +// Used when a user calls help [command]. +// Can be defined by user by overriding HelpFunc. +func (c *Command) Help() error { + c.HelpFunc()(c, []string{}) + return nil +} + +// UsageString return usage string. +func (c *Command) UsageString() string { + tmpOutput := c.output + bb := new(bytes.Buffer) + c.SetOutput(bb) + c.Usage() + c.output = tmpOutput + return bb.String() +} + +// FlagErrorFunc returns either the function set by SetFlagErrorFunc for this +// command or a parent, or it returns a function which returns the original +// error. +func (c *Command) FlagErrorFunc() (f func(*Command, error) error) { + if c.flagErrorFunc != nil { + return c.flagErrorFunc + } + + if c.HasParent() { + return c.parent.FlagErrorFunc() + } + return func(c *Command, err error) error { + return err + } +} + +var minUsagePadding = 25 + +// UsagePadding return padding for the usage. +func (c *Command) UsagePadding() int { + if c.parent == nil || minUsagePadding > c.parent.commandsMaxUseLen { + return minUsagePadding + } + return c.parent.commandsMaxUseLen +} + +var minCommandPathPadding = 11 + +// CommandPathPadding return padding for the command path. +func (c *Command) CommandPathPadding() int { + if c.parent == nil || minCommandPathPadding > c.parent.commandsMaxCommandPathLen { + return minCommandPathPadding + } + return c.parent.commandsMaxCommandPathLen +} + +var minNamePadding = 11 + +// NamePadding returns padding for the name. +func (c *Command) NamePadding() int { + if c.parent == nil || minNamePadding > c.parent.commandsMaxNameLen { + return minNamePadding + } + return c.parent.commandsMaxNameLen +} + +// UsageTemplate returns usage template for the command. +func (c *Command) UsageTemplate() string { + if c.usageTemplate != "" { + return c.usageTemplate + } + + if c.HasParent() { + return c.parent.UsageTemplate() + } + return `Usage:{{if .Runnable}} + {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} + {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}} + +Aliases: + {{.NameAndAliases}}{{end}}{{if .HasExample}} + +Examples: +{{.Example}}{{end}}{{if .HasAvailableSubCommands}} + +Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} + {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} + +Flags: +{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} + +Global Flags: +{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} + +Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} + {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} + +Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} +` +} + +// HelpTemplate return help template for the command. +func (c *Command) HelpTemplate() string { + if c.helpTemplate != "" { + return c.helpTemplate + } + + if c.HasParent() { + return c.parent.HelpTemplate() + } + return `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}} + +{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` +} + +func hasNoOptDefVal(name string, fs *flag.FlagSet) bool { + flag := fs.Lookup(name) + if flag == nil { + return false + } + return flag.NoOptDefVal != "" +} + +func shortHasNoOptDefVal(name string, fs *flag.FlagSet) bool { + if len(name) == 0 { + return false + } + + flag := fs.ShorthandLookup(name[:1]) + if flag == nil { + return false + } + return flag.NoOptDefVal != "" +} + +func stripFlags(args []string, c *Command) []string { + if len(args) == 0 { + return args + } + c.mergePersistentFlags() + + commands := []string{} + inQuote := false + flags := c.Flags() + +Loop: + for len(args) > 0 { + s := args[0] + args = args[1:] + if !inQuote { + switch { + case strings.HasPrefix(s, "\"") || strings.Contains(s, "=\""): + inQuote = true + case strings.HasPrefix(s, "--") && !strings.Contains(s, "=") && !hasNoOptDefVal(s[2:], flags): + // If '--flag arg' then + // delete arg from args. + fallthrough // (do the same as below) + case strings.HasPrefix(s, "-") && !strings.Contains(s, "=") && len(s) == 2 && !shortHasNoOptDefVal(s[1:], flags): + // If '-f arg' then + // delete 'arg' from args or break the loop if len(args) <= 1. + if len(args) <= 1 { + break Loop + } else { + args = args[1:] + continue + } + case s != "" && !strings.HasPrefix(s, "-"): + commands = append(commands, s) + } + } + + if strings.HasSuffix(s, "\"") && !strings.HasSuffix(s, "\\\"") { + inQuote = false + } + } + + return commands +} + +// argsMinusFirstX removes only the first x from args. Otherwise, commands that look like +// openshift admin policy add-role-to-user admin my-user, lose the admin argument (arg[4]). +func argsMinusFirstX(args []string, x string) []string { + for i, y := range args { + if x == y { + ret := []string{} + ret = append(ret, args[:i]...) + ret = append(ret, args[i+1:]...) + return ret + } + } + return args +} + +// Find the target command given the args and command tree +// Meant to be run on the highest node. Only searches down. +func (c *Command) Find(args []string) (*Command, []string, error) { + if c == nil { + return nil, nil, fmt.Errorf("Called find() on a nil Command") + } + + var innerfind func(*Command, []string) (*Command, []string) + + innerfind = func(c *Command, innerArgs []string) (*Command, []string) { + argsWOflags := stripFlags(innerArgs, c) + if len(argsWOflags) == 0 { + return c, innerArgs + } + nextSubCmd := argsWOflags[0] + matches := make([]*Command, 0) + for _, cmd := range c.commands { + if cmd.Name() == nextSubCmd || cmd.HasAlias(nextSubCmd) { // exact name or alias match + return innerfind(cmd, argsMinusFirstX(innerArgs, nextSubCmd)) + } + if EnablePrefixMatching { + if strings.HasPrefix(cmd.Name(), nextSubCmd) { // prefix match + matches = append(matches, cmd) + } + for _, x := range cmd.Aliases { + if strings.HasPrefix(x, nextSubCmd) { + matches = append(matches, cmd) + } + } + } + } + + // only accept a single prefix match - multiple matches would be ambiguous + if len(matches) == 1 { + return innerfind(matches[0], argsMinusFirstX(innerArgs, argsWOflags[0])) + } + + return c, innerArgs + } + + commandFound, a := innerfind(c, args) + argsWOflags := stripFlags(a, commandFound) + + // no subcommand, always take args + if !commandFound.HasSubCommands() { + return commandFound, a, nil + } + + // root command with subcommands, do subcommand checking + if commandFound == c && len(argsWOflags) > 0 { + suggestionsString := "" + if !c.DisableSuggestions { + if c.SuggestionsMinimumDistance <= 0 { + c.SuggestionsMinimumDistance = 2 + } + if suggestions := c.SuggestionsFor(argsWOflags[0]); len(suggestions) > 0 { + suggestionsString += "\n\nDid you mean this?\n" + for _, s := range suggestions { + suggestionsString += fmt.Sprintf("\t%v\n", s) + } + } + } + return commandFound, a, fmt.Errorf("unknown command %q for %q%s", argsWOflags[0], commandFound.CommandPath(), suggestionsString) + } + + return commandFound, a, nil +} + +// SuggestionsFor provides suggestions for the typedName. +func (c *Command) SuggestionsFor(typedName string) []string { + suggestions := []string{} + for _, cmd := range c.commands { + if cmd.IsAvailableCommand() { + levenshteinDistance := ld(typedName, cmd.Name(), true) + suggestByLevenshtein := levenshteinDistance <= c.SuggestionsMinimumDistance + suggestByPrefix := strings.HasPrefix(strings.ToLower(cmd.Name()), strings.ToLower(typedName)) + if suggestByLevenshtein || suggestByPrefix { + suggestions = append(suggestions, cmd.Name()) + } + for _, explicitSuggestion := range cmd.SuggestFor { + if strings.EqualFold(typedName, explicitSuggestion) { + suggestions = append(suggestions, cmd.Name()) + } + } + } + } + return suggestions +} + +// VisitParents visits all parents of the command and invokes fn on each parent. +func (c *Command) VisitParents(fn func(*Command)) { + if c.HasParent() { + fn(c.Parent()) + c.Parent().VisitParents(fn) + } +} + +// Root finds root command. +func (c *Command) Root() *Command { + if c.HasParent() { + return c.Parent().Root() + } + return c +} + +// ArgsLenAtDash will return the length of f.Args at the moment when a -- was +// found during arg parsing. This allows your program to know which args were +// before the -- and which came after. (Description from +// https://godoc.org/github.com/spf13/pflag#FlagSet.ArgsLenAtDash). +func (c *Command) ArgsLenAtDash() int { + return c.Flags().ArgsLenAtDash() +} + +func (c *Command) execute(a []string) (err error) { + if c == nil { + return fmt.Errorf("Called Execute() on a nil Command") + } + + if len(c.Deprecated) > 0 { + c.Printf("Command %q is deprecated, %s\n", c.Name(), c.Deprecated) + } + + // initialize help flag as the last point possible to allow for user + // overriding + c.InitDefaultHelpFlag() + + err = c.ParseFlags(a) + if err != nil { + return c.FlagErrorFunc()(c, err) + } + + // If help is called, regardless of other flags, return we want help. + // Also say we need help if the command isn't runnable. + helpVal, err := c.Flags().GetBool("help") + if err != nil { + // should be impossible to get here as we always declare a help + // flag in InitDefaultHelpFlag() + c.Println("\"help\" flag declared as non-bool. Please correct your code") + return err + } + + if helpVal || !c.Runnable() { + return flag.ErrHelp + } + + c.preRun() + + argWoFlags := c.Flags().Args() + if c.DisableFlagParsing { + argWoFlags = a + } + + for p := c; p != nil; p = p.Parent() { + if p.PersistentPreRunE != nil { + if err := p.PersistentPreRunE(c, argWoFlags); err != nil { + return err + } + break + } else if p.PersistentPreRun != nil { + p.PersistentPreRun(c, argWoFlags) + break + } + } + if c.PreRunE != nil { + if err := c.PreRunE(c, argWoFlags); err != nil { + return err + } + } else if c.PreRun != nil { + c.PreRun(c, argWoFlags) + } + + if c.RunE != nil { + if err := c.RunE(c, argWoFlags); err != nil { + return err + } + } else { + c.Run(c, argWoFlags) + } + if c.PostRunE != nil { + if err := c.PostRunE(c, argWoFlags); err != nil { + return err + } + } else if c.PostRun != nil { + c.PostRun(c, argWoFlags) + } + for p := c; p != nil; p = p.Parent() { + if p.PersistentPostRunE != nil { + if err := p.PersistentPostRunE(c, argWoFlags); err != nil { + return err + } + break + } else if p.PersistentPostRun != nil { + p.PersistentPostRun(c, argWoFlags) + break + } + } + + return nil +} + +func (c *Command) preRun() { + for _, x := range initializers { + x() + } +} + +// Execute Call execute to use the args (os.Args[1:] by default) +// and run through the command tree finding appropriate matches +// for commands and then corresponding flags. +func (c *Command) Execute() error { + _, err := c.ExecuteC() + return err +} + +// ExecuteC executes the command. +func (c *Command) ExecuteC() (cmd *Command, err error) { + // Regardless of what command execute is called on, run on Root only + if c.HasParent() { + return c.Root().ExecuteC() + } + + // windows hook + if preExecHookFn != nil { + preExecHookFn(c) + } + + // initialize help as the last point possible to allow for user + // overriding + c.initHelpCmd() + + var args []string + + // Workaround FAIL with "go test -v" or "cobra.test -test.v", see #155 + if c.args == nil && filepath.Base(os.Args[0]) != "cobra.test" { + args = os.Args[1:] + } else { + args = c.args + } + + cmd, flags, err := c.Find(args) + if err != nil { + // If found parse to a subcommand and then failed, talk about the subcommand + if cmd != nil { + c = cmd + } + if !c.SilenceErrors { + c.Println("Error:", err.Error()) + c.Printf("Run '%v --help' for usage.\n", c.CommandPath()) + } + return c, err + } + err = cmd.execute(flags) + if err != nil { + // Always show help if requested, even if SilenceErrors is in + // effect + if err == flag.ErrHelp { + cmd.HelpFunc()(cmd, args) + return cmd, nil + } + + // If root command has SilentErrors flagged, + // all subcommands should respect it + if !cmd.SilenceErrors && !c.SilenceErrors { + c.Println("Error:", err.Error()) + } + + // If root command has SilentUsage flagged, + // all subcommands should respect it + if !cmd.SilenceUsage && !c.SilenceUsage { + c.Println(cmd.UsageString()) + } + return cmd, err + } + return cmd, nil +} + +// InitDefaultHelpFlag adds default help flag to c. +// It is called automatically by executing the c or by calling help and usage. +// If c already has help flag, it will do nothing. +func (c *Command) InitDefaultHelpFlag() { + c.mergePersistentFlags() + if c.Flags().Lookup("help") == nil { + usage := "help for " + if c.Name() == "" { + usage += "this command" + } else { + usage += c.Name() + } + c.Flags().BoolP("help", "h", false, usage) + } +} + +func (c *Command) initHelpCmd() { + if c.helpCommand == nil { + if !c.HasSubCommands() { + return + } + + c.helpCommand = &Command{ + Use: "help [command]", + Short: "Help about any command", + Long: `Help provides help for any command in the application. + Simply type ` + c.Name() + ` help [path to command] for full details.`, + PersistentPreRun: func(cmd *Command, args []string) {}, + PersistentPostRun: func(cmd *Command, args []string) {}, + + Run: func(c *Command, args []string) { + cmd, _, e := c.Root().Find(args) + if cmd == nil || e != nil { + c.Printf("Unknown help topic %#q\n", args) + c.Root().Usage() + } else { + cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown + cmd.Help() + } + }, + } + } + c.RemoveCommand(c.helpCommand) + c.AddCommand(c.helpCommand) +} + +// ResetCommands used for testing. +func (c *Command) ResetCommands() { + c.commands = nil + c.helpCommand = nil + c.parentsPflags = nil +} + +// Sorts commands by their names. +type commandSorterByName []*Command + +func (c commandSorterByName) Len() int { return len(c) } +func (c commandSorterByName) Swap(i, j int) { c[i], c[j] = c[j], c[i] } +func (c commandSorterByName) Less(i, j int) bool { return c[i].Name() < c[j].Name() } + +// Commands returns a sorted slice of child commands. +func (c *Command) Commands() []*Command { + // do not sort commands if it already sorted or sorting was disabled + if EnableCommandSorting && !c.commandsAreSorted { + sort.Sort(commandSorterByName(c.commands)) + c.commandsAreSorted = true + } + return c.commands +} + +// AddCommand adds one or more commands to this parent command. +func (c *Command) AddCommand(cmds ...*Command) { + for i, x := range cmds { + if cmds[i] == c { + panic("Command can't be a child of itself") + } + cmds[i].parent = c + // update max lengths + usageLen := len(x.Use) + if usageLen > c.commandsMaxUseLen { + c.commandsMaxUseLen = usageLen + } + commandPathLen := len(x.CommandPath()) + if commandPathLen > c.commandsMaxCommandPathLen { + c.commandsMaxCommandPathLen = commandPathLen + } + nameLen := len(x.Name()) + if nameLen > c.commandsMaxNameLen { + c.commandsMaxNameLen = nameLen + } + // If global normalization function exists, update all children + if c.globNormFunc != nil { + x.SetGlobalNormalizationFunc(c.globNormFunc) + } + c.commands = append(c.commands, x) + c.commandsAreSorted = false + } +} + +// RemoveCommand removes one or more commands from a parent command. +func (c *Command) RemoveCommand(cmds ...*Command) { + commands := []*Command{} +main: + for _, command := range c.commands { + for _, cmd := range cmds { + if command == cmd { + command.parent = nil + continue main + } + } + commands = append(commands, command) + } + c.commands = commands + // recompute all lengths + c.commandsMaxUseLen = 0 + c.commandsMaxCommandPathLen = 0 + c.commandsMaxNameLen = 0 + for _, command := range c.commands { + usageLen := len(command.Use) + if usageLen > c.commandsMaxUseLen { + c.commandsMaxUseLen = usageLen + } + commandPathLen := len(command.CommandPath()) + if commandPathLen > c.commandsMaxCommandPathLen { + c.commandsMaxCommandPathLen = commandPathLen + } + nameLen := len(command.Name()) + if nameLen > c.commandsMaxNameLen { + c.commandsMaxNameLen = nameLen + } + } +} + +// Print is a convenience method to Print to the defined output, fallback to Stderr if not set. +func (c *Command) Print(i ...interface{}) { + fmt.Fprint(c.OutOrStderr(), i...) +} + +// Println is a convenience method to Println to the defined output, fallback to Stderr if not set. +func (c *Command) Println(i ...interface{}) { + c.Print(fmt.Sprintln(i...)) +} + +// Printf is a convenience method to Printf to the defined output, fallback to Stderr if not set. +func (c *Command) Printf(format string, i ...interface{}) { + c.Print(fmt.Sprintf(format, i...)) +} + +// CommandPath returns the full path to this command. +func (c *Command) CommandPath() string { + if c.HasParent() { + return c.Parent().CommandPath() + " " + c.Name() + } + return c.Name() +} + +// UseLine puts out the full usage for a given command (including parents). +func (c *Command) UseLine() string { + var useline string + if c.HasParent() { + useline = c.parent.CommandPath() + " " + c.Use + } else { + useline = c.Use + } + if c.HasAvailableFlags() && !strings.Contains(useline, "[flags]") { + useline += " [flags]" + } + return useline +} + +// DebugFlags used to determine which flags have been assigned to which commands +// and which persist. +func (c *Command) DebugFlags() { + c.Println("DebugFlags called on", c.Name()) + var debugflags func(*Command) + + debugflags = func(x *Command) { + if x.HasFlags() || x.HasPersistentFlags() { + c.Println(x.Name()) + } + if x.HasFlags() { + x.flags.VisitAll(func(f *flag.Flag) { + if x.HasPersistentFlags() && x.persistentFlag(f.Name) != nil { + c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [LP]") + } else { + c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [L]") + } + }) + } + if x.HasPersistentFlags() { + x.pflags.VisitAll(func(f *flag.Flag) { + if x.HasFlags() { + if x.flags.Lookup(f.Name) == nil { + c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [P]") + } + } else { + c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [P]") + } + }) + } + c.Println(x.flagErrorBuf) + if x.HasSubCommands() { + for _, y := range x.commands { + debugflags(y) + } + } + } + + debugflags(c) +} + +// Name returns the command's name: the first word in the use line. +func (c *Command) Name() string { + if c.name == "" { + name := c.Use + i := strings.Index(name, " ") + if i >= 0 { + name = name[:i] + } + c.name = name + } + return c.name +} + +// HasAlias determines if a given string is an alias of the command. +func (c *Command) HasAlias(s string) bool { + for _, a := range c.Aliases { + if a == s { + return true + } + } + return false +} + +// NameAndAliases returns string containing name and all aliases +func (c *Command) NameAndAliases() string { + return strings.Join(append([]string{c.Name()}, c.Aliases...), ", ") +} + +// HasExample determines if the command has example. +func (c *Command) HasExample() bool { + return len(c.Example) > 0 +} + +// Runnable determines if the command is itself runnable. +func (c *Command) Runnable() bool { + return c.Run != nil || c.RunE != nil +} + +// HasSubCommands determines if the command has children commands. +func (c *Command) HasSubCommands() bool { + return len(c.commands) > 0 +} + +// IsAvailableCommand determines if a command is available as a non-help command +// (this includes all non deprecated/hidden commands). +func (c *Command) IsAvailableCommand() bool { + if len(c.Deprecated) != 0 || c.Hidden { + return false + } + + if c.HasParent() && c.Parent().helpCommand == c { + return false + } + + if c.Runnable() || c.HasAvailableSubCommands() { + return true + } + + return false +} + +// IsAdditionalHelpTopicCommand determines if a command is an additional +// help topic command; additional help topic command is determined by the +// fact that it is NOT runnable/hidden/deprecated, and has no sub commands that +// are runnable/hidden/deprecated. +// Concrete example: https://github.com/spf13/cobra/issues/393#issuecomment-282741924. +func (c *Command) IsAdditionalHelpTopicCommand() bool { + // if a command is runnable, deprecated, or hidden it is not a 'help' command + if c.Runnable() || len(c.Deprecated) != 0 || c.Hidden { + return false + } + + // if any non-help sub commands are found, the command is not a 'help' command + for _, sub := range c.commands { + if !sub.IsAdditionalHelpTopicCommand() { + return false + } + } + + // the command either has no sub commands, or no non-help sub commands + return true +} + +// HasHelpSubCommands determines if a command has any available 'help' sub commands +// that need to be shown in the usage/help default template under 'additional help +// topics'. +func (c *Command) HasHelpSubCommands() bool { + // return true on the first found available 'help' sub command + for _, sub := range c.commands { + if sub.IsAdditionalHelpTopicCommand() { + return true + } + } + + // the command either has no sub commands, or no available 'help' sub commands + return false +} + +// HasAvailableSubCommands determines if a command has available sub commands that +// need to be shown in the usage/help default template under 'available commands'. +func (c *Command) HasAvailableSubCommands() bool { + // return true on the first found available (non deprecated/help/hidden) + // sub command + for _, sub := range c.commands { + if sub.IsAvailableCommand() { + return true + } + } + + // the command either has no sub comamnds, or no available (non deprecated/help/hidden) + // sub commands + return false +} + +// HasParent determines if the command is a child command. +func (c *Command) HasParent() bool { + return c.parent != nil +} + +// GlobalNormalizationFunc returns the global normalization function or nil if doesn't exists. +func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) flag.NormalizedName { + return c.globNormFunc +} + +// Flags returns the complete FlagSet that applies +// to this command (local and persistent declared here and by all parents). +func (c *Command) Flags() *flag.FlagSet { + if c.flags == nil { + c.flags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + if c.flagErrorBuf == nil { + c.flagErrorBuf = new(bytes.Buffer) + } + c.flags.SetOutput(c.flagErrorBuf) + } + + return c.flags +} + +// LocalNonPersistentFlags are flags specific to this command which will NOT persist to subcommands. +func (c *Command) LocalNonPersistentFlags() *flag.FlagSet { + persistentFlags := c.PersistentFlags() + + out := flag.NewFlagSet(c.Name(), flag.ContinueOnError) + c.LocalFlags().VisitAll(func(f *flag.Flag) { + if persistentFlags.Lookup(f.Name) == nil { + out.AddFlag(f) + } + }) + return out +} + +// LocalFlags returns the local FlagSet specifically set in the current command. +func (c *Command) LocalFlags() *flag.FlagSet { + c.mergePersistentFlags() + + if c.lflags == nil { + c.lflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + if c.flagErrorBuf == nil { + c.flagErrorBuf = new(bytes.Buffer) + } + c.lflags.SetOutput(c.flagErrorBuf) + } + c.lflags.SortFlags = c.Flags().SortFlags + + addToLocal := func(f *flag.Flag) { + if c.lflags.Lookup(f.Name) == nil && c.parentsPflags.Lookup(f.Name) == nil { + c.lflags.AddFlag(f) + } + } + c.Flags().VisitAll(addToLocal) + c.PersistentFlags().VisitAll(addToLocal) + return c.lflags +} + +// InheritedFlags returns all flags which were inherited from parents commands. +func (c *Command) InheritedFlags() *flag.FlagSet { + c.mergePersistentFlags() + + if c.iflags == nil { + c.iflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + if c.flagErrorBuf == nil { + c.flagErrorBuf = new(bytes.Buffer) + } + c.iflags.SetOutput(c.flagErrorBuf) + } + + local := c.LocalFlags() + c.parentsPflags.VisitAll(func(f *flag.Flag) { + if c.iflags.Lookup(f.Name) == nil && local.Lookup(f.Name) == nil { + c.iflags.AddFlag(f) + } + }) + return c.iflags +} + +// NonInheritedFlags returns all flags which were not inherited from parent commands. +func (c *Command) NonInheritedFlags() *flag.FlagSet { + return c.LocalFlags() +} + +// PersistentFlags returns the persistent FlagSet specifically set in the current command. +func (c *Command) PersistentFlags() *flag.FlagSet { + if c.pflags == nil { + c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + if c.flagErrorBuf == nil { + c.flagErrorBuf = new(bytes.Buffer) + } + c.pflags.SetOutput(c.flagErrorBuf) + } + return c.pflags +} + +// ResetFlags is used in testing. +func (c *Command) ResetFlags() { + c.flagErrorBuf = new(bytes.Buffer) + c.flagErrorBuf.Reset() + c.flags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + c.flags.SetOutput(c.flagErrorBuf) + c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + c.pflags.SetOutput(c.flagErrorBuf) +} + +// HasFlags checks if the command contains any flags (local plus persistent from the entire structure). +func (c *Command) HasFlags() bool { + return c.Flags().HasFlags() +} + +// HasPersistentFlags checks if the command contains persistent flags. +func (c *Command) HasPersistentFlags() bool { + return c.PersistentFlags().HasFlags() +} + +// HasLocalFlags checks if the command has flags specifically declared locally. +func (c *Command) HasLocalFlags() bool { + return c.LocalFlags().HasFlags() +} + +// HasInheritedFlags checks if the command has flags inherited from its parent command. +func (c *Command) HasInheritedFlags() bool { + return c.InheritedFlags().HasFlags() +} + +// HasAvailableFlags checks if the command contains any flags (local plus persistent from the entire +// structure) which are not hidden or deprecated. +func (c *Command) HasAvailableFlags() bool { + return c.Flags().HasAvailableFlags() +} + +// HasAvailablePersistentFlags checks if the command contains persistent flags which are not hidden or deprecated. +func (c *Command) HasAvailablePersistentFlags() bool { + return c.PersistentFlags().HasAvailableFlags() +} + +// HasAvailableLocalFlags checks if the command has flags specifically declared locally which are not hidden +// or deprecated. +func (c *Command) HasAvailableLocalFlags() bool { + return c.LocalFlags().HasAvailableFlags() +} + +// HasAvailableInheritedFlags checks if the command has flags inherited from its parent command which are +// not hidden or deprecated. +func (c *Command) HasAvailableInheritedFlags() bool { + return c.InheritedFlags().HasAvailableFlags() +} + +// Flag climbs up the command tree looking for matching flag. +func (c *Command) Flag(name string) (flag *flag.Flag) { + flag = c.Flags().Lookup(name) + + if flag == nil { + flag = c.persistentFlag(name) + } + + return +} + +// Recursively find matching persistent flag. +func (c *Command) persistentFlag(name string) (flag *flag.Flag) { + if c.HasPersistentFlags() { + flag = c.PersistentFlags().Lookup(name) + } + + if flag == nil { + c.updateParentsPflags() + flag = c.parentsPflags.Lookup(name) + } + return +} + +// ParseFlags parses persistent flag tree and local flags. +func (c *Command) ParseFlags(args []string) (err error) { + if c.DisableFlagParsing { + return nil + } + c.mergePersistentFlags() + err = c.Flags().Parse(args) + return +} + +// Parent returns a commands parent command. +func (c *Command) Parent() *Command { + return c.parent +} + +// mergePersistentFlags merges c.PersistentFlags() to c.Flags() +// and adds missing persistent flags of all parents. +func (c *Command) mergePersistentFlags() { + c.Flags().AddFlagSet(c.PersistentFlags()) + c.updateParentsPflags() + c.Flags().AddFlagSet(c.parentsPflags) +} + +// updateParentsPflags updates c.parentsPflags by adding +// new persistent flags of all parents. +// If c.parentsPflags == nil, it makes new. +func (c *Command) updateParentsPflags() { + if c.parentsPflags == nil { + c.parentsPflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + c.parentsPflags.SetOutput(c.flagErrorBuf) + c.parentsPflags.SortFlags = false + } + + c.Root().PersistentFlags().AddFlagSet(flag.CommandLine) + + c.VisitParents(func(parent *Command) { + c.parentsPflags.AddFlagSet(parent.PersistentFlags()) + }) +} diff --git a/vendor/github.com/spf13/cobra/command_notwin.go b/vendor/github.com/spf13/cobra/command_notwin.go new file mode 100644 index 00000000..6159c1cc --- /dev/null +++ b/vendor/github.com/spf13/cobra/command_notwin.go @@ -0,0 +1,5 @@ +// +build !windows + +package cobra + +var preExecHookFn func(*Command) diff --git a/vendor/github.com/spf13/cobra/command_win.go b/vendor/github.com/spf13/cobra/command_win.go new file mode 100644 index 00000000..4b0eaa1b --- /dev/null +++ b/vendor/github.com/spf13/cobra/command_win.go @@ -0,0 +1,26 @@ +// +build windows + +package cobra + +import ( + "os" + "time" + + "github.com/inconshreveable/mousetrap" +) + +var preExecHookFn = preExecHook + +// enables an information splash screen on Windows if the CLI is started from explorer.exe. +var MousetrapHelpText string = `This is a command line tool + +You need to open cmd.exe and run it from there. +` + +func preExecHook(c *Command) { + if mousetrap.StartedByExplorer() { + c.Print(MousetrapHelpText) + time.Sleep(5 * time.Second) + os.Exit(1) + } +} diff --git a/vendor/github.com/spf13/pflag/LICENSE b/vendor/github.com/spf13/pflag/LICENSE new file mode 100644 index 00000000..63ed1cfe --- /dev/null +++ b/vendor/github.com/spf13/pflag/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2012 Alex Ogier. All rights reserved. +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/spf13/pflag/README.md b/vendor/github.com/spf13/pflag/README.md new file mode 100644 index 00000000..b052414d --- /dev/null +++ b/vendor/github.com/spf13/pflag/README.md @@ -0,0 +1,296 @@ +[![Build Status](https://travis-ci.org/spf13/pflag.svg?branch=master)](https://travis-ci.org/spf13/pflag) +[![Go Report Card](https://goreportcard.com/badge/github.com/spf13/pflag)](https://goreportcard.com/report/github.com/spf13/pflag) +[![GoDoc](https://godoc.org/github.com/spf13/pflag?status.svg)](https://godoc.org/github.com/spf13/pflag) + +## Description + +pflag is a drop-in replacement for Go's flag package, implementing +POSIX/GNU-style --flags. + +pflag is compatible with the [GNU extensions to the POSIX recommendations +for command-line options][1]. For a more precise description, see the +"Command-line flag syntax" section below. + +[1]: http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html + +pflag is available under the same style of BSD license as the Go language, +which can be found in the LICENSE file. + +## Installation + +pflag is available using the standard `go get` command. + +Install by running: + + go get github.com/spf13/pflag + +Run tests by running: + + go test github.com/spf13/pflag + +## Usage + +pflag is a drop-in replacement of Go's native flag package. If you import +pflag under the name "flag" then all code should continue to function +with no changes. + +``` go +import flag "github.com/spf13/pflag" +``` + +There is one exception to this: if you directly instantiate the Flag struct +there is one more field "Shorthand" that you will need to set. +Most code never instantiates this struct directly, and instead uses +functions such as String(), BoolVar(), and Var(), and is therefore +unaffected. + +Define flags using flag.String(), Bool(), Int(), etc. + +This declares an integer flag, -flagname, stored in the pointer ip, with type *int. + +``` go +var ip *int = flag.Int("flagname", 1234, "help message for flagname") +``` + +If you like, you can bind the flag to a variable using the Var() functions. + +``` go +var flagvar int +func init() { + flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname") +} +``` + +Or you can create custom flags that satisfy the Value interface (with +pointer receivers) and couple them to flag parsing by + +``` go +flag.Var(&flagVal, "name", "help message for flagname") +``` + +For such flags, the default value is just the initial value of the variable. + +After all flags are defined, call + +``` go +flag.Parse() +``` + +to parse the command line into the defined flags. + +Flags may then be used directly. If you're using the flags themselves, +they are all pointers; if you bind to variables, they're values. + +``` go +fmt.Println("ip has value ", *ip) +fmt.Println("flagvar has value ", flagvar) +``` + +There are helpers function to get values later if you have the FlagSet but +it was difficult to keep up with all of the flag pointers in your code. +If you have a pflag.FlagSet with a flag called 'flagname' of type int you +can use GetInt() to get the int value. But notice that 'flagname' must exist +and it must be an int. GetString("flagname") will fail. + +``` go +i, err := flagset.GetInt("flagname") +``` + +After parsing, the arguments after the flag are available as the +slice flag.Args() or individually as flag.Arg(i). +The arguments are indexed from 0 through flag.NArg()-1. + +The pflag package also defines some new functions that are not in flag, +that give one-letter shorthands for flags. You can use these by appending +'P' to the name of any function that defines a flag. + +``` go +var ip = flag.IntP("flagname", "f", 1234, "help message") +var flagvar bool +func init() { + flag.BoolVarP(&flagvar, "boolname", "b", true, "help message") +} +flag.VarP(&flagVal, "varname", "v", "help message") +``` + +Shorthand letters can be used with single dashes on the command line. +Boolean shorthand flags can be combined with other shorthand flags. + +The default set of command-line flags is controlled by +top-level functions. The FlagSet type allows one to define +independent sets of flags, such as to implement subcommands +in a command-line interface. The methods of FlagSet are +analogous to the top-level functions for the command-line +flag set. + +## Setting no option default values for flags + +After you create a flag it is possible to set the pflag.NoOptDefVal for +the given flag. Doing this changes the meaning of the flag slightly. If +a flag has a NoOptDefVal and the flag is set on the command line without +an option the flag will be set to the NoOptDefVal. For example given: + +``` go +var ip = flag.IntP("flagname", "f", 1234, "help message") +flag.Lookup("flagname").NoOptDefVal = "4321" +``` + +Would result in something like + +| Parsed Arguments | Resulting Value | +| ------------- | ------------- | +| --flagname=1357 | ip=1357 | +| --flagname | ip=4321 | +| [nothing] | ip=1234 | + +## Command line flag syntax + +``` +--flag // boolean flags, or flags with no option default values +--flag x // only on flags without a default value +--flag=x +``` + +Unlike the flag package, a single dash before an option means something +different than a double dash. Single dashes signify a series of shorthand +letters for flags. All but the last shorthand letter must be boolean flags +or a flag with a default value + +``` +// boolean or flags where the 'no option default value' is set +-f +-f=true +-abc +but +-b true is INVALID + +// non-boolean and flags without a 'no option default value' +-n 1234 +-n=1234 +-n1234 + +// mixed +-abcs "hello" +-absd="hello" +-abcs1234 +``` + +Flag parsing stops after the terminator "--". Unlike the flag package, +flags can be interspersed with arguments anywhere on the command line +before this terminator. + +Integer flags accept 1234, 0664, 0x1234 and may be negative. +Boolean flags (in their long form) accept 1, 0, t, f, true, false, +TRUE, FALSE, True, False. +Duration flags accept any input valid for time.ParseDuration. + +## Mutating or "Normalizing" Flag names + +It is possible to set a custom flag name 'normalization function.' It allows flag names to be mutated both when created in the code and when used on the command line to some 'normalized' form. The 'normalized' form is used for comparison. Two examples of using the custom normalization func follow. + +**Example #1**: You want -, _, and . in flags to compare the same. aka --my-flag == --my_flag == --my.flag + +``` go +func wordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { + from := []string{"-", "_"} + to := "." + for _, sep := range from { + name = strings.Replace(name, sep, to, -1) + } + return pflag.NormalizedName(name) +} + +myFlagSet.SetNormalizeFunc(wordSepNormalizeFunc) +``` + +**Example #2**: You want to alias two flags. aka --old-flag-name == --new-flag-name + +``` go +func aliasNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { + switch name { + case "old-flag-name": + name = "new-flag-name" + break + } + return pflag.NormalizedName(name) +} + +myFlagSet.SetNormalizeFunc(aliasNormalizeFunc) +``` + +## Deprecating a flag or its shorthand +It is possible to deprecate a flag, or just its shorthand. Deprecating a flag/shorthand hides it from help text and prints a usage message when the deprecated flag/shorthand is used. + +**Example #1**: You want to deprecate a flag named "badflag" as well as inform the users what flag they should use instead. +```go +// deprecate a flag by specifying its name and a usage message +flags.MarkDeprecated("badflag", "please use --good-flag instead") +``` +This hides "badflag" from help text, and prints `Flag --badflag has been deprecated, please use --good-flag instead` when "badflag" is used. + +**Example #2**: You want to keep a flag name "noshorthandflag" but deprecate its shortname "n". +```go +// deprecate a flag shorthand by specifying its flag name and a usage message +flags.MarkShorthandDeprecated("noshorthandflag", "please use --noshorthandflag only") +``` +This hides the shortname "n" from help text, and prints `Flag shorthand -n has been deprecated, please use --noshorthandflag only` when the shorthand "n" is used. + +Note that usage message is essential here, and it should not be empty. + +## Hidden flags +It is possible to mark a flag as hidden, meaning it will still function as normal, however will not show up in usage/help text. + +**Example**: You have a flag named "secretFlag" that you need for internal use only and don't want it showing up in help text, or for its usage text to be available. +```go +// hide a flag by specifying its name +flags.MarkHidden("secretFlag") +``` + +## Disable sorting of flags +`pflag` allows you to disable sorting of flags for help and usage message. + +**Example**: +```go +flags.BoolP("verbose", "v", false, "verbose output") +flags.String("coolflag", "yeaah", "it's really cool flag") +flags.Int("usefulflag", 777, "sometimes it's very useful") +flags.SortFlags = false +flags.PrintDefaults() +``` +**Output**: +``` + -v, --verbose verbose output + --coolflag string it's really cool flag (default "yeaah") + --usefulflag int sometimes it's very useful (default 777) +``` + + +## Supporting Go flags when using pflag +In order to support flags defined using Go's `flag` package, they must be added to the `pflag` flagset. This is usually necessary +to support flags defined by third-party dependencies (e.g. `golang/glog`). + +**Example**: You want to add the Go flags to the `CommandLine` flagset +```go +import ( + goflag "flag" + flag "github.com/spf13/pflag" +) + +var ip *int = flag.Int("flagname", 1234, "help message for flagname") + +func main() { + flag.CommandLine.AddGoFlagSet(goflag.CommandLine) + flag.Parse() +} +``` + +## More info + +You can see the full reference documentation of the pflag package +[at godoc.org][3], or through go's standard documentation system by +running `godoc -http=:6060` and browsing to +[http://localhost:6060/pkg/github.com/spf13/pflag][2] after +installation. + +[2]: http://localhost:6060/pkg/github.com/spf13/pflag +[3]: http://godoc.org/github.com/spf13/pflag diff --git a/vendor/github.com/spf13/pflag/bool.go b/vendor/github.com/spf13/pflag/bool.go new file mode 100644 index 00000000..c4c5c0bf --- /dev/null +++ b/vendor/github.com/spf13/pflag/bool.go @@ -0,0 +1,94 @@ +package pflag + +import "strconv" + +// optional interface to indicate boolean flags that can be +// supplied without "=value" text +type boolFlag interface { + Value + IsBoolFlag() bool +} + +// -- bool Value +type boolValue bool + +func newBoolValue(val bool, p *bool) *boolValue { + *p = val + return (*boolValue)(p) +} + +func (b *boolValue) Set(s string) error { + v, err := strconv.ParseBool(s) + *b = boolValue(v) + return err +} + +func (b *boolValue) Type() string { + return "bool" +} + +func (b *boolValue) String() string { return strconv.FormatBool(bool(*b)) } + +func (b *boolValue) IsBoolFlag() bool { return true } + +func boolConv(sval string) (interface{}, error) { + return strconv.ParseBool(sval) +} + +// GetBool return the bool value of a flag with the given name +func (f *FlagSet) GetBool(name string) (bool, error) { + val, err := f.getFlagType(name, "bool", boolConv) + if err != nil { + return false, err + } + return val.(bool), nil +} + +// BoolVar defines a bool flag with specified name, default value, and usage string. +// The argument p points to a bool variable in which to store the value of the flag. +func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) { + f.BoolVarP(p, name, "", value, usage) +} + +// BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) BoolVarP(p *bool, name, shorthand string, value bool, usage string) { + flag := f.VarPF(newBoolValue(value, p), name, shorthand, usage) + flag.NoOptDefVal = "true" +} + +// BoolVar defines a bool flag with specified name, default value, and usage string. +// The argument p points to a bool variable in which to store the value of the flag. +func BoolVar(p *bool, name string, value bool, usage string) { + BoolVarP(p, name, "", value, usage) +} + +// BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash. +func BoolVarP(p *bool, name, shorthand string, value bool, usage string) { + flag := CommandLine.VarPF(newBoolValue(value, p), name, shorthand, usage) + flag.NoOptDefVal = "true" +} + +// Bool defines a bool flag with specified name, default value, and usage string. +// The return value is the address of a bool variable that stores the value of the flag. +func (f *FlagSet) Bool(name string, value bool, usage string) *bool { + return f.BoolP(name, "", value, usage) +} + +// BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) BoolP(name, shorthand string, value bool, usage string) *bool { + p := new(bool) + f.BoolVarP(p, name, shorthand, value, usage) + return p +} + +// Bool defines a bool flag with specified name, default value, and usage string. +// The return value is the address of a bool variable that stores the value of the flag. +func Bool(name string, value bool, usage string) *bool { + return BoolP(name, "", value, usage) +} + +// BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash. +func BoolP(name, shorthand string, value bool, usage string) *bool { + b := CommandLine.BoolP(name, shorthand, value, usage) + return b +} diff --git a/vendor/github.com/spf13/pflag/bool_slice.go b/vendor/github.com/spf13/pflag/bool_slice.go new file mode 100644 index 00000000..5af02f1a --- /dev/null +++ b/vendor/github.com/spf13/pflag/bool_slice.go @@ -0,0 +1,147 @@ +package pflag + +import ( + "io" + "strconv" + "strings" +) + +// -- boolSlice Value +type boolSliceValue struct { + value *[]bool + changed bool +} + +func newBoolSliceValue(val []bool, p *[]bool) *boolSliceValue { + bsv := new(boolSliceValue) + bsv.value = p + *bsv.value = val + return bsv +} + +// Set converts, and assigns, the comma-separated boolean argument string representation as the []bool value of this flag. +// If Set is called on a flag that already has a []bool assigned, the newly converted values will be appended. +func (s *boolSliceValue) Set(val string) error { + + // remove all quote characters + rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "") + + // read flag arguments with CSV parser + boolStrSlice, err := readAsCSV(rmQuote.Replace(val)) + if err != nil && err != io.EOF { + return err + } + + // parse boolean values into slice + out := make([]bool, 0, len(boolStrSlice)) + for _, boolStr := range boolStrSlice { + b, err := strconv.ParseBool(strings.TrimSpace(boolStr)) + if err != nil { + return err + } + out = append(out, b) + } + + if !s.changed { + *s.value = out + } else { + *s.value = append(*s.value, out...) + } + + s.changed = true + + return nil +} + +// Type returns a string that uniquely represents this flag's type. +func (s *boolSliceValue) Type() string { + return "boolSlice" +} + +// String defines a "native" format for this boolean slice flag value. +func (s *boolSliceValue) String() string { + + boolStrSlice := make([]string, len(*s.value)) + for i, b := range *s.value { + boolStrSlice[i] = strconv.FormatBool(b) + } + + out, _ := writeAsCSV(boolStrSlice) + + return "[" + out + "]" +} + +func boolSliceConv(val string) (interface{}, error) { + val = strings.Trim(val, "[]") + // Empty string would cause a slice with one (empty) entry + if len(val) == 0 { + return []bool{}, nil + } + ss := strings.Split(val, ",") + out := make([]bool, len(ss)) + for i, t := range ss { + var err error + out[i], err = strconv.ParseBool(t) + if err != nil { + return nil, err + } + } + return out, nil +} + +// GetBoolSlice returns the []bool value of a flag with the given name. +func (f *FlagSet) GetBoolSlice(name string) ([]bool, error) { + val, err := f.getFlagType(name, "boolSlice", boolSliceConv) + if err != nil { + return []bool{}, err + } + return val.([]bool), nil +} + +// BoolSliceVar defines a boolSlice flag with specified name, default value, and usage string. +// The argument p points to a []bool variable in which to store the value of the flag. +func (f *FlagSet) BoolSliceVar(p *[]bool, name string, value []bool, usage string) { + f.VarP(newBoolSliceValue(value, p), name, "", usage) +} + +// BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) { + f.VarP(newBoolSliceValue(value, p), name, shorthand, usage) +} + +// BoolSliceVar defines a []bool flag with specified name, default value, and usage string. +// The argument p points to a []bool variable in which to store the value of the flag. +func BoolSliceVar(p *[]bool, name string, value []bool, usage string) { + CommandLine.VarP(newBoolSliceValue(value, p), name, "", usage) +} + +// BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash. +func BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) { + CommandLine.VarP(newBoolSliceValue(value, p), name, shorthand, usage) +} + +// BoolSlice defines a []bool flag with specified name, default value, and usage string. +// The return value is the address of a []bool variable that stores the value of the flag. +func (f *FlagSet) BoolSlice(name string, value []bool, usage string) *[]bool { + p := []bool{} + f.BoolSliceVarP(&p, name, "", value, usage) + return &p +} + +// BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool { + p := []bool{} + f.BoolSliceVarP(&p, name, shorthand, value, usage) + return &p +} + +// BoolSlice defines a []bool flag with specified name, default value, and usage string. +// The return value is the address of a []bool variable that stores the value of the flag. +func BoolSlice(name string, value []bool, usage string) *[]bool { + return CommandLine.BoolSliceP(name, "", value, usage) +} + +// BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash. +func BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool { + return CommandLine.BoolSliceP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/count.go b/vendor/github.com/spf13/pflag/count.go new file mode 100644 index 00000000..250a4381 --- /dev/null +++ b/vendor/github.com/spf13/pflag/count.go @@ -0,0 +1,96 @@ +package pflag + +import "strconv" + +// -- count Value +type countValue int + +func newCountValue(val int, p *int) *countValue { + *p = val + return (*countValue)(p) +} + +func (i *countValue) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 64) + // -1 means that no specific value was passed, so increment + if v == -1 { + *i = countValue(*i + 1) + } else { + *i = countValue(v) + } + return err +} + +func (i *countValue) Type() string { + return "count" +} + +func (i *countValue) String() string { return strconv.Itoa(int(*i)) } + +func countConv(sval string) (interface{}, error) { + i, err := strconv.Atoi(sval) + if err != nil { + return nil, err + } + return i, nil +} + +// GetCount return the int value of a flag with the given name +func (f *FlagSet) GetCount(name string) (int, error) { + val, err := f.getFlagType(name, "count", countConv) + if err != nil { + return 0, err + } + return val.(int), nil +} + +// CountVar defines a count flag with specified name, default value, and usage string. +// The argument p points to an int variable in which to store the value of the flag. +// A count flag will add 1 to its value evey time it is found on the command line +func (f *FlagSet) CountVar(p *int, name string, usage string) { + f.CountVarP(p, name, "", usage) +} + +// CountVarP is like CountVar only take a shorthand for the flag name. +func (f *FlagSet) CountVarP(p *int, name, shorthand string, usage string) { + flag := f.VarPF(newCountValue(0, p), name, shorthand, usage) + flag.NoOptDefVal = "-1" +} + +// CountVar like CountVar only the flag is placed on the CommandLine instead of a given flag set +func CountVar(p *int, name string, usage string) { + CommandLine.CountVar(p, name, usage) +} + +// CountVarP is like CountVar only take a shorthand for the flag name. +func CountVarP(p *int, name, shorthand string, usage string) { + CommandLine.CountVarP(p, name, shorthand, usage) +} + +// Count defines a count flag with specified name, default value, and usage string. +// The return value is the address of an int variable that stores the value of the flag. +// A count flag will add 1 to its value evey time it is found on the command line +func (f *FlagSet) Count(name string, usage string) *int { + p := new(int) + f.CountVarP(p, name, "", usage) + return p +} + +// CountP is like Count only takes a shorthand for the flag name. +func (f *FlagSet) CountP(name, shorthand string, usage string) *int { + p := new(int) + f.CountVarP(p, name, shorthand, usage) + return p +} + +// Count defines a count flag with specified name, default value, and usage string. +// The return value is the address of an int variable that stores the value of the flag. +// A count flag will add 1 to its value evey time it is found on the command line +func Count(name string, usage string) *int { + return CommandLine.CountP(name, "", usage) +} + +// CountP is like Count only takes a shorthand for the flag name. +func CountP(name, shorthand string, usage string) *int { + return CommandLine.CountP(name, shorthand, usage) +} diff --git a/vendor/github.com/spf13/pflag/duration.go b/vendor/github.com/spf13/pflag/duration.go new file mode 100644 index 00000000..e9debef8 --- /dev/null +++ b/vendor/github.com/spf13/pflag/duration.go @@ -0,0 +1,86 @@ +package pflag + +import ( + "time" +) + +// -- time.Duration Value +type durationValue time.Duration + +func newDurationValue(val time.Duration, p *time.Duration) *durationValue { + *p = val + return (*durationValue)(p) +} + +func (d *durationValue) Set(s string) error { + v, err := time.ParseDuration(s) + *d = durationValue(v) + return err +} + +func (d *durationValue) Type() string { + return "duration" +} + +func (d *durationValue) String() string { return (*time.Duration)(d).String() } + +func durationConv(sval string) (interface{}, error) { + return time.ParseDuration(sval) +} + +// GetDuration return the duration value of a flag with the given name +func (f *FlagSet) GetDuration(name string) (time.Duration, error) { + val, err := f.getFlagType(name, "duration", durationConv) + if err != nil { + return 0, err + } + return val.(time.Duration), nil +} + +// DurationVar defines a time.Duration flag with specified name, default value, and usage string. +// The argument p points to a time.Duration variable in which to store the value of the flag. +func (f *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) { + f.VarP(newDurationValue(value, p), name, "", usage) +} + +// DurationVarP is like DurationVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) { + f.VarP(newDurationValue(value, p), name, shorthand, usage) +} + +// DurationVar defines a time.Duration flag with specified name, default value, and usage string. +// The argument p points to a time.Duration variable in which to store the value of the flag. +func DurationVar(p *time.Duration, name string, value time.Duration, usage string) { + CommandLine.VarP(newDurationValue(value, p), name, "", usage) +} + +// DurationVarP is like DurationVar, but accepts a shorthand letter that can be used after a single dash. +func DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) { + CommandLine.VarP(newDurationValue(value, p), name, shorthand, usage) +} + +// Duration defines a time.Duration flag with specified name, default value, and usage string. +// The return value is the address of a time.Duration variable that stores the value of the flag. +func (f *FlagSet) Duration(name string, value time.Duration, usage string) *time.Duration { + p := new(time.Duration) + f.DurationVarP(p, name, "", value, usage) + return p +} + +// DurationP is like Duration, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration { + p := new(time.Duration) + f.DurationVarP(p, name, shorthand, value, usage) + return p +} + +// Duration defines a time.Duration flag with specified name, default value, and usage string. +// The return value is the address of a time.Duration variable that stores the value of the flag. +func Duration(name string, value time.Duration, usage string) *time.Duration { + return CommandLine.DurationP(name, "", value, usage) +} + +// DurationP is like Duration, but accepts a shorthand letter that can be used after a single dash. +func DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration { + return CommandLine.DurationP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/flag.go b/vendor/github.com/spf13/pflag/flag.go new file mode 100644 index 00000000..6f1fc300 --- /dev/null +++ b/vendor/github.com/spf13/pflag/flag.go @@ -0,0 +1,1128 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package pflag is a drop-in replacement for Go's flag package, implementing +POSIX/GNU-style --flags. + +pflag is compatible with the GNU extensions to the POSIX recommendations +for command-line options. See +http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html + +Usage: + +pflag is a drop-in replacement of Go's native flag package. If you import +pflag under the name "flag" then all code should continue to function +with no changes. + + import flag "github.com/spf13/pflag" + +There is one exception to this: if you directly instantiate the Flag struct +there is one more field "Shorthand" that you will need to set. +Most code never instantiates this struct directly, and instead uses +functions such as String(), BoolVar(), and Var(), and is therefore +unaffected. + +Define flags using flag.String(), Bool(), Int(), etc. + +This declares an integer flag, -flagname, stored in the pointer ip, with type *int. + var ip = flag.Int("flagname", 1234, "help message for flagname") +If you like, you can bind the flag to a variable using the Var() functions. + var flagvar int + func init() { + flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname") + } +Or you can create custom flags that satisfy the Value interface (with +pointer receivers) and couple them to flag parsing by + flag.Var(&flagVal, "name", "help message for flagname") +For such flags, the default value is just the initial value of the variable. + +After all flags are defined, call + flag.Parse() +to parse the command line into the defined flags. + +Flags may then be used directly. If you're using the flags themselves, +they are all pointers; if you bind to variables, they're values. + fmt.Println("ip has value ", *ip) + fmt.Println("flagvar has value ", flagvar) + +After parsing, the arguments after the flag are available as the +slice flag.Args() or individually as flag.Arg(i). +The arguments are indexed from 0 through flag.NArg()-1. + +The pflag package also defines some new functions that are not in flag, +that give one-letter shorthands for flags. You can use these by appending +'P' to the name of any function that defines a flag. + var ip = flag.IntP("flagname", "f", 1234, "help message") + var flagvar bool + func init() { + flag.BoolVarP("boolname", "b", true, "help message") + } + flag.VarP(&flagVar, "varname", "v", 1234, "help message") +Shorthand letters can be used with single dashes on the command line. +Boolean shorthand flags can be combined with other shorthand flags. + +Command line flag syntax: + --flag // boolean flags only + --flag=x + +Unlike the flag package, a single dash before an option means something +different than a double dash. Single dashes signify a series of shorthand +letters for flags. All but the last shorthand letter must be boolean flags. + // boolean flags + -f + -abc + // non-boolean flags + -n 1234 + -Ifile + // mixed + -abcs "hello" + -abcn1234 + +Flag parsing stops after the terminator "--". Unlike the flag package, +flags can be interspersed with arguments anywhere on the command line +before this terminator. + +Integer flags accept 1234, 0664, 0x1234 and may be negative. +Boolean flags (in their long form) accept 1, 0, t, f, true, false, +TRUE, FALSE, True, False. +Duration flags accept any input valid for time.ParseDuration. + +The default set of command-line flags is controlled by +top-level functions. The FlagSet type allows one to define +independent sets of flags, such as to implement subcommands +in a command-line interface. The methods of FlagSet are +analogous to the top-level functions for the command-line +flag set. +*/ +package pflag + +import ( + "bytes" + "errors" + "fmt" + "io" + "os" + "sort" + "strings" +) + +// ErrHelp is the error returned if the flag -help is invoked but no such flag is defined. +var ErrHelp = errors.New("pflag: help requested") + +// ErrorHandling defines how to handle flag parsing errors. +type ErrorHandling int + +const ( + // ContinueOnError will return an err from Parse() if an error is found + ContinueOnError ErrorHandling = iota + // ExitOnError will call os.Exit(2) if an error is found when parsing + ExitOnError + // PanicOnError will panic() if an error is found when parsing flags + PanicOnError +) + +// NormalizedName is a flag name that has been normalized according to rules +// for the FlagSet (e.g. making '-' and '_' equivalent). +type NormalizedName string + +// A FlagSet represents a set of defined flags. +type FlagSet struct { + // Usage is the function called when an error occurs while parsing flags. + // The field is a function (not a method) that may be changed to point to + // a custom error handler. + Usage func() + + // SortFlags is used to indicate, if user wants to have sorted flags in + // help/usage messages. + SortFlags bool + + name string + parsed bool + actual map[NormalizedName]*Flag + orderedActual []*Flag + sortedActual []*Flag + formal map[NormalizedName]*Flag + orderedFormal []*Flag + sortedFormal []*Flag + shorthands map[byte]*Flag + args []string // arguments after flags + argsLenAtDash int // len(args) when a '--' was located when parsing, or -1 if no -- + errorHandling ErrorHandling + output io.Writer // nil means stderr; use out() accessor + interspersed bool // allow interspersed option/non-option args + normalizeNameFunc func(f *FlagSet, name string) NormalizedName +} + +// A Flag represents the state of a flag. +type Flag struct { + Name string // name as it appears on command line + Shorthand string // one-letter abbreviated flag + Usage string // help message + Value Value // value as set + DefValue string // default value (as text); for usage message + Changed bool // If the user set the value (or if left to default) + NoOptDefVal string // default value (as text); if the flag is on the command line without any options + Deprecated string // If this flag is deprecated, this string is the new or now thing to use + Hidden bool // used by cobra.Command to allow flags to be hidden from help/usage text + ShorthandDeprecated string // If the shorthand of this flag is deprecated, this string is the new or now thing to use + Annotations map[string][]string // used by cobra.Command bash autocomple code +} + +// Value is the interface to the dynamic value stored in a flag. +// (The default value is represented as a string.) +type Value interface { + String() string + Set(string) error + Type() string +} + +// sortFlags returns the flags as a slice in lexicographical sorted order. +func sortFlags(flags map[NormalizedName]*Flag) []*Flag { + list := make(sort.StringSlice, len(flags)) + i := 0 + for k := range flags { + list[i] = string(k) + i++ + } + list.Sort() + result := make([]*Flag, len(list)) + for i, name := range list { + result[i] = flags[NormalizedName(name)] + } + return result +} + +// SetNormalizeFunc allows you to add a function which can translate flag names. +// Flags added to the FlagSet will be translated and then when anything tries to +// look up the flag that will also be translated. So it would be possible to create +// a flag named "getURL" and have it translated to "geturl". A user could then pass +// "--getUrl" which may also be translated to "geturl" and everything will work. +func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) { + f.normalizeNameFunc = n + f.sortedFormal = f.sortedFormal[:0] + for k, v := range f.orderedFormal { + delete(f.formal, NormalizedName(v.Name)) + nname := f.normalizeFlagName(v.Name) + v.Name = string(nname) + f.formal[nname] = v + f.orderedFormal[k] = v + } +} + +// GetNormalizeFunc returns the previously set NormalizeFunc of a function which +// does no translation, if not set previously. +func (f *FlagSet) GetNormalizeFunc() func(f *FlagSet, name string) NormalizedName { + if f.normalizeNameFunc != nil { + return f.normalizeNameFunc + } + return func(f *FlagSet, name string) NormalizedName { return NormalizedName(name) } +} + +func (f *FlagSet) normalizeFlagName(name string) NormalizedName { + n := f.GetNormalizeFunc() + return n(f, name) +} + +func (f *FlagSet) out() io.Writer { + if f.output == nil { + return os.Stderr + } + return f.output +} + +// SetOutput sets the destination for usage and error messages. +// If output is nil, os.Stderr is used. +func (f *FlagSet) SetOutput(output io.Writer) { + f.output = output +} + +// VisitAll visits the flags in lexicographical order or +// in primordial order if f.SortFlags is false, calling fn for each. +// It visits all flags, even those not set. +func (f *FlagSet) VisitAll(fn func(*Flag)) { + if len(f.formal) == 0 { + return + } + + var flags []*Flag + if f.SortFlags { + if len(f.formal) != len(f.sortedFormal) { + f.sortedFormal = sortFlags(f.formal) + } + flags = f.sortedFormal + } else { + flags = f.orderedFormal + } + + for _, flag := range flags { + fn(flag) + } +} + +// HasFlags returns a bool to indicate if the FlagSet has any flags definied. +func (f *FlagSet) HasFlags() bool { + return len(f.formal) > 0 +} + +// HasAvailableFlags returns a bool to indicate if the FlagSet has any flags +// definied that are not hidden or deprecated. +func (f *FlagSet) HasAvailableFlags() bool { + for _, flag := range f.formal { + if !flag.Hidden && len(flag.Deprecated) == 0 { + return true + } + } + return false +} + +// VisitAll visits the command-line flags in lexicographical order or +// in primordial order if f.SortFlags is false, calling fn for each. +// It visits all flags, even those not set. +func VisitAll(fn func(*Flag)) { + CommandLine.VisitAll(fn) +} + +// Visit visits the flags in lexicographical order or +// in primordial order if f.SortFlags is false, calling fn for each. +// It visits only those flags that have been set. +func (f *FlagSet) Visit(fn func(*Flag)) { + if len(f.actual) == 0 { + return + } + + var flags []*Flag + if f.SortFlags { + if len(f.actual) != len(f.sortedActual) { + f.sortedActual = sortFlags(f.actual) + } + flags = f.sortedActual + } else { + flags = f.orderedActual + } + + for _, flag := range flags { + fn(flag) + } +} + +// Visit visits the command-line flags in lexicographical order or +// in primordial order if f.SortFlags is false, calling fn for each. +// It visits only those flags that have been set. +func Visit(fn func(*Flag)) { + CommandLine.Visit(fn) +} + +// Lookup returns the Flag structure of the named flag, returning nil if none exists. +func (f *FlagSet) Lookup(name string) *Flag { + return f.lookup(f.normalizeFlagName(name)) +} + +// ShorthandLookup returns the Flag structure of the short handed flag, +// returning nil if none exists. +// It panics, if len(name) > 1. +func (f *FlagSet) ShorthandLookup(name string) *Flag { + if name == "" { + return nil + } + if len(name) > 1 { + msg := fmt.Sprintf("can not look up shorthand which is more than one ASCII character: %q", name) + fmt.Fprintf(f.out(), msg) + panic(msg) + } + c := name[0] + return f.shorthands[c] +} + +// lookup returns the Flag structure of the named flag, returning nil if none exists. +func (f *FlagSet) lookup(name NormalizedName) *Flag { + return f.formal[name] +} + +// func to return a given type for a given flag name +func (f *FlagSet) getFlagType(name string, ftype string, convFunc func(sval string) (interface{}, error)) (interface{}, error) { + flag := f.Lookup(name) + if flag == nil { + err := fmt.Errorf("flag accessed but not defined: %s", name) + return nil, err + } + + if flag.Value.Type() != ftype { + err := fmt.Errorf("trying to get %s value of flag of type %s", ftype, flag.Value.Type()) + return nil, err + } + + sval := flag.Value.String() + result, err := convFunc(sval) + if err != nil { + return nil, err + } + return result, nil +} + +// ArgsLenAtDash will return the length of f.Args at the moment when a -- was +// found during arg parsing. This allows your program to know which args were +// before the -- and which came after. +func (f *FlagSet) ArgsLenAtDash() int { + return f.argsLenAtDash +} + +// MarkDeprecated indicated that a flag is deprecated in your program. It will +// continue to function but will not show up in help or usage messages. Using +// this flag will also print the given usageMessage. +func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error { + flag := f.Lookup(name) + if flag == nil { + return fmt.Errorf("flag %q does not exist", name) + } + if usageMessage == "" { + return fmt.Errorf("deprecated message for flag %q must be set", name) + } + flag.Deprecated = usageMessage + return nil +} + +// MarkShorthandDeprecated will mark the shorthand of a flag deprecated in your +// program. It will continue to function but will not show up in help or usage +// messages. Using this flag will also print the given usageMessage. +func (f *FlagSet) MarkShorthandDeprecated(name string, usageMessage string) error { + flag := f.Lookup(name) + if flag == nil { + return fmt.Errorf("flag %q does not exist", name) + } + if usageMessage == "" { + return fmt.Errorf("deprecated message for flag %q must be set", name) + } + flag.ShorthandDeprecated = usageMessage + return nil +} + +// MarkHidden sets a flag to 'hidden' in your program. It will continue to +// function but will not show up in help or usage messages. +func (f *FlagSet) MarkHidden(name string) error { + flag := f.Lookup(name) + if flag == nil { + return fmt.Errorf("flag %q does not exist", name) + } + flag.Hidden = true + return nil +} + +// Lookup returns the Flag structure of the named command-line flag, +// returning nil if none exists. +func Lookup(name string) *Flag { + return CommandLine.Lookup(name) +} + +// ShorthandLookup returns the Flag structure of the short handed flag, +// returning nil if none exists. +func ShorthandLookup(name string) *Flag { + return CommandLine.ShorthandLookup(name) +} + +// Set sets the value of the named flag. +func (f *FlagSet) Set(name, value string) error { + normalName := f.normalizeFlagName(name) + flag, ok := f.formal[normalName] + if !ok { + return fmt.Errorf("no such flag -%v", name) + } + + err := flag.Value.Set(value) + if err != nil { + var flagName string + if flag.Shorthand != "" && flag.ShorthandDeprecated == "" { + flagName = fmt.Sprintf("-%s, --%s", flag.Shorthand, flag.Name) + } else { + flagName = fmt.Sprintf("--%s", flag.Name) + } + return fmt.Errorf("invalid argument %q for %q flag: %v", value, flagName, err) + } + + if f.actual == nil { + f.actual = make(map[NormalizedName]*Flag) + } + f.actual[normalName] = flag + f.orderedActual = append(f.orderedActual, flag) + + flag.Changed = true + + if flag.Deprecated != "" { + fmt.Fprintf(f.out(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated) + } + return nil +} + +// SetAnnotation allows one to set arbitrary annotations on a flag in the FlagSet. +// This is sometimes used by spf13/cobra programs which want to generate additional +// bash completion information. +func (f *FlagSet) SetAnnotation(name, key string, values []string) error { + normalName := f.normalizeFlagName(name) + flag, ok := f.formal[normalName] + if !ok { + return fmt.Errorf("no such flag -%v", name) + } + if flag.Annotations == nil { + flag.Annotations = map[string][]string{} + } + flag.Annotations[key] = values + return nil +} + +// Changed returns true if the flag was explicitly set during Parse() and false +// otherwise +func (f *FlagSet) Changed(name string) bool { + flag := f.Lookup(name) + // If a flag doesn't exist, it wasn't changed.... + if flag == nil { + return false + } + return flag.Changed +} + +// Set sets the value of the named command-line flag. +func Set(name, value string) error { + return CommandLine.Set(name, value) +} + +// PrintDefaults prints, to standard error unless configured +// otherwise, the default values of all defined flags in the set. +func (f *FlagSet) PrintDefaults() { + usages := f.FlagUsages() + fmt.Fprint(f.out(), usages) +} + +// defaultIsZeroValue returns true if the default value for this flag represents +// a zero value. +func (f *Flag) defaultIsZeroValue() bool { + switch f.Value.(type) { + case boolFlag: + return f.DefValue == "false" + case *durationValue: + // Beginning in Go 1.7, duration zero values are "0s" + return f.DefValue == "0" || f.DefValue == "0s" + case *intValue, *int8Value, *int32Value, *int64Value, *uintValue, *uint8Value, *uint16Value, *uint32Value, *uint64Value, *countValue, *float32Value, *float64Value: + return f.DefValue == "0" + case *stringValue: + return f.DefValue == "" + case *ipValue, *ipMaskValue, *ipNetValue: + return f.DefValue == "" + case *intSliceValue, *stringSliceValue, *stringArrayValue: + return f.DefValue == "[]" + default: + switch f.Value.String() { + case "false": + return true + case "": + return true + case "": + return true + case "0": + return true + } + return false + } +} + +// UnquoteUsage extracts a back-quoted name from the usage +// string for a flag and returns it and the un-quoted usage. +// Given "a `name` to show" it returns ("name", "a name to show"). +// If there are no back quotes, the name is an educated guess of the +// type of the flag's value, or the empty string if the flag is boolean. +func UnquoteUsage(flag *Flag) (name string, usage string) { + // Look for a back-quoted name, but avoid the strings package. + usage = flag.Usage + for i := 0; i < len(usage); i++ { + if usage[i] == '`' { + for j := i + 1; j < len(usage); j++ { + if usage[j] == '`' { + name = usage[i+1 : j] + usage = usage[:i] + name + usage[j+1:] + return name, usage + } + } + break // Only one back quote; use type name. + } + } + + name = flag.Value.Type() + switch name { + case "bool": + name = "" + case "float64": + name = "float" + case "int64": + name = "int" + case "uint64": + name = "uint" + } + + return +} + +// Splits the string `s` on whitespace into an initial substring up to +// `i` runes in length and the remainder. Will go `slop` over `i` if +// that encompasses the entire string (which allows the caller to +// avoid short orphan words on the final line). +func wrapN(i, slop int, s string) (string, string) { + if i+slop > len(s) { + return s, "" + } + + w := strings.LastIndexAny(s[:i], " \t") + if w <= 0 { + return s, "" + } + + return s[:w], s[w+1:] +} + +// Wraps the string `s` to a maximum width `w` with leading indent +// `i`. The first line is not indented (this is assumed to be done by +// caller). Pass `w` == 0 to do no wrapping +func wrap(i, w int, s string) string { + if w == 0 { + return s + } + + // space between indent i and end of line width w into which + // we should wrap the text. + wrap := w - i + + var r, l string + + // Not enough space for sensible wrapping. Wrap as a block on + // the next line instead. + if wrap < 24 { + i = 16 + wrap = w - i + r += "\n" + strings.Repeat(" ", i) + } + // If still not enough space then don't even try to wrap. + if wrap < 24 { + return s + } + + // Try to avoid short orphan words on the final line, by + // allowing wrapN to go a bit over if that would fit in the + // remainder of the line. + slop := 5 + wrap = wrap - slop + + // Handle first line, which is indented by the caller (or the + // special case above) + l, s = wrapN(wrap, slop, s) + r = r + l + + // Now wrap the rest + for s != "" { + var t string + + t, s = wrapN(wrap, slop, s) + r = r + "\n" + strings.Repeat(" ", i) + t + } + + return r + +} + +// FlagUsagesWrapped returns a string containing the usage information +// for all flags in the FlagSet. Wrapped to `cols` columns (0 for no +// wrapping) +func (f *FlagSet) FlagUsagesWrapped(cols int) string { + buf := new(bytes.Buffer) + + lines := make([]string, 0, len(f.formal)) + + maxlen := 0 + f.VisitAll(func(flag *Flag) { + if flag.Deprecated != "" || flag.Hidden { + return + } + + line := "" + if flag.Shorthand != "" && flag.ShorthandDeprecated == "" { + line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name) + } else { + line = fmt.Sprintf(" --%s", flag.Name) + } + + varname, usage := UnquoteUsage(flag) + if varname != "" { + line += " " + varname + } + if flag.NoOptDefVal != "" { + switch flag.Value.Type() { + case "string": + line += fmt.Sprintf("[=\"%s\"]", flag.NoOptDefVal) + case "bool": + if flag.NoOptDefVal != "true" { + line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) + } + default: + line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) + } + } + + // This special character will be replaced with spacing once the + // correct alignment is calculated + line += "\x00" + if len(line) > maxlen { + maxlen = len(line) + } + + line += usage + if !flag.defaultIsZeroValue() { + if flag.Value.Type() == "string" { + line += fmt.Sprintf(" (default %q)", flag.DefValue) + } else { + line += fmt.Sprintf(" (default %s)", flag.DefValue) + } + } + + lines = append(lines, line) + }) + + for _, line := range lines { + sidx := strings.Index(line, "\x00") + spacing := strings.Repeat(" ", maxlen-sidx) + // maxlen + 2 comes from + 1 for the \x00 and + 1 for the (deliberate) off-by-one in maxlen-sidx + fmt.Fprintln(buf, line[:sidx], spacing, wrap(maxlen+2, cols, line[sidx+1:])) + } + + return buf.String() +} + +// FlagUsages returns a string containing the usage information for all flags in +// the FlagSet +func (f *FlagSet) FlagUsages() string { + return f.FlagUsagesWrapped(0) +} + +// PrintDefaults prints to standard error the default values of all defined command-line flags. +func PrintDefaults() { + CommandLine.PrintDefaults() +} + +// defaultUsage is the default function to print a usage message. +func defaultUsage(f *FlagSet) { + fmt.Fprintf(f.out(), "Usage of %s:\n", f.name) + f.PrintDefaults() +} + +// NOTE: Usage is not just defaultUsage(CommandLine) +// because it serves (via godoc flag Usage) as the example +// for how to write your own usage function. + +// Usage prints to standard error a usage message documenting all defined command-line flags. +// The function is a variable that may be changed to point to a custom function. +// By default it prints a simple header and calls PrintDefaults; for details about the +// format of the output and how to control it, see the documentation for PrintDefaults. +var Usage = func() { + fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) + PrintDefaults() +} + +// NFlag returns the number of flags that have been set. +func (f *FlagSet) NFlag() int { return len(f.actual) } + +// NFlag returns the number of command-line flags that have been set. +func NFlag() int { return len(CommandLine.actual) } + +// Arg returns the i'th argument. Arg(0) is the first remaining argument +// after flags have been processed. +func (f *FlagSet) Arg(i int) string { + if i < 0 || i >= len(f.args) { + return "" + } + return f.args[i] +} + +// Arg returns the i'th command-line argument. Arg(0) is the first remaining argument +// after flags have been processed. +func Arg(i int) string { + return CommandLine.Arg(i) +} + +// NArg is the number of arguments remaining after flags have been processed. +func (f *FlagSet) NArg() int { return len(f.args) } + +// NArg is the number of arguments remaining after flags have been processed. +func NArg() int { return len(CommandLine.args) } + +// Args returns the non-flag arguments. +func (f *FlagSet) Args() []string { return f.args } + +// Args returns the non-flag command-line arguments. +func Args() []string { return CommandLine.args } + +// Var defines a flag with the specified name and usage string. The type and +// value of the flag are represented by the first argument, of type Value, which +// typically holds a user-defined implementation of Value. For instance, the +// caller could create a flag that turns a comma-separated string into a slice +// of strings by giving the slice the methods of Value; in particular, Set would +// decompose the comma-separated string into the slice. +func (f *FlagSet) Var(value Value, name string, usage string) { + f.VarP(value, name, "", usage) +} + +// VarPF is like VarP, but returns the flag created +func (f *FlagSet) VarPF(value Value, name, shorthand, usage string) *Flag { + // Remember the default value as a string; it won't change. + flag := &Flag{ + Name: name, + Shorthand: shorthand, + Usage: usage, + Value: value, + DefValue: value.String(), + } + f.AddFlag(flag) + return flag +} + +// VarP is like Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) VarP(value Value, name, shorthand, usage string) { + f.VarPF(value, name, shorthand, usage) +} + +// AddFlag will add the flag to the FlagSet +func (f *FlagSet) AddFlag(flag *Flag) { + normalizedFlagName := f.normalizeFlagName(flag.Name) + + _, alreadyThere := f.formal[normalizedFlagName] + if alreadyThere { + msg := fmt.Sprintf("%s flag redefined: %s", f.name, flag.Name) + fmt.Fprintln(f.out(), msg) + panic(msg) // Happens only if flags are declared with identical names + } + if f.formal == nil { + f.formal = make(map[NormalizedName]*Flag) + } + + flag.Name = string(normalizedFlagName) + f.formal[normalizedFlagName] = flag + f.orderedFormal = append(f.orderedFormal, flag) + + if flag.Shorthand == "" { + return + } + if len(flag.Shorthand) > 1 { + msg := fmt.Sprintf("%q shorthand is more than one ASCII character", flag.Shorthand) + fmt.Fprintf(f.out(), msg) + panic(msg) + } + if f.shorthands == nil { + f.shorthands = make(map[byte]*Flag) + } + c := flag.Shorthand[0] + used, alreadyThere := f.shorthands[c] + if alreadyThere { + msg := fmt.Sprintf("unable to redefine %q shorthand in %q flagset: it's already used for %q flag", c, f.name, used.Name) + fmt.Fprintf(f.out(), msg) + panic(msg) + } + f.shorthands[c] = flag +} + +// AddFlagSet adds one FlagSet to another. If a flag is already present in f +// the flag from newSet will be ignored. +func (f *FlagSet) AddFlagSet(newSet *FlagSet) { + if newSet == nil { + return + } + newSet.VisitAll(func(flag *Flag) { + if f.Lookup(flag.Name) == nil { + f.AddFlag(flag) + } + }) +} + +// Var defines a flag with the specified name and usage string. The type and +// value of the flag are represented by the first argument, of type Value, which +// typically holds a user-defined implementation of Value. For instance, the +// caller could create a flag that turns a comma-separated string into a slice +// of strings by giving the slice the methods of Value; in particular, Set would +// decompose the comma-separated string into the slice. +func Var(value Value, name string, usage string) { + CommandLine.VarP(value, name, "", usage) +} + +// VarP is like Var, but accepts a shorthand letter that can be used after a single dash. +func VarP(value Value, name, shorthand, usage string) { + CommandLine.VarP(value, name, shorthand, usage) +} + +// failf prints to standard error a formatted error and usage message and +// returns the error. +func (f *FlagSet) failf(format string, a ...interface{}) error { + err := fmt.Errorf(format, a...) + fmt.Fprintln(f.out(), err) + f.usage() + return err +} + +// usage calls the Usage method for the flag set, or the usage function if +// the flag set is CommandLine. +func (f *FlagSet) usage() { + if f == CommandLine { + Usage() + } else if f.Usage == nil { + defaultUsage(f) + } else { + f.Usage() + } +} + +func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []string, err error) { + a = args + name := s[2:] + if len(name) == 0 || name[0] == '-' || name[0] == '=' { + err = f.failf("bad flag syntax: %s", s) + return + } + + split := strings.SplitN(name, "=", 2) + name = split[0] + flag, exists := f.formal[f.normalizeFlagName(name)] + if !exists { + if name == "help" { // special case for nice help message. + f.usage() + return a, ErrHelp + } + err = f.failf("unknown flag: --%s", name) + return + } + + var value string + if len(split) == 2 { + // '--flag=arg' + value = split[1] + } else if flag.NoOptDefVal != "" { + // '--flag' (arg was optional) + value = flag.NoOptDefVal + } else if len(a) > 0 { + // '--flag arg' + value = a[0] + a = a[1:] + } else { + // '--flag' (arg was required) + err = f.failf("flag needs an argument: %s", s) + return + } + + err = fn(flag, value) + return +} + +func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parseFunc) (outShorts string, outArgs []string, err error) { + if strings.HasPrefix(shorthands, "test.") { + return + } + + outArgs = args + outShorts = shorthands[1:] + c := shorthands[0] + + flag, exists := f.shorthands[c] + if !exists { + if c == 'h' { // special case for nice help message. + f.usage() + err = ErrHelp + return + } + err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands) + return + } + + var value string + if len(shorthands) > 2 && shorthands[1] == '=' { + // '-f=arg' + value = shorthands[2:] + outShorts = "" + } else if flag.NoOptDefVal != "" { + // '-f' (arg was optional) + value = flag.NoOptDefVal + } else if len(shorthands) > 1 { + // '-farg' + value = shorthands[1:] + outShorts = "" + } else if len(args) > 0 { + // '-f arg' + value = args[0] + outArgs = args[1:] + } else { + // '-f' (arg was required) + err = f.failf("flag needs an argument: %q in -%s", c, shorthands) + return + } + + if flag.ShorthandDeprecated != "" { + fmt.Fprintf(f.out(), "Flag shorthand -%s has been deprecated, %s\n", flag.Shorthand, flag.ShorthandDeprecated) + } + + err = fn(flag, value) + return +} + +func (f *FlagSet) parseShortArg(s string, args []string, fn parseFunc) (a []string, err error) { + a = args + shorthands := s[1:] + + // "shorthands" can be a series of shorthand letters of flags (e.g. "-vvv"). + for len(shorthands) > 0 { + shorthands, a, err = f.parseSingleShortArg(shorthands, args, fn) + if err != nil { + return + } + } + + return +} + +func (f *FlagSet) parseArgs(args []string, fn parseFunc) (err error) { + for len(args) > 0 { + s := args[0] + args = args[1:] + if len(s) == 0 || s[0] != '-' || len(s) == 1 { + if !f.interspersed { + f.args = append(f.args, s) + f.args = append(f.args, args...) + return nil + } + f.args = append(f.args, s) + continue + } + + if s[1] == '-' { + if len(s) == 2 { // "--" terminates the flags + f.argsLenAtDash = len(f.args) + f.args = append(f.args, args...) + break + } + args, err = f.parseLongArg(s, args, fn) + } else { + args, err = f.parseShortArg(s, args, fn) + } + if err != nil { + return + } + } + return +} + +// Parse parses flag definitions from the argument list, which should not +// include the command name. Must be called after all flags in the FlagSet +// are defined and before flags are accessed by the program. +// The return value will be ErrHelp if -help was set but not defined. +func (f *FlagSet) Parse(arguments []string) error { + f.parsed = true + + if len(arguments) < 0 { + return nil + } + + f.args = make([]string, 0, len(arguments)) + + set := func(flag *Flag, value string) error { + return f.Set(flag.Name, value) + } + + err := f.parseArgs(arguments, set) + if err != nil { + switch f.errorHandling { + case ContinueOnError: + return err + case ExitOnError: + os.Exit(2) + case PanicOnError: + panic(err) + } + } + return nil +} + +type parseFunc func(flag *Flag, value string) error + +// ParseAll parses flag definitions from the argument list, which should not +// include the command name. The arguments for fn are flag and value. Must be +// called after all flags in the FlagSet are defined and before flags are +// accessed by the program. The return value will be ErrHelp if -help was set +// but not defined. +func (f *FlagSet) ParseAll(arguments []string, fn func(flag *Flag, value string) error) error { + f.parsed = true + f.args = make([]string, 0, len(arguments)) + + err := f.parseArgs(arguments, fn) + if err != nil { + switch f.errorHandling { + case ContinueOnError: + return err + case ExitOnError: + os.Exit(2) + case PanicOnError: + panic(err) + } + } + return nil +} + +// Parsed reports whether f.Parse has been called. +func (f *FlagSet) Parsed() bool { + return f.parsed +} + +// Parse parses the command-line flags from os.Args[1:]. Must be called +// after all flags are defined and before flags are accessed by the program. +func Parse() { + // Ignore errors; CommandLine is set for ExitOnError. + CommandLine.Parse(os.Args[1:]) +} + +// ParseAll parses the command-line flags from os.Args[1:] and called fn for each. +// The arguments for fn are flag and value. Must be called after all flags are +// defined and before flags are accessed by the program. +func ParseAll(fn func(flag *Flag, value string) error) { + // Ignore errors; CommandLine is set for ExitOnError. + CommandLine.ParseAll(os.Args[1:], fn) +} + +// SetInterspersed sets whether to support interspersed option/non-option arguments. +func SetInterspersed(interspersed bool) { + CommandLine.SetInterspersed(interspersed) +} + +// Parsed returns true if the command-line flags have been parsed. +func Parsed() bool { + return CommandLine.Parsed() +} + +// CommandLine is the default set of command-line flags, parsed from os.Args. +var CommandLine = NewFlagSet(os.Args[0], ExitOnError) + +// NewFlagSet returns a new, empty flag set with the specified name, +// error handling property and SortFlags set to true. +func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet { + f := &FlagSet{ + name: name, + errorHandling: errorHandling, + argsLenAtDash: -1, + interspersed: true, + SortFlags: true, + } + return f +} + +// SetInterspersed sets whether to support interspersed option/non-option arguments. +func (f *FlagSet) SetInterspersed(interspersed bool) { + f.interspersed = interspersed +} + +// Init sets the name and error handling property for a flag set. +// By default, the zero FlagSet uses an empty name and the +// ContinueOnError error handling policy. +func (f *FlagSet) Init(name string, errorHandling ErrorHandling) { + f.name = name + f.errorHandling = errorHandling + f.argsLenAtDash = -1 +} diff --git a/vendor/github.com/spf13/pflag/float32.go b/vendor/github.com/spf13/pflag/float32.go new file mode 100644 index 00000000..a243f81f --- /dev/null +++ b/vendor/github.com/spf13/pflag/float32.go @@ -0,0 +1,88 @@ +package pflag + +import "strconv" + +// -- float32 Value +type float32Value float32 + +func newFloat32Value(val float32, p *float32) *float32Value { + *p = val + return (*float32Value)(p) +} + +func (f *float32Value) Set(s string) error { + v, err := strconv.ParseFloat(s, 32) + *f = float32Value(v) + return err +} + +func (f *float32Value) Type() string { + return "float32" +} + +func (f *float32Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 32) } + +func float32Conv(sval string) (interface{}, error) { + v, err := strconv.ParseFloat(sval, 32) + if err != nil { + return 0, err + } + return float32(v), nil +} + +// GetFloat32 return the float32 value of a flag with the given name +func (f *FlagSet) GetFloat32(name string) (float32, error) { + val, err := f.getFlagType(name, "float32", float32Conv) + if err != nil { + return 0, err + } + return val.(float32), nil +} + +// Float32Var defines a float32 flag with specified name, default value, and usage string. +// The argument p points to a float32 variable in which to store the value of the flag. +func (f *FlagSet) Float32Var(p *float32, name string, value float32, usage string) { + f.VarP(newFloat32Value(value, p), name, "", usage) +} + +// Float32VarP is like Float32Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Float32VarP(p *float32, name, shorthand string, value float32, usage string) { + f.VarP(newFloat32Value(value, p), name, shorthand, usage) +} + +// Float32Var defines a float32 flag with specified name, default value, and usage string. +// The argument p points to a float32 variable in which to store the value of the flag. +func Float32Var(p *float32, name string, value float32, usage string) { + CommandLine.VarP(newFloat32Value(value, p), name, "", usage) +} + +// Float32VarP is like Float32Var, but accepts a shorthand letter that can be used after a single dash. +func Float32VarP(p *float32, name, shorthand string, value float32, usage string) { + CommandLine.VarP(newFloat32Value(value, p), name, shorthand, usage) +} + +// Float32 defines a float32 flag with specified name, default value, and usage string. +// The return value is the address of a float32 variable that stores the value of the flag. +func (f *FlagSet) Float32(name string, value float32, usage string) *float32 { + p := new(float32) + f.Float32VarP(p, name, "", value, usage) + return p +} + +// Float32P is like Float32, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Float32P(name, shorthand string, value float32, usage string) *float32 { + p := new(float32) + f.Float32VarP(p, name, shorthand, value, usage) + return p +} + +// Float32 defines a float32 flag with specified name, default value, and usage string. +// The return value is the address of a float32 variable that stores the value of the flag. +func Float32(name string, value float32, usage string) *float32 { + return CommandLine.Float32P(name, "", value, usage) +} + +// Float32P is like Float32, but accepts a shorthand letter that can be used after a single dash. +func Float32P(name, shorthand string, value float32, usage string) *float32 { + return CommandLine.Float32P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/float64.go b/vendor/github.com/spf13/pflag/float64.go new file mode 100644 index 00000000..04b5492a --- /dev/null +++ b/vendor/github.com/spf13/pflag/float64.go @@ -0,0 +1,84 @@ +package pflag + +import "strconv" + +// -- float64 Value +type float64Value float64 + +func newFloat64Value(val float64, p *float64) *float64Value { + *p = val + return (*float64Value)(p) +} + +func (f *float64Value) Set(s string) error { + v, err := strconv.ParseFloat(s, 64) + *f = float64Value(v) + return err +} + +func (f *float64Value) Type() string { + return "float64" +} + +func (f *float64Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 64) } + +func float64Conv(sval string) (interface{}, error) { + return strconv.ParseFloat(sval, 64) +} + +// GetFloat64 return the float64 value of a flag with the given name +func (f *FlagSet) GetFloat64(name string) (float64, error) { + val, err := f.getFlagType(name, "float64", float64Conv) + if err != nil { + return 0, err + } + return val.(float64), nil +} + +// Float64Var defines a float64 flag with specified name, default value, and usage string. +// The argument p points to a float64 variable in which to store the value of the flag. +func (f *FlagSet) Float64Var(p *float64, name string, value float64, usage string) { + f.VarP(newFloat64Value(value, p), name, "", usage) +} + +// Float64VarP is like Float64Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Float64VarP(p *float64, name, shorthand string, value float64, usage string) { + f.VarP(newFloat64Value(value, p), name, shorthand, usage) +} + +// Float64Var defines a float64 flag with specified name, default value, and usage string. +// The argument p points to a float64 variable in which to store the value of the flag. +func Float64Var(p *float64, name string, value float64, usage string) { + CommandLine.VarP(newFloat64Value(value, p), name, "", usage) +} + +// Float64VarP is like Float64Var, but accepts a shorthand letter that can be used after a single dash. +func Float64VarP(p *float64, name, shorthand string, value float64, usage string) { + CommandLine.VarP(newFloat64Value(value, p), name, shorthand, usage) +} + +// Float64 defines a float64 flag with specified name, default value, and usage string. +// The return value is the address of a float64 variable that stores the value of the flag. +func (f *FlagSet) Float64(name string, value float64, usage string) *float64 { + p := new(float64) + f.Float64VarP(p, name, "", value, usage) + return p +} + +// Float64P is like Float64, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Float64P(name, shorthand string, value float64, usage string) *float64 { + p := new(float64) + f.Float64VarP(p, name, shorthand, value, usage) + return p +} + +// Float64 defines a float64 flag with specified name, default value, and usage string. +// The return value is the address of a float64 variable that stores the value of the flag. +func Float64(name string, value float64, usage string) *float64 { + return CommandLine.Float64P(name, "", value, usage) +} + +// Float64P is like Float64, but accepts a shorthand letter that can be used after a single dash. +func Float64P(name, shorthand string, value float64, usage string) *float64 { + return CommandLine.Float64P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/golangflag.go b/vendor/github.com/spf13/pflag/golangflag.go new file mode 100644 index 00000000..c4f47ebe --- /dev/null +++ b/vendor/github.com/spf13/pflag/golangflag.go @@ -0,0 +1,101 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pflag + +import ( + goflag "flag" + "reflect" + "strings" +) + +// flagValueWrapper implements pflag.Value around a flag.Value. The main +// difference here is the addition of the Type method that returns a string +// name of the type. As this is generally unknown, we approximate that with +// reflection. +type flagValueWrapper struct { + inner goflag.Value + flagType string +} + +// We are just copying the boolFlag interface out of goflag as that is what +// they use to decide if a flag should get "true" when no arg is given. +type goBoolFlag interface { + goflag.Value + IsBoolFlag() bool +} + +func wrapFlagValue(v goflag.Value) Value { + // If the flag.Value happens to also be a pflag.Value, just use it directly. + if pv, ok := v.(Value); ok { + return pv + } + + pv := &flagValueWrapper{ + inner: v, + } + + t := reflect.TypeOf(v) + if t.Kind() == reflect.Interface || t.Kind() == reflect.Ptr { + t = t.Elem() + } + + pv.flagType = strings.TrimSuffix(t.Name(), "Value") + return pv +} + +func (v *flagValueWrapper) String() string { + return v.inner.String() +} + +func (v *flagValueWrapper) Set(s string) error { + return v.inner.Set(s) +} + +func (v *flagValueWrapper) Type() string { + return v.flagType +} + +// PFlagFromGoFlag will return a *pflag.Flag given a *flag.Flag +// If the *flag.Flag.Name was a single character (ex: `v`) it will be accessiblei +// with both `-v` and `--v` in flags. If the golang flag was more than a single +// character (ex: `verbose`) it will only be accessible via `--verbose` +func PFlagFromGoFlag(goflag *goflag.Flag) *Flag { + // Remember the default value as a string; it won't change. + flag := &Flag{ + Name: goflag.Name, + Usage: goflag.Usage, + Value: wrapFlagValue(goflag.Value), + // Looks like golang flags don't set DefValue correctly :-( + //DefValue: goflag.DefValue, + DefValue: goflag.Value.String(), + } + // Ex: if the golang flag was -v, allow both -v and --v to work + if len(flag.Name) == 1 { + flag.Shorthand = flag.Name + } + if fv, ok := goflag.Value.(goBoolFlag); ok && fv.IsBoolFlag() { + flag.NoOptDefVal = "true" + } + return flag +} + +// AddGoFlag will add the given *flag.Flag to the pflag.FlagSet +func (f *FlagSet) AddGoFlag(goflag *goflag.Flag) { + if f.Lookup(goflag.Name) != nil { + return + } + newflag := PFlagFromGoFlag(goflag) + f.AddFlag(newflag) +} + +// AddGoFlagSet will add the given *flag.FlagSet to the pflag.FlagSet +func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet) { + if newSet == nil { + return + } + newSet.VisitAll(func(goflag *goflag.Flag) { + f.AddGoFlag(goflag) + }) +} diff --git a/vendor/github.com/spf13/pflag/int.go b/vendor/github.com/spf13/pflag/int.go new file mode 100644 index 00000000..1474b89d --- /dev/null +++ b/vendor/github.com/spf13/pflag/int.go @@ -0,0 +1,84 @@ +package pflag + +import "strconv" + +// -- int Value +type intValue int + +func newIntValue(val int, p *int) *intValue { + *p = val + return (*intValue)(p) +} + +func (i *intValue) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 64) + *i = intValue(v) + return err +} + +func (i *intValue) Type() string { + return "int" +} + +func (i *intValue) String() string { return strconv.Itoa(int(*i)) } + +func intConv(sval string) (interface{}, error) { + return strconv.Atoi(sval) +} + +// GetInt return the int value of a flag with the given name +func (f *FlagSet) GetInt(name string) (int, error) { + val, err := f.getFlagType(name, "int", intConv) + if err != nil { + return 0, err + } + return val.(int), nil +} + +// IntVar defines an int flag with specified name, default value, and usage string. +// The argument p points to an int variable in which to store the value of the flag. +func (f *FlagSet) IntVar(p *int, name string, value int, usage string) { + f.VarP(newIntValue(value, p), name, "", usage) +} + +// IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IntVarP(p *int, name, shorthand string, value int, usage string) { + f.VarP(newIntValue(value, p), name, shorthand, usage) +} + +// IntVar defines an int flag with specified name, default value, and usage string. +// The argument p points to an int variable in which to store the value of the flag. +func IntVar(p *int, name string, value int, usage string) { + CommandLine.VarP(newIntValue(value, p), name, "", usage) +} + +// IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash. +func IntVarP(p *int, name, shorthand string, value int, usage string) { + CommandLine.VarP(newIntValue(value, p), name, shorthand, usage) +} + +// Int defines an int flag with specified name, default value, and usage string. +// The return value is the address of an int variable that stores the value of the flag. +func (f *FlagSet) Int(name string, value int, usage string) *int { + p := new(int) + f.IntVarP(p, name, "", value, usage) + return p +} + +// IntP is like Int, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IntP(name, shorthand string, value int, usage string) *int { + p := new(int) + f.IntVarP(p, name, shorthand, value, usage) + return p +} + +// Int defines an int flag with specified name, default value, and usage string. +// The return value is the address of an int variable that stores the value of the flag. +func Int(name string, value int, usage string) *int { + return CommandLine.IntP(name, "", value, usage) +} + +// IntP is like Int, but accepts a shorthand letter that can be used after a single dash. +func IntP(name, shorthand string, value int, usage string) *int { + return CommandLine.IntP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/int32.go b/vendor/github.com/spf13/pflag/int32.go new file mode 100644 index 00000000..9b95944f --- /dev/null +++ b/vendor/github.com/spf13/pflag/int32.go @@ -0,0 +1,88 @@ +package pflag + +import "strconv" + +// -- int32 Value +type int32Value int32 + +func newInt32Value(val int32, p *int32) *int32Value { + *p = val + return (*int32Value)(p) +} + +func (i *int32Value) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 32) + *i = int32Value(v) + return err +} + +func (i *int32Value) Type() string { + return "int32" +} + +func (i *int32Value) String() string { return strconv.FormatInt(int64(*i), 10) } + +func int32Conv(sval string) (interface{}, error) { + v, err := strconv.ParseInt(sval, 0, 32) + if err != nil { + return 0, err + } + return int32(v), nil +} + +// GetInt32 return the int32 value of a flag with the given name +func (f *FlagSet) GetInt32(name string) (int32, error) { + val, err := f.getFlagType(name, "int32", int32Conv) + if err != nil { + return 0, err + } + return val.(int32), nil +} + +// Int32Var defines an int32 flag with specified name, default value, and usage string. +// The argument p points to an int32 variable in which to store the value of the flag. +func (f *FlagSet) Int32Var(p *int32, name string, value int32, usage string) { + f.VarP(newInt32Value(value, p), name, "", usage) +} + +// Int32VarP is like Int32Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Int32VarP(p *int32, name, shorthand string, value int32, usage string) { + f.VarP(newInt32Value(value, p), name, shorthand, usage) +} + +// Int32Var defines an int32 flag with specified name, default value, and usage string. +// The argument p points to an int32 variable in which to store the value of the flag. +func Int32Var(p *int32, name string, value int32, usage string) { + CommandLine.VarP(newInt32Value(value, p), name, "", usage) +} + +// Int32VarP is like Int32Var, but accepts a shorthand letter that can be used after a single dash. +func Int32VarP(p *int32, name, shorthand string, value int32, usage string) { + CommandLine.VarP(newInt32Value(value, p), name, shorthand, usage) +} + +// Int32 defines an int32 flag with specified name, default value, and usage string. +// The return value is the address of an int32 variable that stores the value of the flag. +func (f *FlagSet) Int32(name string, value int32, usage string) *int32 { + p := new(int32) + f.Int32VarP(p, name, "", value, usage) + return p +} + +// Int32P is like Int32, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Int32P(name, shorthand string, value int32, usage string) *int32 { + p := new(int32) + f.Int32VarP(p, name, shorthand, value, usage) + return p +} + +// Int32 defines an int32 flag with specified name, default value, and usage string. +// The return value is the address of an int32 variable that stores the value of the flag. +func Int32(name string, value int32, usage string) *int32 { + return CommandLine.Int32P(name, "", value, usage) +} + +// Int32P is like Int32, but accepts a shorthand letter that can be used after a single dash. +func Int32P(name, shorthand string, value int32, usage string) *int32 { + return CommandLine.Int32P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/int64.go b/vendor/github.com/spf13/pflag/int64.go new file mode 100644 index 00000000..0026d781 --- /dev/null +++ b/vendor/github.com/spf13/pflag/int64.go @@ -0,0 +1,84 @@ +package pflag + +import "strconv" + +// -- int64 Value +type int64Value int64 + +func newInt64Value(val int64, p *int64) *int64Value { + *p = val + return (*int64Value)(p) +} + +func (i *int64Value) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 64) + *i = int64Value(v) + return err +} + +func (i *int64Value) Type() string { + return "int64" +} + +func (i *int64Value) String() string { return strconv.FormatInt(int64(*i), 10) } + +func int64Conv(sval string) (interface{}, error) { + return strconv.ParseInt(sval, 0, 64) +} + +// GetInt64 return the int64 value of a flag with the given name +func (f *FlagSet) GetInt64(name string) (int64, error) { + val, err := f.getFlagType(name, "int64", int64Conv) + if err != nil { + return 0, err + } + return val.(int64), nil +} + +// Int64Var defines an int64 flag with specified name, default value, and usage string. +// The argument p points to an int64 variable in which to store the value of the flag. +func (f *FlagSet) Int64Var(p *int64, name string, value int64, usage string) { + f.VarP(newInt64Value(value, p), name, "", usage) +} + +// Int64VarP is like Int64Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Int64VarP(p *int64, name, shorthand string, value int64, usage string) { + f.VarP(newInt64Value(value, p), name, shorthand, usage) +} + +// Int64Var defines an int64 flag with specified name, default value, and usage string. +// The argument p points to an int64 variable in which to store the value of the flag. +func Int64Var(p *int64, name string, value int64, usage string) { + CommandLine.VarP(newInt64Value(value, p), name, "", usage) +} + +// Int64VarP is like Int64Var, but accepts a shorthand letter that can be used after a single dash. +func Int64VarP(p *int64, name, shorthand string, value int64, usage string) { + CommandLine.VarP(newInt64Value(value, p), name, shorthand, usage) +} + +// Int64 defines an int64 flag with specified name, default value, and usage string. +// The return value is the address of an int64 variable that stores the value of the flag. +func (f *FlagSet) Int64(name string, value int64, usage string) *int64 { + p := new(int64) + f.Int64VarP(p, name, "", value, usage) + return p +} + +// Int64P is like Int64, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Int64P(name, shorthand string, value int64, usage string) *int64 { + p := new(int64) + f.Int64VarP(p, name, shorthand, value, usage) + return p +} + +// Int64 defines an int64 flag with specified name, default value, and usage string. +// The return value is the address of an int64 variable that stores the value of the flag. +func Int64(name string, value int64, usage string) *int64 { + return CommandLine.Int64P(name, "", value, usage) +} + +// Int64P is like Int64, but accepts a shorthand letter that can be used after a single dash. +func Int64P(name, shorthand string, value int64, usage string) *int64 { + return CommandLine.Int64P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/int8.go b/vendor/github.com/spf13/pflag/int8.go new file mode 100644 index 00000000..4da92228 --- /dev/null +++ b/vendor/github.com/spf13/pflag/int8.go @@ -0,0 +1,88 @@ +package pflag + +import "strconv" + +// -- int8 Value +type int8Value int8 + +func newInt8Value(val int8, p *int8) *int8Value { + *p = val + return (*int8Value)(p) +} + +func (i *int8Value) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 8) + *i = int8Value(v) + return err +} + +func (i *int8Value) Type() string { + return "int8" +} + +func (i *int8Value) String() string { return strconv.FormatInt(int64(*i), 10) } + +func int8Conv(sval string) (interface{}, error) { + v, err := strconv.ParseInt(sval, 0, 8) + if err != nil { + return 0, err + } + return int8(v), nil +} + +// GetInt8 return the int8 value of a flag with the given name +func (f *FlagSet) GetInt8(name string) (int8, error) { + val, err := f.getFlagType(name, "int8", int8Conv) + if err != nil { + return 0, err + } + return val.(int8), nil +} + +// Int8Var defines an int8 flag with specified name, default value, and usage string. +// The argument p points to an int8 variable in which to store the value of the flag. +func (f *FlagSet) Int8Var(p *int8, name string, value int8, usage string) { + f.VarP(newInt8Value(value, p), name, "", usage) +} + +// Int8VarP is like Int8Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Int8VarP(p *int8, name, shorthand string, value int8, usage string) { + f.VarP(newInt8Value(value, p), name, shorthand, usage) +} + +// Int8Var defines an int8 flag with specified name, default value, and usage string. +// The argument p points to an int8 variable in which to store the value of the flag. +func Int8Var(p *int8, name string, value int8, usage string) { + CommandLine.VarP(newInt8Value(value, p), name, "", usage) +} + +// Int8VarP is like Int8Var, but accepts a shorthand letter that can be used after a single dash. +func Int8VarP(p *int8, name, shorthand string, value int8, usage string) { + CommandLine.VarP(newInt8Value(value, p), name, shorthand, usage) +} + +// Int8 defines an int8 flag with specified name, default value, and usage string. +// The return value is the address of an int8 variable that stores the value of the flag. +func (f *FlagSet) Int8(name string, value int8, usage string) *int8 { + p := new(int8) + f.Int8VarP(p, name, "", value, usage) + return p +} + +// Int8P is like Int8, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Int8P(name, shorthand string, value int8, usage string) *int8 { + p := new(int8) + f.Int8VarP(p, name, shorthand, value, usage) + return p +} + +// Int8 defines an int8 flag with specified name, default value, and usage string. +// The return value is the address of an int8 variable that stores the value of the flag. +func Int8(name string, value int8, usage string) *int8 { + return CommandLine.Int8P(name, "", value, usage) +} + +// Int8P is like Int8, but accepts a shorthand letter that can be used after a single dash. +func Int8P(name, shorthand string, value int8, usage string) *int8 { + return CommandLine.Int8P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/int_slice.go b/vendor/github.com/spf13/pflag/int_slice.go new file mode 100644 index 00000000..1e7c9edd --- /dev/null +++ b/vendor/github.com/spf13/pflag/int_slice.go @@ -0,0 +1,128 @@ +package pflag + +import ( + "fmt" + "strconv" + "strings" +) + +// -- intSlice Value +type intSliceValue struct { + value *[]int + changed bool +} + +func newIntSliceValue(val []int, p *[]int) *intSliceValue { + isv := new(intSliceValue) + isv.value = p + *isv.value = val + return isv +} + +func (s *intSliceValue) Set(val string) error { + ss := strings.Split(val, ",") + out := make([]int, len(ss)) + for i, d := range ss { + var err error + out[i], err = strconv.Atoi(d) + if err != nil { + return err + } + + } + if !s.changed { + *s.value = out + } else { + *s.value = append(*s.value, out...) + } + s.changed = true + return nil +} + +func (s *intSliceValue) Type() string { + return "intSlice" +} + +func (s *intSliceValue) String() string { + out := make([]string, len(*s.value)) + for i, d := range *s.value { + out[i] = fmt.Sprintf("%d", d) + } + return "[" + strings.Join(out, ",") + "]" +} + +func intSliceConv(val string) (interface{}, error) { + val = strings.Trim(val, "[]") + // Empty string would cause a slice with one (empty) entry + if len(val) == 0 { + return []int{}, nil + } + ss := strings.Split(val, ",") + out := make([]int, len(ss)) + for i, d := range ss { + var err error + out[i], err = strconv.Atoi(d) + if err != nil { + return nil, err + } + + } + return out, nil +} + +// GetIntSlice return the []int value of a flag with the given name +func (f *FlagSet) GetIntSlice(name string) ([]int, error) { + val, err := f.getFlagType(name, "intSlice", intSliceConv) + if err != nil { + return []int{}, err + } + return val.([]int), nil +} + +// IntSliceVar defines a intSlice flag with specified name, default value, and usage string. +// The argument p points to a []int variable in which to store the value of the flag. +func (f *FlagSet) IntSliceVar(p *[]int, name string, value []int, usage string) { + f.VarP(newIntSliceValue(value, p), name, "", usage) +} + +// IntSliceVarP is like IntSliceVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IntSliceVarP(p *[]int, name, shorthand string, value []int, usage string) { + f.VarP(newIntSliceValue(value, p), name, shorthand, usage) +} + +// IntSliceVar defines a int[] flag with specified name, default value, and usage string. +// The argument p points to a int[] variable in which to store the value of the flag. +func IntSliceVar(p *[]int, name string, value []int, usage string) { + CommandLine.VarP(newIntSliceValue(value, p), name, "", usage) +} + +// IntSliceVarP is like IntSliceVar, but accepts a shorthand letter that can be used after a single dash. +func IntSliceVarP(p *[]int, name, shorthand string, value []int, usage string) { + CommandLine.VarP(newIntSliceValue(value, p), name, shorthand, usage) +} + +// IntSlice defines a []int flag with specified name, default value, and usage string. +// The return value is the address of a []int variable that stores the value of the flag. +func (f *FlagSet) IntSlice(name string, value []int, usage string) *[]int { + p := []int{} + f.IntSliceVarP(&p, name, "", value, usage) + return &p +} + +// IntSliceP is like IntSlice, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IntSliceP(name, shorthand string, value []int, usage string) *[]int { + p := []int{} + f.IntSliceVarP(&p, name, shorthand, value, usage) + return &p +} + +// IntSlice defines a []int flag with specified name, default value, and usage string. +// The return value is the address of a []int variable that stores the value of the flag. +func IntSlice(name string, value []int, usage string) *[]int { + return CommandLine.IntSliceP(name, "", value, usage) +} + +// IntSliceP is like IntSlice, but accepts a shorthand letter that can be used after a single dash. +func IntSliceP(name, shorthand string, value []int, usage string) *[]int { + return CommandLine.IntSliceP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/ip.go b/vendor/github.com/spf13/pflag/ip.go new file mode 100644 index 00000000..3d414ba6 --- /dev/null +++ b/vendor/github.com/spf13/pflag/ip.go @@ -0,0 +1,94 @@ +package pflag + +import ( + "fmt" + "net" + "strings" +) + +// -- net.IP value +type ipValue net.IP + +func newIPValue(val net.IP, p *net.IP) *ipValue { + *p = val + return (*ipValue)(p) +} + +func (i *ipValue) String() string { return net.IP(*i).String() } +func (i *ipValue) Set(s string) error { + ip := net.ParseIP(strings.TrimSpace(s)) + if ip == nil { + return fmt.Errorf("failed to parse IP: %q", s) + } + *i = ipValue(ip) + return nil +} + +func (i *ipValue) Type() string { + return "ip" +} + +func ipConv(sval string) (interface{}, error) { + ip := net.ParseIP(sval) + if ip != nil { + return ip, nil + } + return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval) +} + +// GetIP return the net.IP value of a flag with the given name +func (f *FlagSet) GetIP(name string) (net.IP, error) { + val, err := f.getFlagType(name, "ip", ipConv) + if err != nil { + return nil, err + } + return val.(net.IP), nil +} + +// IPVar defines an net.IP flag with specified name, default value, and usage string. +// The argument p points to an net.IP variable in which to store the value of the flag. +func (f *FlagSet) IPVar(p *net.IP, name string, value net.IP, usage string) { + f.VarP(newIPValue(value, p), name, "", usage) +} + +// IPVarP is like IPVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) { + f.VarP(newIPValue(value, p), name, shorthand, usage) +} + +// IPVar defines an net.IP flag with specified name, default value, and usage string. +// The argument p points to an net.IP variable in which to store the value of the flag. +func IPVar(p *net.IP, name string, value net.IP, usage string) { + CommandLine.VarP(newIPValue(value, p), name, "", usage) +} + +// IPVarP is like IPVar, but accepts a shorthand letter that can be used after a single dash. +func IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) { + CommandLine.VarP(newIPValue(value, p), name, shorthand, usage) +} + +// IP defines an net.IP flag with specified name, default value, and usage string. +// The return value is the address of an net.IP variable that stores the value of the flag. +func (f *FlagSet) IP(name string, value net.IP, usage string) *net.IP { + p := new(net.IP) + f.IPVarP(p, name, "", value, usage) + return p +} + +// IPP is like IP, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IPP(name, shorthand string, value net.IP, usage string) *net.IP { + p := new(net.IP) + f.IPVarP(p, name, shorthand, value, usage) + return p +} + +// IP defines an net.IP flag with specified name, default value, and usage string. +// The return value is the address of an net.IP variable that stores the value of the flag. +func IP(name string, value net.IP, usage string) *net.IP { + return CommandLine.IPP(name, "", value, usage) +} + +// IPP is like IP, but accepts a shorthand letter that can be used after a single dash. +func IPP(name, shorthand string, value net.IP, usage string) *net.IP { + return CommandLine.IPP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/ip_slice.go b/vendor/github.com/spf13/pflag/ip_slice.go new file mode 100644 index 00000000..7dd196fe --- /dev/null +++ b/vendor/github.com/spf13/pflag/ip_slice.go @@ -0,0 +1,148 @@ +package pflag + +import ( + "fmt" + "io" + "net" + "strings" +) + +// -- ipSlice Value +type ipSliceValue struct { + value *[]net.IP + changed bool +} + +func newIPSliceValue(val []net.IP, p *[]net.IP) *ipSliceValue { + ipsv := new(ipSliceValue) + ipsv.value = p + *ipsv.value = val + return ipsv +} + +// Set converts, and assigns, the comma-separated IP argument string representation as the []net.IP value of this flag. +// If Set is called on a flag that already has a []net.IP assigned, the newly converted values will be appended. +func (s *ipSliceValue) Set(val string) error { + + // remove all quote characters + rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "") + + // read flag arguments with CSV parser + ipStrSlice, err := readAsCSV(rmQuote.Replace(val)) + if err != nil && err != io.EOF { + return err + } + + // parse ip values into slice + out := make([]net.IP, 0, len(ipStrSlice)) + for _, ipStr := range ipStrSlice { + ip := net.ParseIP(strings.TrimSpace(ipStr)) + if ip == nil { + return fmt.Errorf("invalid string being converted to IP address: %s", ipStr) + } + out = append(out, ip) + } + + if !s.changed { + *s.value = out + } else { + *s.value = append(*s.value, out...) + } + + s.changed = true + + return nil +} + +// Type returns a string that uniquely represents this flag's type. +func (s *ipSliceValue) Type() string { + return "ipSlice" +} + +// String defines a "native" format for this net.IP slice flag value. +func (s *ipSliceValue) String() string { + + ipStrSlice := make([]string, len(*s.value)) + for i, ip := range *s.value { + ipStrSlice[i] = ip.String() + } + + out, _ := writeAsCSV(ipStrSlice) + + return "[" + out + "]" +} + +func ipSliceConv(val string) (interface{}, error) { + val = strings.Trim(val, "[]") + // Emtpy string would cause a slice with one (empty) entry + if len(val) == 0 { + return []net.IP{}, nil + } + ss := strings.Split(val, ",") + out := make([]net.IP, len(ss)) + for i, sval := range ss { + ip := net.ParseIP(strings.TrimSpace(sval)) + if ip == nil { + return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval) + } + out[i] = ip + } + return out, nil +} + +// GetIPSlice returns the []net.IP value of a flag with the given name +func (f *FlagSet) GetIPSlice(name string) ([]net.IP, error) { + val, err := f.getFlagType(name, "ipSlice", ipSliceConv) + if err != nil { + return []net.IP{}, err + } + return val.([]net.IP), nil +} + +// IPSliceVar defines a ipSlice flag with specified name, default value, and usage string. +// The argument p points to a []net.IP variable in which to store the value of the flag. +func (f *FlagSet) IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) { + f.VarP(newIPSliceValue(value, p), name, "", usage) +} + +// IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) { + f.VarP(newIPSliceValue(value, p), name, shorthand, usage) +} + +// IPSliceVar defines a []net.IP flag with specified name, default value, and usage string. +// The argument p points to a []net.IP variable in which to store the value of the flag. +func IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) { + CommandLine.VarP(newIPSliceValue(value, p), name, "", usage) +} + +// IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash. +func IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) { + CommandLine.VarP(newIPSliceValue(value, p), name, shorthand, usage) +} + +// IPSlice defines a []net.IP flag with specified name, default value, and usage string. +// The return value is the address of a []net.IP variable that stores the value of that flag. +func (f *FlagSet) IPSlice(name string, value []net.IP, usage string) *[]net.IP { + p := []net.IP{} + f.IPSliceVarP(&p, name, "", value, usage) + return &p +} + +// IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP { + p := []net.IP{} + f.IPSliceVarP(&p, name, shorthand, value, usage) + return &p +} + +// IPSlice defines a []net.IP flag with specified name, default value, and usage string. +// The return value is the address of a []net.IP variable that stores the value of the flag. +func IPSlice(name string, value []net.IP, usage string) *[]net.IP { + return CommandLine.IPSliceP(name, "", value, usage) +} + +// IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash. +func IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP { + return CommandLine.IPSliceP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/ipmask.go b/vendor/github.com/spf13/pflag/ipmask.go new file mode 100644 index 00000000..5bd44bd2 --- /dev/null +++ b/vendor/github.com/spf13/pflag/ipmask.go @@ -0,0 +1,122 @@ +package pflag + +import ( + "fmt" + "net" + "strconv" +) + +// -- net.IPMask value +type ipMaskValue net.IPMask + +func newIPMaskValue(val net.IPMask, p *net.IPMask) *ipMaskValue { + *p = val + return (*ipMaskValue)(p) +} + +func (i *ipMaskValue) String() string { return net.IPMask(*i).String() } +func (i *ipMaskValue) Set(s string) error { + ip := ParseIPv4Mask(s) + if ip == nil { + return fmt.Errorf("failed to parse IP mask: %q", s) + } + *i = ipMaskValue(ip) + return nil +} + +func (i *ipMaskValue) Type() string { + return "ipMask" +} + +// ParseIPv4Mask written in IP form (e.g. 255.255.255.0). +// This function should really belong to the net package. +func ParseIPv4Mask(s string) net.IPMask { + mask := net.ParseIP(s) + if mask == nil { + if len(s) != 8 { + return nil + } + // net.IPMask.String() actually outputs things like ffffff00 + // so write a horrible parser for that as well :-( + m := []int{} + for i := 0; i < 4; i++ { + b := "0x" + s[2*i:2*i+2] + d, err := strconv.ParseInt(b, 0, 0) + if err != nil { + return nil + } + m = append(m, int(d)) + } + s := fmt.Sprintf("%d.%d.%d.%d", m[0], m[1], m[2], m[3]) + mask = net.ParseIP(s) + if mask == nil { + return nil + } + } + return net.IPv4Mask(mask[12], mask[13], mask[14], mask[15]) +} + +func parseIPv4Mask(sval string) (interface{}, error) { + mask := ParseIPv4Mask(sval) + if mask == nil { + return nil, fmt.Errorf("unable to parse %s as net.IPMask", sval) + } + return mask, nil +} + +// GetIPv4Mask return the net.IPv4Mask value of a flag with the given name +func (f *FlagSet) GetIPv4Mask(name string) (net.IPMask, error) { + val, err := f.getFlagType(name, "ipMask", parseIPv4Mask) + if err != nil { + return nil, err + } + return val.(net.IPMask), nil +} + +// IPMaskVar defines an net.IPMask flag with specified name, default value, and usage string. +// The argument p points to an net.IPMask variable in which to store the value of the flag. +func (f *FlagSet) IPMaskVar(p *net.IPMask, name string, value net.IPMask, usage string) { + f.VarP(newIPMaskValue(value, p), name, "", usage) +} + +// IPMaskVarP is like IPMaskVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IPMaskVarP(p *net.IPMask, name, shorthand string, value net.IPMask, usage string) { + f.VarP(newIPMaskValue(value, p), name, shorthand, usage) +} + +// IPMaskVar defines an net.IPMask flag with specified name, default value, and usage string. +// The argument p points to an net.IPMask variable in which to store the value of the flag. +func IPMaskVar(p *net.IPMask, name string, value net.IPMask, usage string) { + CommandLine.VarP(newIPMaskValue(value, p), name, "", usage) +} + +// IPMaskVarP is like IPMaskVar, but accepts a shorthand letter that can be used after a single dash. +func IPMaskVarP(p *net.IPMask, name, shorthand string, value net.IPMask, usage string) { + CommandLine.VarP(newIPMaskValue(value, p), name, shorthand, usage) +} + +// IPMask defines an net.IPMask flag with specified name, default value, and usage string. +// The return value is the address of an net.IPMask variable that stores the value of the flag. +func (f *FlagSet) IPMask(name string, value net.IPMask, usage string) *net.IPMask { + p := new(net.IPMask) + f.IPMaskVarP(p, name, "", value, usage) + return p +} + +// IPMaskP is like IPMask, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IPMaskP(name, shorthand string, value net.IPMask, usage string) *net.IPMask { + p := new(net.IPMask) + f.IPMaskVarP(p, name, shorthand, value, usage) + return p +} + +// IPMask defines an net.IPMask flag with specified name, default value, and usage string. +// The return value is the address of an net.IPMask variable that stores the value of the flag. +func IPMask(name string, value net.IPMask, usage string) *net.IPMask { + return CommandLine.IPMaskP(name, "", value, usage) +} + +// IPMaskP is like IP, but accepts a shorthand letter that can be used after a single dash. +func IPMaskP(name, shorthand string, value net.IPMask, usage string) *net.IPMask { + return CommandLine.IPMaskP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/ipnet.go b/vendor/github.com/spf13/pflag/ipnet.go new file mode 100644 index 00000000..e2c1b8bc --- /dev/null +++ b/vendor/github.com/spf13/pflag/ipnet.go @@ -0,0 +1,98 @@ +package pflag + +import ( + "fmt" + "net" + "strings" +) + +// IPNet adapts net.IPNet for use as a flag. +type ipNetValue net.IPNet + +func (ipnet ipNetValue) String() string { + n := net.IPNet(ipnet) + return n.String() +} + +func (ipnet *ipNetValue) Set(value string) error { + _, n, err := net.ParseCIDR(strings.TrimSpace(value)) + if err != nil { + return err + } + *ipnet = ipNetValue(*n) + return nil +} + +func (*ipNetValue) Type() string { + return "ipNet" +} + +func newIPNetValue(val net.IPNet, p *net.IPNet) *ipNetValue { + *p = val + return (*ipNetValue)(p) +} + +func ipNetConv(sval string) (interface{}, error) { + _, n, err := net.ParseCIDR(strings.TrimSpace(sval)) + if err == nil { + return *n, nil + } + return nil, fmt.Errorf("invalid string being converted to IPNet: %s", sval) +} + +// GetIPNet return the net.IPNet value of a flag with the given name +func (f *FlagSet) GetIPNet(name string) (net.IPNet, error) { + val, err := f.getFlagType(name, "ipNet", ipNetConv) + if err != nil { + return net.IPNet{}, err + } + return val.(net.IPNet), nil +} + +// IPNetVar defines an net.IPNet flag with specified name, default value, and usage string. +// The argument p points to an net.IPNet variable in which to store the value of the flag. +func (f *FlagSet) IPNetVar(p *net.IPNet, name string, value net.IPNet, usage string) { + f.VarP(newIPNetValue(value, p), name, "", usage) +} + +// IPNetVarP is like IPNetVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IPNetVarP(p *net.IPNet, name, shorthand string, value net.IPNet, usage string) { + f.VarP(newIPNetValue(value, p), name, shorthand, usage) +} + +// IPNetVar defines an net.IPNet flag with specified name, default value, and usage string. +// The argument p points to an net.IPNet variable in which to store the value of the flag. +func IPNetVar(p *net.IPNet, name string, value net.IPNet, usage string) { + CommandLine.VarP(newIPNetValue(value, p), name, "", usage) +} + +// IPNetVarP is like IPNetVar, but accepts a shorthand letter that can be used after a single dash. +func IPNetVarP(p *net.IPNet, name, shorthand string, value net.IPNet, usage string) { + CommandLine.VarP(newIPNetValue(value, p), name, shorthand, usage) +} + +// IPNet defines an net.IPNet flag with specified name, default value, and usage string. +// The return value is the address of an net.IPNet variable that stores the value of the flag. +func (f *FlagSet) IPNet(name string, value net.IPNet, usage string) *net.IPNet { + p := new(net.IPNet) + f.IPNetVarP(p, name, "", value, usage) + return p +} + +// IPNetP is like IPNet, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IPNetP(name, shorthand string, value net.IPNet, usage string) *net.IPNet { + p := new(net.IPNet) + f.IPNetVarP(p, name, shorthand, value, usage) + return p +} + +// IPNet defines an net.IPNet flag with specified name, default value, and usage string. +// The return value is the address of an net.IPNet variable that stores the value of the flag. +func IPNet(name string, value net.IPNet, usage string) *net.IPNet { + return CommandLine.IPNetP(name, "", value, usage) +} + +// IPNetP is like IPNet, but accepts a shorthand letter that can be used after a single dash. +func IPNetP(name, shorthand string, value net.IPNet, usage string) *net.IPNet { + return CommandLine.IPNetP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/string.go b/vendor/github.com/spf13/pflag/string.go new file mode 100644 index 00000000..04e0a26f --- /dev/null +++ b/vendor/github.com/spf13/pflag/string.go @@ -0,0 +1,80 @@ +package pflag + +// -- string Value +type stringValue string + +func newStringValue(val string, p *string) *stringValue { + *p = val + return (*stringValue)(p) +} + +func (s *stringValue) Set(val string) error { + *s = stringValue(val) + return nil +} +func (s *stringValue) Type() string { + return "string" +} + +func (s *stringValue) String() string { return string(*s) } + +func stringConv(sval string) (interface{}, error) { + return sval, nil +} + +// GetString return the string value of a flag with the given name +func (f *FlagSet) GetString(name string) (string, error) { + val, err := f.getFlagType(name, "string", stringConv) + if err != nil { + return "", err + } + return val.(string), nil +} + +// StringVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a string variable in which to store the value of the flag. +func (f *FlagSet) StringVar(p *string, name string, value string, usage string) { + f.VarP(newStringValue(value, p), name, "", usage) +} + +// StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) StringVarP(p *string, name, shorthand string, value string, usage string) { + f.VarP(newStringValue(value, p), name, shorthand, usage) +} + +// StringVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a string variable in which to store the value of the flag. +func StringVar(p *string, name string, value string, usage string) { + CommandLine.VarP(newStringValue(value, p), name, "", usage) +} + +// StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash. +func StringVarP(p *string, name, shorthand string, value string, usage string) { + CommandLine.VarP(newStringValue(value, p), name, shorthand, usage) +} + +// String defines a string flag with specified name, default value, and usage string. +// The return value is the address of a string variable that stores the value of the flag. +func (f *FlagSet) String(name string, value string, usage string) *string { + p := new(string) + f.StringVarP(p, name, "", value, usage) + return p +} + +// StringP is like String, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) StringP(name, shorthand string, value string, usage string) *string { + p := new(string) + f.StringVarP(p, name, shorthand, value, usage) + return p +} + +// String defines a string flag with specified name, default value, and usage string. +// The return value is the address of a string variable that stores the value of the flag. +func String(name string, value string, usage string) *string { + return CommandLine.StringP(name, "", value, usage) +} + +// StringP is like String, but accepts a shorthand letter that can be used after a single dash. +func StringP(name, shorthand string, value string, usage string) *string { + return CommandLine.StringP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/string_array.go b/vendor/github.com/spf13/pflag/string_array.go new file mode 100644 index 00000000..276b7ed4 --- /dev/null +++ b/vendor/github.com/spf13/pflag/string_array.go @@ -0,0 +1,103 @@ +package pflag + +// -- stringArray Value +type stringArrayValue struct { + value *[]string + changed bool +} + +func newStringArrayValue(val []string, p *[]string) *stringArrayValue { + ssv := new(stringArrayValue) + ssv.value = p + *ssv.value = val + return ssv +} + +func (s *stringArrayValue) Set(val string) error { + if !s.changed { + *s.value = []string{val} + s.changed = true + } else { + *s.value = append(*s.value, val) + } + return nil +} + +func (s *stringArrayValue) Type() string { + return "stringArray" +} + +func (s *stringArrayValue) String() string { + str, _ := writeAsCSV(*s.value) + return "[" + str + "]" +} + +func stringArrayConv(sval string) (interface{}, error) { + sval = sval[1 : len(sval)-1] + // An empty string would cause a array with one (empty) string + if len(sval) == 0 { + return []string{}, nil + } + return readAsCSV(sval) +} + +// GetStringArray return the []string value of a flag with the given name +func (f *FlagSet) GetStringArray(name string) ([]string, error) { + val, err := f.getFlagType(name, "stringArray", stringArrayConv) + if err != nil { + return []string{}, err + } + return val.([]string), nil +} + +// StringArrayVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a []string variable in which to store the values of the multiple flags. +// The value of each argument will not try to be separated by comma +func (f *FlagSet) StringArrayVar(p *[]string, name string, value []string, usage string) { + f.VarP(newStringArrayValue(value, p), name, "", usage) +} + +// StringArrayVarP is like StringArrayVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) StringArrayVarP(p *[]string, name, shorthand string, value []string, usage string) { + f.VarP(newStringArrayValue(value, p), name, shorthand, usage) +} + +// StringArrayVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a []string variable in which to store the value of the flag. +// The value of each argument will not try to be separated by comma +func StringArrayVar(p *[]string, name string, value []string, usage string) { + CommandLine.VarP(newStringArrayValue(value, p), name, "", usage) +} + +// StringArrayVarP is like StringArrayVar, but accepts a shorthand letter that can be used after a single dash. +func StringArrayVarP(p *[]string, name, shorthand string, value []string, usage string) { + CommandLine.VarP(newStringArrayValue(value, p), name, shorthand, usage) +} + +// StringArray defines a string flag with specified name, default value, and usage string. +// The return value is the address of a []string variable that stores the value of the flag. +// The value of each argument will not try to be separated by comma +func (f *FlagSet) StringArray(name string, value []string, usage string) *[]string { + p := []string{} + f.StringArrayVarP(&p, name, "", value, usage) + return &p +} + +// StringArrayP is like StringArray, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) StringArrayP(name, shorthand string, value []string, usage string) *[]string { + p := []string{} + f.StringArrayVarP(&p, name, shorthand, value, usage) + return &p +} + +// StringArray defines a string flag with specified name, default value, and usage string. +// The return value is the address of a []string variable that stores the value of the flag. +// The value of each argument will not try to be separated by comma +func StringArray(name string, value []string, usage string) *[]string { + return CommandLine.StringArrayP(name, "", value, usage) +} + +// StringArrayP is like StringArray, but accepts a shorthand letter that can be used after a single dash. +func StringArrayP(name, shorthand string, value []string, usage string) *[]string { + return CommandLine.StringArrayP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/string_slice.go b/vendor/github.com/spf13/pflag/string_slice.go new file mode 100644 index 00000000..05eee754 --- /dev/null +++ b/vendor/github.com/spf13/pflag/string_slice.go @@ -0,0 +1,129 @@ +package pflag + +import ( + "bytes" + "encoding/csv" + "strings" +) + +// -- stringSlice Value +type stringSliceValue struct { + value *[]string + changed bool +} + +func newStringSliceValue(val []string, p *[]string) *stringSliceValue { + ssv := new(stringSliceValue) + ssv.value = p + *ssv.value = val + return ssv +} + +func readAsCSV(val string) ([]string, error) { + if val == "" { + return []string{}, nil + } + stringReader := strings.NewReader(val) + csvReader := csv.NewReader(stringReader) + return csvReader.Read() +} + +func writeAsCSV(vals []string) (string, error) { + b := &bytes.Buffer{} + w := csv.NewWriter(b) + err := w.Write(vals) + if err != nil { + return "", err + } + w.Flush() + return strings.TrimSuffix(b.String(), "\n"), nil +} + +func (s *stringSliceValue) Set(val string) error { + v, err := readAsCSV(val) + if err != nil { + return err + } + if !s.changed { + *s.value = v + } else { + *s.value = append(*s.value, v...) + } + s.changed = true + return nil +} + +func (s *stringSliceValue) Type() string { + return "stringSlice" +} + +func (s *stringSliceValue) String() string { + str, _ := writeAsCSV(*s.value) + return "[" + str + "]" +} + +func stringSliceConv(sval string) (interface{}, error) { + sval = sval[1 : len(sval)-1] + // An empty string would cause a slice with one (empty) string + if len(sval) == 0 { + return []string{}, nil + } + return readAsCSV(sval) +} + +// GetStringSlice return the []string value of a flag with the given name +func (f *FlagSet) GetStringSlice(name string) ([]string, error) { + val, err := f.getFlagType(name, "stringSlice", stringSliceConv) + if err != nil { + return []string{}, err + } + return val.([]string), nil +} + +// StringSliceVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a []string variable in which to store the value of the flag. +func (f *FlagSet) StringSliceVar(p *[]string, name string, value []string, usage string) { + f.VarP(newStringSliceValue(value, p), name, "", usage) +} + +// StringSliceVarP is like StringSliceVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) StringSliceVarP(p *[]string, name, shorthand string, value []string, usage string) { + f.VarP(newStringSliceValue(value, p), name, shorthand, usage) +} + +// StringSliceVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a []string variable in which to store the value of the flag. +func StringSliceVar(p *[]string, name string, value []string, usage string) { + CommandLine.VarP(newStringSliceValue(value, p), name, "", usage) +} + +// StringSliceVarP is like StringSliceVar, but accepts a shorthand letter that can be used after a single dash. +func StringSliceVarP(p *[]string, name, shorthand string, value []string, usage string) { + CommandLine.VarP(newStringSliceValue(value, p), name, shorthand, usage) +} + +// StringSlice defines a string flag with specified name, default value, and usage string. +// The return value is the address of a []string variable that stores the value of the flag. +func (f *FlagSet) StringSlice(name string, value []string, usage string) *[]string { + p := []string{} + f.StringSliceVarP(&p, name, "", value, usage) + return &p +} + +// StringSliceP is like StringSlice, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) StringSliceP(name, shorthand string, value []string, usage string) *[]string { + p := []string{} + f.StringSliceVarP(&p, name, shorthand, value, usage) + return &p +} + +// StringSlice defines a string flag with specified name, default value, and usage string. +// The return value is the address of a []string variable that stores the value of the flag. +func StringSlice(name string, value []string, usage string) *[]string { + return CommandLine.StringSliceP(name, "", value, usage) +} + +// StringSliceP is like StringSlice, but accepts a shorthand letter that can be used after a single dash. +func StringSliceP(name, shorthand string, value []string, usage string) *[]string { + return CommandLine.StringSliceP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/uint.go b/vendor/github.com/spf13/pflag/uint.go new file mode 100644 index 00000000..dcbc2b75 --- /dev/null +++ b/vendor/github.com/spf13/pflag/uint.go @@ -0,0 +1,88 @@ +package pflag + +import "strconv" + +// -- uint Value +type uintValue uint + +func newUintValue(val uint, p *uint) *uintValue { + *p = val + return (*uintValue)(p) +} + +func (i *uintValue) Set(s string) error { + v, err := strconv.ParseUint(s, 0, 64) + *i = uintValue(v) + return err +} + +func (i *uintValue) Type() string { + return "uint" +} + +func (i *uintValue) String() string { return strconv.FormatUint(uint64(*i), 10) } + +func uintConv(sval string) (interface{}, error) { + v, err := strconv.ParseUint(sval, 0, 0) + if err != nil { + return 0, err + } + return uint(v), nil +} + +// GetUint return the uint value of a flag with the given name +func (f *FlagSet) GetUint(name string) (uint, error) { + val, err := f.getFlagType(name, "uint", uintConv) + if err != nil { + return 0, err + } + return val.(uint), nil +} + +// UintVar defines a uint flag with specified name, default value, and usage string. +// The argument p points to a uint variable in which to store the value of the flag. +func (f *FlagSet) UintVar(p *uint, name string, value uint, usage string) { + f.VarP(newUintValue(value, p), name, "", usage) +} + +// UintVarP is like UintVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) UintVarP(p *uint, name, shorthand string, value uint, usage string) { + f.VarP(newUintValue(value, p), name, shorthand, usage) +} + +// UintVar defines a uint flag with specified name, default value, and usage string. +// The argument p points to a uint variable in which to store the value of the flag. +func UintVar(p *uint, name string, value uint, usage string) { + CommandLine.VarP(newUintValue(value, p), name, "", usage) +} + +// UintVarP is like UintVar, but accepts a shorthand letter that can be used after a single dash. +func UintVarP(p *uint, name, shorthand string, value uint, usage string) { + CommandLine.VarP(newUintValue(value, p), name, shorthand, usage) +} + +// Uint defines a uint flag with specified name, default value, and usage string. +// The return value is the address of a uint variable that stores the value of the flag. +func (f *FlagSet) Uint(name string, value uint, usage string) *uint { + p := new(uint) + f.UintVarP(p, name, "", value, usage) + return p +} + +// UintP is like Uint, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) UintP(name, shorthand string, value uint, usage string) *uint { + p := new(uint) + f.UintVarP(p, name, shorthand, value, usage) + return p +} + +// Uint defines a uint flag with specified name, default value, and usage string. +// The return value is the address of a uint variable that stores the value of the flag. +func Uint(name string, value uint, usage string) *uint { + return CommandLine.UintP(name, "", value, usage) +} + +// UintP is like Uint, but accepts a shorthand letter that can be used after a single dash. +func UintP(name, shorthand string, value uint, usage string) *uint { + return CommandLine.UintP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/uint16.go b/vendor/github.com/spf13/pflag/uint16.go new file mode 100644 index 00000000..7e9914ed --- /dev/null +++ b/vendor/github.com/spf13/pflag/uint16.go @@ -0,0 +1,88 @@ +package pflag + +import "strconv" + +// -- uint16 value +type uint16Value uint16 + +func newUint16Value(val uint16, p *uint16) *uint16Value { + *p = val + return (*uint16Value)(p) +} + +func (i *uint16Value) Set(s string) error { + v, err := strconv.ParseUint(s, 0, 16) + *i = uint16Value(v) + return err +} + +func (i *uint16Value) Type() string { + return "uint16" +} + +func (i *uint16Value) String() string { return strconv.FormatUint(uint64(*i), 10) } + +func uint16Conv(sval string) (interface{}, error) { + v, err := strconv.ParseUint(sval, 0, 16) + if err != nil { + return 0, err + } + return uint16(v), nil +} + +// GetUint16 return the uint16 value of a flag with the given name +func (f *FlagSet) GetUint16(name string) (uint16, error) { + val, err := f.getFlagType(name, "uint16", uint16Conv) + if err != nil { + return 0, err + } + return val.(uint16), nil +} + +// Uint16Var defines a uint flag with specified name, default value, and usage string. +// The argument p points to a uint variable in which to store the value of the flag. +func (f *FlagSet) Uint16Var(p *uint16, name string, value uint16, usage string) { + f.VarP(newUint16Value(value, p), name, "", usage) +} + +// Uint16VarP is like Uint16Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Uint16VarP(p *uint16, name, shorthand string, value uint16, usage string) { + f.VarP(newUint16Value(value, p), name, shorthand, usage) +} + +// Uint16Var defines a uint flag with specified name, default value, and usage string. +// The argument p points to a uint variable in which to store the value of the flag. +func Uint16Var(p *uint16, name string, value uint16, usage string) { + CommandLine.VarP(newUint16Value(value, p), name, "", usage) +} + +// Uint16VarP is like Uint16Var, but accepts a shorthand letter that can be used after a single dash. +func Uint16VarP(p *uint16, name, shorthand string, value uint16, usage string) { + CommandLine.VarP(newUint16Value(value, p), name, shorthand, usage) +} + +// Uint16 defines a uint flag with specified name, default value, and usage string. +// The return value is the address of a uint variable that stores the value of the flag. +func (f *FlagSet) Uint16(name string, value uint16, usage string) *uint16 { + p := new(uint16) + f.Uint16VarP(p, name, "", value, usage) + return p +} + +// Uint16P is like Uint16, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Uint16P(name, shorthand string, value uint16, usage string) *uint16 { + p := new(uint16) + f.Uint16VarP(p, name, shorthand, value, usage) + return p +} + +// Uint16 defines a uint flag with specified name, default value, and usage string. +// The return value is the address of a uint variable that stores the value of the flag. +func Uint16(name string, value uint16, usage string) *uint16 { + return CommandLine.Uint16P(name, "", value, usage) +} + +// Uint16P is like Uint16, but accepts a shorthand letter that can be used after a single dash. +func Uint16P(name, shorthand string, value uint16, usage string) *uint16 { + return CommandLine.Uint16P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/uint32.go b/vendor/github.com/spf13/pflag/uint32.go new file mode 100644 index 00000000..d8024539 --- /dev/null +++ b/vendor/github.com/spf13/pflag/uint32.go @@ -0,0 +1,88 @@ +package pflag + +import "strconv" + +// -- uint32 value +type uint32Value uint32 + +func newUint32Value(val uint32, p *uint32) *uint32Value { + *p = val + return (*uint32Value)(p) +} + +func (i *uint32Value) Set(s string) error { + v, err := strconv.ParseUint(s, 0, 32) + *i = uint32Value(v) + return err +} + +func (i *uint32Value) Type() string { + return "uint32" +} + +func (i *uint32Value) String() string { return strconv.FormatUint(uint64(*i), 10) } + +func uint32Conv(sval string) (interface{}, error) { + v, err := strconv.ParseUint(sval, 0, 32) + if err != nil { + return 0, err + } + return uint32(v), nil +} + +// GetUint32 return the uint32 value of a flag with the given name +func (f *FlagSet) GetUint32(name string) (uint32, error) { + val, err := f.getFlagType(name, "uint32", uint32Conv) + if err != nil { + return 0, err + } + return val.(uint32), nil +} + +// Uint32Var defines a uint32 flag with specified name, default value, and usage string. +// The argument p points to a uint32 variable in which to store the value of the flag. +func (f *FlagSet) Uint32Var(p *uint32, name string, value uint32, usage string) { + f.VarP(newUint32Value(value, p), name, "", usage) +} + +// Uint32VarP is like Uint32Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Uint32VarP(p *uint32, name, shorthand string, value uint32, usage string) { + f.VarP(newUint32Value(value, p), name, shorthand, usage) +} + +// Uint32Var defines a uint32 flag with specified name, default value, and usage string. +// The argument p points to a uint32 variable in which to store the value of the flag. +func Uint32Var(p *uint32, name string, value uint32, usage string) { + CommandLine.VarP(newUint32Value(value, p), name, "", usage) +} + +// Uint32VarP is like Uint32Var, but accepts a shorthand letter that can be used after a single dash. +func Uint32VarP(p *uint32, name, shorthand string, value uint32, usage string) { + CommandLine.VarP(newUint32Value(value, p), name, shorthand, usage) +} + +// Uint32 defines a uint32 flag with specified name, default value, and usage string. +// The return value is the address of a uint32 variable that stores the value of the flag. +func (f *FlagSet) Uint32(name string, value uint32, usage string) *uint32 { + p := new(uint32) + f.Uint32VarP(p, name, "", value, usage) + return p +} + +// Uint32P is like Uint32, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Uint32P(name, shorthand string, value uint32, usage string) *uint32 { + p := new(uint32) + f.Uint32VarP(p, name, shorthand, value, usage) + return p +} + +// Uint32 defines a uint32 flag with specified name, default value, and usage string. +// The return value is the address of a uint32 variable that stores the value of the flag. +func Uint32(name string, value uint32, usage string) *uint32 { + return CommandLine.Uint32P(name, "", value, usage) +} + +// Uint32P is like Uint32, but accepts a shorthand letter that can be used after a single dash. +func Uint32P(name, shorthand string, value uint32, usage string) *uint32 { + return CommandLine.Uint32P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/uint64.go b/vendor/github.com/spf13/pflag/uint64.go new file mode 100644 index 00000000..f62240f2 --- /dev/null +++ b/vendor/github.com/spf13/pflag/uint64.go @@ -0,0 +1,88 @@ +package pflag + +import "strconv" + +// -- uint64 Value +type uint64Value uint64 + +func newUint64Value(val uint64, p *uint64) *uint64Value { + *p = val + return (*uint64Value)(p) +} + +func (i *uint64Value) Set(s string) error { + v, err := strconv.ParseUint(s, 0, 64) + *i = uint64Value(v) + return err +} + +func (i *uint64Value) Type() string { + return "uint64" +} + +func (i *uint64Value) String() string { return strconv.FormatUint(uint64(*i), 10) } + +func uint64Conv(sval string) (interface{}, error) { + v, err := strconv.ParseUint(sval, 0, 64) + if err != nil { + return 0, err + } + return uint64(v), nil +} + +// GetUint64 return the uint64 value of a flag with the given name +func (f *FlagSet) GetUint64(name string) (uint64, error) { + val, err := f.getFlagType(name, "uint64", uint64Conv) + if err != nil { + return 0, err + } + return val.(uint64), nil +} + +// Uint64Var defines a uint64 flag with specified name, default value, and usage string. +// The argument p points to a uint64 variable in which to store the value of the flag. +func (f *FlagSet) Uint64Var(p *uint64, name string, value uint64, usage string) { + f.VarP(newUint64Value(value, p), name, "", usage) +} + +// Uint64VarP is like Uint64Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Uint64VarP(p *uint64, name, shorthand string, value uint64, usage string) { + f.VarP(newUint64Value(value, p), name, shorthand, usage) +} + +// Uint64Var defines a uint64 flag with specified name, default value, and usage string. +// The argument p points to a uint64 variable in which to store the value of the flag. +func Uint64Var(p *uint64, name string, value uint64, usage string) { + CommandLine.VarP(newUint64Value(value, p), name, "", usage) +} + +// Uint64VarP is like Uint64Var, but accepts a shorthand letter that can be used after a single dash. +func Uint64VarP(p *uint64, name, shorthand string, value uint64, usage string) { + CommandLine.VarP(newUint64Value(value, p), name, shorthand, usage) +} + +// Uint64 defines a uint64 flag with specified name, default value, and usage string. +// The return value is the address of a uint64 variable that stores the value of the flag. +func (f *FlagSet) Uint64(name string, value uint64, usage string) *uint64 { + p := new(uint64) + f.Uint64VarP(p, name, "", value, usage) + return p +} + +// Uint64P is like Uint64, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Uint64P(name, shorthand string, value uint64, usage string) *uint64 { + p := new(uint64) + f.Uint64VarP(p, name, shorthand, value, usage) + return p +} + +// Uint64 defines a uint64 flag with specified name, default value, and usage string. +// The return value is the address of a uint64 variable that stores the value of the flag. +func Uint64(name string, value uint64, usage string) *uint64 { + return CommandLine.Uint64P(name, "", value, usage) +} + +// Uint64P is like Uint64, but accepts a shorthand letter that can be used after a single dash. +func Uint64P(name, shorthand string, value uint64, usage string) *uint64 { + return CommandLine.Uint64P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/uint8.go b/vendor/github.com/spf13/pflag/uint8.go new file mode 100644 index 00000000..bb0e83c1 --- /dev/null +++ b/vendor/github.com/spf13/pflag/uint8.go @@ -0,0 +1,88 @@ +package pflag + +import "strconv" + +// -- uint8 Value +type uint8Value uint8 + +func newUint8Value(val uint8, p *uint8) *uint8Value { + *p = val + return (*uint8Value)(p) +} + +func (i *uint8Value) Set(s string) error { + v, err := strconv.ParseUint(s, 0, 8) + *i = uint8Value(v) + return err +} + +func (i *uint8Value) Type() string { + return "uint8" +} + +func (i *uint8Value) String() string { return strconv.FormatUint(uint64(*i), 10) } + +func uint8Conv(sval string) (interface{}, error) { + v, err := strconv.ParseUint(sval, 0, 8) + if err != nil { + return 0, err + } + return uint8(v), nil +} + +// GetUint8 return the uint8 value of a flag with the given name +func (f *FlagSet) GetUint8(name string) (uint8, error) { + val, err := f.getFlagType(name, "uint8", uint8Conv) + if err != nil { + return 0, err + } + return val.(uint8), nil +} + +// Uint8Var defines a uint8 flag with specified name, default value, and usage string. +// The argument p points to a uint8 variable in which to store the value of the flag. +func (f *FlagSet) Uint8Var(p *uint8, name string, value uint8, usage string) { + f.VarP(newUint8Value(value, p), name, "", usage) +} + +// Uint8VarP is like Uint8Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) { + f.VarP(newUint8Value(value, p), name, shorthand, usage) +} + +// Uint8Var defines a uint8 flag with specified name, default value, and usage string. +// The argument p points to a uint8 variable in which to store the value of the flag. +func Uint8Var(p *uint8, name string, value uint8, usage string) { + CommandLine.VarP(newUint8Value(value, p), name, "", usage) +} + +// Uint8VarP is like Uint8Var, but accepts a shorthand letter that can be used after a single dash. +func Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) { + CommandLine.VarP(newUint8Value(value, p), name, shorthand, usage) +} + +// Uint8 defines a uint8 flag with specified name, default value, and usage string. +// The return value is the address of a uint8 variable that stores the value of the flag. +func (f *FlagSet) Uint8(name string, value uint8, usage string) *uint8 { + p := new(uint8) + f.Uint8VarP(p, name, "", value, usage) + return p +} + +// Uint8P is like Uint8, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Uint8P(name, shorthand string, value uint8, usage string) *uint8 { + p := new(uint8) + f.Uint8VarP(p, name, shorthand, value, usage) + return p +} + +// Uint8 defines a uint8 flag with specified name, default value, and usage string. +// The return value is the address of a uint8 variable that stores the value of the flag. +func Uint8(name string, value uint8, usage string) *uint8 { + return CommandLine.Uint8P(name, "", value, usage) +} + +// Uint8P is like Uint8, but accepts a shorthand letter that can be used after a single dash. +func Uint8P(name, shorthand string, value uint8, usage string) *uint8 { + return CommandLine.Uint8P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/uint_slice.go b/vendor/github.com/spf13/pflag/uint_slice.go new file mode 100644 index 00000000..edd94c60 --- /dev/null +++ b/vendor/github.com/spf13/pflag/uint_slice.go @@ -0,0 +1,126 @@ +package pflag + +import ( + "fmt" + "strconv" + "strings" +) + +// -- uintSlice Value +type uintSliceValue struct { + value *[]uint + changed bool +} + +func newUintSliceValue(val []uint, p *[]uint) *uintSliceValue { + uisv := new(uintSliceValue) + uisv.value = p + *uisv.value = val + return uisv +} + +func (s *uintSliceValue) Set(val string) error { + ss := strings.Split(val, ",") + out := make([]uint, len(ss)) + for i, d := range ss { + u, err := strconv.ParseUint(d, 10, 0) + if err != nil { + return err + } + out[i] = uint(u) + } + if !s.changed { + *s.value = out + } else { + *s.value = append(*s.value, out...) + } + s.changed = true + return nil +} + +func (s *uintSliceValue) Type() string { + return "uintSlice" +} + +func (s *uintSliceValue) String() string { + out := make([]string, len(*s.value)) + for i, d := range *s.value { + out[i] = fmt.Sprintf("%d", d) + } + return "[" + strings.Join(out, ",") + "]" +} + +func uintSliceConv(val string) (interface{}, error) { + val = strings.Trim(val, "[]") + // Empty string would cause a slice with one (empty) entry + if len(val) == 0 { + return []uint{}, nil + } + ss := strings.Split(val, ",") + out := make([]uint, len(ss)) + for i, d := range ss { + u, err := strconv.ParseUint(d, 10, 0) + if err != nil { + return nil, err + } + out[i] = uint(u) + } + return out, nil +} + +// GetUintSlice returns the []uint value of a flag with the given name. +func (f *FlagSet) GetUintSlice(name string) ([]uint, error) { + val, err := f.getFlagType(name, "uintSlice", uintSliceConv) + if err != nil { + return []uint{}, err + } + return val.([]uint), nil +} + +// UintSliceVar defines a uintSlice flag with specified name, default value, and usage string. +// The argument p points to a []uint variable in which to store the value of the flag. +func (f *FlagSet) UintSliceVar(p *[]uint, name string, value []uint, usage string) { + f.VarP(newUintSliceValue(value, p), name, "", usage) +} + +// UintSliceVarP is like UintSliceVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) { + f.VarP(newUintSliceValue(value, p), name, shorthand, usage) +} + +// UintSliceVar defines a uint[] flag with specified name, default value, and usage string. +// The argument p points to a uint[] variable in which to store the value of the flag. +func UintSliceVar(p *[]uint, name string, value []uint, usage string) { + CommandLine.VarP(newUintSliceValue(value, p), name, "", usage) +} + +// UintSliceVarP is like the UintSliceVar, but accepts a shorthand letter that can be used after a single dash. +func UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) { + CommandLine.VarP(newUintSliceValue(value, p), name, shorthand, usage) +} + +// UintSlice defines a []uint flag with specified name, default value, and usage string. +// The return value is the address of a []uint variable that stores the value of the flag. +func (f *FlagSet) UintSlice(name string, value []uint, usage string) *[]uint { + p := []uint{} + f.UintSliceVarP(&p, name, "", value, usage) + return &p +} + +// UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) UintSliceP(name, shorthand string, value []uint, usage string) *[]uint { + p := []uint{} + f.UintSliceVarP(&p, name, shorthand, value, usage) + return &p +} + +// UintSlice defines a []uint flag with specified name, default value, and usage string. +// The return value is the address of a []uint variable that stores the value of the flag. +func UintSlice(name string, value []uint, usage string) *[]uint { + return CommandLine.UintSliceP(name, "", value, usage) +} + +// UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash. +func UintSliceP(name, shorthand string, value []uint, usage string) *[]uint { + return CommandLine.UintSliceP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/strickyak/jsonnet_cgo/COMPARE-jsonnet.sh b/vendor/github.com/strickyak/jsonnet_cgo/COMPARE-jsonnet.sh new file mode 100644 index 00000000..8b54cd82 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/COMPARE-jsonnet.sh @@ -0,0 +1,73 @@ +#!/bin/bash + +# To help me keep up-to-date with jsonnet, +# this will compare our copies of jsonnet files +# with the ones in a jsonnet directory. +# See "Usage:" a few lines below. + +case "$#/$1" in + 1/*/jsonnet/ ) + : ok + ;; + * ) + echo >&2 ' +Usage: + sh $0 /path/to/jsonnet/ + +This command requires one argument, +the jsonnet repository directory, +ending in /jsonnet/ +' + exit 13 + ;; +esac + +J="$1" +test -d "$J" + +for x in \ + ast.h \ + desugarer.cpp \ + desugarer.h \ + formatter.cpp \ + formatter.h \ + json.h \ + lexer.cpp \ + lexer.h \ + libjsonnet.cpp \ + libjsonnet.h \ + md5.cpp \ + md5.h \ + parser.cpp \ + parser.h \ + pass.cpp \ + pass.h \ + state.h \ + static_analysis.cpp \ + static_analysis.h \ + static_error.h \ + std.jsonnet.h \ + string_utils.cpp \ + string_utils.h \ + unicode.h \ + vm.cpp \ + vm.h \ + # +do + ok=false + for subdir in core cpp third_party/md5 include + do + if cmp "$J/$subdir/$x" "./$x" 2>/dev/null + then + ok=true + break + fi + done + + if $ok + then + echo "ok: $x" + else + echo "******** NOT OK: $x" + fi +done diff --git a/vendor/github.com/strickyak/jsonnet_cgo/LICENSE b/vendor/github.com/strickyak/jsonnet_cgo/LICENSE new file mode 100644 index 00000000..adea0b86 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014 Strick Yak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/vendor/github.com/strickyak/jsonnet_cgo/LICENSE.jsonnet b/vendor/github.com/strickyak/jsonnet_cgo/LICENSE.jsonnet new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/LICENSE.jsonnet @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/strickyak/jsonnet_cgo/LICENSE.md5 b/vendor/github.com/strickyak/jsonnet_cgo/LICENSE.md5 new file mode 100644 index 00000000..e1ec4b8d --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/LICENSE.md5 @@ -0,0 +1,29 @@ +MD5 +Converted to C++ class by Frank Thilo (thilo@unix-ag.org) +for bzflag (http://www.bzflag.org) + +based on: + +md5.h and md5.c +reference implementation of RFC 1321 + +Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. diff --git a/vendor/github.com/strickyak/jsonnet_cgo/README.md b/vendor/github.com/strickyak/jsonnet_cgo/README.md new file mode 100644 index 00000000..7633a565 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/README.md @@ -0,0 +1,25 @@ +jsonnet_cgo +=========== + +Simple golang cgo wrapper around JSonnet VM. + +Everything in libjsonnet.h is covered except the multi-file evaluators. + +See jsonnet_test.go for how to use it. + +Quick example: + + vm := jsonnet.Make() + vm.ExtVar("color", "purple") + + x, err := vm.EvaluateSnippet(`Test_Demo`, `"dark " + std.extVar("color")`) + + if err != nil { + panic(err) + } + if x != "\"dark purple\"\n" { + panic("fail: we got " + x) + } + + vm.Destroy() + diff --git a/vendor/github.com/strickyak/jsonnet_cgo/ast.h b/vendor/github.com/strickyak/jsonnet_cgo/ast.h new file mode 100644 index 00000000..5556fb99 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/ast.h @@ -0,0 +1,879 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef JSONNET_AST_H +#define JSONNET_AST_H + +#include +#include + +#include +#include +#include +#include + +#include "lexer.h" +#include "unicode.h" + +enum ASTType { + AST_APPLY, + AST_ARRAY, + AST_ARRAY_COMPREHENSION, + AST_ARRAY_COMPREHENSION_SIMPLE, + AST_ASSERT, + AST_BINARY, + AST_BUILTIN_FUNCTION, + AST_CONDITIONAL, + AST_DESUGARED_OBJECT, + AST_DOLLAR, + AST_ERROR, + AST_FUNCTION, + AST_IMPORT, + AST_IMPORTSTR, + AST_INDEX, + AST_LOCAL, + AST_LITERAL_BOOLEAN, + AST_LITERAL_NULL, + AST_LITERAL_NUMBER, + AST_LITERAL_STRING, + AST_OBJECT, + AST_OBJECT_COMPREHENSION, + AST_OBJECT_COMPREHENSION_SIMPLE, + AST_PARENS, + AST_SELF, + AST_SUPER_INDEX, + AST_UNARY, + AST_VAR +}; + +/** Represents a variable / parameter / field name. */ +struct Identifier { + String name; + Identifier(const String &name) + : name(name) + { } +}; + +static inline std::ostream &operator<<(std::ostream &o, const Identifier *id) +{ + o << encode_utf8(id->name); + return o; +} + +typedef std::vector Identifiers; + + +/** All AST nodes are subtypes of this class. + */ +struct AST { + LocationRange location; + ASTType type; + Fodder openFodder; + Identifiers freeVariables; + AST(const LocationRange &location, ASTType type, const Fodder &open_fodder) + : location(location), type(type), openFodder(open_fodder) + { + } + virtual ~AST(void) + { + } +}; + +typedef std::vector ASTs; + +/** Either an arg in a function apply, or a param in a closure / other function definition. + * + * They happen to have exactly the same structure. + * + * In the case of an arg, the id is optional and the expr is required. Presence of the id indicates + * that this is a named rather than positional argument. + * + * In the case of a param, the id is required and if expr is given, it is a default argument to be + * used when no argument is bound to the param. + */ +struct ArgParam { + Fodder idFodder; // Empty if no id. + const Identifier *id; // nullptr if there isn't one + Fodder eqFodder; // Empty if no id or no expr. + AST *expr; // nullptr if there wasn't one. + Fodder commaFodder; // Before the comma (if there is a comma). + // Only has id + ArgParam (const Fodder &id_fodder, const Identifier *id, const Fodder &comma_fodder) + : idFodder(id_fodder), id(id), expr(nullptr), commaFodder(comma_fodder) + { } + // Only has expr + ArgParam (AST *expr, const Fodder &comma_fodder) + : id(nullptr), expr(expr), commaFodder(comma_fodder) + { } + // Has both id and expr + ArgParam (const Fodder &id_fodder, const Identifier *id, const Fodder &eq_fodder, + AST *expr, const Fodder &comma_fodder) + : idFodder(id_fodder), id(id), eqFodder(eq_fodder), expr(expr), commaFodder(comma_fodder) + { } +}; + +typedef std::vector ArgParams; + +/** Used in Object & Array Comprehensions. */ +struct ComprehensionSpec { + enum Kind { + FOR, + IF + }; + Kind kind; + Fodder openFodder; + Fodder varFodder; // {} when kind != SPEC_FOR. + const Identifier *var; // Null when kind != SPEC_FOR. + Fodder inFodder; // {} when kind != SPEC_FOR. + AST *expr; + ComprehensionSpec(Kind kind, const Fodder &open_fodder, const Fodder &var_fodder, + const Identifier *var, const Fodder &in_fodder, AST *expr) + : kind(kind), openFodder(open_fodder), varFodder(var_fodder), var(var), inFodder(in_fodder), + expr(expr) + { } +}; + + +/** Represents function calls. */ +struct Apply : public AST { + AST *target; + Fodder fodderL; + ArgParams args; + bool trailingComma; + Fodder fodderR; + Fodder tailstrictFodder; + bool tailstrict; + Apply(const LocationRange &lr, const Fodder &open_fodder, AST *target, const Fodder &fodder_l, + const ArgParams &args, bool trailing_comma, const Fodder &fodder_r, + const Fodder &tailstrict_fodder, bool tailstrict) + : AST(lr, AST_APPLY, open_fodder), target(target), fodderL(fodder_l), args(args), + trailingComma(trailing_comma), fodderR(fodder_r), tailstrictFodder(tailstrict_fodder), + tailstrict(tailstrict) + { } +}; + +/** Represents e { }. Desugared to e + { }. */ +struct ApplyBrace : public AST { + AST *left; + AST *right; // This is always an object or object comprehension. + ApplyBrace(const LocationRange &lr, const Fodder &open_fodder, AST *left, AST *right) + : AST(lr, AST_BINARY, open_fodder), left(left), right(right) + { } +}; + +/** Represents array constructors [1, 2, 3]. */ +struct Array : public AST { + struct Element { + AST *expr; + Fodder commaFodder; + Element(AST *expr, const Fodder &comma_fodder) + : expr(expr), commaFodder(comma_fodder) + { } + }; + typedef std::vector Elements; + Elements elements; + bool trailingComma; + Fodder closeFodder; + Array(const LocationRange &lr, const Fodder &open_fodder, const Elements &elements, + bool trailing_comma, const Fodder &close_fodder) + : AST(lr, AST_ARRAY, open_fodder), elements(elements), trailingComma(trailing_comma), + closeFodder(close_fodder) + { } +}; + +/** Represents array comprehensions (which are like Python list comprehensions). */ +struct ArrayComprehension : public AST { + AST* body; + Fodder commaFodder; + bool trailingComma; + std::vector specs; + Fodder closeFodder; + ArrayComprehension(const LocationRange &lr, const Fodder &open_fodder, AST *body, + const Fodder &comma_fodder, bool trailing_comma, + const std::vector &specs, const Fodder &close_fodder) + : AST(lr, AST_ARRAY_COMPREHENSION, open_fodder), body(body), commaFodder(comma_fodder), + trailingComma(trailing_comma), specs(specs), closeFodder(close_fodder) + { + assert(specs.size() > 0); + } +}; + +/** Represents an assert expression (not an object-level assert). + * + * After parsing, message can be nullptr indicating that no message was specified. This AST is + * elimiated by desugaring. + */ +struct Assert : public AST { + AST *cond; + Fodder colonFodder; + AST *message; + Fodder semicolonFodder; + AST *rest; + Assert(const LocationRange &lr, const Fodder &open_fodder, AST *cond, + const Fodder &colon_fodder, AST *message, const Fodder &semicolon_fodder, AST *rest) + : AST(lr, AST_ASSERT, open_fodder), cond(cond), colonFodder(colon_fodder), + message(message), semicolonFodder(semicolon_fodder), rest(rest) + { } +}; + +enum BinaryOp { + BOP_MULT, + BOP_DIV, + BOP_PERCENT, + + BOP_PLUS, + BOP_MINUS, + + BOP_SHIFT_L, + BOP_SHIFT_R, + + BOP_GREATER, + BOP_GREATER_EQ, + BOP_LESS, + BOP_LESS_EQ, + + BOP_MANIFEST_EQUAL, + BOP_MANIFEST_UNEQUAL, + + BOP_BITWISE_AND, + BOP_BITWISE_XOR, + BOP_BITWISE_OR, + + BOP_AND, + BOP_OR +}; + +static inline std::string bop_string (BinaryOp bop) +{ + switch (bop) { + case BOP_MULT: return "*"; + case BOP_DIV: return "/"; + case BOP_PERCENT: return "%"; + + case BOP_PLUS: return "+"; + case BOP_MINUS: return "-"; + + case BOP_SHIFT_L: return "<<"; + case BOP_SHIFT_R: return ">>"; + + case BOP_GREATER: return ">"; + case BOP_GREATER_EQ: return ">="; + case BOP_LESS: return "<"; + case BOP_LESS_EQ: return "<="; + + case BOP_MANIFEST_EQUAL: return "=="; + case BOP_MANIFEST_UNEQUAL: return "!="; + + case BOP_BITWISE_AND: return "&"; + case BOP_BITWISE_XOR: return "^"; + case BOP_BITWISE_OR: return "|"; + + case BOP_AND: return "&&"; + case BOP_OR: return "||"; + + default: + std::cerr << "INTERNAL ERROR: Unrecognised binary operator: " << bop << std::endl; + std::abort(); + } +} + +/** Represents binary operators. */ +struct Binary : public AST { + AST *left; + Fodder opFodder; + BinaryOp op; + AST *right; + Binary(const LocationRange &lr, const Fodder &open_fodder, AST *left, const Fodder &op_fodder, + BinaryOp op, AST *right) + : AST(lr, AST_BINARY, open_fodder), left(left), opFodder(op_fodder), op(op), right(right) + { } +}; + +/** Represents built-in functions. + * + * There is no parse rule to build this AST. Instead, it is used to build the std object in the + * interpreter. + */ +struct BuiltinFunction : public AST { + std::string name; + Identifiers params; + BuiltinFunction(const LocationRange &lr, const std::string &name, + const Identifiers ¶ms) + : AST(lr, AST_BUILTIN_FUNCTION, Fodder{}), name(name), params(params) + { } +}; + +/** Represents if then else. + * + * After parsing, branchFalse can be nullptr indicating that no else branch was specified. The + * desugarer fills this in with a LiteralNull. + */ +struct Conditional : public AST { + AST *cond; + Fodder thenFodder; + AST *branchTrue; + Fodder elseFodder; + AST *branchFalse; + Conditional(const LocationRange &lr, const Fodder &open_fodder, AST *cond, + const Fodder &then_fodder, AST *branch_true, const Fodder &else_fodder, + AST *branch_false) + : AST(lr, AST_CONDITIONAL, open_fodder), cond(cond), thenFodder(then_fodder), + branchTrue(branch_true), elseFodder(else_fodder), branchFalse(branch_false) + { } +}; + +/** Represents the $ keyword. */ +struct Dollar : public AST { + Dollar(const LocationRange &lr, const Fodder &open_fodder) + : AST(lr, AST_DOLLAR, open_fodder) + { } +}; + +/** Represents error e. */ +struct Error : public AST { + AST *expr; + Error(const LocationRange &lr, const Fodder &open_fodder, AST *expr) + : AST(lr, AST_ERROR, open_fodder), expr(expr) + { } +}; + +/** Represents closures. */ +struct Function : public AST { + Fodder parenLeftFodder; + ArgParams params; + bool trailingComma; + Fodder parenRightFodder; + AST *body; + Function(const LocationRange &lr, const Fodder &open_fodder, const Fodder &paren_left_fodder, + const ArgParams ¶ms, bool trailing_comma, const Fodder &paren_right_fodder, + AST *body) + : AST(lr, AST_FUNCTION, open_fodder), parenLeftFodder(paren_left_fodder), + params(params), trailingComma(trailing_comma), parenRightFodder(paren_right_fodder), + body(body) + { } +}; + +struct LiteralString; + +/** Represents import "file". */ +struct Import : public AST { + LiteralString *file; + Import(const LocationRange &lr, const Fodder &open_fodder, LiteralString *file) + : AST(lr, AST_IMPORT, open_fodder), file(file) + { } +}; + +/** Represents importstr "file". */ +struct Importstr : public AST { + LiteralString *file; + Importstr(const LocationRange &lr, const Fodder &open_fodder, LiteralString *file) + : AST(lr, AST_IMPORTSTR, open_fodder), file(file) + { } +}; + +/** Represents both e[e] and the syntax sugar e.f. + * + * One of index and id will be nullptr before desugaring. After desugaring id will be nullptr. + */ +struct Index : public AST { + AST *target; + Fodder dotFodder; // When index is being used, this is the fodder before the [. + bool isSlice; + AST *index; + Fodder endColonFodder; // When end is being used, this is the fodder before the :. + AST *end; + Fodder stepColonFodder; // When step is being used, this is the fodder before the :. + AST *step; + Fodder idFodder; // When index is being used, this is the fodder before the ]. + const Identifier *id; + // Use this constructor for e.f + Index(const LocationRange &lr, const Fodder &open_fodder, AST *target, const Fodder &dot_fodder, + const Fodder &id_fodder, const Identifier *id) + : AST(lr, AST_INDEX, open_fodder), target(target), dotFodder(dot_fodder), isSlice(false), + index(nullptr), end(nullptr), step(nullptr), idFodder(id_fodder), id(id) + { } + // Use this constructor for e[x:y:z] with nullptr for index, end or step if not present. + Index(const LocationRange &lr, const Fodder &open_fodder, AST *target, const Fodder &dot_fodder, + bool is_slice, AST *index, const Fodder &end_colon_fodder, AST *end, + const Fodder &step_colon_fodder, AST *step, const Fodder &id_fodder) + : AST(lr, AST_INDEX, open_fodder), target(target), dotFodder(dot_fodder), isSlice(is_slice), + index(index), endColonFodder(end_colon_fodder), end(end), + stepColonFodder(step_colon_fodder), step(step), idFodder(id_fodder), id(nullptr) + { } +}; + +/** Represents local x = e; e. After desugaring, functionSugar is false. */ +struct Local : public AST { + struct Bind { + Fodder varFodder; + const Identifier *var; + Fodder opFodder; + AST *body; + bool functionSugar; + Fodder parenLeftFodder; + ArgParams params; // If functionSugar == true + bool trailingComma; + Fodder parenRightFodder; + Fodder closeFodder; + Bind(const Fodder &var_fodder, const Identifier *var, const Fodder &op_fodder, AST *body, + bool function_sugar, const Fodder &paren_left_fodder, const ArgParams ¶ms, + bool trailing_comma, const Fodder &paren_right_fodder, const Fodder &close_fodder) + : varFodder(var_fodder), var(var), opFodder(op_fodder), body(body), + functionSugar(function_sugar), parenLeftFodder(paren_left_fodder), params(params), + trailingComma(trailing_comma), parenRightFodder(paren_right_fodder), + closeFodder(close_fodder) + { } + }; + typedef std::vector Binds; + Binds binds; + AST *body; + Local(const LocationRange &lr, const Fodder &open_fodder, const Binds &binds, AST *body) + : AST(lr, AST_LOCAL, open_fodder), binds(binds), body(body) + { } +}; + +/** Represents true and false. */ +struct LiteralBoolean : public AST { + bool value; + LiteralBoolean(const LocationRange &lr, const Fodder &open_fodder, bool value) + : AST(lr, AST_LITERAL_BOOLEAN, open_fodder), value(value) + { } +}; + +/** Represents the null keyword. */ +struct LiteralNull : public AST { + LiteralNull(const LocationRange &lr, const Fodder &open_fodder) + : AST(lr, AST_LITERAL_NULL, open_fodder) + { } +}; + +/** Represents JSON numbers. */ +struct LiteralNumber : public AST { + double value; + std::string originalString; + LiteralNumber(const LocationRange &lr, const Fodder &open_fodder, const std::string &str) + : AST(lr, AST_LITERAL_NUMBER, open_fodder), value(strtod(str.c_str(), nullptr)), + originalString(str) + { } +}; + +/** Represents JSON strings. */ +struct LiteralString : public AST { + String value; + enum TokenKind { SINGLE, DOUBLE, BLOCK, VERBATIM_SINGLE, VERBATIM_DOUBLE }; + TokenKind tokenKind; + std::string blockIndent; // Only contains ' ' and '\t'. + std::string blockTermIndent; // Only contains ' ' and '\t'. + LiteralString(const LocationRange &lr, const Fodder &open_fodder, const String &value, + TokenKind token_kind, const std::string &block_indent, + const std::string &block_term_indent) + : AST(lr, AST_LITERAL_STRING, open_fodder), value(value), tokenKind(token_kind), + blockIndent(block_indent), blockTermIndent(block_term_indent) + { } +}; + + +struct ObjectField { + // Depending on the kind of Jsonnet field, the fields of this C++ class are used for storing + // different parts of the AST. + enum Kind { + + // 'assert' + // [ : ] + // + ASSERT, + + // id + // [ '(' ')' ] + // [+]:[:[:]] + // + FIELD_ID, + + // '[' ']' + // [ '(' ')' ] + // [+]:[:[:]] + // + FIELD_EXPR, + + // + // '(' ')' + // [+]:[:[:]] + // + FIELD_STR, + + // 'local' id + // [ '(' ')' ] + // [ = ] + // + LOCAL, + }; + + // NOTE TO SELF: sort out fodder1-4, then modify desugarer (maybe) parser and unparser. + + enum Hide { + HIDDEN, // f:: e + INHERIT, // f: e + VISIBLE, // f::: e + }; + enum Kind kind; + Fodder fodder1, fodder2, fodderL, fodderR; + enum Hide hide; // (ignore if kind != FIELD_something + bool superSugar; // +: (ignore if kind != FIELD_something) + bool methodSugar; // f(x, y, z): ... (ignore if kind == ASSERT) + AST *expr1; // Not in scope of the object + const Identifier *id; + ArgParams params; // If methodSugar == true then holds the params. + bool trailingComma; // If methodSugar == true then remembers the trailing comma. + Fodder opFodder; // Before the : or = + AST *expr2, *expr3; // In scope of the object (can see self). + Fodder commaFodder; // If this field is followed by a comma, this is its fodder. + + ObjectField( + enum Kind kind, const Fodder &fodder1, const Fodder &fodder2, const Fodder &fodder_l, + const Fodder &fodder_r, enum Hide hide, bool super_sugar, bool method_sugar, AST *expr1, + const Identifier *id, const ArgParams ¶ms, bool trailing_comma, const Fodder &op_fodder, + AST *expr2, AST *expr3, const Fodder &comma_fodder) + : kind(kind), fodder1(fodder1), fodder2(fodder2), fodderL(fodder_l), fodderR(fodder_r), + hide(hide), superSugar(super_sugar), methodSugar(method_sugar), expr1(expr1), id(id), + params(params), trailingComma(trailing_comma), opFodder(op_fodder), expr2(expr2), + expr3(expr3), commaFodder(comma_fodder) + { + // Enforce what is written in comments above. + assert(kind != ASSERT || (hide == VISIBLE && !superSugar && !methodSugar)); + assert(kind != LOCAL || (hide == VISIBLE && !superSugar)); + assert(kind != FIELD_ID || (id != nullptr && expr1 == nullptr)); + assert(kind == FIELD_ID || kind == LOCAL || id == nullptr); + assert(methodSugar || (params.size() == 0 && !trailingComma)); + assert(kind == ASSERT || expr3 == nullptr); + } + // For when we don't know if it's a function or not. + static ObjectField Local( + const Fodder &fodder1, const Fodder &fodder2, const Fodder &fodder_l, + const Fodder &fodder_r, bool method_sugar, const Identifier *id, const ArgParams ¶ms, + bool trailing_comma, const Fodder &op_fodder, AST *body, const Fodder &comma_fodder) + { + return ObjectField( + LOCAL, fodder1, fodder2, fodder_l, fodder_r, VISIBLE, false, method_sugar, nullptr, id, + params, trailing_comma, op_fodder, body, nullptr, comma_fodder); + } + static ObjectField Local( + const Fodder &fodder1, const Fodder &fodder2, const Identifier *id, + const Fodder &op_fodder, AST *body, const Fodder &comma_fodder) + { + return ObjectField( + LOCAL, fodder1, fodder2, Fodder{}, Fodder{}, VISIBLE, false, false, nullptr, id, + ArgParams{}, false, op_fodder, body, nullptr, comma_fodder); + } + static ObjectField LocalMethod( + const Fodder &fodder1, const Fodder &fodder2, const Fodder &fodder_l, + const Fodder &fodder_r, const Identifier *id, const ArgParams ¶ms, bool trailing_comma, + const Fodder &op_fodder, AST *body, const Fodder &comma_fodder) + { + return ObjectField( + LOCAL, fodder1, fodder2, fodder_l, fodder_r, VISIBLE, false, true, nullptr, id, params, + trailing_comma, op_fodder, body, nullptr, comma_fodder); + } + static ObjectField Assert(const Fodder &fodder1, AST *body, const Fodder &op_fodder, AST *msg, + const Fodder &comma_fodder) + { + return ObjectField( + ASSERT, fodder1, Fodder{}, Fodder{}, Fodder{}, VISIBLE, false, false, nullptr, nullptr, + ArgParams{}, false, op_fodder, body, msg, comma_fodder); + } +}; +typedef std::vector ObjectFields; + +/** Represents object constructors { f: e ... }. + * + * The trailing comma is only allowed if fields.size() > 0. Converted to DesugaredObject during + * desugaring. + */ +struct Object : public AST { + ObjectFields fields; + bool trailingComma; + Fodder closeFodder; + Object(const LocationRange &lr, const Fodder &open_fodder, const ObjectFields &fields, + bool trailing_comma, const Fodder &close_fodder) + : AST(lr, AST_OBJECT, open_fodder), fields(fields), trailingComma(trailing_comma), + closeFodder(close_fodder) + { + assert(fields.size() > 0 || !trailing_comma); + if (fields.size() > 0) + assert(trailing_comma || fields[fields.size() - 1].commaFodder.size() == 0); + } +}; + +/** Represents object constructors { f: e ... } after desugaring. + * + * The assertions either return true or raise an error. + */ +struct DesugaredObject : public AST { + struct Field { + enum ObjectField::Hide hide; + AST *name; + AST *body; + Field(enum ObjectField::Hide hide, AST *name, AST *body) + : hide(hide), name(name), body(body) + { } + }; + typedef std::vector Fields; + ASTs asserts; + Fields fields; + DesugaredObject(const LocationRange &lr, const ASTs &asserts, const Fields &fields) + : AST(lr, AST_DESUGARED_OBJECT, Fodder{}), asserts(asserts), fields(fields) + { } +}; + + +/** Represents object comprehension { [e]: e for x in e for.. if... }. */ +struct ObjectComprehension : public AST { + ObjectFields fields; + bool trailingComma; + std::vector specs; + Fodder closeFodder; + ObjectComprehension(const LocationRange &lr, const Fodder &open_fodder, + const ObjectFields &fields, bool trailing_comma, + const std::vector &specs, const Fodder &close_fodder) + + : AST(lr, AST_OBJECT_COMPREHENSION, open_fodder), fields(fields), + trailingComma(trailing_comma), specs(specs), closeFodder(close_fodder) + { } +}; + +/** Represents post-desugaring object comprehension { [e]: e for x in e }. */ +struct ObjectComprehensionSimple : public AST { + AST *field; + AST *value; + const Identifier *id; + AST *array; + ObjectComprehensionSimple(const LocationRange &lr, AST *field, AST *value, + const Identifier *id, AST *array) + : AST(lr, AST_OBJECT_COMPREHENSION_SIMPLE, Fodder{}), field(field), value(value), id(id), array(array) + { } +}; + +/** Represents (e), which is desugared. */ +struct Parens : public AST { + AST *expr; + Fodder closeFodder; + Parens(const LocationRange &lr, const Fodder &open_fodder, AST *expr, + const Fodder &close_fodder) + : AST(lr, AST_PARENS, open_fodder), expr(expr), closeFodder(close_fodder) + { } +}; + +/** Represents the self keyword. */ +struct Self : public AST { + Self(const LocationRange &lr, const Fodder &open_fodder) + : AST(lr, AST_SELF, open_fodder) + { } +}; + +/** Represents the super[e] and super.f constructs. + * + * Either index or identifier will be set before desugaring. After desugaring, id will be + * nullptr. + */ +struct SuperIndex : public AST { + Fodder dotFodder; + AST *index; + Fodder idFodder; + const Identifier *id; + SuperIndex(const LocationRange &lr, const Fodder &open_fodder, const Fodder &dot_fodder, + AST *index, const Fodder &id_fodder, const Identifier *id) + : AST(lr, AST_SUPER_INDEX, open_fodder), dotFodder(dot_fodder), index(index), + idFodder(id_fodder), id(id) + { } +}; + +enum UnaryOp { + UOP_NOT, + UOP_BITWISE_NOT, + UOP_PLUS, + UOP_MINUS +}; + +static inline std::string uop_string (UnaryOp uop) +{ + switch (uop) { + case UOP_PLUS: return "+"; + case UOP_MINUS: return "-"; + case UOP_BITWISE_NOT: return "~"; + case UOP_NOT: return "!"; + + default: + std::cerr << "INTERNAL ERROR: Unrecognised unary operator: " << uop << std::endl; + std::abort(); + } +} + +/** Represents unary operators. */ +struct Unary : public AST { + UnaryOp op; + AST *expr; + Unary(const LocationRange &lr, const Fodder &open_fodder, UnaryOp op, AST *expr) + : AST(lr, AST_UNARY, open_fodder), op(op), expr(expr) + { } +}; + +/** Represents variables. */ +struct Var : public AST { + const Identifier *id; + Var(const LocationRange &lr, const Fodder &open_fodder, const Identifier *id) + : AST(lr, AST_VAR, open_fodder), id(id) + { } +}; + + +/** Allocates ASTs on demand, frees them in its destructor. + */ +class Allocator { + std::map internedIdentifiers; + ASTs allocated; + public: + template T* make(Args&&... args) + { + auto r = new T(std::forward(args)...); + allocated.push_back(r); + return r; + } + + template T *clone(T * ast) { + auto r = new T(*ast); + allocated.push_back(r); + return r; + } + /** Returns interned identifiers. + * + * The location used in the Identifier AST is that of the first one parsed. + */ + const Identifier *makeIdentifier(const String &name) + { + auto it = internedIdentifiers.find(name); + if (it != internedIdentifiers.end()) { + return it->second; + } + auto r = new Identifier(name); + internedIdentifiers[name] = r; + return r; + } + ~Allocator() + { + for (auto x : allocated) { + delete x; + } + allocated.clear(); + for (auto x : internedIdentifiers) { + delete x.second; + } + internedIdentifiers.clear(); + } +}; + +namespace { + +// Precedences used by various compilation units are defined here. +const int APPLY_PRECEDENCE = 2; // Function calls and indexing. +const int UNARY_PRECEDENCE = 4; // Logical and bitwise negation, unary + - +const int BEFORE_ELSE_PRECEDENCE = 15; // True branch of an if. +const int MAX_PRECEDENCE = 16; // Local, If, Import, Function, Error + +/** These are the binary operator precedences, unary precedence is given by + * UNARY_PRECEDENCE. + */ +std::map build_precedence_map(void) +{ + std::map r; + + r[BOP_MULT] = 5; + r[BOP_DIV] = 5; + r[BOP_PERCENT] = 5; + + r[BOP_PLUS] = 6; + r[BOP_MINUS] = 6; + + r[BOP_SHIFT_L] = 7; + r[BOP_SHIFT_R] = 7; + + r[BOP_GREATER] = 8; + r[BOP_GREATER_EQ] = 8; + r[BOP_LESS] = 8; + r[BOP_LESS_EQ] = 8; + + r[BOP_MANIFEST_EQUAL] = 9; + r[BOP_MANIFEST_UNEQUAL] = 9; + + r[BOP_BITWISE_AND] = 10; + + r[BOP_BITWISE_XOR] = 11; + + r[BOP_BITWISE_OR] = 12; + + r[BOP_AND] = 13; + + r[BOP_OR] = 14; + + return r; +} + +std::map build_unary_map(void) +{ + std::map r; + r["!"] = UOP_NOT; + r["~"] = UOP_BITWISE_NOT; + r["+"] = UOP_PLUS; + r["-"] = UOP_MINUS; + return r; +} + +std::map build_binary_map(void) +{ + std::map r; + + r["*"] = BOP_MULT; + r["/"] = BOP_DIV; + r["%"] = BOP_PERCENT; + + r["+"] = BOP_PLUS; + r["-"] = BOP_MINUS; + + r["<<"] = BOP_SHIFT_L; + r[">>"] = BOP_SHIFT_R; + + r[">"] = BOP_GREATER; + r[">="] = BOP_GREATER_EQ; + r["<"] = BOP_LESS; + r["<="] = BOP_LESS_EQ; + + r["=="] = BOP_MANIFEST_EQUAL; + r["!="] = BOP_MANIFEST_UNEQUAL; + + r["&"] = BOP_BITWISE_AND; + r["^"] = BOP_BITWISE_XOR; + r["|"] = BOP_BITWISE_OR; + + r["&&"] = BOP_AND; + r["||"] = BOP_OR; + return r; +} + +auto precedence_map = build_precedence_map(); +auto unary_map = build_unary_map(); +auto binary_map = build_binary_map(); + +} // namespace + +#endif // JSONNET_AST_H diff --git a/vendor/github.com/strickyak/jsonnet_cgo/bridge.c b/vendor/github.com/strickyak/jsonnet_cgo/bridge.c new file mode 100644 index 00000000..2eb824dc --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/bridge.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include "bridge.h" + +char* CallImport_cgo(void *ctx, const char *base, const char *rel, char **found_here, int *success) { + struct JsonnetVm* vm = ctx; + char *path = NULL; + char* result = go_call_import(vm, (char*)base, (char*)rel, &path, success); + if (*success) { + char* found_here_buf = jsonnet_realloc(vm, NULL, strlen(path)+1); + strcpy(found_here_buf, path); + *found_here = found_here_buf; + } + char* buf = jsonnet_realloc(vm, NULL, strlen(result)+1); + strcpy(buf, result); + return buf; +} diff --git a/vendor/github.com/strickyak/jsonnet_cgo/bridge.h b/vendor/github.com/strickyak/jsonnet_cgo/bridge.h new file mode 100644 index 00000000..2cafd512 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/bridge.h @@ -0,0 +1,13 @@ +#ifndef LIBJSONNET_BRIDGE_H +#define LIBJSONNET_BRIDGE_H +#include + +typedef JsonnetImportCallback* JsonnetImportCallbackPtr; + +struct JsonnetVm* go_get_guts(void* ctx); + +char* CallImport_cgo(void *ctx, const char *base, const char *rel, char **found_here, int *success); + +char* go_call_import(void* vm, char *base, char *rel, char **path, int *success); + +#endif diff --git a/vendor/github.com/strickyak/jsonnet_cgo/desugarer.cpp b/vendor/github.com/strickyak/jsonnet_cgo/desugarer.cpp new file mode 100644 index 00000000..6b480787 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/desugarer.cpp @@ -0,0 +1,906 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include + +#include "ast.h" +#include "desugarer.h" +#include "lexer.h" +#include "parser.h" +#include "pass.h" +#include "string_utils.h" + +static const Fodder EF; // Empty fodder. + +static const LocationRange E; // Empty. + +struct BuiltinDecl { + String name; + std::vector params; +}; + +static unsigned long max_builtin = 26; +BuiltinDecl jsonnet_builtin_decl(unsigned long builtin) +{ + switch (builtin) { + case 0: return {U"makeArray", {U"sz", U"func"}}; + case 1: return {U"pow", {U"x", U"n"}}; + case 2: return {U"floor", {U"x"}}; + case 3: return {U"ceil", {U"x"}}; + case 4: return {U"sqrt", {U"x"}}; + case 5: return {U"sin", {U"x"}}; + case 6: return {U"cos", {U"x"}}; + case 7: return {U"tan", {U"x"}}; + case 8: return {U"asin", {U"x"}}; + case 9: return {U"acos", {U"x"}}; + case 10: return {U"atan", {U"x"}}; + case 11: return {U"type", {U"x"}}; + case 12: return {U"filter", {U"func", U"arr"}}; + case 13: return {U"objectHasEx", {U"obj", U"f", U"inc_hidden"}}; + case 14: return {U"length", {U"x"}}; + case 15: return {U"objectFieldsEx", {U"obj", U"inc_hidden"}}; + case 16: return {U"codepoint", {U"str"}}; + case 17: return {U"char", {U"n"}}; + case 18: return {U"log", {U"n"}}; + case 19: return {U"exp", {U"n"}}; + case 20: return {U"mantissa", {U"n"}}; + case 21: return {U"exponent", {U"n"}}; + case 22: return {U"modulo", {U"a", U"b"}}; + case 23: return {U"extVar", {U"x"}}; + case 24: return {U"primitiveEquals", {U"a", U"b"}}; + case 25: return {U"native", {U"name"}}; + case 26: return {U"md5", {U"str"}}; + default: + std::cerr << "INTERNAL ERROR: Unrecognized builtin function: " << builtin << std::endl; + std::abort(); + } + // Quiet, compiler. + return BuiltinDecl(); +} + +static constexpr char STD_CODE[] = { + #include "std.jsonnet.h" +}; + +/** Desugar Jsonnet expressions to reduce the number of constructs the rest of the implementation + * needs to understand. + * + * Desugaring should happen immediately after parsing, i.e. before static analysis and execution. + * Temporary variables introduced here should be prefixed with $ to ensure they do not clash with + * variables used in user code. + */ +class Desugarer { + + Allocator *alloc; + + template T* make(Args&&... args) + { + return alloc->make(std::forward(args)...); + } + + const Identifier *id(const String &s) + { return alloc->makeIdentifier(s); } + + LiteralString *str(const String &s) + { return make(E, EF, s, LiteralString::DOUBLE, "", ""); } + + LiteralString *str(const LocationRange &loc, const String &s) + { return make(loc, EF, s, LiteralString::DOUBLE, "", ""); } + + LiteralNull *null(void) + { return make(E, EF); } + + Var *var(const Identifier *ident) + { return make(E, EF, ident); } + + Var *std(void) + { return var(id(U"std")); } + + + Local::Bind bind(const Identifier *id, AST *body) + { + return Local::Bind(EF, id, EF, body, false, EF, ArgParams{}, false, EF, EF); + } + + Local::Binds singleBind(const Identifier *id, AST *body) + { + return {bind(id, body)}; + } + + Array *singleton(AST *body) + { + return make(body->location, EF, Array::Elements{Array::Element(body, EF)}, + false, EF); + } + + Apply *stdFunc(const String &name, AST *v) + { + return make( + v->location, + EF, + make(E, EF, std(), EF, false, str(name), EF, nullptr, EF, nullptr, EF), + EF, + ArgParams{{v, EF}}, + false, // trailingComma + EF, + EF, + true // tailstrict + ); + } + + Apply *stdFunc(const LocationRange &loc, const String &name, AST *a, AST *b) + { + return make( + loc, + EF, + make(E, EF, std(), EF, false, str(name), EF, nullptr, EF, nullptr, EF), + EF, + ArgParams{{a, EF}, {b, EF}}, + false, // trailingComma + EF, + EF, + true // tailstrict + ); + } + + Apply *length(AST *v) + { + return stdFunc(U"length", v); + } + + Apply *type(AST *v) + { + return stdFunc(U"type", v); + } + + Apply *primitiveEquals(const LocationRange &loc, AST *a, AST *b) + { + return stdFunc(loc, U"primitiveEquals", a, b); + } + + Apply *equals(const LocationRange &loc, AST *a, AST *b) + { + return stdFunc(loc, U"equals", a, b); + } + + Error *error(AST *msg) + { + return make(msg->location, EF, msg); + } + + Error *error(const LocationRange &loc, const String &msg) + { + return error(str(loc, msg)); + } + + public: + Desugarer(Allocator *alloc) + : alloc(alloc) + { } + + void desugarParams(ArgParams ¶ms, unsigned obj_level) + { + for (auto ¶m : params) { + if (param.expr) { + // Default arg. + desugar(param.expr, obj_level); + } + } + } + + // For all occurrences, records the identifier that will replace super[e] + // If self occurs, also map the self identifier to nullptr. + typedef std::vector> SuperVars; + + SuperVars desugarFields(AST *ast, ObjectFields &fields, unsigned obj_level) + { + // Desugar children + for (auto &field : fields) { + if (field.expr1 != nullptr) desugar(field.expr1, obj_level); + desugar(field.expr2, obj_level + 1); + if (field.expr3 != nullptr) desugar(field.expr3, obj_level + 1); + desugarParams(field.params, obj_level + 1); + } + + // Simplify asserts + for (auto &field : fields) { + if (field.kind != ObjectField::ASSERT) continue; + AST *msg = field.expr3; + field.expr3 = nullptr; + if (msg == nullptr) { + // The location is what appears in the stacktrace. + msg = str(field.expr2->location, U"Object assertion failed."); + } + + // if expr2 then true else error msg + field.expr2 = make( + field.expr2->location, + EF, + field.expr2, + EF, + make(E, EF, true), + EF, + error(msg)); + } + + // Remove methods + for (auto &field : fields) { + if (!field.methodSugar) continue; + field.expr2 = make( + field.expr2->location, EF, field.fodderL, field.params, field.trailingComma, + field.fodderR, field.expr2); + field.methodSugar = false; + field.params.clear(); + } + + + // Remove object-level locals + auto copy = fields; + fields.clear(); + Local::Binds binds; + for (auto &local : copy) { + if (local.kind != ObjectField::LOCAL) continue; + binds.push_back(bind(local.id, local.expr2)); + } + for (auto &field : copy) { + if (field.kind == ObjectField::LOCAL) continue; + if (!binds.empty()) + field.expr2 = make(field.expr2->location, EF, binds, field.expr2); + fields.push_back(field); + } + + // Change all to FIELD_EXPR + for (auto &field : fields) { + switch (field.kind) { + case ObjectField::ASSERT: + // Nothing to do. + break; + + case ObjectField::FIELD_ID: + field.expr1 = str(field.id->name); + field.kind = ObjectField::FIELD_EXPR; + break; + + case ObjectField::FIELD_EXPR: + // Nothing to do. + break; + + case ObjectField::FIELD_STR: + // Just set the flag. + field.kind = ObjectField::FIELD_EXPR; + break; + + case ObjectField::LOCAL: + std::cerr << "Locals should be removed by now." << std::endl; + abort(); + } + } + + class SubstituteSelfSuper : public CompilerPass { + Desugarer *desugarer; + SuperVars &superVars; + unsigned &counter; + const Identifier *newSelf; + public: + SubstituteSelfSuper(Desugarer *desugarer, SuperVars &super_vars, unsigned &counter) + : CompilerPass(*desugarer->alloc), desugarer(desugarer), superVars(super_vars), + counter(counter), newSelf(nullptr) + { + } + void visitExpr(AST *&expr) + { + if (dynamic_cast(expr)) { + if (newSelf == nullptr) { + newSelf = desugarer->id(U"$outer_self"); + superVars.emplace_back(newSelf, nullptr); + } + expr = alloc.make(expr->location, expr->openFodder, newSelf); + } else if (auto *super_index = dynamic_cast(expr)) { + StringStream ss; + ss << "$outer_super" << (counter++); + const Identifier *super_var = desugarer->id(ss.str()); + AST *index = super_index->index; + // Desugaring of expr should already have occurred. + assert(index != nullptr); + // Re-use super_index since we're replacing it here. + superVars.emplace_back(super_var, super_index); + expr = alloc.make(expr->location, expr->openFodder, super_var); + } + CompilerPass::visitExpr(expr); + } + }; + + SuperVars super_vars; + unsigned counter; + + // Remove +: + for (auto &field : fields) { + if (!field.superSugar) continue; + // We have to bind self/super from expr1 outside the class, as we copy the expression + // into the field body. + AST *index = field.expr1; + // Clone it so that we maintain the AST as a tree. + ClonePass(*alloc).expr(index); + // This will remove self/super. + SubstituteSelfSuper(this, super_vars, counter).expr(index); + AST *super_f = make(field.expr1->location, EF, EF, index, EF, nullptr); + field.expr2 = make(ast->location, EF, super_f, EF, BOP_PLUS, field.expr2); + field.superSugar = false; + } + + return super_vars; + } + + void desugar(AST *&ast_, unsigned obj_level) + { + if (auto *ast = dynamic_cast(ast_)) { + desugar(ast->target, obj_level); + for (ArgParam &arg : ast->args) + desugar(arg.expr, obj_level); + + } else if (auto *ast = dynamic_cast(ast_)) { + desugar(ast->left, obj_level); + desugar(ast->right, obj_level); + ast_ = make(ast->location, ast->openFodder, + ast->left, EF, BOP_PLUS, ast->right); + + } else if (auto *ast = dynamic_cast(ast_)) { + for (auto &el : ast->elements) + desugar(el.expr, obj_level); + + } else if (auto *ast = dynamic_cast(ast_)) { + for (ComprehensionSpec &spec : ast->specs) + desugar(spec.expr, obj_level); + desugar(ast->body, obj_level + 1); + + int n = ast->specs.size(); + AST *zero = make(E, EF, "0.0"); + AST *one = make(E, EF, "1.0"); + auto *_r = id(U"$r"); + auto *_l = id(U"$l"); + std::vector _i(n); + for (int i = 0; i < n ; ++i) { + StringStream ss; + ss << U"$i_" << i; + _i[i] = id(ss.str()); + } + std::vector _aux(n); + for (int i = 0; i < n ; ++i) { + StringStream ss; + ss << U"$aux_" << i; + _aux[i] = id(ss.str()); + } + + // Build it from the inside out. We keep wrapping 'in' with more ASTs. + assert(ast->specs[0].kind == ComprehensionSpec::FOR); + + int last_for = n - 1; + while (ast->specs[last_for].kind != ComprehensionSpec::FOR) + last_for--; + // $aux_{last_for}($i_{last_for} + 1, $r + [body]) + AST *in = make( + ast->body->location, + EF, + var(_aux[last_for]), + EF, + ArgParams { + { make(E, EF, var(_i[last_for]), EF, BOP_PLUS, one), EF}, + { make(E, EF, var(_r), EF, BOP_PLUS, singleton(ast->body)), EF} + }, + false, // trailingComma + EF, + EF, + true // tailstrict + ); + for (int i = n - 1; i >= 0 ; --i) { + const ComprehensionSpec &spec = ast->specs[i]; + AST *out; + if (i > 0) { + int prev_for = i - 1; + while (ast->specs[prev_for].kind != ComprehensionSpec::FOR) + prev_for--; + + // aux_{prev_for}($i_{prev_for} + 1, $r) + out = make( // False branch. + E, + EF, + var(_aux[prev_for]), + EF, + ArgParams { + { make(E, EF, var(_i[prev_for]), EF, BOP_PLUS, one), EF, }, + { var(_r), EF, } + }, + false, // trailingComma + EF, + EF, + true // tailstrict + ); + } else { + out = var(_r); + } + switch (spec.kind) { + case ComprehensionSpec::IF: { + /* + if [[[...cond...]]] then + [[[...in...]]] + else + [[[...out...]]] + */ + in = make( + ast->location, + EF, + spec.expr, + EF, + in, // True branch. + EF, + out); // False branch. + } break; + case ComprehensionSpec::FOR: { + /* + local $l = [[[...array...]]] + aux_{i}(i_{i}, r) = + if i_{i} >= std.length($l) then + [[[...out...]]] + else + local [[[...var...]]] = $l[i_{i}]; + [[[...in...]]]; + if std.type($l) == "array" then + aux_{i}(0, $r) tailstrict + else + error "In comprehension, can only iterate over array.."; + */ + in = make( + ast->location, + EF, + Local::Binds { + bind(_l, spec.expr), // Need to check expr is an array + bind(_aux[i], make( + ast->location, + EF, + EF, + ArgParams{{EF, _i[i], EF}, {EF, _r, EF}}, + false, // trailingComma + EF, + make( + ast->location, + EF, + make( + E, EF, var(_i[i]), EF, BOP_GREATER_EQ, length(var(_l))), + EF, + out, + EF, + make( + ast->location, + EF, + singleBind( + spec.var, + make(E, EF, var(_l), EF, false, var(_i[i]), + EF, nullptr, EF, nullptr, EF) + ), + in) + ) + ))}, + make( + ast->location, + EF, + equals(ast->location, type(var(_l)), str(U"array")), + EF, + make( + E, + EF, + var(_aux[i]), + EF, + ArgParams { + {zero, EF}, + { + i == 0 + ? make(E, EF, Array::Elements{}, false, EF) + : static_cast(var(_r)), + EF, + } + }, + false, // trailingComma + EF, + EF, + true), // tailstrict + EF, + error(ast->location, + U"In comprehension, can only iterate over array."))); + } break; + } + } + + ast_ = in; + + } else if (auto *ast = dynamic_cast(ast_)) { + desugar(ast->cond, obj_level); + if (ast->message == nullptr) { + ast->message = str(U"Assertion failed."); + } + desugar(ast->message, obj_level); + desugar(ast->rest, obj_level); + + // if cond then rest else error msg + AST *branch_false = make(ast->location, EF, ast->message); + ast_ = make(ast->location, ast->openFodder, + ast->cond, EF, ast->rest, EF, branch_false); + + } else if (auto *ast = dynamic_cast(ast_)) { + desugar(ast->left, obj_level); + desugar(ast->right, obj_level); + + bool invert = false; + + switch (ast->op) { + case BOP_PERCENT: { + AST *f_mod = make(E, EF, std(), EF, false, str(U"mod"), EF, + nullptr, EF, nullptr, EF); + ArgParams args = {{ast->left, EF}, {ast->right, EF}}; + ast_ = make(ast->location, ast->openFodder, f_mod, EF, args, + false, EF, EF, false); + } break; + + case BOP_MANIFEST_UNEQUAL: + invert = true; + case BOP_MANIFEST_EQUAL: { + ast_ = equals(ast->location, ast->left, ast->right); + if (invert) + ast_ = make(ast->location, ast->openFodder, UOP_NOT, ast_); + } + break; + + default:; + // Otherwise don't change it. + } + + } else if (dynamic_cast(ast_)) { + // Nothing to do. + + } else if (auto *ast = dynamic_cast(ast_)) { + desugar(ast->cond, obj_level); + desugar(ast->branchTrue, obj_level); + if (ast->branchFalse == nullptr) + ast->branchFalse = null(); + desugar(ast->branchFalse, obj_level); + + } else if (auto *ast = dynamic_cast(ast_)) { + if (obj_level == 0) { + throw StaticError(ast->location, "No top-level object found."); + } + ast_ = var(id(U"$")); + + } else if (auto *ast = dynamic_cast(ast_)) { + desugar(ast->expr, obj_level); + + } else if (auto *ast = dynamic_cast(ast_)) { + desugar(ast->body, obj_level); + desugarParams(ast->params, obj_level); + + } else if (dynamic_cast(ast_)) { + // Nothing to do. + + } else if (dynamic_cast(ast_)) { + // Nothing to do. + + } else if (auto *ast = dynamic_cast(ast_)) { + desugar(ast->target, obj_level); + if (ast->isSlice) { + if (ast->index == nullptr) + ast->index = null(); + desugar(ast->index, obj_level); + + if (ast->end == nullptr) + ast->end = null(); + desugar(ast->end, obj_level); + + if (ast->step == nullptr) + ast->step = null(); + desugar(ast->step, obj_level); + + ast_ = make( + ast->location, + EF, + make( + E, EF, std(), EF, false, str(U"slice"), EF, nullptr, EF, nullptr, EF), + EF, + ArgParams{ + {ast->target, EF}, + {ast->index, EF}, + {ast->end, EF}, + {ast->step, EF}, + }, + false, // trailing comma + EF, + EF, + false // tailstrict + ); + } else { + if (ast->id != nullptr) { + assert(ast->index == nullptr); + ast->index = str(ast->id->name); + ast->id = nullptr; + } + desugar(ast->index, obj_level); + } + + } else if (auto *ast = dynamic_cast(ast_)) { + for (auto &bind: ast->binds) + desugar(bind.body, obj_level); + desugar(ast->body, obj_level); + + for (auto &bind: ast->binds) { + if (bind.functionSugar) { + desugarParams(bind.params, obj_level); + bind.body = make( + ast->location, ast->openFodder, bind.parenLeftFodder, bind.params, false, + bind.parenRightFodder, bind.body); + bind.functionSugar = false; + bind.params.clear(); + } + } + + } else if (dynamic_cast(ast_)) { + // Nothing to do. + + } else if (dynamic_cast(ast_)) { + // Nothing to do. + + } else if (auto *ast = dynamic_cast(ast_)) { + if ((ast->tokenKind != LiteralString::BLOCK) && + (ast->tokenKind != LiteralString::VERBATIM_DOUBLE) && + (ast->tokenKind != LiteralString::VERBATIM_SINGLE)) { + ast->value = jsonnet_string_unescape(ast->location, ast->value); + } + ast->tokenKind = LiteralString::DOUBLE; + ast->blockIndent.clear(); + + } else if (dynamic_cast(ast_)) { + // Nothing to do. + + } else if (auto *ast = dynamic_cast(ast_)) { + for (auto &field : ast->fields) { + desugar(field.name, obj_level); + desugar(field.body, obj_level + 1); + } + for (AST *assert : ast->asserts) { + desugar(assert, obj_level + 1); + } + + } else if (auto *ast = dynamic_cast(ast_)) { + // Hidden variable to allow outer/top binding. + if (obj_level == 0) { + const Identifier *hidden_var = id(U"$"); + auto *body = make(E, EF); + ast->fields.push_back(ObjectField::Local(EF, EF, hidden_var, EF, body, EF)); + } + + SuperVars svs = desugarFields(ast, ast->fields, obj_level); + + DesugaredObject::Fields new_fields; + ASTs new_asserts; + for (const ObjectField &field : ast->fields) { + if (field.kind == ObjectField::ASSERT) { + new_asserts.push_back(field.expr2); + } else if (field.kind == ObjectField::FIELD_EXPR) { + new_fields.emplace_back(field.hide, field.expr1, field.expr2); + } else { + std::cerr << "INTERNAL ERROR: field should have been desugared: " + << field.kind << std::endl; + } + } + ast_ = make(ast->location, new_asserts, new_fields); + if (svs.size() > 0) { + Local::Binds binds; + for (const auto &pair : svs) { + if (pair.second == nullptr) { + // Self binding + binds.push_back(bind(pair.first, make(E, EF))); + } else { + // Super binding + binds.push_back(bind(pair.first, pair.second)); + } + } + ast_ = make(ast->location, EF, binds, ast_); + } + + } else if (auto *ast = dynamic_cast(ast_)) { + // Hidden variable to allow outer/top binding. + if (obj_level == 0) { + const Identifier *hidden_var = id(U"$"); + auto *body = make(E, EF); + ast->fields.push_back(ObjectField::Local(EF, EF, hidden_var, EF, body, EF)); + } + + SuperVars svs = desugarFields(ast, ast->fields, obj_level); + + for (ComprehensionSpec &spec : ast->specs) + desugar(spec.expr, obj_level); + + AST *field = ast->fields.front().expr1; + AST *value = ast->fields.front().expr2; + + /* { + [arr[0]]: local x = arr[1], y = arr[2], z = arr[3]; val_expr + for arr in [ [key_expr, x, y, z] for ... ] + } + */ + auto *_arr = id(U"$arr"); + AST *zero = make(E, EF, "0.0"); + int counter = 1; + Local::Binds binds; + Array::Elements arr_e {Array::Element(field, EF)}; + for (ComprehensionSpec &spec : ast->specs) { + if (spec.kind == ComprehensionSpec::FOR) { + std::stringstream num; + num << counter++; + binds.push_back(bind( + spec.var, + make(E, EF, var(_arr), EF, false, + make(E, EF, num.str()), EF, nullptr, EF, nullptr, + EF))); + arr_e.emplace_back(var(spec.var), EF); + } + } + AST *arr = make( + ast->location, + EF, + make(ast->location, EF, arr_e, false, EF), + EF, + false, + ast->specs, + EF); + desugar(arr, obj_level); + ast_ = make( + ast->location, + make(E, EF, var(_arr), EF, false, zero, EF, nullptr, EF, nullptr, EF), + make( + ast->location, + EF, + binds, + value), + _arr, + arr); + + } else if (auto *ast = dynamic_cast(ast_)) { + desugar(ast->field, obj_level); + desugar(ast->value, obj_level + 1); + desugar(ast->array, obj_level); + + } else if (auto *ast = dynamic_cast(ast_)) { + // Strip parens. + desugar(ast->expr, obj_level); + ast_ = ast->expr; + + } else if (dynamic_cast(ast_)) { + // Nothing to do. + + } else if (auto * ast = dynamic_cast(ast_)) { + if (ast->id != nullptr) { + assert(ast->index == nullptr); + ast->index = str(ast->id->name); + ast->id = nullptr; + } + desugar(ast->index, obj_level); + + } else if (auto *ast = dynamic_cast(ast_)) { + desugar(ast->expr, obj_level); + + } else if (dynamic_cast(ast_)) { + // Nothing to do. + + } else { + std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_ << std::endl; + std::abort(); + + } + } + + void desugarFile(AST *&ast, std::map *tlas) + { + desugar(ast, 0); + + // Now, implement the std library by wrapping in a local construct. + Tokens tokens = jsonnet_lex("std.jsonnet", STD_CODE); + AST *std_ast = jsonnet_parse(alloc, tokens); + desugar(std_ast, 0); + auto *std_obj = dynamic_cast(std_ast); + if (std_obj == nullptr) { + std::cerr << "INTERNAL ERROR: std.jsonnet not an object." << std::endl; + std::abort(); + } + + // Bind 'std' builtins that are implemented natively. + DesugaredObject::Fields &fields = std_obj->fields; + for (unsigned long c=0 ; c <= max_builtin ; ++c) { + const auto &decl = jsonnet_builtin_decl(c); + Identifiers params; + for (const auto &p : decl.params) + params.push_back(id(p)); + fields.emplace_back( + ObjectField::HIDDEN, + str(decl.name), + make(E, encode_utf8(decl.name), params)); + } + fields.emplace_back( + ObjectField::HIDDEN, + str(U"thisFile"), + str(decode_utf8(ast->location.file))); + + std::vector empty; + auto line_end_blank = Fodder{{FodderElement::LINE_END, 1, 0, empty}}; + auto line_end = Fodder{{FodderElement::LINE_END, 0, 0, empty}}; + + // local body = ast; + // if std.type(body) == "function") then + // body(tlas...) + // else + // body + if (tlas != nullptr) { + LocationRange tla_loc("Top-level function"); + ArgParams args; + for (const auto &pair : *tlas) + { + AST *expr; + if (pair.second.isCode) { + // Now, implement the std library by wrapping in a local construct. + Tokens tokens = jsonnet_lex("tla:" + pair.first, pair.second.data.c_str()); + expr = jsonnet_parse(alloc, tokens); + desugar(expr, 0); + } else { + expr = str(decode_utf8(pair.second.data)); + } + // Add them as named arguments, so order does not matter. + args.emplace_back(EF, id(decode_utf8(pair.first)), EF, expr, EF); + } + const Identifier *body = id(U"top_level"); + ast = make( + ast->location, + line_end_blank, + singleBind(body, ast), + make( + E, + line_end, + primitiveEquals(E, type(var(body)), str(U"function")), + EF, + make( + tla_loc, + EF, + make(E, line_end, body), + EF, + args, + false, // trailing comma + EF, + EF, + false // tailstrict + ), + line_end, + make(E, line_end, body))); + } + + // local std = (std.jsonnet stuff); ast + ast = make( + ast->location, + EF, + singleBind(id(U"std"), std_obj), + ast); + } +}; + +void jsonnet_desugar(Allocator *alloc, AST *&ast, std::map *tlas) +{ + Desugarer desugarer(alloc); + desugarer.desugarFile(ast, tlas); +} diff --git a/vendor/github.com/strickyak/jsonnet_cgo/desugarer.h b/vendor/github.com/strickyak/jsonnet_cgo/desugarer.h new file mode 100644 index 00000000..6e33ee61 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/desugarer.h @@ -0,0 +1,34 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef JSONNET_DESUGARING_H +#define JSONNET_DESUGARING_H + +#include +#include + +#include "ast.h" +#include "vm.h" + +/** Translate the AST to remove syntax sugar. + * \param alloc Allocator for making new identifiers / ASTs. + * \param ast The AST to change. + * \param tla the top level arguments. If null then do not try to process + * top-level functions. + */ +void jsonnet_desugar(Allocator *alloc, AST *&ast, std::map *tla); + +#endif diff --git a/vendor/github.com/strickyak/jsonnet_cgo/formatter.cpp b/vendor/github.com/strickyak/jsonnet_cgo/formatter.cpp new file mode 100644 index 00000000..3b6452f9 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/formatter.cpp @@ -0,0 +1,1747 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include + +#include "formatter.h" +#include "lexer.h" +#include "pass.h" +#include "string_utils.h" +#include "unicode.h" + +static std::string unparse_id(const Identifier *id) +{ + return encode_utf8(id->name); +} + +/** If left recursive, return the left hand side, else return nullptr. */ +static AST *left_recursive(AST *ast_) +{ + if (auto *ast = dynamic_cast(ast_)) + return ast->target; + if (auto *ast = dynamic_cast(ast_)) + return ast->left; + if (auto *ast = dynamic_cast(ast_)) + return ast->left; + if (auto *ast = dynamic_cast(ast_)) + return ast->target; + return nullptr; +} +static const AST *left_recursive(const AST *ast_) +{ + return left_recursive(const_cast(ast_)); +} + +/** Pretty-print fodder. + * + * \param fodder The fodder to print + * \param space_before Whether a space should be printed before any other output. + * \param separate_token If the last fodder was an interstitial, whether a space should follow it. + */ +void fodder_fill(std::ostream &o, const Fodder &fodder, bool space_before, bool separate_token) +{ + unsigned last_indent = 0; + for (const auto &fod : fodder) { + switch (fod.kind) { + case FodderElement::LINE_END: + if (fod.comment.size() > 0) + o << " " << fod.comment[0]; + o << '\n'; + o << std::string(fod.blanks, '\n'); + o << std::string(fod.indent, ' '); + last_indent = fod.indent; + space_before = false; + break; + + case FodderElement::INTERSTITIAL: + if (space_before) + o << ' '; + o << fod.comment[0]; + space_before = true; + break; + + case FodderElement::PARAGRAPH: { + bool first = true; + for (const std::string &l : fod.comment) { + // Do not indent empty lines (note: first line is never empty). + if (l.length() > 0) { + // First line is already indented by previous fod. + if (!first) + o << std::string(last_indent, ' '); + o << l; + } + o << '\n'; + first = false; + } + o << std::string(fod.blanks, '\n'); + o << std::string(fod.indent, ' '); + last_indent = fod.indent; + space_before = false; + } break; + } + } + if (separate_token && space_before) + o << ' '; +} + +/** A model of fodder_fill that just keeps track of the column counter. */ +static void fodder_count(unsigned &column, const Fodder &fodder, bool space_before, + bool separate_token) +{ + for (const auto &fod : fodder) { + switch (fod.kind) { + case FodderElement::PARAGRAPH: + case FodderElement::LINE_END: + column = fod.indent; + space_before = false; + break; + + case FodderElement::INTERSTITIAL: + if (space_before) + column++; + column += fod.comment[0].length(); + space_before = true; + break; + } + } + if (separate_token && space_before) + column++; +} + +class Unparser { + public: + + private: + std::ostream &o; + FmtOpts opts; + + public: + Unparser(std::ostream &o, const FmtOpts &opts) + : o(o), opts(opts) + { } + + void unparseSpecs(const std::vector &specs) + { + for (const auto &spec : specs) { + fill(spec.openFodder, true, true); + switch (spec.kind) { + case ComprehensionSpec::FOR: + o << "for"; + fill(spec.varFodder, true, true); + o << unparse_id(spec.var); + fill(spec.inFodder, true, true); + o << "in"; + unparse(spec.expr, true); + break; + case ComprehensionSpec::IF: + o << "if"; + unparse(spec.expr, true); + break; + } + } + } + + void fill(const Fodder &fodder, bool space_before, bool separate_token) + { + fodder_fill(o, fodder, space_before, separate_token); + } + + void unparseParams(const Fodder &fodder_l, const ArgParams ¶ms, bool trailing_comma, + const Fodder &fodder_r) + { + fill(fodder_l, false, false); + o << "("; + bool first = true; + for (const auto ¶m : params) { + if (!first) o << ","; + fill(param.idFodder, !first, true); + o << unparse_id(param.id); + if (param.expr != nullptr) { + // default arg, no spacing: x=e + fill(param.eqFodder, false, false); + o << "="; + unparse(param.expr, false); + } + fill(param.commaFodder, false, false); + first = false; + } + if (trailing_comma) + o << ","; + fill(fodder_r, false, false); + o << ")"; + } + + void unparseFieldParams(const ObjectField &field) + { + if (field.methodSugar) { + unparseParams(field.fodderL, field.params, field.trailingComma, field.fodderR); + } + } + + void unparseFields(const ObjectFields &fields, bool space_before) + { + bool first = true; + for (const auto &field : fields) { + + if (!first) o << ','; + + switch (field.kind) { + case ObjectField::LOCAL: { + fill(field.fodder1, !first || space_before, true); + o << "local"; + fill(field.fodder2, true, true); + o << unparse_id(field.id); + unparseFieldParams(field); + fill(field.opFodder, true, true); + o << "="; + unparse(field.expr2, true); + } break; + + case ObjectField::FIELD_ID: + case ObjectField::FIELD_STR: + case ObjectField::FIELD_EXPR: { + + + if (field.kind == ObjectField::FIELD_ID) { + fill(field.fodder1, !first || space_before, true); + o << unparse_id(field.id); + + } else if (field.kind == ObjectField::FIELD_STR) { + unparse(field.expr1, !first || space_before); + + } else if (field.kind == ObjectField::FIELD_EXPR) { + fill(field.fodder1, !first || space_before, true); + o << "["; + unparse(field.expr1, false); + fill(field.fodder2, false, false); + o << "]"; + } + unparseFieldParams(field); + + fill(field.opFodder, false, false); + + if (field.superSugar) o << "+"; + switch (field.hide) { + case ObjectField::INHERIT: o << ":"; break; + case ObjectField::HIDDEN: o << "::"; break; + case ObjectField::VISIBLE: o << ":::"; break; + } + unparse(field.expr2, true); + + } break; + + case ObjectField::ASSERT: { + fill(field.fodder1, !first || space_before, true); + o << "assert"; + unparse(field.expr2, true); + if (field.expr3 != nullptr) { + fill(field.opFodder, true, true); + o << ":"; + unparse(field.expr3, true); + } + } break; + } + + first = false; + fill(field.commaFodder, false, false); + } + } + + /** Unparse the given AST. + * + * \param ast_ The AST to be unparsed. + * + * \param precedence The precedence of the enclosing AST. If this is greater than the current + * precedence, parens are not needed. + */ + void unparse(const AST *ast_, bool space_before) + { + bool separate_token = !left_recursive(ast_); + + fill(ast_->openFodder, space_before, separate_token); + + if (auto *ast = dynamic_cast(ast_)) { + unparse(ast->target, space_before); + fill(ast->fodderL, false, false); + o << "("; + bool first = true; + for (const auto &arg : ast->args) { + if (!first) o << ','; + bool space = !first; + if (arg.id != nullptr) { + fill(arg.idFodder, space, true); + o << unparse_id(arg.id); + space = false; + o << "="; + } + unparse(arg.expr, space); + fill(arg.commaFodder, false, false); + first = false; + } + if (ast->trailingComma) o << ","; + fill(ast->fodderR, false, false); + o << ")"; + if (ast->tailstrict) { + fill(ast->tailstrictFodder, true, true); + o << "tailstrict"; + } + + } else if (auto *ast = dynamic_cast(ast_)) { + unparse(ast->left, space_before); + unparse(ast->right, true); + + } else if (auto *ast = dynamic_cast(ast_)) { + o << "["; + bool first = true; + for (const auto &element : ast->elements) { + if (!first) o << ','; + unparse(element.expr, !first || opts.padArrays); + fill(element.commaFodder, false, false); + first = false; + } + if (ast->trailingComma) o << ","; + fill(ast->closeFodder, ast->elements.size() > 0, opts.padArrays); + o << "]"; + + } else if (auto *ast = dynamic_cast(ast_)) { + o << "["; + unparse(ast->body, opts.padArrays); + fill(ast->commaFodder, false, false); + if (ast->trailingComma) o << ","; + unparseSpecs(ast->specs); + fill(ast->closeFodder, true, opts.padArrays); + o << "]"; + + } else if (auto *ast = dynamic_cast(ast_)) { + o << "assert"; + unparse(ast->cond, true); + if (ast->message != nullptr) { + fill(ast->colonFodder, true, true); + o << ":"; + unparse(ast->message, true); + } + fill(ast->semicolonFodder, false, false); + o << ";"; + unparse(ast->rest, true); + + } else if (auto *ast = dynamic_cast(ast_)) { + unparse(ast->left, space_before); + fill(ast->opFodder, true, true); + o << bop_string(ast->op); + // The - 1 is for left associativity. + unparse(ast->right, true); + + } else if (auto *ast = dynamic_cast(ast_)) { + o << "/* builtin " << ast->name << " */ null"; + + } else if (auto *ast = dynamic_cast(ast_)) { + o << "if"; + unparse(ast->cond, true); + fill(ast->thenFodder, true, true); + o << "then"; + if (ast->branchFalse != nullptr) { + unparse(ast->branchTrue, true); + fill(ast->elseFodder, true, true); + o << "else"; + unparse(ast->branchFalse, true); + } else { + unparse(ast->branchTrue, true); + } + + } else if (dynamic_cast(ast_)) { + o << "$"; + + } else if (auto *ast = dynamic_cast(ast_)) { + o << "error"; + unparse(ast->expr, true); + + } else if (auto *ast = dynamic_cast(ast_)) { + o << "function"; + unparseParams(ast->parenLeftFodder, ast->params, ast->trailingComma, + ast->parenRightFodder); + unparse(ast->body, true); + + } else if (auto *ast = dynamic_cast(ast_)) { + o << "import"; + unparse(ast->file, true); + + } else if (auto *ast = dynamic_cast(ast_)) { + o << "importstr"; + unparse(ast->file, true); + + } else if (auto *ast = dynamic_cast(ast_)) { + unparse(ast->target, space_before); + fill(ast->dotFodder, false, false); + if (ast->id != nullptr) { + o << "."; + fill(ast->idFodder, false, false); + o << unparse_id(ast->id); + } else { + o << "["; + if (ast->isSlice) { + if (ast->index != nullptr) { + unparse(ast->index, false); + } + fill(ast->endColonFodder, false, false); + o << ":"; + if (ast->end != nullptr) { + unparse(ast->end, false); + } + if (ast->step != nullptr || ast->stepColonFodder.size() > 0) { + fill(ast->stepColonFodder, false, false); + o << ":"; + if (ast->step != nullptr) { + unparse(ast->step, false); + } + } + } else { + unparse(ast->index, false); + } + fill(ast->idFodder, false, false); + o << "]"; + } + + } else if (auto *ast = dynamic_cast(ast_)) { + o << "local"; + assert(ast->binds.size() > 0); + bool first = true; + for (const auto &bind : ast->binds) { + if (!first) + o << ","; + first = false; + fill(bind.varFodder, true, true); + o << unparse_id(bind.var); + if (bind.functionSugar) { + unparseParams(bind.parenLeftFodder, bind.params, bind.trailingComma, + bind.parenRightFodder); + } + fill(bind.opFodder, true, true); + o << "="; + unparse(bind.body, true); + fill(bind.closeFodder, false, false); + } + o << ";"; + unparse(ast->body, true); + + } else if (auto *ast = dynamic_cast(ast_)) { + o << (ast->value ? "true" : "false"); + + } else if (auto *ast = dynamic_cast(ast_)) { + o << ast->originalString; + + } else if (auto *ast = dynamic_cast(ast_)) { + if (ast->tokenKind == LiteralString::DOUBLE) { + o << "\""; + o << encode_utf8(ast->value); + o << "\""; + } else if (ast->tokenKind == LiteralString::SINGLE) { + o << "'"; + o << encode_utf8(ast->value); + o << "'"; + } else if (ast->tokenKind == LiteralString::BLOCK) { + o << "|||\n"; + if (ast->value.c_str()[0] != U'\n') + o << ast->blockIndent; + for (const char32_t *cp = ast->value.c_str() ; *cp != U'\0' ; ++cp) { + std::string utf8; + encode_utf8(*cp, utf8); + o << utf8; + if (*cp == U'\n' && *(cp + 1) != U'\n' && *(cp + 1) != U'\0') { + o << ast->blockIndent; + } + } + o << ast->blockTermIndent << "|||"; + } else if (ast->tokenKind == LiteralString::VERBATIM_DOUBLE) { + o << "@\""; + for (const char32_t *cp = ast->value.c_str() ; *cp != U'\0' ; ++cp) { + if (*cp == U'"') { + o << "\"\""; + } else { + std::string utf8; + encode_utf8(*cp, utf8); + o << utf8; + } + } + o << "\""; + } else if (ast->tokenKind == LiteralString::VERBATIM_SINGLE) { + o << "@'"; + for (const char32_t *cp = ast->value.c_str() ; *cp != U'\0' ; ++cp) { + if (*cp == U'\'') { + o << "''"; + } else { + std::string utf8; + encode_utf8(*cp, utf8); + o << utf8; + } + } + o << "'"; + } + + } else if (dynamic_cast(ast_)) { + o << "null"; + + } else if (auto *ast = dynamic_cast(ast_)) { + o << "{"; + unparseFields(ast->fields, opts.padObjects); + if (ast->trailingComma) o << ","; + fill(ast->closeFodder, ast->fields.size() > 0, opts.padObjects); + o << "}"; + + } else if (auto *ast = dynamic_cast(ast_)) { + o << "{"; + for (AST *assert : ast->asserts) { + o << "assert"; + unparse(assert, true); + o << ","; + } + for (auto &field : ast->fields) { + o << "["; + unparse(field.name, false); + o << "]"; + switch (field.hide) { + case ObjectField::INHERIT: o << ":"; break; + case ObjectField::HIDDEN: o << "::"; break; + case ObjectField::VISIBLE: o << ":::"; break; + } + unparse(field.body, true); + o << ","; + } + o << "}"; + + } else if (auto *ast = dynamic_cast(ast_)) { + o << "{"; + unparseFields(ast->fields, opts.padObjects); + if (ast->trailingComma) o << ","; + unparseSpecs(ast->specs); + fill(ast->closeFodder, true, opts.padObjects); + o << "}"; + + } else if (auto *ast = dynamic_cast(ast_)) { + o << "{["; + unparse(ast->field, false); + o << "]:"; + unparse(ast->value, true); + o << " for " << unparse_id(ast->id) << " in"; + unparse(ast->array, true); + o << "}"; + + } else if (auto *ast = dynamic_cast(ast_)) { + o << "("; + unparse(ast->expr, false); + fill(ast->closeFodder, false, false); + o << ")"; + + } else if (dynamic_cast(ast_)) { + o << "self"; + + } else if (auto *ast = dynamic_cast(ast_)) { + o << "super"; + fill(ast->dotFodder, false, false); + if (ast->id != nullptr) { + o << "."; + fill(ast->idFodder, false, false); + o << unparse_id(ast->id); + } else { + o << "["; + unparse(ast->index, false); + fill(ast->idFodder, false, false); + o << "]"; + } + + } else if (auto *ast = dynamic_cast(ast_)) { + o << uop_string(ast->op); + if (dynamic_cast(left_recursive(ast->expr))) { + unparse(ast->expr, true); + } else { + unparse(ast->expr, false); + } + + } else if (auto *ast = dynamic_cast(ast_)) { + o << encode_utf8(ast->id->name); + + } else { + std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_ << std::endl; + std::abort(); + + } + } +}; + + +/******************************************************************************** + * The rest of this file contains transformations on the ASTs before unparsing. * + ********************************************************************************/ + +/** As a + b but preserves constraints. + * + * Namely, a LINE_END is not allowed to follow a PARAGRAPH or a LINE_END. + */ +static Fodder concat_fodder(const Fodder &a, const Fodder &b) +{ + if (a.size() == 0) return b; + if (b.size() == 0) return a; + Fodder r = a; + // Add the first element of b somehow. + if (r[a.size() - 1].kind != FodderElement::INTERSTITIAL && + b[0].kind == FodderElement::LINE_END) { + if (b[0].comment.size() > 0) { + // The line end had a comment, so create a single line paragraph for it. + r.emplace_back(FodderElement::PARAGRAPH, b[0].blanks, b[0].indent, b[0].comment); + } else { + // Merge it into the previous line end. + r[r.size() - 1].indent = b[0].indent; + r[r.size() - 1].blanks += b[0].blanks; + } + } else { + r.push_back(b[0]); + } + // Add the rest of b. + for (unsigned i = 1; i < b.size() ; ++i) { + r.push_back(b[i]); + } + return r; +} + +/** Move b to the front of a. */ +static void fodder_move_front(Fodder &a, Fodder &b) +{ + a = concat_fodder(b, a); + b.clear(); +} + +/** A generic Pass that does nothing but can be extended to easily define real passes. + */ +class FmtPass : public CompilerPass { + protected: + FmtOpts opts; + + public: + FmtPass(Allocator &alloc, const FmtOpts &opts) + : CompilerPass(alloc), opts(opts) { } +}; + + +class EnforceStringStyle : public FmtPass { + using FmtPass::visit; + public: + EnforceStringStyle(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + void visit(LiteralString *lit) + { + if (lit->tokenKind == LiteralString::BLOCK) return; + if (lit->tokenKind == LiteralString::VERBATIM_DOUBLE) return; + if (lit->tokenKind == LiteralString::VERBATIM_SINGLE) return; + String canonical = jsonnet_string_unescape(lit->location, lit->value); + unsigned num_single = 0, num_double = 0; + for (char32_t c : canonical) { + if (c == '\'') num_single++; + if (c == '"') num_double++; + } + if (num_single > 0 && num_double > 0) return; // Don't change it. + bool use_single = opts.stringStyle == 's'; + if (num_single > 0) + use_single = false; + if (num_double > 0) + use_single = true; + + // Change it. + lit->value = jsonnet_string_escape(canonical, use_single); + lit->tokenKind = use_single ? LiteralString::SINGLE : LiteralString::DOUBLE; + } +}; + +class EnforceCommentStyle : public FmtPass { + public: + bool firstFodder; + EnforceCommentStyle(Allocator &alloc, const FmtOpts &opts) + : FmtPass(alloc, opts), firstFodder(true) + { } + /** Change the comment to match the given style, but don't break she-bang. + * + * If preserve_hash is true, do not touch a comment that starts with #!. + */ + void fixComment(std::string &s, bool preserve_hash) + { + if (opts.commentStyle == 'h' && s[0] == '/') { + s = "#" + s.substr(2); + } + if (opts.commentStyle == 's' && s[0] == '#') { + if (preserve_hash && s[1] == '!') return; + s = "//" + s.substr(1); + } + } + void fodder(Fodder &fodder) + { + for (auto &f : fodder) { + switch (f.kind) { + case FodderElement::LINE_END: + case FodderElement::PARAGRAPH: + if (f.comment.size() == 1) { + fixComment(f.comment[0], firstFodder); + } + break; + + case FodderElement::INTERSTITIAL: + break; + } + firstFodder = false; + } + } +}; + +class EnforceMaximumBlankLines : public FmtPass { + public: + EnforceMaximumBlankLines(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + void fodderElement(FodderElement &f) + { + if (f.kind != FodderElement::INTERSTITIAL) + if (f.blanks > 2) f.blanks = 2; + } +}; + +class StripComments : public FmtPass { + public: + StripComments(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + void fodder(Fodder &fodder) + { + Fodder copy = fodder; + fodder.clear(); + for (auto &f : copy) { + if (f.kind == FodderElement::LINE_END) + fodder.push_back(f); + } + } +}; + +class StripEverything : public FmtPass { + public: + StripEverything(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + void fodder(Fodder &fodder) { fodder.clear(); } +}; + +class StripAllButComments : public FmtPass { + public: + StripAllButComments(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + Fodder comments; + void fodder(Fodder &fodder) + { + for (auto &f : fodder) { + if (f.kind == FodderElement::PARAGRAPH) { + comments.emplace_back(FodderElement::PARAGRAPH, 0, 0, f.comment); + } else if (f.kind == FodderElement::INTERSTITIAL) { + comments.push_back(f); + comments.emplace_back(FodderElement::LINE_END, 0, 0, std::vector{}); + } + } + fodder.clear(); + } + virtual void file(AST *&body, Fodder &final_fodder) + { + expr(body); + fodder(final_fodder); + body = alloc.make(body->location, comments); + final_fodder.clear(); + } +}; + +/** These cases are infix so we descend on the left to find the fodder. */ +static Fodder &open_fodder(AST *ast_) +{ + AST *left = left_recursive(ast_); + return left != nullptr ? open_fodder(left) : ast_->openFodder; +} + +/** Strip blank lines from the top of the file. */ +void remove_initial_newlines(AST *ast) +{ + Fodder &f = open_fodder(ast); + while (f.size() > 0 && f[0].kind == FodderElement::LINE_END) + f.erase(f.begin()); +} + +bool contains_newline(const Fodder &fodder) +{ + for (const auto &f : fodder) { + if (f.kind != FodderElement::INTERSTITIAL) + return true; + } + return false; +} + +/* Commas should appear at the end of an object/array only if the closing token is on a new line. */ +class FixTrailingCommas : public FmtPass { + using FmtPass::visit; + public: + FixTrailingCommas(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + Fodder comments; + + // Generalized fix that works across a range of ASTs. + void fix_comma(Fodder &last_comma_fodder, bool &trailing_comma, Fodder &close_fodder) + { + bool need_comma = contains_newline(close_fodder) || contains_newline(last_comma_fodder); + if (trailing_comma) { + if (!need_comma) { + // Remove it but keep fodder. + trailing_comma = false; + fodder_move_front(close_fodder, last_comma_fodder); + } else if (contains_newline(last_comma_fodder)) { + // The comma is needed but currently is separated by a newline. + fodder_move_front(close_fodder, last_comma_fodder); + } + } else { + if (need_comma) { + // There was no comma, but there was a newline before the ] so add a comma. + trailing_comma = true; + } + } + } + + void remove_comma(Fodder &last_comma_fodder, bool &trailing_comma, Fodder &close_fodder) + { + if (trailing_comma) { + // Remove it but keep fodder. + trailing_comma = false; + close_fodder = concat_fodder(last_comma_fodder, close_fodder); + last_comma_fodder.clear(); + } + } + + void visit(Array *expr) + { + if (expr->elements.size() == 0) { + // No comma present and none can be added. + return; + } + + fix_comma(expr->elements.back().commaFodder, expr->trailingComma, expr->closeFodder); + FmtPass::visit(expr); + } + + void visit(ArrayComprehension *expr) + { + remove_comma(expr->commaFodder, expr->trailingComma, expr->specs[0].openFodder); + FmtPass::visit(expr); + } + + void visit(Object *expr) + { + if (expr->fields.size() == 0) { + // No comma present and none can be added. + return; + } + + fix_comma(expr->fields.back().commaFodder, expr->trailingComma, expr->closeFodder); + FmtPass::visit(expr); + } + + void visit(ObjectComprehension *expr) + { + remove_comma(expr->fields.back().commaFodder, expr->trailingComma, expr->closeFodder); + FmtPass::visit(expr); + } + +}; + + +/* Remove nested parens. */ +class FixParens : public FmtPass { + using FmtPass::visit; + public: + FixParens(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + void visit(Parens *expr) + { + if (auto *body = dynamic_cast(expr->expr)) { + // Deal with fodder. + expr->expr = body->expr; + fodder_move_front(open_fodder(body->expr), body->openFodder); + fodder_move_front(expr->closeFodder, body->closeFodder); + } + FmtPass::visit(expr); + } +}; + + + +/* Ensure ApplyBrace syntax sugar is used in the case of A + { }. */ +class FixPlusObject : public FmtPass { + using FmtPass::visit; + public: + FixPlusObject(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + void visitExpr(AST *&expr) + { + if (auto *bin_op = dynamic_cast(expr)) { + // Could relax this to allow more ASTs on the LHS but this seems OK for now. + if (dynamic_cast(bin_op->left) + || dynamic_cast(bin_op->left)) { + if (AST *rhs = dynamic_cast(bin_op->right)) { + if (bin_op->op == BOP_PLUS) { + fodder_move_front(rhs->openFodder, bin_op->opFodder); + expr = alloc.make(bin_op->location, bin_op->openFodder, + bin_op->left, rhs); + } + } + } + } + FmtPass::visitExpr(expr); + } +}; + + + +/* Remove final colon in slices. */ +class NoRedundantSliceColon : public FmtPass { + using FmtPass::visit; + public: + NoRedundantSliceColon(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + + void visit(Index *expr) + { + if (expr->isSlice) { + if (expr->step == nullptr) { + if (expr->stepColonFodder.size() > 0) { + fodder_move_front(expr->idFodder, expr->stepColonFodder); + } + } + } + FmtPass::visit(expr); + } +}; + +/* Ensure syntax sugar is used where possible. */ +class PrettyFieldNames : public FmtPass { + using FmtPass::visit; + public: + PrettyFieldNames(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + + bool isIdentifier(const String &str) { + bool first = true; + for (char32_t c : str) { + if (!first && c >= '0' && c <= '9') + continue; + first = false; + if ((c >= 'A' && c <= 'Z') + || (c >= 'a' && c <= 'z') + || (c == '_')) + continue; + return false; + } + // Filter out keywords. + if (lex_get_keyword_kind(encode_utf8(str)) != Token::IDENTIFIER) + return false; + return true; + } + + void visit(Index *expr) + { + if (!expr->isSlice && expr->index != nullptr) { + // Maybe we can use an id instead. + if (auto *lit = dynamic_cast(expr->index)) { + if (isIdentifier(lit->value)) { + expr->id = alloc.makeIdentifier(lit->value); + expr->idFodder = lit->openFodder; + expr->index = nullptr; + } + } + } + FmtPass::visit(expr); + } + + void visit(Object *expr) + { + for (auto &field : expr->fields) { + // First try ["foo"] -> "foo". + if (field.kind == ObjectField::FIELD_EXPR) { + if (auto *field_expr = dynamic_cast(field.expr1)) { + field.kind = ObjectField::FIELD_STR; + fodder_move_front(field_expr->openFodder, field.fodder1); + if (field.methodSugar) { + fodder_move_front(field.fodderL, field.fodder2); + } else { + fodder_move_front(field.opFodder, field.fodder2); + } + } + } + // Then try "foo" -> foo. + if (field.kind == ObjectField::FIELD_STR) { + if (auto *lit = dynamic_cast(field.expr1)) { + if (isIdentifier(lit->value)) { + field.kind = ObjectField::FIELD_ID; + field.id = alloc.makeIdentifier(lit->value); + field.fodder1 = lit->openFodder; + field.expr1 = nullptr; + } + } + } + } + FmtPass::visit(expr); + } +}; + +class FixIndentation { + + FmtOpts opts; + unsigned column; + + public: + FixIndentation(const FmtOpts &opts) : opts(opts), column(0) { } + + /* Set the indentation on the fodder elements, adjust column counter as if it was printed. + * \param fodder The fodder to pretend to print. + * \param space_before Whether a space should be printed before any other output. + * \param separate_token If the last fodder was an interstitial, whether a space should follow + * it. + * \param all_but_last_indent New indentation value for all but final fodder element. + * \param last_indent New indentation value for but final fodder element. + */ + void fill(Fodder &fodder, bool space_before, bool separate_token, + unsigned all_but_last_indent, unsigned last_indent) + { + setIndents(fodder, all_but_last_indent, last_indent); + fodder_count(column, fodder, space_before, separate_token); + } + + void fill(Fodder &fodder, bool space_before, bool separate_token, unsigned indent) + { + fill(fodder, space_before, separate_token, indent, indent); + } + + /* This struct is the representation of the indentation level. The field lineUp is what is + * generally used to indent after a new line. The field base is used to help derive a new + * Indent struct when the indentation level increases. lineUp is generally > base. + * + * In the following case (where spaces are replaced with underscores): + * ____foobar(1, + * ___________2) + * + * At the AST representing the 2, the indent has base == 4 and lineUp == 11. + */ + struct Indent { + unsigned base; + unsigned lineUp; + Indent(unsigned base, unsigned line_up) : base(base), lineUp(line_up) { } + }; + + /** Calculate the indentation of sub-expressions. + * + * If the first sub-expression is on the same line as the current node, then subsequent + * ones will be lined up, otherwise subsequent ones will be on the next line indented + * by 'indent'. + */ + Indent newIndent(const Fodder &first_fodder, const Indent &old, unsigned line_up) + { + if (first_fodder.size() == 0 || first_fodder[0].kind == FodderElement::INTERSTITIAL) { + return Indent(old.base, line_up); + } else { + // Reset + return Indent(old.base + opts.indent, old.base + opts.indent); + } + } + + /** Calculate the indentation of sub-expressions. + * + * If the first sub-expression is on the same line as the current node, then subsequent + * ones will be lined up and further indentations in their subexpressions will be based from + * this column. + */ + Indent newIndentStrong(const Fodder &first_fodder, const Indent &old, unsigned line_up) + { + if (first_fodder.size() == 0 || first_fodder[0].kind == FodderElement::INTERSTITIAL) { + return Indent(line_up, line_up); + } else { + // Reset + return Indent(old.base + opts.indent, old.base + opts.indent); + } + } + + /** Calculate the indentation of sub-expressions. + * + * If the first sub-expression is on the same line as the current node, then subsequent + * ones will be lined up, otherwise subseqeuent ones will be on the next line with no + * additional indent. + */ + Indent align(const Fodder &first_fodder, const Indent &old, unsigned line_up) + { + if (first_fodder.size() == 0 || first_fodder[0].kind == FodderElement::INTERSTITIAL) { + return Indent(old.base, line_up); + } else { + // Reset + return old; + } + } + + /** Calculate the indentation of sub-expressions. + * + * If the first sub-expression is on the same line as the current node, then subsequent + * ones will be lined up and further indentations in their subexpresssions will be based from + * this column. Otherwise, subseqeuent ones will be on the next line with no + * additional indent. + */ + Indent alignStrong(const Fodder &first_fodder, const Indent &old, unsigned line_up) + { + if (first_fodder.size() == 0 || first_fodder[0].kind == FodderElement::INTERSTITIAL) { + return Indent(line_up, line_up); + } else { + // Reset + return old; + } + } + + /* Set indentation values within the fodder elements. + * + * The last one gets a special indentation value, all the others are set to the same thing. + */ + void setIndents(Fodder &fodder, unsigned all_but_last_indent, unsigned last_indent) + { + // First count how many there are. + unsigned count = 0; + for (const auto &f : fodder) { + if (f.kind != FodderElement::INTERSTITIAL) + count++; + } + // Now set the indents. + unsigned i = 0; + for (auto &f : fodder) { + if (f.kind != FodderElement::INTERSTITIAL) { + if (i + 1 < count) { + f.indent = all_but_last_indent; + } else { + assert(i == count - 1); + f.indent = last_indent; + } + i++; + } + } + } + + /** Indent comprehension specs. + * \param indent The indentation level. + */ + void specs(std::vector &specs, const Indent &indent) + { + for (auto &spec : specs) { + fill(spec.openFodder, true, true, indent.lineUp); + switch (spec.kind) { + case ComprehensionSpec::FOR: { + column += 3; // for + fill(spec.varFodder, true, true, indent.lineUp); + column += spec.var->name.length(); + fill(spec.inFodder, true, true, indent.lineUp); + column += 2; // in + Indent new_indent = newIndent(open_fodder(spec.expr), indent, column); + expr(spec.expr, new_indent, true); + } + break; + + case ComprehensionSpec::IF: { + column += 2; // if + Indent new_indent = newIndent(open_fodder(spec.expr), indent, column); + expr(spec.expr, new_indent, true); + } + break; + } + } + } + + void params(Fodder &fodder_l, ArgParams ¶ms, bool trailing_comma, Fodder &fodder_r, + const Indent &indent) + { + fill(fodder_l, false, false, indent.lineUp, indent.lineUp); + column++; // ( + const Fodder &first_inside = params.size() == 0 ? fodder_r : params[0].idFodder; + + Indent new_indent = newIndent(first_inside, indent, column); + bool first = true; + for (auto ¶m : params) { + if (!first) column++; // ',' + fill(param.idFodder, !first, true, new_indent.lineUp); + column += param.id->name.length(); + if (param.expr != nullptr) { + // default arg, no spacing: x=e + fill(param.eqFodder, false, false, new_indent.lineUp); + column++; + expr(param.expr, new_indent, false); + } + fill(param.commaFodder, false, false, new_indent.lineUp); + first = false; + } + if (trailing_comma) + column++; + fill(fodder_r, false, false, new_indent.lineUp, indent.lineUp); + column++; // ) + } + + void fieldParams(ObjectField &field, const Indent &indent) + { + if (field.methodSugar) { + params(field.fodderL, field.params, field.trailingComma, field.fodderR, indent); + } + } + + /** Indent fields within an object. + * + * \params fields + * \param indent Indent of the first field. + * \param space_before + */ + void fields(ObjectFields &fields, const Indent &indent, bool space_before) + { + unsigned new_indent = indent.lineUp; + bool first = true; + for (auto &field : fields) { + if (!first) column++; // ',' + + switch (field.kind) { + case ObjectField::LOCAL: { + + fill(field.fodder1, !first || space_before, true, indent.lineUp); + column += 5; // local + fill(field.fodder2, true, true, indent.lineUp); + column += field.id->name.length(); + fieldParams(field, indent); + fill(field.opFodder, true, true, indent.lineUp); + column++; // = + Indent new_indent2 = newIndent(open_fodder(field.expr2), indent, column); + expr(field.expr2, new_indent2, true); + } break; + + case ObjectField::FIELD_ID: + case ObjectField::FIELD_STR: + case ObjectField::FIELD_EXPR: { + + if (field.kind == ObjectField::FIELD_ID) { + fill(field.fodder1, !first || space_before, true, new_indent); + column += field.id->name.length(); + + } else if (field.kind == ObjectField::FIELD_STR) { + expr(field.expr1, indent, !first || space_before); + + } else if (field.kind == ObjectField::FIELD_EXPR) { + fill(field.fodder1, !first || space_before, true, new_indent); + column++; // [ + expr(field.expr1, indent, false); + fill(field.fodder2, false, false, new_indent); + column++; // ] + } + + fieldParams(field, indent); + + fill(field.opFodder, false, false, new_indent); + + if (field.superSugar) column++; + switch (field.hide) { + case ObjectField::INHERIT: column+=1; break; + case ObjectField::HIDDEN: column+=2; break; + case ObjectField::VISIBLE: column+=3; break; + } + Indent new_indent2 = newIndent(open_fodder(field.expr2), indent, column); + expr(field.expr2, new_indent2, true); + + } break; + + case ObjectField::ASSERT: { + + fill(field.fodder1, !first || space_before, true, new_indent); + column += 6; // assert + // + 1 for the space after the assert + Indent new_indent2 = newIndent(open_fodder(field.expr2), indent, column + 1); + expr(field.expr2, indent, true); + if (field.expr3 != nullptr) { + fill(field.opFodder, true, true, new_indent2.lineUp); + column++; // ":" + expr(field.expr3, new_indent2, true); + } + } break; + } + + first = false; + fill(field.commaFodder, false, false, new_indent); + } + } + + /** Does the given fodder contain at least one new line? */ + bool hasNewLines(const Fodder &fodder) + { + for (const auto &f : fodder) { + if (f.kind != FodderElement::INTERSTITIAL) + return true; + } + return false; + } + + /** Get the first fodder from an ArgParam. */ + const Fodder &argParamFirstFodder(const ArgParam &ap) + { + if (ap.id != nullptr) return ap.idFodder; + return open_fodder(ap.expr); + } + + /** Reindent an expression. + * + * \param ast_ The ast to reindent. + * \param indent Beginning of the line. + * \param space_before As defined in the pretty-printer. + */ + void expr(AST *ast_, const Indent &indent, bool space_before) + { + fill(ast_->openFodder, space_before, !left_recursive(ast_), indent.lineUp); + + if (auto *ast = dynamic_cast(ast_)) { + const Fodder &init_fodder = open_fodder(ast->target); + Indent new_indent = align(init_fodder, indent, + column + (space_before ? 1 : 0)); + expr(ast->target, new_indent, space_before); + fill(ast->fodderL, false, false, new_indent.lineUp); + column++; // ( + const Fodder &first_fodder = ast->args.size() == 0 ? ast->fodderR : argParamFirstFodder(ast->args[0]); + bool strong_indent = false; + // Need to use strong indent if any of the + // arguments (except the first) are preceded by newlines. + bool first = true; + for (auto &arg : ast->args) { + if (first) { + // Skip first element. + first = false; + continue; + } + if (hasNewLines(argParamFirstFodder(arg))) + strong_indent = true; + } + + Indent arg_indent = strong_indent + ? newIndentStrong(first_fodder, indent, column) + : newIndent(first_fodder, indent, column); + first = true; + for (auto &arg : ast->args) { + if (!first) column++; // "," + + bool space = !first; + if (arg.id != nullptr) { + fill(arg.idFodder, space, false, arg_indent.lineUp); + column += arg.id->name.length(); + space = false; + column++; // "=" + } + expr(arg.expr, arg_indent, space); + fill(arg.commaFodder, false, false, arg_indent.lineUp); + first = false; + } + if (ast->trailingComma) column++; // "," + fill(ast->fodderR, false, false, arg_indent.lineUp, indent.base); + column++; // ) + if (ast->tailstrict) { + fill(ast->tailstrictFodder, true, true, indent.base); + column += 10; // tailstrict + } + + } else if (auto *ast = dynamic_cast(ast_)) { + const Fodder &init_fodder = open_fodder(ast->left); + Indent new_indent = align(init_fodder, indent, + column + (space_before ? 1 : 0)); + expr(ast->left, new_indent, space_before); + expr(ast->right, new_indent, true); + + } else if (auto *ast = dynamic_cast(ast_)) { + column++; // '[' + // First fodder element exists and is a newline + const Fodder &first_fodder = ast->elements.size() > 0 + ? open_fodder(ast->elements[0].expr) + : ast->closeFodder; + unsigned new_column = column + (opts.padArrays ? 1 : 0); + bool strong_indent = false; + // Need to use strong indent if there are not newlines before any of the sub-expressions + bool first = true; + for (auto &el : ast->elements) { + if (first) { + first = false; + continue; + } + if (hasNewLines(open_fodder(el.expr))) + strong_indent = true; + } + + Indent new_indent = strong_indent + ? newIndentStrong(first_fodder, indent, new_column) + : newIndent(first_fodder, indent, new_column); + + first = true; + for (auto &element : ast->elements) { + if (!first) column++; + expr(element.expr, new_indent, !first || opts.padArrays); + fill(element.commaFodder, false, false, new_indent.lineUp, new_indent.lineUp); + first = false; + } + if (ast->trailingComma) column++; + + // Handle penultimate newlines from expr.close_fodder if there are any. + fill(ast->closeFodder, ast->elements.size() > 0, opts.padArrays, new_indent.lineUp, + indent.base); + column++; // ']' + + } else if (auto *ast = dynamic_cast(ast_)) { + column++; // [ + Indent new_indent = newIndent(open_fodder(ast->body), indent, + column + (opts.padArrays ? 1 : 0)); + expr(ast->body, new_indent, opts.padArrays); + fill(ast->commaFodder, false, false, new_indent.lineUp); + if (ast->trailingComma) column++; // ',' + specs(ast->specs, new_indent); + fill(ast->closeFodder, true, opts.padArrays, new_indent.lineUp, indent.base); + column++; // ] + + } else if (auto *ast = dynamic_cast(ast_)) { + column += 6; // assert + // + 1 for the space after the assert + Indent new_indent = newIndent(open_fodder(ast->cond), indent, column + 1); + expr(ast->cond, new_indent, true); + if (ast->message != nullptr) { + fill(ast->colonFodder, true, true, new_indent.lineUp); + column++; // ":" + expr(ast->message, new_indent, true); + } + fill(ast->semicolonFodder, false, false, new_indent.lineUp); + column++; // ";" + expr(ast->rest, indent, true); + + } else if (auto *ast = dynamic_cast(ast_)) { + const Fodder &first_fodder = open_fodder(ast->left); + + // Need to use strong indent in the case of + /* + A + + B + or + A + + B + */ + bool strong_indent = hasNewLines(ast->opFodder) || hasNewLines(open_fodder(ast->right)); + + unsigned inner_column = column + (space_before ? 1 : 0); + Indent new_indent = strong_indent + ? alignStrong(first_fodder, indent, inner_column) + : align(first_fodder, indent, inner_column); + expr(ast->left, new_indent, space_before); + fill(ast->opFodder, true, true, new_indent.lineUp); + column += bop_string(ast->op).length(); + // Don't calculate a new indent for here, because we like being able to do: + // true && + // true && + // true + expr(ast->right, new_indent, true); + + } else if (auto *ast = dynamic_cast(ast_)) { + column += 11; // "/* builtin " + column += ast->name.length(); + column += 8; // " */ null" + + } else if (auto *ast = dynamic_cast(ast_)) { + column += 2; // if + Indent cond_indent = newIndent(open_fodder(ast->cond), indent, column + 1); + expr(ast->cond, cond_indent, true); + fill(ast->thenFodder, true, true, indent.base); + column += 4; // then + Indent true_indent = newIndent(open_fodder(ast->branchTrue), indent, column + 1); + expr(ast->branchTrue, true_indent, true); + if (ast->branchFalse != nullptr) { + fill(ast->elseFodder, true, true, indent.base); + column += 4; // else + Indent false_indent = newIndent(open_fodder(ast->branchFalse), indent, column + 1); + expr(ast->branchFalse, false_indent, true); + } + + } else if (dynamic_cast(ast_)) { + column++; // $ + + } else if (auto *ast = dynamic_cast(ast_)) { + column += 5; // error + Indent new_indent = newIndent(open_fodder(ast->expr), indent, column + 1); + expr(ast->expr, new_indent, true); + + } else if (auto *ast = dynamic_cast(ast_)) { + column += 8; // function + params(ast->parenLeftFodder, ast->params, ast->trailingComma, + ast->parenRightFodder, indent); + Indent new_indent = newIndent(open_fodder(ast->body), indent, column + 1); + expr(ast->body, new_indent, true); + + } else if (auto *ast = dynamic_cast(ast_)) { + column += 6; // import + Indent new_indent = newIndent(open_fodder(ast->file), indent, column + 1); + expr(ast->file, new_indent, true); + + } else if (auto *ast = dynamic_cast(ast_)) { + column += 9; // importstr + Indent new_indent = newIndent(open_fodder(ast->file), indent, column + 1); + expr(ast->file, new_indent, true); + + } else if (auto *ast = dynamic_cast(ast_)) { + expr(ast->target, indent, space_before); + fill(ast->dotFodder, false, false, indent.lineUp); + if (ast->id != nullptr) { + Indent new_indent = newIndent(ast->idFodder, indent, column); + column++; // "." + fill(ast->idFodder, false, false, new_indent.lineUp); + column += ast->id->name.length(); + } else { + column++; // "[" + if (ast->isSlice) { + Indent new_indent(0, 0); + if (ast->index != nullptr) { + new_indent = newIndent(open_fodder(ast->index), indent, column); + expr(ast->index, new_indent, false); + } + if (ast->end != nullptr) { + new_indent = newIndent(ast->endColonFodder, indent, column); + fill(ast->endColonFodder, false, false, new_indent.lineUp); + column++; // ":" + expr(ast->end, new_indent, false); + } + if (ast->step != nullptr) { + if (ast->end == nullptr) { + new_indent = newIndent(ast->endColonFodder, indent, column); + fill(ast->endColonFodder, false, false, new_indent.lineUp); + column++; // ":" + } + fill(ast->stepColonFodder, false, false, new_indent.lineUp); + column++; // ":" + expr(ast->step, new_indent, false); + } + if (ast->index == nullptr && ast->end == nullptr && ast->step == nullptr) { + new_indent = newIndent(ast->endColonFodder, indent, column); + fill(ast->endColonFodder, false, false, new_indent.lineUp); + column++; // ":" + } + } else { + Indent new_indent = newIndent(open_fodder(ast->index), indent, column); + expr(ast->index, new_indent, false); + fill(ast->idFodder, false, false, new_indent.lineUp, indent.base); + } + column++; // "]" + } + + } else if (auto *ast = dynamic_cast(ast_)) { + column += 5; // local + assert(ast->binds.size() > 0); + bool first = true; + Indent new_indent = newIndent(ast->binds[0].varFodder, indent, column + 1); + for (auto &bind : ast->binds) { + if (!first) + column++; // ',' + first = false; + fill(bind.varFodder, true, true, new_indent.lineUp); + column += bind.var->name.length(); + if (bind.functionSugar) { + params(bind.parenLeftFodder, bind.params, bind.trailingComma, + bind.parenRightFodder, new_indent); + } + fill(bind.opFodder, true, true, new_indent.lineUp); + column++; // '=' + Indent new_indent2 = newIndent(open_fodder(bind.body), new_indent, column + 1); + expr(bind.body, new_indent2, true); + fill(bind.closeFodder, false, false, new_indent2.lineUp, indent.base); + } + column++; // ';' + expr(ast->body, indent, true); + + } else if (auto *ast = dynamic_cast(ast_)) { + column += (ast->value ? 4 : 5); + + } else if (auto *ast = dynamic_cast(ast_)) { + column += ast->originalString.length(); + + } else if (auto *ast = dynamic_cast(ast_)) { + if (ast->tokenKind == LiteralString::DOUBLE) { + column += 2 + ast->value.length(); // Include quotes + } else if (ast->tokenKind == LiteralString::SINGLE) { + column += 2 + ast->value.length(); // Include quotes + } else if (ast->tokenKind == LiteralString::BLOCK) { + ast->blockIndent = std::string(indent.base + opts.indent, ' '); + ast->blockTermIndent = std::string(indent.base, ' '); + column = indent.base; // blockTermIndent + column += 3; // "|||" + } else if (ast->tokenKind == LiteralString::VERBATIM_SINGLE) { + column += 3; // Include @, start and end quotes + for (const char32_t *cp = ast->value.c_str() ; *cp != U'\0' ; ++cp) { + if (*cp == U'\'') { + column += 2; + } else { + column += 1; + } + } + } else if (ast->tokenKind == LiteralString::VERBATIM_DOUBLE) { + column += 3; // Include @, start and end quotes + for (const char32_t *cp = ast->value.c_str() ; *cp != U'\0' ; ++cp) { + if (*cp == U'"') { + column += 2; + } else { + column += 1; + } + } + } + + } else if (dynamic_cast(ast_)) { + column += 4; // null + + } else if (auto *ast = dynamic_cast(ast_)) { + column++; // '{' + const Fodder &first_fodder = ast->fields.size() == 0 + ? ast->closeFodder + : ast->fields[0].kind == ObjectField::FIELD_STR + ? open_fodder(ast->fields[0].expr1) + : ast->fields[0].fodder1; + Indent new_indent = newIndent(first_fodder, indent, + column + (opts.padObjects ? 1 : 0)); + + fields(ast->fields, new_indent, opts.padObjects); + if (ast->trailingComma) column++; + fill(ast->closeFodder, ast->fields.size() > 0, opts.padObjects, + new_indent.lineUp, indent.base); + column++; // '}' + + } else if (auto *ast = dynamic_cast(ast_)) { + // No fodder but need to recurse and maintain column counter. + column++; // '{' + for (AST *assert : ast->asserts) { + column += 6; // assert + expr(assert, indent, true); + column++; // ',' + } + for (auto &field : ast->fields) { + column++; // '[' + expr(field.name, indent, false); + column++; // ']' + switch (field.hide) { + case ObjectField::INHERIT: column += 1; break; + case ObjectField::HIDDEN: column += 2; break; + case ObjectField::VISIBLE: column += 3; break; + } + expr(field.body, indent, true); + } + column++; // '}' + + } else if (auto *ast = dynamic_cast(ast_)) { + column++; // '{' + unsigned start_column = column; + const Fodder &first_fodder = ast->fields.size() == 0 + ? ast->closeFodder + : ast->fields[0].kind == ObjectField::FIELD_STR + ? open_fodder(ast->fields[0].expr1) + : ast->fields[0].fodder1; + Indent new_indent = newIndent(first_fodder, indent, + start_column + (opts.padObjects ? 1 : 0)); + + fields(ast->fields, new_indent, opts.padObjects); + if (ast->trailingComma) column++; // ',' + specs(ast->specs, new_indent); + fill(ast->closeFodder, true, opts.padObjects, new_indent.lineUp, indent.base); + column++; // '}' + + } else if (auto *ast = dynamic_cast(ast_)) { + column++; // '{' + column++; // '[' + expr(ast->field, indent, false); + column++; // ']' + column++; // ':' + expr(ast->value, indent, true); + column += 5; // " for " + column += ast->id->name.length(); + column += 3; // " in" + expr(ast->array, indent, true); + column++; // '}' + + } else if (auto *ast = dynamic_cast(ast_)) { + column++; // ( + Indent new_indent = newIndentStrong(open_fodder(ast->expr), indent, column); + expr(ast->expr, new_indent, false); + fill(ast->closeFodder, false, false, new_indent.lineUp, indent.base); + column++; // ) + + } else if (dynamic_cast(ast_)) { + column += 4; // self + + } else if (auto *ast = dynamic_cast(ast_)) { + column += 5; // super + fill(ast->dotFodder, false, false, indent.lineUp); + if (ast->id != nullptr) { + column++; // "."; + Indent new_indent = newIndent(ast->idFodder, indent, column); + fill(ast->idFodder, false, false, new_indent.lineUp); + column += ast->id->name.length(); + } else { + column++; // "["; + Indent new_indent = newIndent(open_fodder(ast->index), indent, column); + expr(ast->index, new_indent, false); + fill(ast->idFodder, false, false, new_indent.lineUp, indent.base); + column++; // "]"; + } + + } else if (auto *ast = dynamic_cast(ast_)) { + column += uop_string(ast->op).length(); + Indent new_indent = newIndent(open_fodder(ast->expr), indent, column); + expr(ast->expr, new_indent, false); + + } else if (auto *ast = dynamic_cast(ast_)) { + column += ast->id->name.length(); + + } else { + std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_ << std::endl; + std::abort(); + + } + } + virtual void file(AST *body, Fodder &final_fodder) + { + expr(body, Indent(0, 0), false); + setIndents(final_fodder, 0, 0); + } +}; + + + +// TODO(dcunnin): Add pass to alphabeticize top level imports. + + +std::string jsonnet_fmt(AST *ast, Fodder &final_fodder, const FmtOpts &opts) +{ + Allocator alloc; + + // Passes to enforce style on the AST. + remove_initial_newlines(ast); + if (opts.maxBlankLines > 0) + EnforceMaximumBlankLines(alloc, opts).file(ast, final_fodder); + FixTrailingCommas(alloc, opts).file(ast, final_fodder); + FixParens(alloc, opts).file(ast, final_fodder); + FixPlusObject(alloc, opts).file(ast, final_fodder); + NoRedundantSliceColon(alloc, opts).file(ast, final_fodder); + if (opts.stripComments) + StripComments(alloc, opts).file(ast, final_fodder); + else if (opts.stripAllButComments) + StripAllButComments(alloc, opts).file(ast, final_fodder); + else if (opts.stripEverything) + StripEverything(alloc, opts).file(ast, final_fodder); + if (opts.prettyFieldNames) + PrettyFieldNames(alloc, opts).file(ast, final_fodder); + if (opts.stringStyle != 'l') + EnforceStringStyle(alloc, opts).file(ast, final_fodder); + if (opts.commentStyle != 'l') + EnforceCommentStyle(alloc, opts).file(ast, final_fodder); + if (opts.indent > 0) + FixIndentation(opts).file(ast, final_fodder); + + std::stringstream ss; + Unparser unparser(ss, opts); + unparser.unparse(ast, false); + unparser.fill(final_fodder, true, false); + return ss.str(); +} diff --git a/vendor/github.com/strickyak/jsonnet_cgo/formatter.h b/vendor/github.com/strickyak/jsonnet_cgo/formatter.h new file mode 100644 index 00000000..a3a610b9 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/formatter.h @@ -0,0 +1,51 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef JSONNET_FORMATTER_H +#define JSONNET_FORMATTER_H + +#include "ast.h" + +struct FmtOpts { + char stringStyle; + char commentStyle; + unsigned indent; + unsigned maxBlankLines; + bool padArrays; + bool padObjects; + bool stripComments; + bool stripAllButComments; + bool stripEverything; + bool prettyFieldNames; + FmtOpts(void) + : stringStyle('l'), + commentStyle('l'), + indent(0), + maxBlankLines(2), + padArrays(false), + padObjects(true), + stripComments(false), + stripAllButComments(false), + stripEverything(false), + prettyFieldNames(true) + { } +}; + +/** The inverse of jsonnet_parse. + */ +std::string jsonnet_fmt(AST *ast, Fodder &final_fodder, const FmtOpts &opts); + +#endif // JSONNET_PARSER_H diff --git a/vendor/github.com/strickyak/jsonnet_cgo/json.h b/vendor/github.com/strickyak/jsonnet_cgo/json.h new file mode 100644 index 00000000..d1c54630 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/json.h @@ -0,0 +1,42 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef JSONNET_JSON_H +#define JSONNET_JSON_H + +#include +#include +#include + +#include + +struct JsonnetJsonValue { + enum Kind { + ARRAY, + BOOL, + NULL_KIND, + NUMBER, + OBJECT, + STRING, + }; + Kind kind; + std::string string; + double number; // Also used for bool (0.0 and 1.0) + std::vector> elements; + std::map> fields; +}; + +#endif diff --git a/vendor/github.com/strickyak/jsonnet_cgo/jsonnet.go b/vendor/github.com/strickyak/jsonnet_cgo/jsonnet.go new file mode 100644 index 00000000..594aaf91 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/jsonnet.go @@ -0,0 +1,149 @@ +/* +jsonnet is a simple Go wrapper for the JSonnet VM. + +See http://jsonnet.org/ +*/ +package jsonnet + +// By Henry Strickland <@yak.net:strick> +// Made self-contained by Marko Mikulicic + +/* +#include +#include +#include +#include "bridge.h" +#cgo CXXFLAGS: -std=c++0x -O3 +*/ +import "C" + +import ( + "errors" + "unsafe" +) + +type ImportCallback func(base, rel string) (result string, path string, err error) + +type VM struct { + guts *C.struct_JsonnetVm + importCallback ImportCallback +} + +//export go_call_import +func go_call_import(vmPtr unsafe.Pointer, base, rel *C.char, pathPtr **C.char, okPtr *C.int) *C.char { + vm := (*VM)(vmPtr) + result, path, err := vm.importCallback(C.GoString(base), C.GoString(rel)) + if err != nil { + *okPtr = C.int(0) + return C.CString(err.Error()) + } + *pathPtr = C.CString(path) + *okPtr = C.int(1) + return C.CString(result) +} + +// Evaluate a file containing Jsonnet code, return a JSON string. +func Version() string { + return C.GoString(C.jsonnet_version()) +} + +// Create a new Jsonnet virtual machine. +func Make() *VM { + vm := &VM{guts: C.jsonnet_make()} + return vm +} + +// Complement of Make(). +func (vm *VM) Destroy() { + C.jsonnet_destroy(vm.guts) + vm.guts = nil +} + +// Evaluate a file containing Jsonnet code, return a JSON string. +func (vm *VM) EvaluateFile(filename string) (string, error) { + var e C.int + z := C.GoString(C.jsonnet_evaluate_file(vm.guts, C.CString(filename), &e)) + if e != 0 { + return "", errors.New(z) + } + return z, nil +} + +// Evaluate a string containing Jsonnet code, return a JSON string. +func (vm *VM) EvaluateSnippet(filename, snippet string) (string, error) { + var e C.int + z := C.GoString(C.jsonnet_evaluate_snippet(vm.guts, C.CString(filename), C.CString(snippet), &e)) + if e != 0 { + return "", errors.New(z) + } + return z, nil +} + +// Override the callback used to locate imports. +func (vm *VM) ImportCallback(f ImportCallback) { + vm.importCallback = f + C.jsonnet_import_callback(vm.guts, C.JsonnetImportCallbackPtr(C.CallImport_cgo), unsafe.Pointer(vm)) +} + +// Bind a Jsonnet external var to the given value. +func (vm *VM) ExtVar(key, val string) { + C.jsonnet_ext_var(vm.guts, C.CString(key), C.CString(val)) +} + +// Bind a Jsonnet external var to the given Jsonnet code. +func (vm *VM) ExtCode(key, val string) { + C.jsonnet_ext_code(vm.guts, C.CString(key), C.CString(val)) +} + +// Bind a Jsonnet top-level argument to the given value. +func (vm *VM) TlaVar(key, val string) { + C.jsonnet_tla_var(vm.guts, C.CString(key), C.CString(val)) +} + +// Bind a Jsonnet top-level argument to the given Jsonnet code. +func (vm *VM) TlaCode(key, val string) { + C.jsonnet_tla_code(vm.guts, C.CString(key), C.CString(val)) +} + +// Set the maximum stack depth. +func (vm *VM) MaxStack(v uint) { + C.jsonnet_max_stack(vm.guts, C.uint(v)) +} + +// Set the number of lines of stack trace to display (0 for all of them). +func (vm *VM) MaxTrace(v uint) { + C.jsonnet_max_trace(vm.guts, C.uint(v)) +} + +// Set the number of objects required before a garbage collection cycle is allowed. +func (vm *VM) GcMinObjects(v uint) { + C.jsonnet_gc_min_objects(vm.guts, C.uint(v)) +} + +// Run the garbage collector after this amount of growth in the number of objects. +func (vm *VM) GcGrowthTrigger(v float64) { + C.jsonnet_gc_growth_trigger(vm.guts, C.double(v)) +} + +// Expect a string as output and don't JSON encode it. +func (vm *VM) StringOutput(v bool) { + if v { + C.jsonnet_string_output(vm.guts, C.int(1)) + } else { + C.jsonnet_string_output(vm.guts, C.int(0)) + } +} + +// Add to the default import callback's library search path. +func (vm *VM) JpathAdd(path string) { + C.jsonnet_jpath_add(vm.guts, C.CString(path)) +} + +/* The following are not implemented because they are trivial to implement in Go on top of the + * existing API by parsing and post-processing the JSON output by regular evaluation. + * + * jsonnet_evaluate_file_multi + * jsonnet_evaluate_snippet_multi + * jsonnet_evaluate_file_stream + * jsonnet_evaluate_snippet_stream + */ diff --git a/vendor/github.com/strickyak/jsonnet_cgo/lexer.cpp b/vendor/github.com/strickyak/jsonnet_cgo/lexer.cpp new file mode 100644 index 00000000..b8fccede --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/lexer.cpp @@ -0,0 +1,810 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include + +#include +#include +#include + +#include "lexer.h" +#include "static_error.h" +#include "unicode.h" + +static const std::vector EMPTY; + +/** Strip whitespace from both ends of a string, but only up to margin on the left hand side. */ +static std::string strip_ws(const std::string &s, unsigned margin) +{ + if (s.size() == 0) return s; // Avoid underflow below. + size_t i = 0; + while (i < s.length() && (s[i] == ' ' || s[i] == '\t' || s[i] == '\r') && i < margin) + i++; + size_t j = s.size(); + while (j > i && (s[j - 1] == ' ' || s[j - 1] == '\t' || s[j - 1] == '\r')) { + j--; + } + return std::string(&s[i], &s[j]); +} + +/** Split a string by \n and also strip left (up to margin) & right whitespace from each line. */ +static std::vector line_split(const std::string &s, unsigned margin) +{ + std::vector ret; + std::stringstream ss; + for (size_t i=0 ; i= 'A' && c <= 'Z'; +} + +static bool is_lower(char c) +{ + return c >= 'a' && c <= 'z'; +} + +static bool is_number(char c) +{ + return c >= '0' && c <= '9'; +} + +static bool is_identifier_first(char c) +{ + return is_upper(c) || is_lower(c) || c == '_'; +} + +static bool is_identifier(char c) +{ + return is_identifier_first(c) || is_number(c); +} + +static bool is_symbol(char c) +{ + switch (c) { + case '!': case '$': case ':': + case '~': case '+': case '-': + case '&': case '|': case '^': + case '=': case '<': case '>': + case '*': case '/': case '%': + return true; + } + return false; +} + +static const std::map keywords = { + {"assert", Token::ASSERT}, + {"else", Token::ELSE}, + {"error", Token::ERROR}, + {"false", Token::FALSE}, + {"for", Token::FOR}, + {"function", Token::FUNCTION}, + {"if", Token::IF}, + {"import", Token::IMPORT}, + {"importstr", Token::IMPORTSTR}, + {"in", Token::IN}, + {"local", Token::LOCAL}, + {"null", Token::NULL_LIT}, + {"self", Token::SELF}, + {"super", Token::SUPER}, + {"tailstrict", Token::TAILSTRICT}, + {"then", Token::THEN}, + {"true", Token::TRUE}, +}; + +Token::Kind lex_get_keyword_kind(const std::string &identifier) +{ + auto it = keywords.find(identifier); + if (it == keywords.end()) return Token::IDENTIFIER; + return it->second; +} + +std::string lex_number(const char *&c, const std::string &filename, const Location &begin) +{ + // This function should be understood with reference to the linked image: + // http://www.json.org/number.gif + + // Note, we deviate from the json.org documentation as follows: + // There is no reason to lex negative numbers as atomic tokens, it is better to parse them + // as a unary operator combined with a numeric literal. This avoids x-1 being tokenized as + // instead of the intended . + + enum State { + BEGIN, + AFTER_ZERO, + AFTER_ONE_TO_NINE, + AFTER_DOT, + AFTER_DIGIT, + AFTER_E, + AFTER_EXP_SIGN, + AFTER_EXP_DIGIT + } state; + + std::string r; + + state = BEGIN; + while (true) { + switch (state) { + case BEGIN: + switch (*c) { + case '0': + state = AFTER_ZERO; + break; + + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + state = AFTER_ONE_TO_NINE; + break; + + default: + throw StaticError(filename, begin, "Couldn't lex number"); + } + break; + + case AFTER_ZERO: + switch (*c) { + case '.': + state = AFTER_DOT; + break; + + case 'e': case 'E': + state = AFTER_E; + break; + + default: + goto end; + } + break; + + case AFTER_ONE_TO_NINE: + switch (*c) { + case '.': + state = AFTER_DOT; + break; + + case 'e': case 'E': + state = AFTER_E; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + state = AFTER_ONE_TO_NINE; + break; + + default: + goto end; + } + break; + + case AFTER_DOT: + switch (*c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + state = AFTER_DIGIT; + break; + + default: { + std::stringstream ss; + ss << "Couldn't lex number, junk after decimal point: " << *c; + throw StaticError(filename, begin, ss.str()); + } + } + break; + + case AFTER_DIGIT: + switch (*c) { + case 'e': case 'E': + state = AFTER_E; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + state = AFTER_DIGIT; + break; + + default: + goto end; + } + break; + + case AFTER_E: + switch (*c) { + case '+': case '-': + state = AFTER_EXP_SIGN; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + state = AFTER_EXP_DIGIT; + break; + + default: { + std::stringstream ss; + ss << "Couldn't lex number, junk after 'E': " << *c; + throw StaticError(filename, begin, ss.str()); + } + } + break; + + case AFTER_EXP_SIGN: + switch (*c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + state = AFTER_EXP_DIGIT; + break; + + default: { + std::stringstream ss; + ss << "Couldn't lex number, junk after exponent sign: " << *c; + throw StaticError(filename, begin, ss.str()); + } + } + break; + + case AFTER_EXP_DIGIT: + switch (*c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + state = AFTER_EXP_DIGIT; + break; + + default: + goto end; + } + break; + } + r += *c; + c++; + } + end: + return r; +} + +// Check that b has at least the same whitespace prefix as a and returns the amount of this +// whitespace, otherwise returns 0. If a has no whitespace prefix than return 0. +static int whitespace_check(const char *a, const char *b) +{ + int i = 0; + while (a[i] == ' ' || a[i] == '\t') { + if (b[i] != a[i]) return 0; + i++; + } + return i; +} + +/* +static void add_whitespace(Fodder &fodder, const char *s, size_t n) +{ + std::string ws(s, n); + if (fodder.size() == 0 || fodder.back().kind != FodderElement::WHITESPACE) { + fodder.emplace_back(FodderElement::WHITESPACE, ws); + } else { + fodder.back().data += ws; + } +} +*/ + +Tokens jsonnet_lex(const std::string &filename, const char *input) +{ + unsigned long line_number = 1; + const char *line_start = input; + + Tokens r; + + const char *c = input; + + Fodder fodder; + bool fresh_line = true; // Are we tokenizing from the beginning of a new line? + + while (*c!='\0') { + + // Used to ensure we have actually advanced the pointer by the end of the iteration. + const char *original_c = c; + + Token::Kind kind; + std::string data; + std::string string_block_indent; + std::string string_block_term_indent; + + unsigned new_lines, indent; + lex_ws(c, new_lines, indent, line_start, line_number); + + // If it's the end of the file, discard final whitespace. + if (*c == '\0') + break; + + if (new_lines > 0) { + // Otherwise store whitespace in fodder. + unsigned blanks = new_lines - 1; + fodder.emplace_back(FodderElement::LINE_END, blanks, indent, EMPTY); + fresh_line = true; + } + + Location begin(line_number, c - line_start + 1); + + switch (*c) { + + // The following operators should never be combined with subsequent symbols. + case '{': + kind = Token::BRACE_L; + c++; + break; + + case '}': + kind = Token::BRACE_R; + c++; + break; + + case '[': + kind = Token::BRACKET_L; + c++; + break; + + case ']': + kind = Token::BRACKET_R; + c++; + break; + + case ',': + kind = Token::COMMA; + c++; + break; + + case '.': + kind = Token::DOT; + c++; + break; + + case '(': + kind = Token::PAREN_L; + c++; + break; + + case ')': + kind = Token::PAREN_R; + c++; + break; + + case ';': + kind = Token::SEMICOLON; + c++; + break; + + // Numeric literals. + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + kind = Token::NUMBER; + data = lex_number(c, filename, begin); + break; + + // String literals. + case '"': { + c++; + for (; ; ++c) { + if (*c == '\0') { + throw StaticError(filename, begin, "Unterminated string"); + } + if (*c == '"') { + break; + } + if (*c == '\\' && *(c+1) != '\0') { + data += *c; + ++c; + } + if (*c == '\n') { + // Maintain line/column counters. + line_number++; + line_start = c+1; + } + data += *c; + } + c++; // Advance beyond the ". + kind = Token::STRING_DOUBLE; + } + break; + + // String literals. + case '\'': { + c++; + for (; ; ++c) { + if (*c == '\0') { + throw StaticError(filename, begin, "Unterminated string"); + } + if (*c == '\'') { + break; + } + if (*c == '\\' && *(c+1) != '\0') { + data += *c; + ++c; + } + if (*c == '\n') { + // Maintain line/column counters. + line_number++; + line_start = c+1; + } + data += *c; + } + c++; // Advance beyond the '. + kind = Token::STRING_SINGLE; + } + break; + + // Verbatim string literals. + // ' and " quoting is interpreted here, unlike non-verbatim strings + // where it is done later by jsonnet_string_unescape. This is OK + // in this case because no information is lost by resoving the + // repeated quote into a single quote, so we can go back to the + // original form in the formatter. + case '@': { + c++; + if (*c != '"' && *c != '\'') { + std::stringstream ss; + ss << "Couldn't lex verbatim string, junk after '@': " << *c; + throw StaticError(filename, begin, ss.str()); + } + const char quot = *c; + c++; // Advance beyond the opening quote. + for (; ; ++c) { + if (*c == '\0') { + throw StaticError(filename, begin, "Unterminated verbatim string"); + } + if (*c == quot) { + if (*(c+1) == quot) { + c++; + } else { + break; + } + } + data += *c; + } + c++; // Advance beyond the closing quote. + if (quot == '"') { + kind = Token::VERBATIM_STRING_DOUBLE; + } else { + kind = Token::VERBATIM_STRING_SINGLE; + } + } + break; + + // Keywords + default: + if (is_identifier_first(*c)) { + std::string id; + for (; is_identifier(*c); ++c) + id += *c; + kind = lex_get_keyword_kind(id); + data = id; + + } else if (is_symbol(*c) || *c == '#') { + + // Single line C++ and Python style comments. + if (*c == '#' || (*c == '/' && *(c+1) == '/')) { + std::vector comment(1); + unsigned blanks; + unsigned indent; + lex_until_newline(c, comment[0], blanks, indent, line_start, line_number); + auto kind = fresh_line ? FodderElement::PARAGRAPH : FodderElement::LINE_END; + fodder.emplace_back(kind, blanks, indent, comment); + fresh_line = true; + continue; // We've not got a token, just fodder, so keep scanning. + } + + // Multi-line C style comment. + if (*c == '/' && *(c+1) == '*') { + + unsigned margin = c - line_start; + + const char *initial_c = c; + c += 2; // Avoid matching /*/: skip the /* before starting the search for */. + + while (!(*c == '*' && *(c+1) == '/')) { + if (*c == '\0') { + auto msg = "Multi-line comment has no terminating */."; + throw StaticError(filename, begin, msg); + } + if (*c == '\n') { + // Just keep track of the line / column counters. + line_number++; + line_start = c+1; + } + ++c; + } + c += 2; // Move the pointer to the char after the closing '/'. + + std::string comment(initial_c, c - initial_c); // Includes the "/*" and "*/". + + // Lex whitespace after comment + unsigned new_lines_after, indent_after; + lex_ws(c, new_lines_after, indent_after, line_start, line_number); + std::vector lines; + if (comment.find('\n') >= comment.length()) { + // Comment looks like /* foo */ + lines.push_back(comment); + fodder.emplace_back(FodderElement::INTERSTITIAL, 0, 0, lines); + if (new_lines_after > 0) { + fodder.emplace_back(FodderElement::LINE_END, new_lines_after - 1, + indent_after, EMPTY); + fresh_line = true; + } + } else { + lines = line_split(comment, margin); + assert(lines[0][0] == '/'); + // Little hack to support PARAGRAPHs with * down the LHS: + // Add a space to lines that start with a '*' + bool all_star = true; + for (auto &l : lines) { + if (l[0] != '*') + all_star = false; + } + if (all_star) { + for (auto &l : lines) { + if (l[0] == '*') l = " " + l; + } + } + if (new_lines_after == 0) { + // Ensure a line end after the paragraph. + new_lines_after = 1; + indent_after = 0; + } + if (!fresh_line) + // Ensure a line end before the comment. + fodder.emplace_back(FodderElement::LINE_END, 0, 0, EMPTY); + fodder.emplace_back(FodderElement::PARAGRAPH, new_lines_after - 1, + indent_after, lines); + fresh_line = true; + } + continue; // We've not got a token, just fodder, so keep scanning. + } + + // Text block + if (*c == '|' && *(c+1) == '|' && *(c+2) == '|') { + if (*(c+3) != '\n') { + auto msg = "Text block syntax requires new line after |||."; + throw StaticError(filename, begin, msg); + } + std::stringstream block; + c += 4; // Skip the "|||\n" + line_number++; + // Skip any blank lines at the beginning of the block. + while (*c == '\n') { + line_number++; + ++c; + block << '\n'; + } + line_start = c; + const char *first_line = c; + int ws_chars = whitespace_check(first_line, c); + string_block_indent = std::string(first_line, ws_chars); + if (ws_chars == 0) { + auto msg = "Text block's first line must start with whitespace."; + throw StaticError(filename, begin, msg); + } + while (true) { + assert(ws_chars > 0); + // Read up to the \n + for (c = &c[ws_chars]; *c != '\n' ; ++c) { + if (*c == '\0') + throw StaticError(filename, begin, "Unexpected EOF"); + block << *c; + } + // Add the \n + block << '\n'; + ++c; + line_number++; + line_start = c; + // Skip any blank lines + while (*c == '\n') { + line_number++; + ++c; + block << '\n'; + } + // Examine next line + ws_chars = whitespace_check(first_line, c); + if (ws_chars == 0) { + // End of text block + // Skip over any whitespace + while (*c == ' ' || *c == '\t') { + string_block_term_indent += *c; + ++c; + } + // Expect ||| + if (!(*c == '|' && *(c+1) == '|' && *(c+2) == '|')) { + auto msg = "Text block not terminated with |||"; + throw StaticError(filename, begin, msg); + } + c += 3; // Leave after the last | + data = block.str(); + kind = Token::STRING_BLOCK; + break; // Out of the while loop. + } + } + + break; // Out of the switch. + } + + const char *operator_begin = c; + for (; is_symbol(*c) ; ++c) { + // Not allowed // in operators + if (*c == '/' && *(c+1) == '/') break; + // Not allowed /* in operators + if (*c == '/' && *(c+1) == '*') break; + // Not allowed ||| in operators + if (*c == '|' && *(c+1) == '|' && *(c+2) == '|') break; + } + // Not allowed to end with a + - ~ ! unless a single char. + // So, wind it back if we need to (but not too far). + while (c > operator_begin + 1 + && (*(c-1) == '+' || *(c-1) == '-' || *(c-1) == '~' || *(c-1) == '!')) { + c--; + } + data += std::string(operator_begin, c); + if (data == "$") { + kind = Token::DOLLAR; + data = ""; + } else { + kind = Token::OPERATOR; + } + } else { + std::stringstream ss; + ss << "Could not lex the character "; + auto uc = (unsigned char)(*c); + if (*c < 32) + ss << "code " << unsigned(uc); + else + ss << "'" << *c << "'"; + throw StaticError(filename, begin, ss.str()); + } + } + + // Ensure that a bug in the above code does not cause an infinite memory consuming loop due + // to pushing empty tokens. + if (c == original_c) { + throw StaticError(filename, begin, "Internal lexing error: Pointer did not advance"); + } + + Location end(line_number, c - line_start); + r.emplace_back(kind, fodder, data, string_block_indent, string_block_term_indent, + LocationRange(filename, begin, end)); + fodder.clear(); + fresh_line = false; + } + + Location end(line_number, c - line_start + 1); + r.emplace_back(Token::END_OF_FILE, fodder, "", "", "", LocationRange(filename, end, end)); + return r; +} + +std::string jsonnet_unlex(const Tokens &tokens) +{ + std::stringstream ss; + for (const auto &t : tokens) { + for (const auto &f : t.fodder) { + switch (f.kind) { + case FodderElement::LINE_END: { + if (f.comment.size() > 0) { + ss << "LineEnd(" << f.blanks << ", " << f.indent << ", " + << f.comment[0] << ")\n"; + } else { + ss << "LineEnd(" << f.blanks << ", " << f.indent << ")\n"; + } + } break; + + case FodderElement::INTERSTITIAL: { + ss << "Interstitial(" << f.comment[0] << ")\n"; + } break; + + case FodderElement::PARAGRAPH: { + ss << "Paragraph(\n"; + for (const auto &line : f.comment) { + ss << " " << line << '\n'; + } + ss << ")\n"; + } break; + } + } + if (t.kind == Token::END_OF_FILE) { + ss << "EOF\n"; + break; + } + if (t.kind == Token::STRING_DOUBLE) { + ss << "\"" << t.data << "\"\n"; + } else if (t.kind == Token::STRING_SINGLE) { + ss << "'" << t.data << "'\n"; + } else if (t.kind == Token::STRING_BLOCK) { + ss << "|||\n"; + ss << t.stringBlockIndent; + for (const char *cp = t.data.c_str() ; *cp != '\0' ; ++cp) { + ss << *cp; + if (*cp == '\n' && *(cp + 1) != '\n' && *(cp + 1) != '\0') { + ss << t.stringBlockIndent; + } + } + ss << t.stringBlockTermIndent << "|||\n"; + } else { + ss << t.data << "\n"; + } + } + return ss.str(); +} diff --git a/vendor/github.com/strickyak/jsonnet_cgo/lexer.h b/vendor/github.com/strickyak/jsonnet_cgo/lexer.h new file mode 100644 index 00000000..33637429 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/lexer.h @@ -0,0 +1,250 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef JSONNET_LEXER_H +#define JSONNET_LEXER_H + +#include +#include + +#include +#include +#include +#include +#include + +#include "unicode.h" +#include "static_error.h" + +/** Whitespace and comments. + * + * "Fodder" (as in cannon fodder) implies this data is expendable. + */ +struct FodderElement { + enum Kind { + LINE_END, + INTERSTITIAL, + PARAGRAPH, + }; + Kind kind; + unsigned blanks; + unsigned indent; + std::vector comment; + FodderElement(Kind kind, unsigned blanks, unsigned indent, + const std::vector &comment) + : kind(kind), blanks(blanks), indent(indent), comment(comment) + { + assert(kind != LINE_END || comment.size() <= 1); + assert(kind != INTERSTITIAL || (blanks == 0 && indent == 0 && comment.size() == 1)); + assert(kind != PARAGRAPH || comment.size() >= 1); + } +}; +static inline std::ostream &operator<<(std::ostream &o, const FodderElement &f) +{ + switch (f.kind) { + case FodderElement::LINE_END: + o << "END(" << f.blanks << ", " << f.indent << ", " << f.comment[0] << ")"; + break; + case FodderElement::INTERSTITIAL: + o << "INT(" << f.blanks << ", " << f.indent << ", " << f.comment[0] << ")"; + break; + case FodderElement::PARAGRAPH: + o << "PAR(" << f.blanks << ", " << f.indent << ", " << f.comment[0] << "...)"; + break; + } + return o; +} +typedef std::vector Fodder; + +static inline std::ostream &operator<<(std::ostream &o, const Fodder &fodder) +{ + bool first = true; + for (const auto &f : fodder) { + o << (first ? "[" : ", "); + first = false; + o << f; + } + o << (first ? "[]" : "]"); + return o; +} + +struct Token { + enum Kind { + // Symbols + BRACE_L, + BRACE_R, + BRACKET_L, + BRACKET_R, + COMMA, + DOLLAR, + DOT, + PAREN_L, + PAREN_R, + SEMICOLON, + + // Arbitrary length lexemes + IDENTIFIER, + NUMBER, + OPERATOR, + STRING_DOUBLE, + STRING_SINGLE, + STRING_BLOCK, + VERBATIM_STRING_SINGLE, + VERBATIM_STRING_DOUBLE, + + // Keywords + ASSERT, + ELSE, + ERROR, + FALSE, + FOR, + FUNCTION, + IF, + IMPORT, + IMPORTSTR, + IN, + LOCAL, + NULL_LIT, + TAILSTRICT, + THEN, + SELF, + SUPER, + TRUE, + + // A special token that holds line/column information about the end of the file. + END_OF_FILE + } kind; + + /** Fodder before this token. */ + Fodder fodder; + + /** Content of the token if it wasn't a keyword. */ + std::string data; + + /** If kind == STRING_BLOCK then stores the sequence of whitespace that indented the block. */ + std::string stringBlockIndent; + + /** If kind == STRING_BLOCK then stores the sequence of whitespace that indented the end of + * the block. + * + * This is always fewer whitespace characters than in stringBlockIndent. + */ + std::string stringBlockTermIndent; + + String data32(void) { return decode_utf8(data); } + + LocationRange location; + + Token(Kind kind, const Fodder &fodder, const std::string &data, + const std::string &string_block_indent, const std::string &string_block_term_indent, + const LocationRange &location) + : kind(kind), fodder(fodder), data(data), stringBlockIndent(string_block_indent), + stringBlockTermIndent(string_block_term_indent), location(location) + { } + + Token(Kind kind, const std::string &data="") + : kind(kind), data(data) { } + + static const char *toString(Kind v) + { + switch (v) { + case BRACE_L: return "\"{\""; + case BRACE_R: return "\"}\""; + case BRACKET_L: return "\"[\""; + case BRACKET_R: return "\"]\""; + case COMMA: return "\",\""; + case DOLLAR: return "\"$\""; + case DOT: return "\".\""; + + case PAREN_L: return "\"(\""; + case PAREN_R: return "\")\""; + case SEMICOLON: return "\";\""; + + case IDENTIFIER: return "IDENTIFIER"; + case NUMBER: return "NUMBER"; + case OPERATOR: return "OPERATOR"; + case STRING_SINGLE: return "STRING_SINGLE"; + case STRING_DOUBLE: return "STRING_DOUBLE"; + case VERBATIM_STRING_SINGLE: return "VERBATIM_STRING_SINGLE"; + case VERBATIM_STRING_DOUBLE: return "VERBATIM_STRING_DOUBLE"; + case STRING_BLOCK: return "STRING_BLOCK"; + + case ASSERT: return "assert"; + case ELSE: return "else"; + case ERROR: return "error"; + case FALSE: return "false"; + case FOR: return "for"; + case FUNCTION: return "function"; + case IF: return "if"; + case IMPORT: return "import"; + case IMPORTSTR: return "importstr"; + case IN: return "in"; + case LOCAL: return "local"; + case NULL_LIT: return "null"; + case SELF: return "self"; + case SUPER: return "super"; + case TAILSTRICT: return "tailstrict"; + case THEN: return "then"; + case TRUE: return "true"; + + case END_OF_FILE: return "end of file"; + default: + std::cerr << "INTERNAL ERROR: Unknown token kind: " << v << std::endl; + std::abort(); + } + } +}; + +/** The result of lexing. + * + * Because of the EOF token, this will always contain at least one token. So element 0 can be used + * to get the filename. + */ +typedef std::list Tokens; + +static inline bool operator==(const Token &a, const Token &b) +{ + if (a.kind != b.kind) return false; + if (a.data != b.data) return false; + return true; +} + +static inline std::ostream &operator<<(std::ostream &o, Token::Kind v) +{ + o << Token::toString(v); + return o; +} + +static inline std::ostream &operator<<(std::ostream &o, const Token &v) +{ + if (v.data == "") { + o << Token::toString(v.kind); + } else if (v.kind == Token::OPERATOR) { + o << "\"" << v.data << "\""; + } else { + o << "(" << Token::toString(v.kind) << ", \"" << v.data << "\")"; + } + return o; +} + +/** IF the given identifier is a keyword, return its kind, otherwise return IDENTIFIER. */ +Token::Kind lex_get_keyword_kind(const std::string &identifier); + +Tokens jsonnet_lex(const std::string &filename, const char *input); + +std::string jsonnet_unlex(const Tokens &tokens); + +#endif // JSONNET_LEXER_H diff --git a/vendor/github.com/strickyak/jsonnet_cgo/libjsonnet.cpp b/vendor/github.com/strickyak/jsonnet_cgo/libjsonnet.cpp new file mode 100644 index 00000000..ec759edc --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/libjsonnet.cpp @@ -0,0 +1,672 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include + +extern "C" { +#include "libjsonnet.h" +} + +#include "desugarer.h" +#include "formatter.h" +#include "json.h" +#include "parser.h" +#include "static_analysis.h" +#include "vm.h" + +static void memory_panic(void) +{ + fputs("FATAL ERROR: A memory allocation error occurred.\n", stderr); + abort(); +} + +static char *from_string(JsonnetVm* vm, const std::string &v) +{ + char *r = jsonnet_realloc(vm, nullptr, v.length() + 1); + std::strcpy(r, v.c_str()); + return r; +} + +static char *default_import_callback(void *ctx, const char *dir, const char *file, + char **found_here_cptr, int *success); + +const char *jsonnet_json_extract_string(JsonnetVm *vm, const struct JsonnetJsonValue *v) +{ + (void) vm; + if (v->kind != JsonnetJsonValue::STRING) + return nullptr; + return v->string.c_str(); +} + +int jsonnet_json_extract_number(struct JsonnetVm *vm, const struct JsonnetJsonValue *v, double *out) +{ + (void) vm; + if (v->kind != JsonnetJsonValue::NUMBER) + return 0; + *out = v->number; + return 1; +} + +int jsonnet_json_extract_bool(struct JsonnetVm *vm, const struct JsonnetJsonValue *v) +{ + (void) vm; + if (v->kind != JsonnetJsonValue::BOOL) return 2; + return v->number != 0; +} + +int jsonnet_json_extract_null(struct JsonnetVm *vm, const struct JsonnetJsonValue *v) +{ + (void) vm; + return v->kind == JsonnetJsonValue::NULL_KIND; +} + +JsonnetJsonValue *jsonnet_json_make_string(JsonnetVm *vm, const char *v) +{ + (void) vm; + JsonnetJsonValue *r = new JsonnetJsonValue(); + r->kind = JsonnetJsonValue::STRING; + r->string = v; + return r; +} + +JsonnetJsonValue *jsonnet_json_make_number(struct JsonnetVm *vm, double v) +{ + (void) vm; + JsonnetJsonValue *r = new JsonnetJsonValue(); + r->kind = JsonnetJsonValue::NUMBER; + r->number = v; + return r; +} + +JsonnetJsonValue *jsonnet_json_make_bool(struct JsonnetVm *vm, int v) +{ + (void) vm; + JsonnetJsonValue *r = new JsonnetJsonValue(); + r->kind = JsonnetJsonValue::BOOL; + r->number = v != 0; + return r; +} + +JsonnetJsonValue *jsonnet_json_make_null(struct JsonnetVm *vm) +{ + (void) vm; + JsonnetJsonValue *r = new JsonnetJsonValue(); + r->kind = JsonnetJsonValue::NULL_KIND; + return r; +} + +JsonnetJsonValue *jsonnet_json_make_array(JsonnetVm *vm) +{ + (void) vm; + JsonnetJsonValue *r = new JsonnetJsonValue(); + r->kind = JsonnetJsonValue::ARRAY; + return r; +} + +void jsonnet_json_array_append(JsonnetVm *vm, JsonnetJsonValue *arr, JsonnetJsonValue *v) +{ + (void) vm; + assert(arr->kind == JsonnetJsonValue::ARRAY); + arr->elements.emplace_back(v); +} + +JsonnetJsonValue *jsonnet_json_make_object(JsonnetVm *vm) +{ + (void) vm; + JsonnetJsonValue *r = new JsonnetJsonValue(); + r->kind = JsonnetJsonValue::OBJECT; + return r; +} + +void jsonnet_json_object_append(JsonnetVm *vm, JsonnetJsonValue *obj, + const char *f, JsonnetJsonValue *v) +{ + (void) vm; + assert(obj->kind == JsonnetJsonValue::OBJECT); + obj->fields[std::string(f)] = std::unique_ptr(v); +} + +void jsonnet_json_destroy(JsonnetVm *vm, JsonnetJsonValue *v) +{ + (void) vm; + delete v; +} + +struct JsonnetVm { + double gcGrowthTrigger; + unsigned maxStack; + unsigned gcMinObjects; + unsigned maxTrace; + std::map ext; + std::map tla; + JsonnetImportCallback *importCallback; + VmNativeCallbackMap nativeCallbacks; + void *importCallbackContext; + bool stringOutput; + std::vector jpaths; + + FmtOpts fmtOpts; + bool fmtDebugDesugaring; + + JsonnetVm(void) + : gcGrowthTrigger(2.0), maxStack(500), gcMinObjects(1000), maxTrace(20), + importCallback(default_import_callback), importCallbackContext(this), stringOutput(false), + fmtDebugDesugaring(false) + { + jpaths.emplace_back("/usr/share/" + std::string(jsonnet_version()) + "/"); + jpaths.emplace_back("/usr/local/share/" + std::string(jsonnet_version()) + "/"); + } +}; + +enum ImportStatus { + IMPORT_STATUS_OK, + IMPORT_STATUS_FILE_NOT_FOUND, + IMPORT_STATUS_IO_ERROR +}; + +static enum ImportStatus try_path(const std::string &dir, const std::string &rel, + std::string &content, std::string &found_here, + std::string &err_msg) +{ + std::string abs_path; + if (rel.length() == 0) { + err_msg = "The empty string is not a valid filename"; + return IMPORT_STATUS_IO_ERROR; + } + // It is possible that rel is actually absolute. + if (rel[0] == '/') { + abs_path = rel; + } else { + abs_path = dir + rel; + } + + if (abs_path[abs_path.length() - 1] == '/') { + err_msg = "Attempted to import a directory"; + return IMPORT_STATUS_IO_ERROR; + } + + std::ifstream f; + f.open(abs_path.c_str()); + if (!f.good()) return IMPORT_STATUS_FILE_NOT_FOUND; + try { + content.assign(std::istreambuf_iterator(f), std::istreambuf_iterator()); + } catch (const std::ios_base::failure &io_err) { + err_msg = io_err.what(); + return IMPORT_STATUS_IO_ERROR; + } + if (!f.good()) { + err_msg = strerror(errno); + return IMPORT_STATUS_IO_ERROR; + } + + found_here = abs_path; + + return IMPORT_STATUS_OK; +} + +static char *default_import_callback(void *ctx, const char *dir, const char *file, + char **found_here_cptr, int *success) +{ + auto *vm = static_cast(ctx); + + std::string input, found_here, err_msg; + + ImportStatus status = try_path(dir, file, input, found_here, err_msg); + + std::vector jpaths(vm->jpaths); + + // If not found, try library search path. + while (status == IMPORT_STATUS_FILE_NOT_FOUND) { + if (jpaths.size() == 0) { + *success = 0; + const char *err = "No match locally or in the Jsonnet library paths."; + char *r = jsonnet_realloc(vm, nullptr, std::strlen(err) + 1); + std::strcpy(r, err); + return r; + } + status = try_path(jpaths.back(), file, input, found_here, err_msg); + jpaths.pop_back(); + } + + if (status == IMPORT_STATUS_IO_ERROR) { + *success = 0; + return from_string(vm, err_msg); + } else { + assert(status == IMPORT_STATUS_OK); + *success = 1; + *found_here_cptr = from_string(vm, found_here); + return from_string(vm, input); + } +} + +#define TRY try { +#define CATCH(func) \ + } catch (const std::bad_alloc &) {\ + memory_panic(); \ + } catch (const std::exception &e) {\ + std::cerr << "Something went wrong during " func ", please report this: " \ + << e.what() << std::endl; \ + abort(); \ + } + +const char *jsonnet_version(void) +{ + return LIB_JSONNET_VERSION; +} + +JsonnetVm *jsonnet_make(void) +{ + TRY + return new JsonnetVm(); + CATCH("jsonnet_make") + return nullptr; +} + +void jsonnet_destroy(JsonnetVm *vm) +{ + TRY + delete vm; + CATCH("jsonnet_destroy") +} + +void jsonnet_max_stack(JsonnetVm *vm, unsigned v) +{ + vm->maxStack = v; +} + +void jsonnet_gc_min_objects(JsonnetVm *vm, unsigned v) +{ + vm->gcMinObjects = v; +} + +void jsonnet_gc_growth_trigger(JsonnetVm *vm, double v) +{ + vm->gcGrowthTrigger = v; +} + +void jsonnet_string_output(struct JsonnetVm *vm, int v) +{ + vm->stringOutput = bool(v); +} + +void jsonnet_import_callback(struct JsonnetVm *vm, JsonnetImportCallback *cb, void *ctx) +{ + vm->importCallback = cb; + vm->importCallbackContext = ctx; +} + +void jsonnet_native_callback(struct JsonnetVm *vm, const char *name, JsonnetNativeCallback *cb, + void *ctx, const char * const *params) +{ + std::vector params2; + for (; *params != nullptr; params++) + params2.push_back(*params); + vm->nativeCallbacks[name] = VmNativeCallback {cb, ctx, params2}; +} + + +void jsonnet_ext_var(JsonnetVm *vm, const char *key, const char *val) +{ + vm->ext[key] = VmExt(val, false); +} + +void jsonnet_ext_code(JsonnetVm *vm, const char *key, const char *val) +{ + vm->ext[key] = VmExt(val, true); +} + +void jsonnet_tla_var(JsonnetVm *vm, const char *key, const char *val) +{ + vm->tla[key] = VmExt(val, false); +} + +void jsonnet_tla_code(JsonnetVm *vm, const char *key, const char *val) +{ + vm->tla[key] = VmExt(val, true); +} + +void jsonnet_fmt_debug_desugaring(JsonnetVm *vm, int v) +{ + vm->fmtDebugDesugaring = v; +} + +void jsonnet_fmt_indent(JsonnetVm *vm, int v) +{ + vm->fmtOpts.indent = v; +} + +void jsonnet_fmt_max_blank_lines(JsonnetVm *vm, int v) +{ + vm->fmtOpts.maxBlankLines = v; +} + +void jsonnet_fmt_string(JsonnetVm *vm, int v) +{ + if (v != 'd' && v != 's' && v != 'l') + v = 'l'; + vm->fmtOpts.stringStyle = v; +} + +void jsonnet_fmt_comment(JsonnetVm *vm, int v) +{ + if (v != 'h' && v != 's' && v != 'l') + v = 'l'; + vm->fmtOpts.commentStyle = v; +} + +void jsonnet_fmt_pad_arrays(JsonnetVm *vm, int v) +{ + vm->fmtOpts.padArrays = v; +} + +void jsonnet_fmt_pad_objects(JsonnetVm *vm, int v) +{ + vm->fmtOpts.padObjects = v; +} + +void jsonnet_fmt_pretty_field_names(JsonnetVm *vm, int v) +{ + vm->fmtOpts.prettyFieldNames = v; +} + +void jsonnet_max_trace(JsonnetVm *vm, unsigned v) +{ + vm->maxTrace = v; +} + +void jsonnet_jpath_add(JsonnetVm *vm, const char *path_) +{ + if (std::strlen(path_) == 0) return; + std::string path = path_; + if (path[path.length() - 1] != '/') path += '/'; + vm->jpaths.emplace_back(path); +} + +static char *jsonnet_fmt_snippet_aux(JsonnetVm *vm, const char *filename, const char *snippet, + int *error) +{ + try { + Allocator alloc; + std::string json_str; + AST *expr; + std::map files; + Tokens tokens = jsonnet_lex(filename, snippet); + + // std::cout << jsonnet_unlex(tokens); + + expr = jsonnet_parse(&alloc, tokens); + Fodder final_fodder = tokens.front().fodder; + + if (vm->fmtDebugDesugaring) + jsonnet_desugar(&alloc, expr, &vm->tla); + + json_str = jsonnet_fmt(expr, final_fodder, vm->fmtOpts); + + json_str += "\n"; + + *error = false; + return from_string(vm, json_str); + + } catch (StaticError &e) { + std::stringstream ss; + ss << "STATIC ERROR: " << e << std::endl; + *error = true; + return from_string(vm, ss.str()); + } + +} + +char *jsonnet_fmt_file(JsonnetVm *vm, const char *filename, int *error) +{ + TRY + std::ifstream f; + f.open(filename); + if (!f.good()) { + std::stringstream ss; + ss << "Opening input file: " << filename << ": " << strerror(errno); + *error = true; + return from_string(vm, ss.str()); + } + std::string input; + input.assign(std::istreambuf_iterator(f), + std::istreambuf_iterator()); + + return jsonnet_fmt_snippet_aux(vm, filename, input.c_str(), error); + CATCH("jsonnet_fmt_file") + return nullptr; // Never happens. +} + +char *jsonnet_fmt_snippet(JsonnetVm *vm, const char *filename, const char *snippet, int *error) +{ + TRY + return jsonnet_fmt_snippet_aux(vm, filename, snippet, error); + CATCH("jsonnet_fmt_snippet") + return nullptr; // Never happens. +} + + +namespace { +enum EvalKind { REGULAR, MULTI, STREAM }; +} // namespace + +static char *jsonnet_evaluate_snippet_aux(JsonnetVm *vm, const char *filename, + const char *snippet, int *error, EvalKind kind) +{ + try { + Allocator alloc; + AST *expr; + Tokens tokens = jsonnet_lex(filename, snippet); + + expr = jsonnet_parse(&alloc, tokens); + + jsonnet_desugar(&alloc, expr, &vm->tla); + + jsonnet_static_analysis(expr); + switch (kind) { + case REGULAR: { + std::string json_str = jsonnet_vm_execute( + &alloc, expr, vm->ext, vm->maxStack, vm->gcMinObjects, + vm->gcGrowthTrigger, vm->nativeCallbacks, vm->importCallback, + vm->importCallbackContext, vm->stringOutput); + json_str += "\n"; + *error = false; + return from_string(vm, json_str); + } + break; + + case MULTI: { + std::map files = jsonnet_vm_execute_multi( + &alloc, expr, vm->ext, vm->maxStack, vm->gcMinObjects, + vm->gcGrowthTrigger, vm->nativeCallbacks, vm->importCallback, + vm->importCallbackContext, vm->stringOutput); + size_t sz = 1; // final sentinel + for (const auto &pair : files) { + sz += pair.first.length() + 1; // include sentinel + sz += pair.second.length() + 2; // Add a '\n' as well as sentinel + } + char *buf = (char*)::malloc(sz); + if (buf == nullptr) memory_panic(); + std::ptrdiff_t i = 0; + for (const auto &pair : files) { + memcpy(&buf[i], pair.first.c_str(), pair.first.length() + 1); + i += pair.first.length() + 1; + memcpy(&buf[i], pair.second.c_str(), pair.second.length()); + i += pair.second.length(); + buf[i] = '\n'; + i++; + buf[i] = '\0'; + i++; + } + buf[i] = '\0'; // final sentinel + *error = false; + return buf; + } + break; + + case STREAM: { + std::vector documents = jsonnet_vm_execute_stream( + &alloc, expr, vm->ext, vm->maxStack, vm->gcMinObjects, + vm->gcGrowthTrigger, vm->nativeCallbacks, vm->importCallback, + vm->importCallbackContext); + size_t sz = 1; // final sentinel + for (const auto &doc : documents) { + sz += doc.length() + 2; // Add a '\n' as well as sentinel + } + char *buf = (char*)::malloc(sz); + if (buf == nullptr) memory_panic(); + std::ptrdiff_t i = 0; + for (const auto &doc : documents) { + memcpy(&buf[i], doc.c_str(), doc.length()); + i += doc.length(); + buf[i] = '\n'; + i++; + buf[i] = '\0'; + i++; + } + buf[i] = '\0'; // final sentinel + *error = false; + return buf; + } + break; + + default: + fputs("INTERNAL ERROR: bad value of 'kind', probably memory corruption.\n", stderr); + abort(); + } + + } catch (StaticError &e) { + std::stringstream ss; + ss << "STATIC ERROR: " << e << std::endl; + *error = true; + return from_string(vm, ss.str()); + + } catch (RuntimeError &e) { + std::stringstream ss; + ss << "RUNTIME ERROR: " << e.msg << std::endl; + const long max_above = vm->maxTrace / 2; + const long max_below = vm->maxTrace - max_above; + const long sz = e.stackTrace.size(); + for (long i = 0 ; i < sz ; ++i) { + const auto &f = e.stackTrace[i]; + if (vm->maxTrace > 0 && i >= max_above && i < sz - max_below) { + if (i == max_above) + ss << "\t..." << std::endl; + } else { + ss << "\t" << f.location << "\t" << f.name << std::endl; + } + } + *error = true; + return from_string(vm, ss.str()); + } + + return nullptr; // Quiet, compiler. +} + +static char *jsonnet_evaluate_file_aux(JsonnetVm *vm, const char *filename, int *error, EvalKind kind) +{ + std::ifstream f; + f.open(filename); + if (!f.good()) { + std::stringstream ss; + ss << "Opening input file: " << filename << ": " << strerror(errno); + *error = true; + return from_string(vm, ss.str()); + } + std::string input; + input.assign(std::istreambuf_iterator(f), + std::istreambuf_iterator()); + + return jsonnet_evaluate_snippet_aux(vm, filename, input.c_str(), error, kind); +} + +char *jsonnet_evaluate_file(JsonnetVm *vm, const char *filename, int *error) +{ + TRY + return jsonnet_evaluate_file_aux(vm, filename, error, REGULAR); + CATCH("jsonnet_evaluate_file") + return nullptr; // Never happens. +} + +char *jsonnet_evaluate_file_multi(JsonnetVm *vm, const char *filename, int *error) +{ + TRY + return jsonnet_evaluate_file_aux(vm, filename, error, MULTI); + CATCH("jsonnet_evaluate_file_multi") + return nullptr; // Never happens. +} + +char *jsonnet_evaluate_file_stream(JsonnetVm *vm, const char *filename, int *error) +{ + TRY + return jsonnet_evaluate_file_aux(vm, filename, error, STREAM); + CATCH("jsonnet_evaluate_file_stream") + return nullptr; // Never happens. +} + +char *jsonnet_evaluate_snippet(JsonnetVm *vm, const char *filename, const char *snippet, int *error) +{ + TRY + return jsonnet_evaluate_snippet_aux(vm, filename, snippet, error, REGULAR); + CATCH("jsonnet_evaluate_snippet") + return nullptr; // Never happens. +} + +char *jsonnet_evaluate_snippet_multi(JsonnetVm *vm, const char *filename, + const char *snippet, int *error) +{ + TRY + return jsonnet_evaluate_snippet_aux(vm, filename, snippet, error, MULTI); + CATCH("jsonnet_evaluate_snippet_multi") + return nullptr; // Never happens. +} + +char *jsonnet_evaluate_snippet_stream(JsonnetVm *vm, const char *filename, + const char *snippet, int *error) +{ + TRY + return jsonnet_evaluate_snippet_aux(vm, filename, snippet, error, STREAM); + CATCH("jsonnet_evaluate_snippet_stream") + return nullptr; // Never happens. +} + +char *jsonnet_realloc(JsonnetVm *vm, char *str, size_t sz) +{ + (void) vm; + if (str == nullptr) { + if (sz == 0) return nullptr; + auto *r = static_cast(::malloc(sz)); + if (r == nullptr) memory_panic(); + return r; + } else { + if (sz == 0) { + ::free(str); + return nullptr; + } else { + auto *r = static_cast(::realloc(str, sz)); + if (r == nullptr) memory_panic(); + return r; + } + } +} + diff --git a/vendor/github.com/strickyak/jsonnet_cgo/libjsonnet.h b/vendor/github.com/strickyak/jsonnet_cgo/libjsonnet.h new file mode 100644 index 00000000..e58f3852 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/libjsonnet.h @@ -0,0 +1,365 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef LIB_JSONNET_H +#define LIB_JSONNET_H + +#include + +/** \file This file is a library interface for evaluating Jsonnet. It is written in C++ but exposes + * a C interface for easier wrapping by other languages. See \see jsonnet_lib_test.c for an example + * of using the library. + */ + + +#define LIB_JSONNET_VERSION "v0.9.3" + + +/** Return the version string of the Jsonnet interpreter. Conforms to semantic versioning + * http://semver.org/ If this does not match LIB_JSONNET_VERSION then there is a mismatch between + * header and compiled library. + */ +const char *jsonnet_version(void); + +/** Jsonnet virtual machine context. */ +struct JsonnetVm; + +/** Create a new Jsonnet virtual machine. */ +struct JsonnetVm *jsonnet_make(void); + +/** Set the maximum stack depth. */ +void jsonnet_max_stack(struct JsonnetVm *vm, unsigned v); + +/** Set the number of objects required before a garbage collection cycle is allowed. */ +void jsonnet_gc_min_objects(struct JsonnetVm *vm, unsigned v); + +/** Run the garbage collector after this amount of growth in the number of objects. */ +void jsonnet_gc_growth_trigger(struct JsonnetVm *vm, double v); + +/** Expect a string as output and don't JSON encode it. */ +void jsonnet_string_output(struct JsonnetVm *vm, int v); + +/** Callback used to load imports. + * + * The returned char* should be allocated with jsonnet_realloc. It will be cleaned up by + * libjsonnet when no-longer needed. + * + * \param ctx User pointer, given in jsonnet_import_callback. + * \param base The directory containing the code that did the import. + * \param rel The path imported by the code. + * \param found_here Set this byref param to path to the file, absolute or relative to the + * process's CWD. This is necessary so that imports from the content of the imported file can + * be resolved correctly. Allocate memory with jsonnet_realloc. Only use when *success = 0. + * \param success Set this byref param to 1 to indicate success and 0 for failure. + * \returns The content of the imported file, or an error message. + */ +typedef char *JsonnetImportCallback(void *ctx, const char *base, const char *rel, char **found_here, int *success); + +/** An opaque type which can only be utilized via the jsonnet_json_* family of functions. + */ +struct JsonnetJsonValue; + +/** If the value is a string, return it as UTF8 otherwise return NULL. + */ +const char *jsonnet_json_extract_string(struct JsonnetVm *vm, const struct JsonnetJsonValue *v); + +/** If the value is a number, return 1 and store the number in out, otherwise return 0. + */ +int jsonnet_json_extract_number(struct JsonnetVm *vm, const struct JsonnetJsonValue *v, double *out); + +/** Return 0 if the value is false, 1 if it is true, and 2 if it is not a bool. + */ +int jsonnet_json_extract_bool(struct JsonnetVm *vm, const struct JsonnetJsonValue *v); + +/** Return 1 if the value is null, else 0. + */ +int jsonnet_json_extract_null(struct JsonnetVm *vm, const struct JsonnetJsonValue *v); + +/** Convert the given UTF8 string to a JsonnetJsonValue. + */ +struct JsonnetJsonValue *jsonnet_json_make_string(struct JsonnetVm *vm, const char *v); + +/** Convert the given double to a JsonnetJsonValue. + */ +struct JsonnetJsonValue *jsonnet_json_make_number(struct JsonnetVm *vm, double v); + +/** Convert the given bool (1 or 0) to a JsonnetJsonValue. + */ +struct JsonnetJsonValue *jsonnet_json_make_bool(struct JsonnetVm *vm, int v); + +/** Make a JsonnetJsonValue representing null. + */ +struct JsonnetJsonValue *jsonnet_json_make_null(struct JsonnetVm *vm); + +/** Make a JsonnetJsonValue representing an array. + * + * Assign elements with jsonnet_json_array_append. + */ +struct JsonnetJsonValue *jsonnet_json_make_array(struct JsonnetVm *vm); + +/** Add v to the end of the array. + */ +void jsonnet_json_array_append(struct JsonnetVm *vm, + struct JsonnetJsonValue *arr, + struct JsonnetJsonValue *v); + +/** Make a JsonnetJsonValue representing an object with the given number of fields. + * + * Every index of the array must have a unique value assigned with jsonnet_json_array_element. + */ +struct JsonnetJsonValue *jsonnet_json_make_object(struct JsonnetVm *vm); + +/** Add the field f to the object, bound to v. + * + * This replaces any previous binding of the field. + */ +void jsonnet_json_object_append(struct JsonnetVm *vm, + struct JsonnetJsonValue *obj, + const char *f, + struct JsonnetJsonValue *v); + +/** Clean up a JSON subtree. + * + * This is useful if you want to abort with an error mid-way through building a complex value. + */ +void jsonnet_json_destroy(struct JsonnetVm *vm, struct JsonnetJsonValue *v); + +/** Callback to provide native extensions to Jsonnet. + * + * The returned JsonnetJsonValue* should be allocated with jsonnet_realloc. It will be cleaned up + * along with the objects rooted at argv by libjsonnet when no-longer needed. Return a string upon + * failure, which will appear in Jsonnet as an error. + * + * \param ctx User pointer, given in jsonnet_native_callback. + * \param argc The number of arguments from Jsonnet code. + * \param argv Array of arguments from Jsonnet code. + * \param success Set this byref param to 1 to indicate success and 0 for failure. + * \returns The content of the imported file, or an error message. + */ +typedef struct JsonnetJsonValue *JsonnetNativeCallback(void *ctx, + const struct JsonnetJsonValue * const *argv, + int *success); + +/** Allocate, resize, or free a buffer. This will abort if the memory cannot be allocated. It will + * only return NULL if sz was zero. + * + * \param buf If NULL, allocate a new buffer. If an previously allocated buffer, resize it. + * \param sz The size of the buffer to return. If zero, frees the buffer. + * \returns The new buffer. + */ +char *jsonnet_realloc(struct JsonnetVm *vm, char *buf, size_t sz); + +/** Override the callback used to locate imports. + */ +void jsonnet_import_callback(struct JsonnetVm *vm, JsonnetImportCallback *cb, void *ctx); + +/** Register a native extension. + * + * This will appear in Jsonnet as a function type and can be accessed from std.nativeExt("foo"). + * + * DO NOT register native callbacks with side-effects! Jsonnet is a lazy functional language and + * will call your function when you least expect it, more times than you expect, or not at all. + * + * \param vm The vm. + * \param name The name of the function as visible to Jsonnet code, e.g. "foo". + * \param cb The PURE function that implements the behavior you want. + * \param ctx User pointer, stash non-global state you need here. + * \param params NULL-terminated array of the names of the params. Must be valid identifiers. + */ +void jsonnet_native_callback(struct JsonnetVm *vm, const char *name, JsonnetNativeCallback *cb, + void *ctx, const char * const *params); + +/** Bind a Jsonnet external var to the given string. + * + * Argument values are copied so memory should be managed by caller. + */ +void jsonnet_ext_var(struct JsonnetVm *vm, const char *key, const char *val); + +/** Bind a Jsonnet external var to the given code. + * + * Argument values are copied so memory should be managed by caller. + */ +void jsonnet_ext_code(struct JsonnetVm *vm, const char *key, const char *val); + +/** Bind a string top-level argument for a top-level parameter. + * + * Argument values are copied so memory should be managed by caller. + */ +void jsonnet_tla_var(struct JsonnetVm *vm, const char *key, const char *val); + +/** Bind a code top-level argument for a top-level parameter. + * + * Argument values are copied so memory should be managed by caller. + */ +void jsonnet_tla_code(struct JsonnetVm *vm, const char *key, const char *val); + +/** Indentation level when reformatting (number of spaeces). + * + * \param n Number of spaces, must be > 0. + */ +void jsonnet_fmt_indent(struct JsonnetVm *vm, int n); + +/** Indentation level when reformatting (number of spaeces). + * + * \param n Number of spaces, must be > 0. + */ +void jsonnet_fmt_max_blank_lines(struct JsonnetVm *vm, int n); + +/** Preferred style for string literals ("" or ''). + * + * \param c String style as a char ('d', 's', or 'l' (leave)). + */ +void jsonnet_fmt_string(struct JsonnetVm *vm, int c); + +/** Preferred style for line comments (# or //). + * + * \param c Comment style as a char ('h', 's', or 'l' (leave)). + */ +void jsonnet_fmt_comment(struct JsonnetVm *vm, int c); + +/** Whether to add an extra space on the inside of arrays. + */ +void jsonnet_fmt_pad_arrays(struct JsonnetVm *vm, int v); + +/** Whether to add an extra space on the inside of objects. + */ +void jsonnet_fmt_pad_objects(struct JsonnetVm *vm, int v); + +/** Use syntax sugar where possible with field names. + */ +void jsonnet_fmt_pretty_field_names(struct JsonnetVm *vm, int v); + +/** If set to 1, will reformat the Jsonnet input after desugaring. */ +void jsonnet_fmt_debug_desugaring(struct JsonnetVm *vm, int v); + +/** Reformat a file containing Jsonnet code, return a Jsonnet string. + * + * The returned string should be cleaned up with jsonnet_realloc. + * + * \param filename Path to a file containing Jsonnet code. + * \param error Return by reference whether or not there was an error. + * \returns Either Jsonnet code or the error message. + */ +char *jsonnet_fmt_file(struct JsonnetVm *vm, + const char *filename, + int *error); + +/** Evaluate a string containing Jsonnet code, return a Jsonnet string. + * + * The returned string should be cleaned up with jsonnet_realloc. + * + * \param filename Path to a file (used in error messages). + * \param snippet Jsonnet code to execute. + * \param error Return by reference whether or not there was an error. + * \returns Either JSON or the error message. + */ +char *jsonnet_fmt_snippet(struct JsonnetVm *vm, + const char *filename, + const char *snippet, + int *error); + +/** Set the number of lines of stack trace to display (0 for all of them). */ +void jsonnet_max_trace(struct JsonnetVm *vm, unsigned v); + +/** Add to the default import callback's library search path. */ +void jsonnet_jpath_add(struct JsonnetVm *vm, const char *v); + +/** Evaluate a file containing Jsonnet code, return a JSON string. + * + * The returned string should be cleaned up with jsonnet_realloc. + * + * \param filename Path to a file containing Jsonnet code. + * \param error Return by reference whether or not there was an error. + * \returns Either JSON or the error message. + */ +char *jsonnet_evaluate_file(struct JsonnetVm *vm, + const char *filename, + int *error); + +/** Evaluate a string containing Jsonnet code, return a JSON string. + * + * The returned string should be cleaned up with jsonnet_realloc. + * + * \param filename Path to a file (used in error messages). + * \param snippet Jsonnet code to execute. + * \param error Return by reference whether or not there was an error. + * \returns Either JSON or the error message. + */ +char *jsonnet_evaluate_snippet(struct JsonnetVm *vm, + const char *filename, + const char *snippet, + int *error); + +/** Evaluate a file containing Jsonnet code, return a number of named JSON files. + * + * The returned character buffer contains an even number of strings, the filename and JSON for each + * JSON file interleaved. It should be cleaned up with jsonnet_realloc. + * + * \param filename Path to a file containing Jsonnet code. + * \param error Return by reference whether or not there was an error. + * \returns Either the error, or a sequence of strings separated by \0, terminated with \0\0. + */ +char *jsonnet_evaluate_file_multi(struct JsonnetVm *vm, + const char *filename, + int *error); + +/** Evaluate a string containing Jsonnet code, return a number of named JSON files. + * + * The returned character buffer contains an even number of strings, the filename and JSON for each + * JSON file interleaved. It should be cleaned up with jsonnet_realloc. + * + * \param filename Path to a file containing Jsonnet code. + * \param snippet Jsonnet code to execute. + * \param error Return by reference whether or not there was an error. + * \returns Either the error, or a sequence of strings separated by \0, terminated with \0\0. + */ +char *jsonnet_evaluate_snippet_multi(struct JsonnetVm *vm, + const char *filename, + const char *snippet, + int *error); + +/** Evaluate a file containing Jsonnet code, return a number of JSON files. + * + * The returned character buffer contains several strings. It should be cleaned up with + * jsonnet_realloc. + * + * \param filename Path to a file containing Jsonnet code. + * \param error Return by reference whether or not there was an error. + * \returns Either the error, or a sequence of strings separated by \0, terminated with \0\0. + */ +char *jsonnet_evaluate_file_stream(struct JsonnetVm *vm, + const char *filename, + int *error); + +/** Evaluate a string containing Jsonnet code, return a number of JSON files. + * + * The returned character buffer contains several strings. It should be cleaned up with + * jsonnet_realloc. + * + * \param filename Path to a file containing Jsonnet code. + * \param snippet Jsonnet code to execute. + * \param error Return by reference whether or not there was an error. + * \returns Either the error, or a sequence of strings separated by \0, terminated with \0\0. + */ +char *jsonnet_evaluate_snippet_stream(struct JsonnetVm *vm, + const char *filename, + const char *snippet, + int *error); + +/** Complement of \see jsonnet_vm_make. */ +void jsonnet_destroy(struct JsonnetVm *vm); + +#endif // LIB_JSONNET_H diff --git a/vendor/github.com/strickyak/jsonnet_cgo/md5.cpp b/vendor/github.com/strickyak/jsonnet_cgo/md5.cpp new file mode 100644 index 00000000..b51d2e9b --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/md5.cpp @@ -0,0 +1,363 @@ +/* MD5 + converted to C++ class by Frank Thilo (thilo@unix-ag.org) + for bzflag (http://www.bzflag.org) + + based on: + + md5.h and md5.c + reference implemantion of RFC 1321 + + Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + +*/ + +/* interface header */ +#include "md5.h" + +/* system implementation headers */ +#include + + +// Constants for MD5Transform routine. +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +/////////////////////////////////////////////// + +// F, G, H and I are basic MD5 functions. +inline MD5::uint4 MD5::F(uint4 x, uint4 y, uint4 z) { + return (x&y) | (~x&z); +} + +inline MD5::uint4 MD5::G(uint4 x, uint4 y, uint4 z) { + return (x&z) | (y&~z); +} + +inline MD5::uint4 MD5::H(uint4 x, uint4 y, uint4 z) { + return x^y^z; +} + +inline MD5::uint4 MD5::I(uint4 x, uint4 y, uint4 z) { + return y ^ (x | ~z); +} + +// rotate_left rotates x left n bits. +inline MD5::uint4 MD5::rotate_left(uint4 x, int n) { + return (x << n) | (x >> (32-n)); +} + +// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +// Rotation is separate from addition to prevent recomputation. +inline void MD5::FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { + a = rotate_left(a+ F(b,c,d) + x + ac, s) + b; +} + +inline void MD5::GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { + a = rotate_left(a + G(b,c,d) + x + ac, s) + b; +} + +inline void MD5::HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { + a = rotate_left(a + H(b,c,d) + x + ac, s) + b; +} + +inline void MD5::II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { + a = rotate_left(a + I(b,c,d) + x + ac, s) + b; +} + +////////////////////////////////////////////// + +// default ctor, just initailize +MD5::MD5() +{ + init(); +} + +////////////////////////////////////////////// + +// nifty shortcut ctor, compute MD5 for string and finalize it right away +MD5::MD5(const std::string &text) +{ + init(); + update(text.c_str(), text.length()); + finalize(); +} + +////////////////////////////// + +void MD5::init() +{ + finalized=false; + + count[0] = 0; + count[1] = 0; + + // load magic initialization constants. + state[0] = 0x67452301; + state[1] = 0xefcdab89; + state[2] = 0x98badcfe; + state[3] = 0x10325476; +} + +////////////////////////////// + +// decodes input (unsigned char) into output (uint4). Assumes len is a multiple of 4. +void MD5::decode(uint4 output[], const uint1 input[], size_type len) +{ + for (unsigned int i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) | + (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24); +} + +////////////////////////////// + +// encodes input (uint4) into output (unsigned char). Assumes len is +// a multiple of 4. +void MD5::encode(uint1 output[], const uint4 input[], size_type len) +{ + for (size_type i = 0, j = 0; j < len; i++, j += 4) { + output[j] = input[i] & 0xff; + output[j+1] = (input[i] >> 8) & 0xff; + output[j+2] = (input[i] >> 16) & 0xff; + output[j+3] = (input[i] >> 24) & 0xff; + } +} + +////////////////////////////// + +// apply MD5 algo on a block +void MD5::transform(const uint1 block[blocksize]) +{ + uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + decode (x, block, blocksize); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + // Zeroize sensitive information. + memset(x, 0, sizeof x); +} + +////////////////////////////// + +// MD5 block update operation. Continues an MD5 message-digest +// operation, processing another message block +void MD5::update(const unsigned char input[], size_type length) +{ + // compute number of bytes mod 64 + size_type index = count[0] / 8 % blocksize; + + // Update number of bits + if ((count[0] += (length << 3)) < (length << 3)) + count[1]++; + count[1] += (length >> 29); + + // number of bytes we need to fill in buffer + size_type firstpart = 64 - index; + + size_type i; + + // transform as many times as possible. + if (length >= firstpart) + { + // fill buffer first, transform + memcpy(&buffer[index], input, firstpart); + transform(buffer); + + // transform chunks of blocksize (64 bytes) + for (i = firstpart; i + blocksize <= length; i += blocksize) + transform(&input[i]); + + index = 0; + } + else + i = 0; + + // buffer remaining input + memcpy(&buffer[index], &input[i], length-i); +} + +////////////////////////////// + +// for convenience provide a verson with signed char +void MD5::update(const char input[], size_type length) +{ + update((const unsigned char*)input, length); +} + +////////////////////////////// + +// MD5 finalization. Ends an MD5 message-digest operation, writing the +// the message digest and zeroizing the context. +MD5& MD5::finalize() +{ + static unsigned char padding[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + if (!finalized) { + // Save number of bits + unsigned char bits[8]; + encode(bits, count, 8); + + // pad out to 56 mod 64. + size_type index = count[0] / 8 % 64; + size_type padLen = (index < 56) ? (56 - index) : (120 - index); + update(padding, padLen); + + // Append length (before padding) + update(bits, 8); + + // Store state in digest + encode(digest, state, 16); + + // Zeroize sensitive information. + memset(buffer, 0, sizeof buffer); + memset(count, 0, sizeof count); + + finalized=true; + } + + return *this; +} + +////////////////////////////// + +// return hex representation of digest as string +std::string MD5::hexdigest() const +{ + if (!finalized) + return ""; + + char buf[33]; + for (int i=0; i<16; i++) + sprintf(buf+i*2, "%02x", digest[i]); + buf[32]=0; + + return std::string(buf); +} + +////////////////////////////// + +std::ostream& operator<<(std::ostream& out, MD5 md5) +{ + return out << md5.hexdigest(); +} + +////////////////////////////// + +std::string md5(const std::string str) +{ + MD5 md5 = MD5(str); + + return md5.hexdigest(); +} + diff --git a/vendor/github.com/strickyak/jsonnet_cgo/md5.h b/vendor/github.com/strickyak/jsonnet_cgo/md5.h new file mode 100644 index 00000000..d57b2c64 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/md5.h @@ -0,0 +1,93 @@ +/* MD5 + converted to C++ class by Frank Thilo (thilo@unix-ag.org) + for bzflag (http://www.bzflag.org) + + based on: + + md5.h and md5.c + reference implementation of RFC 1321 + + Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + +*/ + +#ifndef BZF_MD5_H +#define BZF_MD5_H + +#include +#include + + +// a small class for calculating MD5 hashes of strings or byte arrays +// it is not meant to be fast or secure +// +// usage: 1) feed it blocks of uchars with update() +// 2) finalize() +// 3) get hexdigest() string +// or +// MD5(std::string).hexdigest() +// +// assumes that char is 8 bit and int is 32 bit +class MD5 +{ +public: + typedef unsigned int size_type; // must be 32bit + + MD5(); + MD5(const std::string& text); + void update(const unsigned char *buf, size_type length); + void update(const char *buf, size_type length); + MD5& finalize(); + std::string hexdigest() const; + friend std::ostream& operator<<(std::ostream&, MD5 md5); + +private: + void init(); + typedef unsigned char uint1; // 8bit + typedef unsigned int uint4; // 32bit + enum {blocksize = 64}; // VC6 won't eat a const static int here + + void transform(const uint1 block[blocksize]); + static void decode(uint4 output[], const uint1 input[], size_type len); + static void encode(uint1 output[], const uint4 input[], size_type len); + + bool finalized; + uint1 buffer[blocksize]; // bytes that didn't fit in last 64 byte chunk + uint4 count[2]; // 64bit counter for number of bits (lo, hi) + uint4 state[4]; // digest so far + uint1 digest[16]; // the result + + // low level logic operations + static inline uint4 F(uint4 x, uint4 y, uint4 z); + static inline uint4 G(uint4 x, uint4 y, uint4 z); + static inline uint4 H(uint4 x, uint4 y, uint4 z); + static inline uint4 I(uint4 x, uint4 y, uint4 z); + static inline uint4 rotate_left(uint4 x, int n); + static inline void FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); + static inline void GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); + static inline void HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); + static inline void II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); +}; + +std::string md5(const std::string str); + +#endif diff --git a/vendor/github.com/strickyak/jsonnet_cgo/parser.cpp b/vendor/github.com/strickyak/jsonnet_cgo/parser.cpp new file mode 100644 index 00000000..fc20c6d2 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/parser.cpp @@ -0,0 +1,984 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include "ast.h" +#include "desugarer.h" +#include "lexer.h" +#include "parser.h" +#include "static_error.h" + + +std::string jsonnet_unparse_number(double v) +{ + std::stringstream ss; + if (v == floor(v)) { + ss << std::fixed << std::setprecision(0) << v; + } else { + // See "What Every Computer Scientist Should Know About Floating-Point Arithmetic" + // Theorem 15 + // http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html + ss << std::setprecision(17); + ss << v; + } + return ss.str(); +} + + +namespace { + +static bool op_is_unary(const std::string &op, UnaryOp &uop) +{ + auto it = unary_map.find(op); + if (it == unary_map.end()) return false; + uop = it->second; + return true; +} + +static bool op_is_binary(const std::string &op, BinaryOp &bop) +{ + auto it = binary_map.find(op); + if (it == binary_map.end()) return false; + bop = it->second; + return true; +} + +LocationRange span(const Token &begin) +{ + return LocationRange(begin.location.file, begin.location.begin, begin.location.end); +} + +LocationRange span(const Token &begin, const Token &end) +{ + return LocationRange(begin.location.file, begin.location.begin, end.location.end); +} + +LocationRange span(const Token &begin, AST *end) +{ + return LocationRange(begin.location.file, begin.location.begin, end->location.end); +} + +/** Holds state while parsing a given token list. + */ +class Parser { + + // The private member functions are utilities for dealing with the token stream. + + StaticError unexpected(const Token &tok, const std::string &while_) + { + std::stringstream ss; + ss << "Unexpected: " << tok.kind << " while " << while_; + return StaticError(tok.location, ss.str()); + } + + Token pop(void) + { + Token tok = peek(); + tokens.pop_front(); + return tok; + } + + void push(Token tok) { + tokens.push_front(tok); + } + + Token peek(void) + { + Token tok = tokens.front(); + return tok; + } + + /** Only call this is peek() is not an EOF token. */ + Token doublePeek(void) + { + Tokens::iterator it = tokens.begin(); // First one. + it++; // Now pointing at the second one. + return *(it); + } + + Token popExpect(Token::Kind k, const char *data=nullptr) + { + Token tok = pop(); + if (tok.kind != k) { + std::stringstream ss; + ss << "Expected token " << k << " but got " << tok; + throw StaticError(tok.location, ss.str()); + } + if (data != nullptr && tok.data != data) { + std::stringstream ss; + ss << "Expected operator " << data << " but got " << tok.data; + throw StaticError(tok.location, ss.str()); + } + return tok; + } + + std::list &tokens; + Allocator *alloc; + + public: + + Parser(Tokens &tokens, Allocator *alloc) + : tokens(tokens), alloc(alloc) + { } + + /** Parse a comma-separated list of expressions. + * + * Allows an optional ending comma. + * \param exprs Expressions added here. + * \param end The token that ends the list (e.g. ] or )). + * \param element_kind Used in error messages when a comma was not found. + * \returns The last token (the one that matched parameter end). + */ + Token parseArgs(ArgParams &args, Token::Kind end, + const std::string &element_kind, bool &got_comma) + { + got_comma = false; + bool first = true; + do { + Token next = peek(); + if (next.kind == end) { + // got_comma can be true or false here. + return pop(); + } + if (!first && !got_comma) { + std::stringstream ss; + ss << "Expected a comma before next " << element_kind << "."; + throw StaticError(next.location, ss.str()); + } + // Either id=expr or id or expr, but note that expr could be id==1 so this needs + // look-ahead. + Fodder id_fodder; + const Identifier *id = nullptr; + Fodder eq_fodder; + if (peek().kind == Token::IDENTIFIER) { + Token maybe_eq = doublePeek(); + if (maybe_eq.kind == Token::OPERATOR && maybe_eq.data == "=") { + id_fodder = peek().fodder; + id = alloc->makeIdentifier(peek().data32()); + eq_fodder = maybe_eq.fodder; + pop(); // id + pop(); // eq + } + } + AST *expr = parse(MAX_PRECEDENCE); + got_comma = false; + first = false; + Fodder comma_fodder; + if (peek().kind == Token::COMMA) { + Token comma = pop(); + comma_fodder = comma.fodder; + got_comma = true; + } + args.emplace_back(id_fodder, id, eq_fodder, expr, comma_fodder); + } while (true); + } + + ArgParams parseParams(const std::string &element_kind, bool &got_comma, Fodder &close_fodder) + { + ArgParams params; + Token paren_r = parseArgs(params, Token::PAREN_R, element_kind, got_comma); + + // Check they're all identifiers + // parseArgs returns f(x) with x as an expression. Convert it here. + for (auto &p : params) { + if (p.id == nullptr) { + auto *pv = dynamic_cast(p.expr); + if (pv == nullptr) { + throw StaticError(p.expr->location, + "Could not parse parameter here."); + + } + p.id = pv->id; + p.idFodder = pv->openFodder; + p.expr = nullptr; + } + } + + close_fodder = paren_r.fodder; + + return params; + } + + Token parseBind(Local::Binds &binds) + { + Token var_id = popExpect(Token::IDENTIFIER); + auto *id = alloc->makeIdentifier(var_id.data32()); + for (const auto &bind : binds) { + if (bind.var == id) + throw StaticError(var_id.location, "Duplicate local var: " + var_id.data); + } + bool is_function = false; + ArgParams params; + bool trailing_comma = false; + Fodder fodder_l, fodder_r; + if (peek().kind == Token::PAREN_L) { + Token paren_l = pop(); + fodder_l = paren_l.fodder; + params = parseParams("function parameter", trailing_comma, fodder_r); + is_function = true; + } + Token eq = popExpect(Token::OPERATOR, "="); + AST *body = parse(MAX_PRECEDENCE); + Token delim = pop(); + binds.emplace_back(var_id.fodder, id, eq.fodder, body, is_function, fodder_l, params, + trailing_comma, fodder_r, delim.fodder); + return delim; + } + + + Token parseObjectRemainder(AST *&obj, const Token &tok) + { + ObjectFields fields; + std::set literal_fields; // For duplicate fields detection. + std::set binds; // For duplicate locals detection. + + bool got_comma = false; + bool first = true; + Token next = pop(); + + do { + + if (next.kind == Token::BRACE_R) { + obj = alloc->make( + span(tok, next), tok.fodder, fields, got_comma, next.fodder); + return next; + + } else if (next.kind == Token::FOR) { + // It's a comprehension + unsigned num_fields = 0; + unsigned num_asserts = 0; + const ObjectField *field_ptr = nullptr; + for (const auto &field : fields) { + if (field.kind == ObjectField::LOCAL) continue; + if (field.kind == ObjectField::ASSERT) { + num_asserts++; + continue; + } + field_ptr = &field; + num_fields++; + } + if (num_asserts > 0) { + auto msg = "Object comprehension cannot have asserts."; + throw StaticError(next.location, msg); + } + if (num_fields != 1) { + auto msg = "Object comprehension can only have one field."; + throw StaticError(next.location, msg); + } + const ObjectField &field = *field_ptr; + + if (field.hide != ObjectField::INHERIT) { + auto msg = "Object comprehensions cannot have hidden fields."; + throw StaticError(next.location, msg); + } + + if (field.kind != ObjectField::FIELD_EXPR) { + auto msg = "Object comprehensions can only have [e] fields."; + throw StaticError(next.location, msg); + } + + std::vector specs; + Token last = parseComprehensionSpecs(Token::BRACE_R, next.fodder, specs); + obj = alloc->make( + span(tok, last), tok.fodder, fields, got_comma, specs, last.fodder); + + return last; + } + + if (!got_comma && !first) + throw StaticError(next.location, "Expected a comma before next field."); + + first = false; + got_comma = false; + + switch (next.kind) { + case Token::BRACKET_L: case Token::IDENTIFIER: case Token::STRING_DOUBLE: + case Token::STRING_SINGLE: case Token::STRING_BLOCK: { + ObjectField::Kind kind; + AST *expr1 = nullptr; + const Identifier *id = nullptr; + Fodder fodder1, fodder2; + if (next.kind == Token::IDENTIFIER) { + fodder1 = next.fodder; + kind = ObjectField::FIELD_ID; + id = alloc->makeIdentifier(next.data32()); + } else if (next.kind == Token::STRING_DOUBLE) { + kind = ObjectField::FIELD_STR; + expr1 = alloc->make( + next.location, next.fodder, next.data32(), LiteralString::DOUBLE, + "", ""); + } else if (next.kind == Token::STRING_SINGLE) { + kind = ObjectField::FIELD_STR; + expr1 = alloc->make( + next.location, next.fodder, next.data32(), LiteralString::SINGLE, + "", ""); + } else if (next.kind == Token::STRING_BLOCK) { + kind = ObjectField::FIELD_STR; + expr1 = alloc->make( + next.location, next.fodder, next.data32(), LiteralString::BLOCK, + next.stringBlockIndent, next.stringBlockTermIndent); + } else { + kind = ObjectField::FIELD_EXPR; + fodder1 = next.fodder; + expr1 = parse(MAX_PRECEDENCE); + Token bracket_r = popExpect(Token::BRACKET_R); + fodder2 = bracket_r.fodder; + } + + bool is_method = false; + bool meth_comma = false; + ArgParams params; + Fodder fodder_l; + Fodder fodder_r; + if (peek().kind == Token::PAREN_L) { + Token paren_l = pop(); + fodder_l = paren_l.fodder; + params = parseParams("method parameter", meth_comma, fodder_r); + is_method = true; + } + + bool plus_sugar = false; + + Token op = popExpect(Token::OPERATOR); + const char *od = op.data.c_str(); + if (*od == '+') { + plus_sugar = true; + od++; + } + unsigned colons = 0; + for (; *od != '\0' ; ++od) { + if (*od != ':') { + throw StaticError( + next.location, + "Expected one of :, ::, :::, +:, +::, +:::, got: " + op.data); + } + ++colons; + } + ObjectField::Hide field_hide; + switch (colons) { + case 1: + field_hide = ObjectField::INHERIT; + break; + + case 2: + field_hide = ObjectField::HIDDEN; + break; + + case 3: + field_hide = ObjectField::VISIBLE; + break; + + default: + throw StaticError( + next.location, + "Expected one of :, ::, :::, +:, +::, +:::, got: " + op.data); + } + + // Basic checks for invalid Jsonnet code. + if (is_method && plus_sugar) { + throw StaticError( + next.location, "Cannot use +: syntax sugar in a method: " + next.data); + } + if (kind != ObjectField::FIELD_EXPR) { + if (!literal_fields.insert(next.data).second) { + throw StaticError(next.location, "Duplicate field: "+next.data); + } + } + + AST *body = parse(MAX_PRECEDENCE); + + Fodder comma_fodder; + next = pop(); + if (next.kind == Token::COMMA) { + comma_fodder = next.fodder; + next = pop(); + got_comma = true; + } + fields.emplace_back( + kind, fodder1, fodder2, fodder_l, fodder_r, field_hide, plus_sugar, + is_method, expr1, id, params, meth_comma, op.fodder, body, nullptr, + comma_fodder); + } + break; + + case Token::LOCAL: { + Fodder local_fodder = next.fodder; + Token var_id = popExpect(Token::IDENTIFIER); + auto *id = alloc->makeIdentifier(var_id.data32()); + + if (binds.find(id) != binds.end()) { + throw StaticError(var_id.location, "Duplicate local var: " + var_id.data); + } + bool is_method = false; + bool func_comma = false; + ArgParams params; + Fodder paren_l_fodder; + Fodder paren_r_fodder; + if (peek().kind == Token::PAREN_L) { + Token paren_l = pop(); + paren_l_fodder = paren_l.fodder; + is_method = true; + params = parseParams("function parameter", func_comma, paren_r_fodder); + } + Token eq = popExpect(Token::OPERATOR, "="); + AST *body = parse(MAX_PRECEDENCE); + binds.insert(id); + + Fodder comma_fodder; + next = pop(); + if (next.kind == Token::COMMA) { + comma_fodder = next.fodder; + next = pop(); + got_comma = true; + } + fields.push_back( + ObjectField::Local( + local_fodder, var_id.fodder, paren_l_fodder, paren_r_fodder, + is_method, id, params, func_comma, eq.fodder, body, comma_fodder)); + + } + break; + + case Token::ASSERT: { + Fodder assert_fodder = next.fodder; + AST *cond = parse(MAX_PRECEDENCE); + AST *msg = nullptr; + Fodder colon_fodder; + if (peek().kind == Token::OPERATOR && peek().data == ":") { + Token colon = pop(); + colon_fodder = colon.fodder; + msg = parse(MAX_PRECEDENCE); + } + + Fodder comma_fodder; + next = pop(); + if (next.kind == Token::COMMA) { + comma_fodder = next.fodder; + next = pop(); + got_comma = true; + } + fields.push_back(ObjectField::Assert(assert_fodder, cond, colon_fodder, msg, + comma_fodder)); + } + break; + + default: + throw unexpected(next, "parsing field definition"); + } + + + } while (true); + } + + /** parses for x in expr for y in expr if expr for z in expr ... */ + Token parseComprehensionSpecs(Token::Kind end, Fodder for_fodder, + std::vector &specs) + { + while (true) { + LocationRange l; + Token id_token = popExpect(Token::IDENTIFIER); + const Identifier *id = alloc->makeIdentifier(id_token.data32()); + Token in_token = popExpect(Token::IN); + AST *arr = parse(MAX_PRECEDENCE); + specs.emplace_back(ComprehensionSpec::FOR, for_fodder, id_token.fodder, id, + in_token.fodder, arr); + + Token maybe_if = pop(); + for (; maybe_if.kind == Token::IF; maybe_if = pop()) { + AST *cond = parse(MAX_PRECEDENCE); + specs.emplace_back(ComprehensionSpec::IF, maybe_if.fodder, Fodder{}, nullptr, + Fodder{}, cond); + } + if (maybe_if.kind == end) { + return maybe_if; + } + if (maybe_if.kind != Token::FOR) { + std::stringstream ss; + ss << "Expected for, if or " << end << " after for clause, got: " << maybe_if; + throw StaticError(maybe_if.location, ss.str()); + } + for_fodder = maybe_if.fodder; + } + } + + AST *parseTerminal(void) + { + Token tok = pop(); + switch (tok.kind) { + case Token::ASSERT: + case Token::BRACE_R: + case Token::BRACKET_R: + case Token::COMMA: + case Token::DOT: + case Token::ELSE: + case Token::ERROR: + case Token::FOR: + case Token::FUNCTION: + case Token::IF: + case Token::IN: + case Token::IMPORT: + case Token::IMPORTSTR: + case Token::LOCAL: + case Token::OPERATOR: + case Token::PAREN_R: + case Token::SEMICOLON: + case Token::TAILSTRICT: + case Token::THEN: + throw unexpected(tok, "parsing terminal"); + + case Token::END_OF_FILE: + throw StaticError(tok.location, "Unexpected end of file."); + + case Token::BRACE_L: { + AST *obj; + parseObjectRemainder(obj, tok); + return obj; + } + + case Token::BRACKET_L: { + Token next = peek(); + if (next.kind == Token::BRACKET_R) { + Token bracket_r = pop(); + return alloc->make(span(tok, next), tok.fodder, Array::Elements{}, + false, bracket_r.fodder); + } + AST *first = parse(MAX_PRECEDENCE); + bool got_comma = false; + Fodder comma_fodder; + next = peek(); + if (!got_comma && next.kind == Token::COMMA) { + Token comma = pop(); + comma_fodder = comma.fodder; + next = peek(); + got_comma = true; + } + + if (next.kind == Token::FOR) { + // It's a comprehension + Token for_token = pop(); + std::vector specs; + Token last = parseComprehensionSpecs(Token::BRACKET_R, for_token.fodder, specs); + return alloc->make( + span(tok, last), tok.fodder, first, comma_fodder, got_comma, specs, + last.fodder); + } + + // Not a comprehension: It can have more elements. + Array::Elements elements; + elements.emplace_back(first, comma_fodder); + do { + if (next.kind == Token::BRACKET_R) { + Token bracket_r = pop(); + return alloc->make( + span(tok, next), tok.fodder, elements, got_comma, bracket_r.fodder); + } + if (!got_comma) { + std::stringstream ss; + ss << "Expected a comma before next array element."; + throw StaticError(next.location, ss.str()); + } + AST *expr = parse(MAX_PRECEDENCE); + comma_fodder.clear(); + got_comma = false; + next = peek(); + if (next.kind == Token::COMMA) { + Token comma = pop(); + comma_fodder = comma.fodder; + next = peek(); + got_comma = true; + } + elements.emplace_back(expr, comma_fodder); + } while (true); + } + + case Token::PAREN_L: { + auto *inner = parse(MAX_PRECEDENCE); + Token close = popExpect(Token::PAREN_R); + return alloc->make(span(tok, close), tok.fodder, inner, close.fodder); + } + + // Literals + case Token::NUMBER: + return alloc->make(span(tok), tok.fodder, tok.data); + + case Token::STRING_SINGLE: + return alloc->make( + span(tok), tok.fodder, tok.data32(), LiteralString::SINGLE, "", ""); + case Token::STRING_DOUBLE: + return alloc->make( + span(tok), tok.fodder, tok.data32(), LiteralString::DOUBLE, "", ""); + case Token::STRING_BLOCK: + return alloc->make( + span(tok), tok.fodder, tok.data32(), LiteralString::BLOCK, + tok.stringBlockIndent, tok.stringBlockTermIndent); + case Token::VERBATIM_STRING_SINGLE: + return alloc->make( + span(tok), tok.fodder, tok.data32(), LiteralString::VERBATIM_SINGLE, "", ""); + case Token::VERBATIM_STRING_DOUBLE: + return alloc->make( + span(tok), tok.fodder, tok.data32(), LiteralString::VERBATIM_DOUBLE, "", ""); + + + case Token::FALSE: + return alloc->make(span(tok), tok.fodder, false); + + case Token::TRUE: + return alloc->make(span(tok), tok.fodder, true); + + case Token::NULL_LIT: + return alloc->make(span(tok), tok.fodder); + + // Variables + case Token::DOLLAR: + return alloc->make(span(tok), tok.fodder); + + case Token::IDENTIFIER: + return alloc->make(span(tok), tok.fodder, alloc->makeIdentifier(tok.data32())); + + case Token::SELF: + return alloc->make(span(tok), tok.fodder); + + case Token::SUPER: { + Token next = pop(); + AST *index = nullptr; + const Identifier *id = nullptr; + Fodder id_fodder; + switch (next.kind) { + case Token::DOT: { + Token field_id = popExpect(Token::IDENTIFIER); + id_fodder = field_id.fodder; + id = alloc->makeIdentifier(field_id.data32()); + } break; + case Token::BRACKET_L: { + index = parse(MAX_PRECEDENCE); + Token bracket_r = popExpect(Token::BRACKET_R); + id_fodder = bracket_r.fodder; // Not id_fodder, but use the same var. + } break; + default: + throw StaticError(tok.location, "Expected . or [ after super."); + } + return alloc->make(span(tok), tok.fodder, next.fodder, index, + id_fodder, id); + } + } + + std::cerr << "INTERNAL ERROR: Unknown tok kind: " << tok.kind << std::endl; + std::abort(); + return nullptr; // Quiet, compiler. + } + + AST *parse(int precedence) + { + Token begin = peek(); + + switch (begin.kind) { + + // These cases have effectively MAX_PRECEDENCE as the first + // call to parse will parse them. + case Token::ASSERT: { + pop(); + AST *cond = parse(MAX_PRECEDENCE); + Fodder colonFodder; + AST *msg = nullptr; + if (peek().kind == Token::OPERATOR && peek().data == ":") { + Token colon = pop(); + colonFodder = colon.fodder; + msg = parse(MAX_PRECEDENCE); + } + Token semicolon = popExpect(Token::SEMICOLON); + AST *rest = parse(MAX_PRECEDENCE); + return alloc->make(span(begin, rest), begin.fodder, cond, colonFodder, + msg, semicolon.fodder, rest); + } + + case Token::ERROR: { + pop(); + AST *expr = parse(MAX_PRECEDENCE); + return alloc->make(span(begin, expr), begin.fodder, expr); + } + + case Token::IF: { + pop(); + AST *cond = parse(MAX_PRECEDENCE); + Token then = popExpect(Token::THEN); + AST *branch_true = parse(MAX_PRECEDENCE); + if (peek().kind == Token::ELSE) { + Token else_ = pop(); + AST *branch_false = parse(MAX_PRECEDENCE); + return alloc->make( + span(begin, branch_false), begin.fodder, cond, then.fodder, branch_true, + else_.fodder, branch_false); + } + return alloc->make(span(begin, branch_true), begin.fodder, cond, + then.fodder, branch_true, Fodder{}, nullptr); + } + + case Token::FUNCTION: { + pop(); // Still available in 'begin'. + Token paren_l = pop(); + if (paren_l.kind == Token::PAREN_L) { + std::vector params_asts; + bool got_comma; + Fodder paren_r_fodder; + ArgParams params = parseParams( + "function parameter", got_comma, paren_r_fodder); + AST *body = parse(MAX_PRECEDENCE); + return alloc->make( + span(begin, body), begin.fodder, paren_l.fodder, params, got_comma, + paren_r_fodder, body); + } else { + std::stringstream ss; + ss << "Expected ( but got " << paren_l; + throw StaticError(paren_l.location, ss.str()); + } + } + + case Token::IMPORT: { + pop(); + AST *body = parse(MAX_PRECEDENCE); + if (auto *lit = dynamic_cast(body)) { + if (lit->tokenKind == LiteralString::BLOCK) { + throw StaticError(lit->location, + "Cannot use text blocks in import statements."); + } + return alloc->make(span(begin, body), begin.fodder, lit); + } else { + std::stringstream ss; + ss << "Computed imports are not allowed."; + throw StaticError(body->location, ss.str()); + } + } + + case Token::IMPORTSTR: { + pop(); + AST *body = parse(MAX_PRECEDENCE); + if (auto *lit = dynamic_cast(body)) { + if (lit->tokenKind == LiteralString::BLOCK) { + throw StaticError(lit->location, + "Cannot use text blocks in import statements."); + } + return alloc->make(span(begin, body), begin.fodder, lit); + } else { + std::stringstream ss; + ss << "Computed imports are not allowed."; + throw StaticError(body->location, ss.str()); + } + } + + case Token::LOCAL: { + pop(); + Local::Binds binds; + do { + Token delim = parseBind(binds); + if (delim.kind != Token::SEMICOLON && delim.kind != Token::COMMA) { + std::stringstream ss; + ss << "Expected , or ; but got " << delim; + throw StaticError(delim.location, ss.str()); + } + if (delim.kind == Token::SEMICOLON) break; + } while (true); + AST *body = parse(MAX_PRECEDENCE); + return alloc->make(span(begin, body), begin.fodder, binds, body); + } + + default: + + // Unary operator. + if (begin.kind == Token::OPERATOR) { + UnaryOp uop; + if (!op_is_unary(begin.data, uop)) { + std::stringstream ss; + ss << "Not a unary operator: " << begin.data; + throw StaticError(begin.location, ss.str()); + } + if (UNARY_PRECEDENCE == precedence) { + Token op = pop(); + AST *expr = parse(precedence); + return alloc->make(span(op, expr), op.fodder, uop, expr); + } + } + + // Base case + if (precedence == 0) return parseTerminal(); + + AST *lhs = parse(precedence - 1); + + Fodder begin_fodder; + + while (true) { + + // Then next token must be a binary operator. + + // The compiler can't figure out that this is never used uninitialized. + BinaryOp bop = BOP_PLUS; + + // Check precedence is correct for this level. If we're + // parsing operators with higher precedence, then return + // lhs and let lower levels deal with the operator. + switch (peek().kind) { + // Logical / arithmetic binary operator. + case Token::OPERATOR: + if (peek().data == ":") { + // Special case for the colons in assert. + // Since COLON is no-longer a special token, we have to make sure it + // does not trip the op_is_binary test below. It should + // terminate parsing of the expression here, returning control + // to the parsing of the actual assert AST. + return lhs; + } + if (peek().data == "::") { + // Special case for [e::] + // We need to stop parsing e when we see the :: and + // avoid tripping the op_is_binary test below. + return lhs; + } + if (!op_is_binary(peek().data, bop)) { + std::stringstream ss; + ss << "Not a binary operator: " << peek().data; + throw StaticError(peek().location, ss.str()); + } + if (precedence_map[bop] != precedence) return lhs; + break; + + // Index, Apply + case Token::DOT: case Token::BRACKET_L: + case Token::PAREN_L: case Token::BRACE_L: + if (APPLY_PRECEDENCE != precedence) return lhs; + break; + + default: + return lhs; + } + + Token op = pop(); + if (op.kind == Token::BRACKET_L) { + bool is_slice; + AST *first = nullptr; + Fodder second_fodder; + AST *second = nullptr; + Fodder third_fodder; + AST *third = nullptr; + + if (peek().kind == Token::BRACKET_R) + throw unexpected(pop(), "parsing index"); + + if (peek().data != ":" && peek().data != "::") { + first = parse(MAX_PRECEDENCE); + } + + if (peek().kind == Token::OPERATOR && peek().data == "::") { + // Handle :: + is_slice = true; + Token joined = pop(); + second_fodder = joined.fodder; + + if (peek().kind != Token::BRACKET_R) + third = parse(MAX_PRECEDENCE); + + } else if (peek().kind != Token::BRACKET_R) { + is_slice = true; + Token delim = pop(); + if (delim.data != ":") + throw unexpected(delim, "parsing slice"); + + second_fodder = delim.fodder; + + if (peek().data != ":" && peek().kind != Token::BRACKET_R) + second = parse(MAX_PRECEDENCE); + + if (peek().kind != Token::BRACKET_R) { + Token delim = pop(); + if (delim.data != ":") + throw unexpected(delim, "parsing slice"); + + third_fodder = delim.fodder; + + if (peek().kind != Token::BRACKET_R) + third = parse(MAX_PRECEDENCE); + } + } else { + is_slice = false; + } + Token end = popExpect(Token::BRACKET_R); + lhs = alloc->make(span(begin, end), begin_fodder, lhs, op.fodder, + is_slice, first, second_fodder, second, + third_fodder, third, end.fodder); + + } else if (op.kind == Token::DOT) { + Token field_id = popExpect(Token::IDENTIFIER); + const Identifier *id = alloc->makeIdentifier(field_id.data32()); + lhs = alloc->make(span(begin, field_id), begin_fodder, lhs, + op.fodder, field_id.fodder, id); + + } else if (op.kind == Token::PAREN_L) { + ArgParams args; + bool got_comma; + Token end = parseArgs(args, Token::PAREN_R, "function argument", got_comma); + bool tailstrict = false; + Fodder tailstrict_fodder; + if (peek().kind == Token::TAILSTRICT) { + Token tailstrict_token = pop(); + tailstrict_fodder = tailstrict_token.fodder; + tailstrict = true; + } + lhs = alloc->make(span(begin, end), begin_fodder, lhs, op.fodder, + args, got_comma, end.fodder, tailstrict_fodder, + tailstrict); + + } else if (op.kind == Token::BRACE_L) { + AST *obj; + Token end = parseObjectRemainder(obj, op); + lhs = alloc->make(span(begin, end), begin_fodder, lhs, obj); + + } else { + // Logical / arithmetic binary operator. + assert(op.kind == Token::OPERATOR); + AST *rhs = parse(precedence - 1); + lhs = alloc->make(span(begin, rhs), begin_fodder, lhs, op.fodder, + bop, rhs); + } + + begin_fodder.clear(); + } + } + } + +}; + +} // namespace + +AST *jsonnet_parse(Allocator *alloc, Tokens &tokens) +{ + Parser parser(tokens, alloc); + AST *expr = parser.parse(MAX_PRECEDENCE); + if (tokens.front().kind != Token::END_OF_FILE) { + std::stringstream ss; + ss << "Did not expect: " << tokens.front(); + throw StaticError(tokens.front().location, ss.str()); + } + + return expr; +} diff --git a/vendor/github.com/strickyak/jsonnet_cgo/parser.h b/vendor/github.com/strickyak/jsonnet_cgo/parser.h new file mode 100644 index 00000000..ab4d173d --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/parser.h @@ -0,0 +1,44 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef JSONNET_PARSER_H +#define JSONNET_PARSER_H + +#include + +#include "ast.h" +#include "lexer.h" +#include "unicode.h" + +/** Parse a given JSON++ string. + * + * \param alloc Used to allocate the AST nodes. The Allocator must outlive the + * AST pointer returned. + * \param tokens The list of tokens (all tokens are popped except EOF). + * \returns The parsed abstract syntax tree. + */ +AST *jsonnet_parse(Allocator *alloc, Tokens &tokens); + +/** Outputs a number, trying to preserve precision as well as possible. + */ +std::string jsonnet_unparse_number(double v); + +/** The inverse of jsonnet_parse. + */ +std::string jsonnet_unparse_jsonnet(const AST *ast, const Fodder &final_fodder, unsigned indent, + bool pad_arrays, bool pad_objects, char comment_style); + +#endif // JSONNET_PARSER_H diff --git a/vendor/github.com/strickyak/jsonnet_cgo/pass.cpp b/vendor/github.com/strickyak/jsonnet_cgo/pass.cpp new file mode 100644 index 00000000..451e6c75 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/pass.cpp @@ -0,0 +1,426 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "pass.h" + +void CompilerPass::fodder(Fodder &fodder) +{ + for (auto &f : fodder) + fodderElement(f); +} + +void CompilerPass::specs(std::vector &specs) +{ + for (auto &spec : specs) { + fodder(spec.openFodder); + switch (spec.kind) { + case ComprehensionSpec::FOR: + fodder(spec.varFodder); + fodder(spec.inFodder); + expr(spec.expr); + break; + case ComprehensionSpec::IF: + expr(spec.expr); + break; + } + } +} + +void CompilerPass::params(Fodder &fodder_l, ArgParams ¶ms, Fodder &fodder_r) +{ + fodder(fodder_l); + for (auto ¶m : params) { + fodder(param.idFodder); + if (param.expr) { + fodder(param.eqFodder); + expr(param.expr); + } + fodder(param.commaFodder); + } + fodder(fodder_r); +} + +void CompilerPass::fieldParams(ObjectField &field) +{ + if (field.methodSugar) { + params(field.fodderL, field.params, field.fodderR); + } +} + +void CompilerPass::fields(ObjectFields &fields) +{ + for (auto &field : fields) { + + switch (field.kind) { + case ObjectField::LOCAL: { + fodder(field.fodder1); + fodder(field.fodder2); + fieldParams(field); + fodder(field.opFodder); + expr(field.expr2); + } break; + + case ObjectField::FIELD_ID: + case ObjectField::FIELD_STR: + case ObjectField::FIELD_EXPR: { + if (field.kind == ObjectField::FIELD_ID) { + fodder(field.fodder1); + + } else if (field.kind == ObjectField::FIELD_STR) { + expr(field.expr1); + + } else if (field.kind == ObjectField::FIELD_EXPR) { + fodder(field.fodder1); + expr(field.expr1); + fodder(field.fodder2); + } + fieldParams(field); + fodder(field.opFodder); + expr(field.expr2); + + } break; + + case ObjectField::ASSERT: { + fodder(field.fodder1); + expr(field.expr2); + if (field.expr3 != nullptr) { + fodder(field.opFodder); + expr(field.expr3); + } + } break; + } + + fodder(field.commaFodder); + } +} + +void CompilerPass::expr(AST *&ast_) +{ + fodder(ast_->openFodder); + visitExpr(ast_); +} + +void CompilerPass::visit(Apply *ast) +{ + expr(ast->target); + fodder(ast->fodderL); + for (auto &arg : ast->args) { + expr(arg.expr); + fodder(arg.commaFodder); + } + fodder(ast->fodderR); + if (ast->tailstrict) { + fodder(ast->tailstrictFodder); + } +} + +void CompilerPass::visit(ApplyBrace *ast) +{ + expr(ast->left); + expr(ast->right); +} + +void CompilerPass::visit(Array *ast) +{ + for (auto &element : ast->elements) { + expr(element.expr); + fodder(element.commaFodder); + } + fodder(ast->closeFodder); +} + +void CompilerPass::visit(ArrayComprehension *ast) +{ + expr(ast->body); + fodder(ast->commaFodder); + specs(ast->specs); + fodder(ast->closeFodder); +} + +void CompilerPass::visit(Assert *ast) +{ + expr(ast->cond); + if (ast->message != nullptr) { + fodder(ast->colonFodder); + expr(ast->message); + } + fodder(ast->semicolonFodder); + expr(ast->rest); +} + +void CompilerPass::visit(Binary *ast) +{ + expr(ast->left); + fodder(ast->opFodder); + expr(ast->right); +} + +void CompilerPass::visit(Conditional *ast) +{ + expr(ast->cond); + fodder(ast->thenFodder); + if (ast->branchFalse != nullptr) { + expr(ast->branchTrue); + fodder(ast->elseFodder); + expr(ast->branchFalse); + } else { + expr(ast->branchTrue); + } +} + +void CompilerPass::visit(Error *ast) +{ + expr(ast->expr); +} + +void CompilerPass::visit(Function *ast) +{ + params(ast->parenLeftFodder, ast->params, ast->parenRightFodder); + expr(ast->body); +} + +void CompilerPass::visit(Import *ast) +{ + visit(ast->file); +} + +void CompilerPass::visit(Importstr *ast) +{ + visit(ast->file); +} + +void CompilerPass::visit(Index *ast) +{ + expr(ast->target); + if (ast->id != nullptr) { + } else { + if (ast->isSlice) { + if (ast->index != nullptr) + expr(ast->index); + if (ast->end != nullptr) + expr(ast->end); + if (ast->step != nullptr) + expr(ast->step); + } else { + expr(ast->index); + } + } +} + +void CompilerPass::visit(Local *ast) +{ + assert(ast->binds.size() > 0); + for (auto &bind : ast->binds) { + fodder(bind.varFodder); + if (bind.functionSugar) { + params(bind.parenLeftFodder, bind.params, bind.parenRightFodder); + } + fodder(bind.opFodder); + expr(bind.body); + fodder(bind.closeFodder); + } + expr(ast->body); +} + +void CompilerPass::visit(Object *ast) +{ + fields(ast->fields); + fodder(ast->closeFodder); +} + +void CompilerPass::visit(DesugaredObject *ast) +{ + for (AST *assert : ast->asserts) { + expr(assert); + } + for (auto &field : ast->fields) { + expr(field.name); + expr(field.body); + } +} + +void CompilerPass::visit(ObjectComprehension *ast) +{ + fields(ast->fields); + specs(ast->specs); + fodder(ast->closeFodder); +} + +void CompilerPass::visit(ObjectComprehensionSimple *ast) +{ + expr(ast->field); + expr(ast->value); + expr(ast->array); +} + +void CompilerPass::visit(Parens *ast) +{ + expr(ast->expr); + fodder(ast->closeFodder); +} + +void CompilerPass::visit(SuperIndex *ast) +{ + if (ast->id != nullptr) { + } else { + expr(ast->index); + } +} + +void CompilerPass::visit(Unary *ast) +{ + expr(ast->expr); +} + +void CompilerPass::visitExpr(AST *&ast_) +{ + if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + visit(ast); + + } else { + std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_ << std::endl; + std::abort(); + + } +} + +void CompilerPass::file(AST *&body, Fodder &final_fodder) +{ + expr(body); + fodder(final_fodder); +} + +void ClonePass::expr(AST *&ast_) +{ + if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + } else if (auto *ast = dynamic_cast(ast_)) { + ast_ = alloc.clone(ast); + + } else { + std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_ << std::endl; + std::abort(); + + } + + CompilerPass::expr(ast_); +} diff --git a/vendor/github.com/strickyak/jsonnet_cgo/pass.h b/vendor/github.com/strickyak/jsonnet_cgo/pass.h new file mode 100644 index 00000000..7b461f3c --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/pass.h @@ -0,0 +1,115 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef JSONNET_PASS_H +#define JSONNET_PASS_H + +#include "ast.h" + +/** A generic Pass that does nothing but can be extended to easily define real passes. + */ +class CompilerPass { + public: + + protected: + Allocator &alloc; + + public: + CompilerPass(Allocator &alloc) : alloc(alloc) { } + + virtual void fodderElement(FodderElement &) { } + + virtual void fodder(Fodder &fodder); + + virtual void specs(std::vector &specs); + + virtual void params(Fodder &fodder_l, ArgParams ¶ms, Fodder &fodder_r); + + virtual void fieldParams(ObjectField &field); + + virtual void fields(ObjectFields &fields); + + virtual void expr(AST *&ast_); + + virtual void visit(Apply *ast); + + virtual void visit(ApplyBrace *ast); + + virtual void visit(Array *ast); + + virtual void visit(ArrayComprehension *ast); + + virtual void visit(Assert *ast); + + virtual void visit(Binary *ast); + + virtual void visit(BuiltinFunction *) { } + + virtual void visit(Conditional *ast); + + virtual void visit(Dollar *) { } + + virtual void visit(Error *ast); + + virtual void visit(Function *ast); + + virtual void visit(Import *ast); + + virtual void visit(Importstr *ast); + + virtual void visit(Index *ast); + + virtual void visit(Local *ast); + + virtual void visit(LiteralBoolean *) { } + + virtual void visit(LiteralNumber *) { } + + virtual void visit(LiteralString *) { } + + virtual void visit(LiteralNull *) { } + + virtual void visit(Object *ast); + + virtual void visit(DesugaredObject *ast); + + virtual void visit(ObjectComprehension *ast); + + virtual void visit(ObjectComprehensionSimple *ast); + + virtual void visit(Parens *ast); + + virtual void visit(Self *) { } + + virtual void visit(SuperIndex *ast); + + virtual void visit(Unary *ast); + + virtual void visit(Var *) { } + + virtual void visitExpr(AST *&ast_); + + virtual void file(AST *&body, Fodder &final_fodder); +}; + + +/** A pass that clones the AST it is given. */ +class ClonePass : public CompilerPass { + public: + ClonePass(Allocator &alloc) : CompilerPass(alloc) { } + virtual void expr(AST *&ast); +}; +#endif diff --git a/vendor/github.com/strickyak/jsonnet_cgo/state.h b/vendor/github.com/strickyak/jsonnet_cgo/state.h new file mode 100644 index 00000000..e053512b --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/state.h @@ -0,0 +1,444 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef JSONNET_STATE_H +#define JSONNET_STATE_H + +namespace { + +/** Mark & sweep: advanced by 1 each GC cycle. + */ +typedef unsigned char GarbageCollectionMark; + +/** Supertype of everything that is allocated on the heap. + */ +struct HeapEntity { + GarbageCollectionMark mark; + virtual ~HeapEntity() { } +}; + +/** Tagged union of all values. + * + * Primitives (<= 8 bytes) are copied by value. Otherwise a pointer to a HeapEntity is used. + */ +struct Value { + enum Type { + NULL_TYPE = 0x0, // Unfortunately NULL is a macro in C. + BOOLEAN = 0x1, + DOUBLE = 0x2, + + ARRAY = 0x10, + FUNCTION = 0x11, + OBJECT = 0x12, + STRING = 0x13 + }; + Type t; + union { + HeapEntity *h; + double d; + bool b; + } v; + bool isHeap(void) const + { + return t & 0x10; + } +}; + +/** Convert the type into a string, for error messages. */ +std::string type_str(Value::Type t) +{ + switch (t) { + case Value::NULL_TYPE: return "null"; + case Value::BOOLEAN: return "boolean"; + case Value::DOUBLE: return "double"; + case Value::ARRAY: return "array"; + case Value::FUNCTION: return "function"; + case Value::OBJECT: return "object"; + case Value::STRING: return "string"; + default: + std::cerr << "INTERNAL ERROR: Unknown type: " << t << std::endl; + std::abort(); + return ""; // Quiet, compiler. + } +} + +/** Convert the value's type into a string, for error messages. */ +std::string type_str(const Value &v) +{ + return type_str(v.t); +} + +struct HeapThunk; + +/** Stores the values bound to variables. + * + * Each nested local statement, function call, and field access has its own binding frame to + * give the values for the local variable, function parameters, or upValues. + */ +typedef std::map BindingFrame; + +/** Supertype of all objects. Types of Value::OBJECT will point at these. */ +struct HeapObject : public HeapEntity { +}; + +/** Hold an unevaluated expression. This implements lazy semantics. + */ +struct HeapThunk : public HeapEntity { + /** Whether or not the thunk was forced. */ + bool filled; + + /** The result when the thunk was forced, if filled == true. */ + Value content; + + /** Used in error tracebacks. */ + const Identifier *name; + + /** The captured environment. + * + * Note, this is non-const because we have to add cyclic references to it. + */ + BindingFrame upValues; + + /** The captured self variable, or nullptr if there was none. \see CallFrame. */ + HeapObject *self; + + /** The offset from the captured self variable. \see CallFrame. */ + unsigned offset; + + /** Evaluated to force the thunk. */ + const AST *body; + + HeapThunk(const Identifier *name, HeapObject *self, unsigned offset, const AST *body) + : filled(false), name(name), self(self), offset(offset), body(body) + { } + + void fill(const Value &v) + { + content = v; + filled = true; + self = nullptr; + upValues.clear(); + } +}; + +struct HeapArray : public HeapEntity { + // It is convenient for this to not be const, so that we can add elements to it one at a + // time after creation. Thus, elements are not GCed as the array is being + // created. + std::vector elements; + HeapArray(const std::vector &elements) + : elements(elements) + { } +}; + +/** Supertype of all objects that are not super objects or extended objects. */ +struct HeapLeafObject : public HeapObject { +}; + +/** Objects created via the simple object constructor construct. */ +struct HeapSimpleObject : public HeapLeafObject { + /** The captured environment. */ + const BindingFrame upValues; + + struct Field { + /** Will the field appear in output? */ + ObjectField::Hide hide; + /** Expression that is evaluated when indexing this field. */ + AST *body; + }; + + /** The fields. + * + * These are evaluated in the captured environment and with self and super bound + * dynamically. + */ + const std::map fields; + + /** The object's invariants. + * + * These are evaluated in the captured environment with self and super bound. + */ + std::vector asserts; + + HeapSimpleObject(const BindingFrame &up_values, + const std::map fields, std::vector asserts) + : upValues(up_values), fields(fields), asserts(asserts) + { } +}; + +/** Objects created by the extendby construct. */ +struct HeapExtendedObject : public HeapObject { + /** The left hand side of the construct. */ + HeapObject *left; + + /** The right hand side of the construct. */ + HeapObject *right; + + HeapExtendedObject(HeapObject *left, HeapObject *right) + : left(left), right(right) + { } +}; + +/** Objects created by the ObjectComprehensionSimple construct. */ +struct HeapComprehensionObject : public HeapLeafObject { + + /** The captured environment. */ + const BindingFrame upValues; + + /** The expression used to compute the field values. */ + const AST* value; + + /** The identifier of bound variable in that construct. */ + const Identifier * const id; + + /** Binding for id. + * + * For each field, holds the value that should be bound to id. This is the corresponding + * array element from the original array used to define this object. This should not really + * be a thunk, but it makes the implementation easier. + * + * It is convenient to make this non-const to allow building up the values one by one, so that + * the garbage collector can see them at each intermediate point. + */ + std::map compValues; + + HeapComprehensionObject(const BindingFrame &up_values, const AST *value, + const Identifier *id, + const std::map &comp_values) + : upValues(up_values), value(value), id(id), compValues(comp_values) + { } +}; + +/** Stores the function itself and also the captured environment. + * + * Either body is non-null and builtinName is "", or body is null and builtin refers to a built-in + * function. In the former case, the closure represents a user function, otherwise calling it + * will trigger the builtin function to execute. Params is empty when the function is a + * builtin. + */ +struct HeapClosure : public HeapEntity { + /** The captured environment. */ + const BindingFrame upValues; + /** The captured self variable, or nullptr if there was none. \see Frame. */ + HeapObject *self; + /** The offset from the captured self variable. \see Frame.*/ + unsigned offset; + struct Param { + const Identifier *id; + const AST *def; + Param(const Identifier *id, const AST *def) + : id(id), def(def) + { } + }; + typedef std::vector Params; + const Params params; + const AST *body; + std::string builtinName; + HeapClosure(const BindingFrame &up_values, + HeapObject *self, + unsigned offset, + const Params ¶ms, + const AST *body, const std::string &builtin_name) + : upValues(up_values), self(self), offset(offset), + params(params), body(body), builtinName(builtin_name) + { } +}; + +/** Stores a simple string on the heap. */ +struct HeapString : public HeapEntity { + const String value; + HeapString(const String &value) + : value(value) + { } +}; + +/** The heap does memory management, i.e. garbage collection. */ +class Heap { + + /** How many objects must exist in the heap before we bother doing garbage collection? + */ + unsigned gcTuneMinObjects; + + /** How much must the heap have grown since the last cycle to trigger a collection? + */ + double gcTuneGrowthTrigger; + + /** Value used to mark entities at the last garbage collection cycle. */ + GarbageCollectionMark lastMark; + + /** The heap entities (strings, arrays, objects, functions, etc). + * + * Not all may be reachable, all should have o->mark == this->lastMark. Entities are + * removed from the heap via O(1) swap with last element, so the ordering of entities is + * arbitrary and changes every garbage collection cycle. + */ + std::vector entities; + + /** The number of heap entities at the last garbage collection cycle. */ + unsigned long lastNumEntities; + + /** The number of heap entities now. */ + unsigned long numEntities; + + /** Add the HeapEntity inside v to vec, if the value exists on the heap. + */ + void addIfHeapEntity(Value v, std::vector &vec) + { + if (v.isHeap()) vec.push_back(v.v.h); + } + + /** Add the HeapEntity inside v to vec, if the value exists on the heap. + */ + void addIfHeapEntity(HeapEntity *v, std::vector &vec) + { + vec.push_back(v); + } + + public: + + Heap(unsigned gc_tune_min_objects, double gc_tune_growth_trigger) + : gcTuneMinObjects(gc_tune_min_objects), gcTuneGrowthTrigger(gc_tune_growth_trigger), + lastMark(0), lastNumEntities(0), numEntities(0) + { + } + + ~Heap(void) + { + // Nothing is marked, everything will be collected. + sweep(); + } + + /** Garbage collection: Mark v, and entities reachable from v. */ + void markFrom(Value v) + { + if (v.isHeap()) markFrom(v.v.h); + } + + /** Garbage collection: Mark heap entities reachable from the given heap entity. */ + void markFrom(HeapEntity *from) + { + assert(from != nullptr); + const GarbageCollectionMark thisMark = lastMark + 1; + struct State { + HeapEntity *ent; + std::vector children; + State(HeapEntity *ent) : ent(ent) { } + }; + + std::vector stack; + stack.emplace_back(from); + + while (stack.size() > 0) { + size_t curr_index = stack.size() - 1; + State &s = stack[curr_index]; + HeapEntity *curr = s.ent; + if (curr->mark != thisMark) { + curr->mark = thisMark; + + if (auto *obj = dynamic_cast(curr)) { + for (auto upv : obj->upValues) + addIfHeapEntity(upv.second, s.children); + + } else if (auto *obj = dynamic_cast(curr)) { + addIfHeapEntity(obj->left, s.children); + addIfHeapEntity(obj->right, s.children); + + } else if (auto *obj = dynamic_cast(curr)) { + for (auto upv : obj->upValues) + addIfHeapEntity(upv.second, s.children); + for (auto upv : obj->compValues) + addIfHeapEntity(upv.second, s.children); + + + } else if (auto *arr = dynamic_cast(curr)) { + for (auto el : arr->elements) + addIfHeapEntity(el, s.children); + + } else if (auto *func = dynamic_cast(curr)) { + for (auto upv : func->upValues) + addIfHeapEntity(upv.second, s.children); + if (func->self) + addIfHeapEntity(func->self, s.children); + + } else if (auto *thunk = dynamic_cast(curr)) { + if (thunk->filled) { + if (thunk->content.isHeap()) + addIfHeapEntity(thunk->content.v.h, s.children); + } else { + for (auto upv : thunk->upValues) + addIfHeapEntity(upv.second, s.children); + if (thunk->self) + addIfHeapEntity(thunk->self, s.children); + } + } + } + + if (s.children.size() > 0) { + HeapEntity *next = s.children[s.children.size() - 1]; + s.children.pop_back(); + stack.emplace_back(next); // CAUTION: s invalidated here + } else { + stack.pop_back(); // CAUTION: s invalidated here + } + } + } + + /** Delete everything that was not marked since the last collection. */ + void sweep(void) + { + lastMark++; + // Heap shrinks during this loop. Do not cache entities.size(). + for (unsigned long i=0 ; imark != lastMark) { + delete x; + if (i != entities.size() - 1) { + // Swap it with the back. + entities[i] = entities[entities.size()-1]; + } + entities.pop_back(); + --i; + } + } + lastNumEntities = numEntities = entities.size(); + } + + /** Is it time to initiate a GC cycle? */ + bool checkHeap(void) + { + return numEntities > gcTuneMinObjects + && numEntities > gcTuneGrowthTrigger * lastNumEntities; + } + + /** Allocate a heap entity. + * + * If the heap is large enough (\see gcTuneMinObjects) and has grown by enough since the + * last collection cycle (\see gcTuneGrowthTrigger), a collection cycle is performed. + */ + template T* makeEntity(Args&&... args) + { + T *r = new T(std::forward(args)...); + entities.push_back(r); + r->mark = lastMark; + numEntities = entities.size(); + return r; + } + +}; + +} // namespace + +#endif // JSONNET_STATE_H diff --git a/vendor/github.com/strickyak/jsonnet_cgo/static_analysis.cpp b/vendor/github.com/strickyak/jsonnet_cgo/static_analysis.cpp new file mode 100644 index 00000000..868017c0 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/static_analysis.cpp @@ -0,0 +1,178 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include + +#include "static_analysis.h" +#include "static_error.h" +#include "ast.h" + +typedef std::set IdSet; + +/** Inserts all of s into r. */ +static void append(IdSet &r, const IdSet &s) +{ + r.insert(s.begin(), s.end()); +} + +/** Statically analyse the given ast. + * + * \param ast_ The AST. + * \param in_object Whether or not ast_ is within the lexical scope of an object AST. + * \param vars The variables defined within lexical scope of ast_. + * \returns The free variables in ast_. + */ +static IdSet static_analysis(AST *ast_, bool in_object, const IdSet &vars) +{ + IdSet r; + + if (auto *ast = dynamic_cast(ast_)) { + append(r, static_analysis(ast->target, in_object, vars)); + for (const auto &arg : ast->args) + append(r, static_analysis(arg.expr, in_object, vars)); + + } else if (auto *ast = dynamic_cast(ast_)) { + for (auto & el : ast->elements) + append(r, static_analysis(el.expr, in_object, vars)); + + } else if (auto *ast = dynamic_cast(ast_)) { + append(r, static_analysis(ast->left, in_object, vars)); + append(r, static_analysis(ast->right, in_object, vars)); + + } else if (dynamic_cast(ast_)) { + // Nothing to do. + + } else if (auto *ast = dynamic_cast(ast_)) { + append(r, static_analysis(ast->cond, in_object, vars)); + append(r, static_analysis(ast->branchTrue, in_object, vars)); + append(r, static_analysis(ast->branchFalse, in_object, vars)); + + } else if (auto *ast = dynamic_cast(ast_)) { + append(r, static_analysis(ast->expr, in_object, vars)); + + } else if (auto *ast = dynamic_cast(ast_)) { + auto new_vars = vars; + IdSet params; + for (const auto &p : ast->params) { + if (params.find(p.id) != params.end()) { + std::string msg = "Duplicate function parameter: " + encode_utf8(p.id->name); + throw StaticError(ast_->location, msg); + } + params.insert(p.id); + new_vars.insert(p.id); + } + + auto fv = static_analysis(ast->body, in_object, new_vars); + for (const auto &p : ast->params) { + if (p.expr != nullptr) + append(fv, static_analysis(p.expr, in_object, new_vars)); + } + for (const auto &p : ast->params) + fv.erase(p.id); + append(r, fv); + + } else if (dynamic_cast(ast_)) { + // Nothing to do. + + } else if (dynamic_cast(ast_)) { + // Nothing to do. + + } else if (auto *ast = dynamic_cast(ast_)) { + append(r, static_analysis(ast->target, in_object, vars)); + append(r, static_analysis(ast->index, in_object, vars)); + + } else if (auto *ast = dynamic_cast(ast_)) { + IdSet ast_vars; + for (const auto &bind: ast->binds) { + ast_vars.insert(bind.var); + } + auto new_vars = vars; + append(new_vars, ast_vars); + IdSet fvs; + for (const auto &bind: ast->binds) { + append(fvs, static_analysis(bind.body, in_object, new_vars)); + } + + append(fvs, static_analysis(ast->body, in_object, new_vars)); + + for (const auto &bind: ast->binds) + fvs.erase(bind.var); + + append(r, fvs); + + } else if (dynamic_cast(ast_)) { + // Nothing to do. + + } else if (dynamic_cast(ast_)) { + // Nothing to do. + + } else if (dynamic_cast(ast_)) { + // Nothing to do. + + } else if (dynamic_cast(ast_)) { + // Nothing to do. + + } else if (auto *ast = dynamic_cast(ast_)) { + for (auto &field : ast->fields) { + append(r, static_analysis(field.name, in_object, vars)); + append(r, static_analysis(field.body, true, vars)); + } + for (AST *assert : ast->asserts) { + append(r, static_analysis(assert, true, vars)); + } + + } else if (auto *ast = dynamic_cast(ast_)) { + auto new_vars = vars; + new_vars.insert(ast->id); + append(r, static_analysis(ast->field, false, new_vars)); + append(r, static_analysis(ast->value, true, new_vars)); + r.erase(ast->id); + append(r, static_analysis(ast->array, in_object, vars)); + + } else if (dynamic_cast(ast_)) { + if (!in_object) + throw StaticError(ast_->location, "Can't use self outside of an object."); + + } else if (auto *ast = dynamic_cast(ast_)) { + if (!in_object) + throw StaticError(ast_->location, "Can't use super outside of an object."); + append(r, static_analysis(ast->index, in_object, vars)); + + } else if (auto *ast = dynamic_cast(ast_)) { + append(r, static_analysis(ast->expr, in_object, vars)); + + } else if (auto *ast = dynamic_cast(ast_)) { + if (vars.find(ast->id) == vars.end()) { + throw StaticError(ast->location, "Unknown variable: "+encode_utf8(ast->id->name)); + } + r.insert(ast->id); + + } else { + std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_ << std::endl; + std::abort(); + + } + + for (auto *id : r) + ast_->freeVariables.push_back(id); + + return r; +} + +void jsonnet_static_analysis(AST *ast) +{ + static_analysis(ast, false, IdSet{}); +} diff --git a/vendor/github.com/strickyak/jsonnet_cgo/static_analysis.h b/vendor/github.com/strickyak/jsonnet_cgo/static_analysis.h new file mode 100644 index 00000000..3368d4e9 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/static_analysis.h @@ -0,0 +1,27 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef JSONNET_STATIC_ANALYSIS_H +#define JSONNET_STATIC_ANALYSIS_H + +#include "ast.h" + +/** Check the ast for appropriate use of self, super, and correctly bound variables. Also + * initialize the freeVariables member of function and object ASTs. + */ +void jsonnet_static_analysis(AST *ast); + +#endif diff --git a/vendor/github.com/strickyak/jsonnet_cgo/static_error.h b/vendor/github.com/strickyak/jsonnet_cgo/static_error.h new file mode 100644 index 00000000..1b8b7e83 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/static_error.h @@ -0,0 +1,115 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef JSONNET_STATIC_ERROR_H +#define JSONNET_STATIC_ERROR_H + +#include +#include + +struct Location { + unsigned long line; + unsigned long column; + Location(void) + : line(0), column(0) + { } + Location(unsigned long line_number, unsigned long column) + : line(line_number), column(column) + { } + bool isSet(void) const + { + return line != 0; + } +}; + +static inline std::ostream &operator<<(std::ostream &o, const Location &loc) +{ + o << loc.line << ":" << loc.column; + return o; +} + +struct LocationRange { + std::string file; + Location begin, end; + LocationRange(void) + { } + /** This is useful for special locations, e.g. manifestation entry point. */ + LocationRange(const std::string &msg) + : file(msg) + { } + LocationRange(const std::string &file, const Location &begin, const Location &end) + : file(file), begin(begin), end(end) + { } + bool isSet(void) const + { + return begin.isSet(); + } +}; + +static inline std::ostream &operator<<(std::ostream &o, const LocationRange &loc) +{ + if (loc.file.length() > 0) + o << loc.file; + if (loc.isSet()) { + if (loc.file.length() > 0) + o << ":"; + if (loc.begin.line == loc.end.line) { + if (loc.begin.column == loc.end.column) { + o << loc.begin; + } else { + o << loc.begin << "-" << loc.end.column; + } + } else { + o << "(" << loc.begin << ")-(" << loc.end << ")"; + } + } + return o; +} + +struct StaticError { + LocationRange location; + std::string msg; + StaticError(const std::string &msg) + : msg(msg) + { + } + StaticError(const std::string &filename, const Location &location, const std::string &msg) + : location(filename, location, location), msg(msg) + { + } + StaticError(const LocationRange &location, const std::string &msg) + : location(location), msg(msg) + { + } + + std::string toString() const + { + std::stringstream ss; + if (location.isSet()) { + ss << location << ":"; + } + ss << " " << msg; + return ss.str(); + } +}; + +static inline std::ostream &operator<<(std::ostream &o, const StaticError &err) +{ + o << err.toString(); + return o; +} + +#endif // JSONNET_ERROR_H diff --git a/vendor/github.com/strickyak/jsonnet_cgo/std.jsonnet.h b/vendor/github.com/strickyak/jsonnet_cgo/std.jsonnet.h new file mode 100644 index 00000000..cfe892f7 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/std.jsonnet.h @@ -0,0 +1,2 @@ +47,42,10,67,111,112,121,114,105,103,104,116,32,50,48,49,53,32,71,111,111,103,108,101,32,73,110,99,46,32,65,108,108,32,114,105,103,104,116,115,32,114,101,115,101,114,118,101,100,46,10,10,76,105,99,101,110,115,101,100,32,117,110,100,101,114,32,116,104,101,32,65,112,97,99,104,101,32,76,105,99,101,110,115,101,44,32,86,101,114,115,105,111,110,32,50,46,48,32,40,116,104,101,32,34,76,105,99,101,110,115,101,34,41,59,10,121,111,117,32,109,97,121,32,110,111,116,32,117,115,101,32,116,104,105,115,32,102,105,108,101,32,101,120,99,101,112,116,32,105,110,32,99,111,109,112,108,105,97,110,99,101,32,119,105,116,104,32,116,104,101,32,76,105,99,101,110,115,101,46,10,89,111,117,32,109,97,121,32,111,98,116,97,105,110,32,97,32,99,111,112,121,32,111,102,32,116,104,101,32,76,105,99,101,110,115,101,32,97,116,10,10,32,32,32,32,104,116,116,112,58,47,47,119,119,119,46,97,112,97,99,104,101,46,111,114,103,47,108,105,99,101,110,115,101,115,47,76,73,67,69,78,83,69,45,50,46,48,10,10,85,110,108,101,115,115,32,114,101,113,117,105,114,101,100,32,98,121,32,97,112,112,108,105,99,97,98,108,101,32,108,97,119,32,111,114,32,97,103,114,101,101,100,32,116,111,32,105,110,32,119,114,105,116,105,110,103,44,32,115,111,102,116,119,97,114,101,10,100,105,115,116,114,105,98,117,116,101,100,32,117,110,100,101,114,32,116,104,101,32,76,105,99,101,110,115,101,32,105,115,32,100,105,115,116,114,105,98,117,116,101,100,32,111,110,32,97,110,32,34,65,83,32,73,83,34,32,66,65,83,73,83,44,10,87,73,84,72,79,85,84,32,87,65,82,82,65,78,84,73,69,83,32,79,82,32,67,79,78,68,73,84,73,79,78,83,32,79,70,32,65,78,89,32,75,73,78,68,44,32,101,105,116,104,101,114,32,101,120,112,114,101,115,115,32,111,114,32,105,109,112,108,105,101,100,46,10,83,101,101,32,116,104,101,32,76,105,99,101,110,115,101,32,102,111,114,32,116,104,101,32,115,112,101,99,105,102,105,99,32,108,97,110,103,117,97,103,101,32,103,111,118,101,114,110,105,110,103,32,112,101,114,109,105,115,115,105,111,110,115,32,97,110,100,10,108,105,109,105,116,97,116,105,111,110,115,32,117,110,100,101,114,32,116,104,101,32,76,105,99,101,110,115,101,46,10,42,47,10,10,47,42,32,84,104,105,115,32,105,115,32,116,104,101,32,74,115,111,110,110,101,116,32,115,116,97,110,100,97,114,100,32,108,105,98,114,97,114,121,44,32,97,116,32,108,101,97,115,116,32,116,104,101,32,112,97,114,116,115,32,111,102,32,105,116,32,116,104,97,116,32,97,114,101,32,119,114,105,116,116,101,110,32,105,110,32,74,115,111,110,110,101,116,46,10,32,42,10,32,42,32,84,104,101,114,101,32,97,114,101,32,115,111,109,101,32,110,97,116,105,118,101,32,109,101,116,104,111,100,115,32,97,115,32,119,101,108,108,44,32,119,104,105,99,104,32,97,114,101,32,100,101,102,105,110,101,100,32,105,110,32,116,104,101,32,105,110,116,101,114,112,114,101,116,101,114,32,97,110,100,32,97,100,100,101,100,32,116,111,32,116,104,105,115,10,32,42,32,102,105,108,101,46,32,32,73,116,32,105,115,32,110,101,118,101,114,32,110,101,99,101,115,115,97,114,121,32,116,111,32,105,109,112,111,114,116,32,115,116,100,46,106,115,111,110,110,101,116,44,32,105,116,32,105,115,32,101,109,98,101,100,100,101,100,32,105,110,116,111,32,116,104,101,32,105,110,116,101,114,112,114,101,116,101,114,32,97,116,10,32,42,32,99,111,109,112,105,108,101,45,116,105,109,101,32,97,110,100,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,105,109,112,111,114,116,101,100,32,105,110,116,111,32,97,108,108,32,111,116,104,101,114,32,74,115,111,110,110,101,116,32,112,114,111,103,114,97,109,115,46,10,32,42,47,10,123,10,10,32,32,32,32,108,111,99,97,108,32,115,116,100,32,61,32,115,101,108,102,44,10,10,32,32,32,32,116,111,83,116,114,105,110,103,40,97,41,58,58,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,97,41,32,61,61,32,34,115,116,114,105,110,103,34,32,116,104,101,110,32,97,32,101,108,115,101,32,34,34,32,43,32,97,44,10,10,32,32,32,32,115,117,98,115,116,114,40,115,116,114,44,32,102,114,111,109,44,32,108,101,110,41,58,58,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,115,116,114,41,32,33,61,32,34,115,116,114,105,110,103,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,115,117,98,115,116,114,32,102,105,114,115,116,32,112,97,114,97,109,101,116,101,114,32,115,104,111,117,108,100,32,98,101,32,97,32,115,116,114,105,110,103,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,115,116,114,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,102,114,111,109,41,32,33,61,32,34,110,117,109,98,101,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,115,117,98,115,116,114,32,115,101,99,111,110,100,32,112,97,114,97,109,101,116,101,114,32,115,104,111,117,108,100,32,98,101,32,97,32,110,117,109,98,101,114,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,102,114,111,109,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,108,101,110,41,32,33,61,32,34,110,117,109,98,101,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,115,117,98,115,116,114,32,116,104,105,114,100,32,112,97,114,97,109,101,116,101,114,32,115,104,111,117,108,100,32,98,101,32,97,32,110,117,109,98,101,114,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,108,101,110,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,108,101,110,32,60,32,48,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,115,117,98,115,116,114,32,116,104,105,114,100,32,112,97,114,97,109,101,116,101,114,32,115,104,111,117,108,100,32,98,101,32,103,114,101,97,116,101,114,32,116,104,97,110,32,122,101,114,111,44,32,103,111,116,32,34,32,43,32,108,101,110,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,106,111,105,110,40,34,34,44,32,115,116,100,46,109,97,107,101,65,114,114,97,121,40,108,101,110,44,32,102,117,110,99,116,105,111,110,40,105,41,32,115,116,114,91,105,32,43,32,102,114,111,109,93,41,41,44,10,10,32,32,32,32,115,116,97,114,116,115,87,105,116,104,40,97,44,32,98,41,58,58,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,108,101,110,103,116,104,40,97,41,32,60,32,115,116,100,46,108,101,110,103,116,104,40,98,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,102,97,108,115,101,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,115,117,98,115,116,114,40,97,44,32,48,44,32,115,116,100,46,108,101,110,103,116,104,40,98,41,41,32,61,61,32,98,44,10,10,32,32,32,32,101,110,100,115,87,105,116,104,40,97,44,32,98,41,58,58,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,108,101,110,103,116,104,40,97,41,32,60,32,115,116,100,46,108,101,110,103,116,104,40,98,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,102,97,108,115,101,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,115,117,98,115,116,114,40,97,44,32,115,116,100,46,108,101,110,103,116,104,40,97,41,32,45,32,115,116,100,46,108,101,110,103,116,104,40,98,41,44,32,115,116,100,46,108,101,110,103,116,104,40,98,41,41,32,61,61,32,98,44,10,10,32,32,32,32,115,116,114,105,110,103,67,104,97,114,115,40,115,116,114,41,58,58,10,32,32,32,32,32,32,32,32,115,116,100,46,109,97,107,101,65,114,114,97,121,40,115,116,100,46,108,101,110,103,116,104,40,115,116,114,41,44,32,102,117,110,99,116,105,111,110,40,105,41,32,115,116,114,91,105,93,41,44,10,10,32,32,32,32,112,97,114,115,101,73,110,116,40,115,116,114,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,97,100,100,68,105,103,105,116,40,97,103,103,114,101,103,97,116,101,44,32,100,105,103,105,116,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,100,105,103,105,116,32,60,32,48,32,124,124,32,100,105,103,105,116,32,62,32,57,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,40,34,112,97,114,115,101,73,110,116,32,103,111,116,32,115,116,114,105,110,103,32,119,104,105,99,104,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,114,101,103,101,120,32,91,48,45,57,93,43,34,41,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,49,48,32,42,32,97,103,103,114,101,103,97,116,101,32,43,32,100,105,103,105,116,59,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,116,111,68,105,103,105,116,115,40,115,116,114,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,91,115,116,100,46,99,111,100,101,112,111,105,110,116,40,99,104,97,114,41,32,45,32,115,116,100,46,99,111,100,101,112,111,105,110,116,40,34,48,34,41,32,102,111,114,32,99,104,97,114,32,105,110,32,115,116,100,46,115,116,114,105,110,103,67,104,97,114,115,40,115,116,114,41,93,59,10,32,32,32,32,32,32,32,32,105,102,32,115,116,114,91,48,93,32,61,61,32,34,45,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,45,115,116,100,46,102,111,108,100,108,40,97,100,100,68,105,103,105,116,44,32,116,111,68,105,103,105,116,115,40,115,116,114,91,49,58,93,41,44,32,48,41,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,102,111,108,100,108,40,97,100,100,68,105,103,105,116,44,32,116,111,68,105,103,105,116,115,40,115,116,114,41,44,32,48,41,44,10,10,32,32,32,32,115,112,108,105,116,40,115,116,114,44,32,99,41,58,58,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,115,116,114,41,32,33,61,32,34,115,116,114,105,110,103,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,115,116,100,46,115,112,108,105,116,32,102,105,114,115,116,32,112,97,114,97,109,101,116,101,114,32,115,104,111,117,108,100,32,98,101,32,97,32,115,116,114,105,110,103,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,115,116,114,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,99,41,32,33,61,32,34,115,116,114,105,110,103,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,115,116,100,46,115,112,108,105,116,32,115,101,99,111,110,100,32,112,97,114,97,109,101,116,101,114,32,115,104,111,117,108,100,32,98,101,32,97,32,115,116,114,105,110,103,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,99,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,108,101,110,103,116,104,40,99,41,32,33,61,32,49,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,115,116,100,46,115,112,108,105,116,32,115,101,99,111,110,100,32,112,97,114,97,109,101,116,101,114,32,115,104,111,117,108,100,32,104,97,118,101,32,108,101,110,103,116,104,32,49,44,32,103,111,116,32,34,32,43,32,115,116,100,46,108,101,110,103,116,104,40,99,41,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,115,112,108,105,116,76,105,109,105,116,40,115,116,114,44,32,99,44,32,45,49,41,44,10,10,32,32,32,32,115,112,108,105,116,76,105,109,105,116,40,115,116,114,44,32,99,44,32,109,97,120,115,112,108,105,116,115,41,58,58,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,115,116,114,41,32,33,61,32,34,115,116,114,105,110,103,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,115,116,100,46,115,112,108,105,116,76,105,109,105,116,32,102,105,114,115,116,32,112,97,114,97,109,101,116,101,114,32,115,104,111,117,108,100,32,98,101,32,97,32,115,116,114,105,110,103,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,115,116,114,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,99,41,32,33,61,32,34,115,116,114,105,110,103,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,115,116,100,46,115,112,108,105,116,76,105,109,105,116,32,115,101,99,111,110,100,32,112,97,114,97,109,101,116,101,114,32,115,104,111,117,108,100,32,98,101,32,97,32,115,116,114,105,110,103,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,99,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,108,101,110,103,116,104,40,99,41,32,33,61,32,49,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,115,116,100,46,115,112,108,105,116,76,105,109,105,116,32,115,101,99,111,110,100,32,112,97,114,97,109,101,116,101,114,32,115,104,111,117,108,100,32,104,97,118,101,32,108,101,110,103,116,104,32,49,44,32,103,111,116,32,34,32,43,32,115,116,100,46,108,101,110,103,116,104,40,99,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,109,97,120,115,112,108,105,116,115,41,32,33,61,32,34,110,117,109,98,101,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,115,116,100,46,115,112,108,105,116,76,105,109,105,116,32,116,104,105,114,100,32,112,97,114,97,109,101,116,101,114,32,115,104,111,117,108,100,32,98,101,32,97,32,110,117,109,98,101,114,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,109,97,120,115,112,108,105,116,115,41,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,97,117,120,40,115,116,114,44,32,100,101,108,105,109,44,32,105,44,32,97,114,114,44,32,118,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,32,61,32,115,116,114,91,105,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,105,50,32,61,32,105,32,43,32,49,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,115,116,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,114,114,32,43,32,91,118,93,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,100,101,108,105,109,32,38,38,32,40,109,97,120,115,112,108,105,116,115,32,61,61,32,45,49,32,124,124,32,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,32,60,32,109,97,120,115,112,108,105,116,115,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,115,116,114,44,32,100,101,108,105,109,44,32,105,50,44,32,97,114,114,32,43,32,91,118,93,44,32,34,34,41,32,116,97,105,108,115,116,114,105,99,116,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,115,116,114,44,32,100,101,108,105,109,44,32,105,50,44,32,97,114,114,44,32,118,32,43,32,99,41,32,116,97,105,108,115,116,114,105,99,116,59,10,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,115,116,114,44,32,99,44,32,48,44,32,91,93,44,32,34,34,41,44,10,10,32,32,32,32,114,97,110,103,101,40,102,114,111,109,44,32,116,111,41,58,58,10,32,32,32,32,32,32,32,32,115,116,100,46,109,97,107,101,65,114,114,97,121,40,116,111,32,45,32,102,114,111,109,32,43,32,49,44,32,102,117,110,99,116,105,111,110,40,105,41,32,105,32,43,32,102,114,111,109,41,44,10,10,32,32,32,32,115,108,105,99,101,40,105,110,100,101,120,97,98,108,101,44,32,105,110,100,101,120,44,32,101,110,100,44,32,115,116,101,112,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,105,110,118,97,114,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,47,47,32,108,111,111,112,32,105,110,118,97,114,105,97,110,116,32,119,105,116,104,32,100,101,102,97,117,108,116,115,32,97,112,112,108,105,101,100,10,32,32,32,32,32,32,32,32,32,32,32,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,110,100,101,120,97,98,108,101,58,32,105,110,100,101,120,97,98,108,101,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,110,100,101,120,58,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,110,100,101,120,32,61,61,32,110,117,108,108,32,116,104,101,110,32,48,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,110,100,101,120,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,110,100,58,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,101,110,100,32,61,61,32,110,117,108,108,32,116,104,101,110,32,115,116,100,46,108,101,110,103,116,104,40,105,110,100,101,120,97,98,108,101,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,101,110,100,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,116,101,112,58,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,101,112,32,61,61,32,110,117,108,108,32,116,104,101,110,32,49,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,115,116,101,112,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,101,110,103,116,104,58,32,115,116,100,46,108,101,110,103,116,104,40,105,110,100,101,120,97,98,108,101,41,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,116,121,112,101,58,32,115,116,100,46,116,121,112,101,40,105,110,100,101,120,97,98,108,101,41,44,10,32,32,32,32,32,32,32,32,32,32,32,32,125,59,10,32,32,32,32,32,32,32,32,105,102,32,105,110,118,97,114,46,105,110,100,101,120,32,60,32,48,32,124,124,32,105,110,118,97,114,46,101,110,100,32,60,32,48,32,124,124,32,105,110,118,97,114,46,115,116,101,112,32,60,32,48,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,40,34,103,111,116,32,91,37,115,58,37,115,58,37,115,93,32,98,117,116,32,110,101,103,97,116,105,118,101,32,105,110,100,101,120,44,32,101,110,100,44,32,97,110,100,32,115,116,101,112,115,32,97,114,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,34,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,37,32,91,105,110,118,97,114,46,105,110,100,101,120,44,32,105,110,118,97,114,46,101,110,100,44,32,105,110,118,97,114,46,115,116,101,112,93,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,101,112,32,61,61,32,48,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,40,34,103,111,116,32,37,115,32,98,117,116,32,115,116,101,112,32,109,117,115,116,32,98,101,32,103,114,101,97,116,101,114,32,116,104,97,110,32,48,34,32,37,32,115,116,101,112,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,105,110,100,101,120,97,98,108,101,41,32,33,61,32,34,115,116,114,105,110,103,34,32,38,38,32,115,116,100,46,116,121,112,101,40,105,110,100,101,120,97,98,108,101,41,32,33,61,32,34,97,114,114,97,121,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,40,34,115,116,100,46,115,108,105,99,101,32,97,99,99,101,112,116,115,32,97,32,115,116,114,105,110,103,32,111,114,32,97,110,32,97,114,114,97,121,44,32,98,117,116,32,103,111,116,58,32,37,115,34,32,37,32,115,116,100,46,116,121,112,101,40,105,110,100,101,120,97,98,108,101,41,41,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,98,117,105,108,100,40,115,108,105,99,101,44,32,99,117,114,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,117,114,32,62,61,32,105,110,118,97,114,46,101,110,100,32,124,124,32,99,117,114,32,62,61,32,105,110,118,97,114,46,108,101,110,103,116,104,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,108,105,99,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,98,117,105,108,100,40,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,110,118,97,114,46,116,121,112,101,32,61,61,32,34,115,116,114,105,110,103,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,108,105,99,101,32,43,32,105,110,118,97,114,46,105,110,100,101,120,97,98,108,101,91,99,117,114,93,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,108,105,99,101,32,43,32,91,105,110,118,97,114,46,105,110,100,101,120,97,98,108,101,91,99,117,114,93,93,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,117,114,32,43,32,105,110,118,97,114,46,115,116,101,112,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,41,32,116,97,105,108,115,116,114,105,99,116,59,10,32,32,32,32,32,32,32,32,32,32,32,32,98,117,105,108,100,40,105,102,32,105,110,118,97,114,46,116,121,112,101,32,61,61,32,34,115,116,114,105,110,103,34,32,116,104,101,110,32,34,34,32,101,108,115,101,32,91,93,44,32,105,110,118,97,114,46,105,110,100,101,120,41,44,10,10,32,32,32,32,99,111,117,110,116,40,97,114,114,44,32,120,41,58,58,32,115,116,100,46,108,101,110,103,116,104,40,115,116,100,46,102,105,108,116,101,114,40,102,117,110,99,116,105,111,110,40,118,41,32,118,32,61,61,32,120,44,32,97,114,114,41,41,44,10,10,32,32,32,32,109,111,100,40,97,44,32,98,41,58,58,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,97,41,32,61,61,32,34,110,117,109,98,101,114,34,32,38,38,32,115,116,100,46,116,121,112,101,40,98,41,32,61,61,32,34,110,117,109,98,101,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,109,111,100,117,108,111,40,97,44,32,98,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,97,41,32,61,61,32,34,115,116,114,105,110,103,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,102,111,114,109,97,116,40,97,44,32,98,41,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,79,112,101,114,97,116,111,114,32,37,32,99,97,110,110,111,116,32,98,101,32,117,115,101,100,32,111,110,32,116,121,112,101,115,32,34,32,43,32,115,116,100,46,116,121,112,101,40,97,41,32,43,32,34,32,97,110,100,32,34,32,43,32,115,116,100,46,116,121,112,101,40,98,41,32,43,32,34,46,34,44,10,10,32,32,32,32,109,97,112,40,102,117,110,99,44,32,97,114,114,41,58,58,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,102,117,110,99,41,32,33,61,32,34,102,117,110,99,116,105,111,110,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,40,34,115,116,100,46,109,97,112,32,102,105,114,115,116,32,112,97,114,97,109,32,109,117,115,116,32,98,101,32,102,117,110,99,116,105,111,110,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,102,117,110,99,41,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,97,114,114,41,32,33,61,32,34,97,114,114,97,121,34,32,38,38,32,115,116,100,46,116,121,112,101,40,97,114,114,41,32,33,61,32,34,115,116,114,105,110,103,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,40,34,115,116,100,46,109,97,112,32,115,101,99,111,110,100,32,112,97,114,97,109,32,109,117,115,116,32,98,101,32,97,114,114,97,121,32,47,32,115,116,114,105,110,103,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,97,114,114,41,41,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,109,97,107,101,65,114,114,97,121,40,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,44,32,102,117,110,99,116,105,111,110,40,105,41,32,102,117,110,99,40,97,114,114,91,105,93,41,41,44,10,10,32,32,32,32,106,111,105,110,40,115,101,112,44,32,97,114,114,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,97,117,120,40,97,114,114,44,32,105,44,32,102,105,114,115,116,44,32,114,117,110,110,105,110,103,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,114,117,110,110,105,110,103,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,97,114,114,91,105,93,32,61,61,32,110,117,108,108,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,114,114,44,32,105,32,43,32,49,44,32,102,105,114,115,116,44,32,114,117,110,110,105,110,103,41,32,116,97,105,108,115,116,114,105,99,116,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,102,105,114,115,116,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,114,114,44,32,105,32,43,32,49,44,32,102,97,108,115,101,44,32,114,117,110,110,105,110,103,32,43,32,97,114,114,91,105,93,41,32,116,97,105,108,115,116,114,105,99,116,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,114,114,44,32,105,32,43,32,49,44,32,102,97,108,115,101,44,32,114,117,110,110,105,110,103,32,43,32,115,101,112,32,43,32,97,114,114,91,105,93,41,32,116,97,105,108,115,116,114,105,99,116,59,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,97,114,114,41,32,33,61,32,34,97,114,114,97,121,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,106,111,105,110,32,115,101,99,111,110,100,32,112,97,114,97,109,101,116,101,114,32,115,104,111,117,108,100,32,98,101,32,97,114,114,97,121,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,97,114,114,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,115,101,112,41,32,61,61,32,34,115,116,114,105,110,103,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,114,114,44,32,48,44,32,116,114,117,101,44,32,34,34,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,115,101,112,41,32,61,61,32,34,97,114,114,97,121,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,114,114,44,32,48,44,32,116,114,117,101,44,32,91,93,41,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,106,111,105,110,32,102,105,114,115,116,32,112,97,114,97,109,101,116,101,114,32,115,104,111,117,108,100,32,98,101,32,115,116,114,105,110,103,32,111,114,32,97,114,114,97,121,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,115,101,112,41,44,10,10,32,32,32,32,108,105,110,101,115,40,97,114,114,41,58,58,10,32,32,32,32,32,32,32,32,115,116,100,46,106,111,105,110,40,34,92,110,34,44,32,97,114,114,32,43,32,91,34,34,93,41,44,10,10,32,32,32,32,102,111,114,109,97,116,40,115,116,114,44,32,118,97,108,115,41,58,58,10,10,32,32,32,32,32,32,32,32,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,10,32,32,32,32,32,32,32,32,47,47,32,80,97,114,115,101,32,116,104,101,32,109,105,110,105,45,108,97,110,103,117,97,103,101,32,47,47,10,32,32,32,32,32,32,32,32,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,10,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,116,114,121,95,112,97,114,115,101,95,109,97,112,112,105,110,103,95,107,101,121,40,115,116,114,44,32,105,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,115,116,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,84,114,117,110,99,97,116,101,100,32,102,111,114,109,97,116,32,99,111,100,101,46,34,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,32,61,32,115,116,114,91,105,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,32,61,61,32,34,40,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,44,32,118,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,106,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,115,116,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,84,114,117,110,99,97,116,101,100,32,102,111,114,109,97,116,32,99,111,100,101,46,34,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,32,61,32,115,116,114,91,106,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,32,33,61,32,34,41,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,32,43,32,49,44,32,118,32,43,32,99,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,106,32,43,32,49,44,32,118,58,32,118,32,125,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,105,32,43,32,49,44,32,34,34,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,105,44,32,118,58,32,110,117,108,108,32,125,59,10,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,116,114,121,95,112,97,114,115,101,95,99,102,108,97,103,115,40,115,116,114,44,32,105,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,44,32,118,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,106,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,115,116,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,84,114,117,110,99,97,116,101,100,32,102,111,114,109,97,116,32,99,111,100,101,46,34,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,32,61,32,115,116,114,91,106,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,32,61,61,32,34,35,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,32,43,32,49,44,32,118,32,123,32,97,108,116,58,32,116,114,117,101,32,125,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,48,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,32,43,32,49,44,32,118,32,123,32,122,101,114,111,58,32,116,114,117,101,32,125,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,45,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,32,43,32,49,44,32,118,32,123,32,108,101,102,116,58,32,116,114,117,101,32,125,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,32,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,32,43,32,49,44,32,118,32,123,32,98,108,97,110,107,58,32,116,114,117,101,32,125,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,43,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,32,43,32,49,44,32,118,32,123,32,115,105,103,110,58,32,116,114,117,101,32,125,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,106,44,32,118,58,32,118,32,125,59,10,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,105,44,32,123,32,97,108,116,58,32,102,97,108,115,101,44,32,122,101,114,111,58,32,102,97,108,115,101,44,32,108,101,102,116,58,32,102,97,108,115,101,44,32,98,108,97,110,107,58,32,102,97,108,115,101,44,32,115,105,103,110,58,32,102,97,108,115,101,32,125,41,59,10,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,116,114,121,95,112,97,114,115,101,95,102,105,101,108,100,95,119,105,100,116,104,40,115,116,114,44,32,105,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,32,60,32,115,116,100,46,108,101,110,103,116,104,40,115,116,114,41,32,38,38,32,115,116,114,91,105,93,32,61,61,32,34,42,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,105,32,43,32,49,44,32,118,58,32,34,42,34,32,125,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,44,32,118,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,106,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,115,116,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,84,114,117,110,99,97,116,101,100,32,102,111,114,109,97,116,32,99,111,100,101,46,34,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,32,61,32,115,116,114,91,106,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,32,61,61,32,34,48,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,32,43,32,49,44,32,118,32,42,32,49,48,32,43,32,48,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,49,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,32,43,32,49,44,32,118,32,42,32,49,48,32,43,32,49,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,50,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,32,43,32,49,44,32,118,32,42,32,49,48,32,43,32,50,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,51,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,32,43,32,49,44,32,118,32,42,32,49,48,32,43,32,51,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,52,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,32,43,32,49,44,32,118,32,42,32,49,48,32,43,32,52,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,53,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,32,43,32,49,44,32,118,32,42,32,49,48,32,43,32,53,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,54,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,32,43,32,49,44,32,118,32,42,32,49,48,32,43,32,54,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,55,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,32,43,32,49,44,32,118,32,42,32,49,48,32,43,32,55,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,56,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,32,43,32,49,44,32,118,32,42,32,49,48,32,43,32,56,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,57,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,106,32,43,32,49,44,32,118,32,42,32,49,48,32,43,32,57,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,106,44,32,118,58,32,118,32,125,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,117,109,101,40,115,116,114,44,32,105,44,32,48,41,59,10,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,116,114,121,95,112,97,114,115,101,95,112,114,101,99,105,115,105,111,110,40,115,116,114,44,32,105,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,115,116,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,84,114,117,110,99,97,116,101,100,32,102,111,114,109,97,116,32,99,111,100,101,46,34,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,32,61,32,115,116,114,91,105,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,32,61,61,32,34,46,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,116,114,121,95,112,97,114,115,101,95,102,105,101,108,100,95,119,105,100,116,104,40,115,116,114,44,32,105,32,43,32,49,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,105,44,32,118,58,32,110,117,108,108,32,125,59,10,10,32,32,32,32,32,32,32,32,47,47,32,73,103,110,111,114,101,100,44,32,105,102,32,105,116,32,101,120,105,115,116,115,46,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,116,114,121,95,112,97,114,115,101,95,108,101,110,103,116,104,95,109,111,100,105,102,105,101,114,40,115,116,114,44,32,105,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,115,116,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,84,114,117,110,99,97,116,101,100,32,102,111,114,109,97,116,32,99,111,100,101,46,34,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,32,61,32,115,116,114,91,105,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,32,61,61,32,34,104,34,32,124,124,32,99,32,61,61,32,34,108,34,32,124,124,32,99,32,61,61,32,34,76,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,32,43,32,49,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,59,10,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,112,97,114,115,101,95,99,111,110,118,95,116,121,112,101,40,115,116,114,44,32,105,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,115,116,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,84,114,117,110,99,97,116,101,100,32,102,111,114,109,97,116,32,99,111,100,101,46,34,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,32,61,32,115,116,114,91,105,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,32,61,61,32,34,100,34,32,124,124,32,99,32,61,61,32,34,105,34,32,124,124,32,99,32,61,61,32,34,117,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,105,32,43,32,49,44,32,118,58,32,34,100,34,44,32,99,97,112,115,58,32,102,97,108,115,101,32,125,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,111,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,105,32,43,32,49,44,32,118,58,32,34,111,34,44,32,99,97,112,115,58,32,102,97,108,115,101,32,125,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,120,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,105,32,43,32,49,44,32,118,58,32,34,120,34,44,32,99,97,112,115,58,32,102,97,108,115,101,32,125,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,88,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,105,32,43,32,49,44,32,118,58,32,34,120,34,44,32,99,97,112,115,58,32,116,114,117,101,32,125,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,101,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,105,32,43,32,49,44,32,118,58,32,34,101,34,44,32,99,97,112,115,58,32,102,97,108,115,101,32,125,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,69,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,105,32,43,32,49,44,32,118,58,32,34,101,34,44,32,99,97,112,115,58,32,116,114,117,101,32,125,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,102,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,105,32,43,32,49,44,32,118,58,32,34,102,34,44,32,99,97,112,115,58,32,102,97,108,115,101,32,125,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,70,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,105,32,43,32,49,44,32,118,58,32,34,102,34,44,32,99,97,112,115,58,32,116,114,117,101,32,125,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,103,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,105,32,43,32,49,44,32,118,58,32,34,103,34,44,32,99,97,112,115,58,32,102,97,108,115,101,32,125,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,71,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,105,32,43,32,49,44,32,118,58,32,34,103,34,44,32,99,97,112,115,58,32,116,114,117,101,32,125,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,99,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,105,32,43,32,49,44,32,118,58,32,34,99,34,44,32,99,97,112,115,58,32,102,97,108,115,101,32,125,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,115,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,105,32,43,32,49,44,32,118,58,32,34,115,34,44,32,99,97,112,115,58,32,102,97,108,115,101,32,125,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,32,61,61,32,34,37,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,32,105,58,32,105,32,43,32,49,44,32,118,58,32,34,37,34,44,32,99,97,112,115,58,32,102,97,108,115,101,32,125,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,85,110,114,101,99,111,103,110,105,115,101,100,32,99,111,110,118,101,114,115,105,111,110,32,116,121,112,101,58,32,34,32,43,32,99,59,10,10,10,32,32,32,32,32,32,32,32,47,47,32,80,97,114,115,101,100,32,105,110,105,116,105,97,108,32,37,44,32,110,111,119,32,116,104,101,32,114,101,115,116,46,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,112,97,114,115,101,95,99,111,100,101,40,115,116,114,44,32,105,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,115,116,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,84,114,117,110,99,97,116,101,100,32,102,111,114,109,97,116,32,99,111,100,101,46,34,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,109,107,101,121,32,61,32,116,114,121,95,112,97,114,115,101,95,109,97,112,112,105,110,103,95,107,101,121,40,115,116,114,44,32,105,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,102,108,97,103,115,32,61,32,116,114,121,95,112,97,114,115,101,95,99,102,108,97,103,115,40,115,116,114,44,32,109,107,101,121,46,105,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,102,119,32,61,32,116,114,121,95,112,97,114,115,101,95,102,105,101,108,100,95,119,105,100,116,104,40,115,116,114,44,32,99,102,108,97,103,115,46,105,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,112,114,101,99,32,61,32,116,114,121,95,112,97,114,115,101,95,112,114,101,99,105,115,105,111,110,40,115,116,114,44,32,102,119,46,105,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,108,101,110,95,109,111,100,32,61,32,116,114,121,95,112,97,114,115,101,95,108,101,110,103,116,104,95,109,111,100,105,102,105,101,114,40,115,116,114,44,32,112,114,101,99,46,105,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,116,121,112,101,32,61,32,112,97,114,115,101,95,99,111,110,118,95,116,121,112,101,40,115,116,114,44,32,108,101,110,95,109,111,100,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,58,32,99,116,121,112,101,46,105,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,100,101,58,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,109,107,101,121,58,32,109,107,101,121,46,118,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,102,108,97,103,115,58,32,99,102,108,97,103,115,46,118,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,102,119,58,32,102,119,46,118,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,112,114,101,99,58,32,112,114,101,99,46,118,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,116,121,112,101,58,32,99,116,121,112,101,46,118,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,97,112,115,58,32,99,116,121,112,101,46,99,97,112,115,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,125,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,125,59,10,10,32,32,32,32,32,32,32,32,47,47,32,80,97,114,115,101,32,97,32,102,111,114,109,97,116,32,115,116,114,105,110,103,32,40,99,111,110,116,97,105,110,105,110,103,32,110,111,110,101,32,111,114,32,109,111,114,101,32,37,32,102,111,114,109,97,116,32,116,97,103,115,41,46,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,112,97,114,115,101,95,99,111,100,101,115,40,115,116,114,44,32,105,44,32,111,117,116,44,32,99,117,114,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,115,116,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,111,117,116,32,43,32,91,99,117,114,93,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,32,61,32,115,116,114,91,105,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,32,61,61,32,34,37,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,114,32,61,32,112,97,114,115,101,95,99,111,100,101,40,115,116,114,44,32,105,32,43,32,49,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,112,97,114,115,101,95,99,111,100,101,115,40,115,116,114,44,32,114,46,105,44,32,111,117,116,32,43,32,91,99,117,114,44,32,114,46,99,111,100,101,93,44,32,34,34,41,32,116,97,105,108,115,116,114,105,99,116,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,112,97,114,115,101,95,99,111,100,101,115,40,115,116,114,44,32,105,32,43,32,49,44,32,111,117,116,44,32,99,117,114,32,43,32,99,41,32,116,97,105,108,115,116,114,105,99,116,59,10,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,111,100,101,115,32,61,32,112,97,114,115,101,95,99,111,100,101,115,40,115,116,114,44,32,48,44,32,91,93,44,32,34,34,41,59,10,10,10,32,32,32,32,32,32,32,32,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,10,32,32,32,32,32,32,32,32,47,47,32,70,111,114,109,97,116,32,116,104,101,32,118,97,108,117,101,115,32,47,47,10,32,32,32,32,32,32,32,32,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,10,10,32,32,32,32,32,32,32,32,47,47,32,85,115,101,102,117,108,32,117,116,105,108,105,116,105,101,115,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,112,97,100,100,105,110,103,40,119,44,32,115,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,97,117,120,40,119,44,32,118,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,119,32,60,61,32,48,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,118,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,119,32,45,32,49,44,32,118,32,43,32,115,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,119,44,32,34,34,41,59,10,10,32,32,32,32,32,32,32,32,47,47,32,65,100,100,32,115,32,116,111,32,116,104,101,32,108,101,102,116,32,111,102,32,115,116,114,32,115,111,32,116,104,97,116,32,105,116,115,32,108,101,110,103,116,104,32,105,115,32,97,116,32,108,101,97,115,116,32,119,46,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,112,97,100,95,108,101,102,116,40,115,116,114,44,32,119,44,32,115,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,112,97,100,100,105,110,103,40,119,32,45,32,115,116,100,46,108,101,110,103,116,104,40,115,116,114,41,44,32,115,41,32,43,32,115,116,114,59,10,10,32,32,32,32,32,32,32,32,47,47,32,65,100,100,32,115,32,116,111,32,116,104,101,32,114,105,103,104,116,32,111,102,32,115,116,114,32,115,111,32,116,104,97,116,32,105,116,115,32,108,101,110,103,116,104,32,105,115,32,97,116,32,108,101,97,115,116,32,119,46,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,112,97,100,95,114,105,103,104,116,40,115,116,114,44,32,119,44,32,115,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,115,116,114,32,43,32,112,97,100,100,105,110,103,40,119,32,45,32,115,116,100,46,108,101,110,103,116,104,40,115,116,114,41,44,32,115,41,59,10,10,32,32,32,32,32,32,32,32,47,47,32,82,101,110,100,101,114,32,97,110,32,105,110,116,101,103,101,114,32,40,101,46,103,46,44,32,100,101,99,105,109,97,108,32,111,114,32,111,99,116,97,108,41,46,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,114,101,110,100,101,114,95,105,110,116,40,110,95,95,44,32,109,105,110,95,99,104,97,114,115,44,32,109,105,110,95,100,105,103,105,116,115,44,32,98,108,97,110,107,44,32,115,105,103,110,44,32,114,97,100,105,120,44,32,122,101,114,111,95,112,114,101,102,105,120,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,110,95,32,61,32,115,116,100,46,97,98,115,40,110,95,95,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,97,117,120,40,110,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,110,32,61,61,32,48,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,122,101,114,111,95,112,114,101,102,105,120,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,115,116,100,46,102,108,111,111,114,40,110,32,47,32,114,97,100,105,120,41,41,32,43,32,40,110,32,37,32,114,97,100,105,120,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,100,101,99,32,61,32,105,102,32,115,116,100,46,102,108,111,111,114,40,110,95,41,32,61,61,32,48,32,116,104,101,110,32,34,48,34,32,101,108,115,101,32,97,117,120,40,115,116,100,46,102,108,111,111,114,40,110,95,41,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,110,101,103,32,61,32,110,95,95,32,60,32,48,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,122,112,32,61,32,109,105,110,95,99,104,97,114,115,32,45,32,40,105,102,32,110,101,103,32,124,124,32,98,108,97,110,107,32,124,124,32,115,105,103,110,32,116,104,101,110,32,49,32,101,108,115,101,32,48,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,122,112,50,32,61,32,115,116,100,46,109,97,120,40,122,112,44,32,109,105,110,95,100,105,103,105,116,115,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,100,101,99,50,32,61,32,112,97,100,95,108,101,102,116,40,100,101,99,44,32,122,112,50,44,32,34,48,34,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,40,105,102,32,110,101,103,32,116,104,101,110,32,34,45,34,32,101,108,115,101,32,105,102,32,115,105,103,110,32,116,104,101,110,32,34,43,34,32,101,108,115,101,32,105,102,32,98,108,97,110,107,32,116,104,101,110,32,34,32,34,32,101,108,115,101,32,34,34,41,32,43,32,100,101,99,50,59,10,10,32,32,32,32,32,32,32,32,47,47,32,82,101,110,100,101,114,32,97,110,32,105,110,116,101,103,101,114,32,105,110,32,104,101,120,97,100,101,99,105,109,97,108,46,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,114,101,110,100,101,114,95,104,101,120,40,110,95,95,44,32,109,105,110,95,99,104,97,114,115,44,32,109,105,110,95,100,105,103,105,116,115,44,32,98,108,97,110,107,44,32,115,105,103,110,44,32,97,100,100,95,122,101,114,111,120,44,32,99,97,112,105,116,97,108,115,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,110,117,109,101,114,97,108,115,32,61,32,91,48,44,32,49,44,32,50,44,32,51,44,32,52,44,32,53,44,32,54,44,32,55,44,32,56,44,32,57,93,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,43,32,105,102,32,99,97,112,105,116,97,108,115,32,116,104,101,110,32,91,34,65,34,44,32,34,66,34,44,32,34,67,34,44,32,34,68,34,44,32,34,69,34,44,32,34,70,34,93,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,91,34,97,34,44,32,34,98,34,44,32,34,99,34,44,32,34,100,34,44,32,34,101,34,44,32,34,102,34,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,110,95,32,61,32,115,116,100,46,97,98,115,40,110,95,95,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,97,117,120,40,110,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,110,32,61,61,32,48,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,34,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,115,116,100,46,102,108,111,111,114,40,110,32,47,32,49,54,41,41,32,43,32,110,117,109,101,114,97,108,115,91,110,32,37,32,49,54,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,104,101,120,32,61,32,105,102,32,115,116,100,46,102,108,111,111,114,40,110,95,41,32,61,61,32,48,32,116,104,101,110,32,34,48,34,32,101,108,115,101,32,97,117,120,40,115,116,100,46,102,108,111,111,114,40,110,95,41,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,110,101,103,32,61,32,110,95,95,32,60,32,48,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,122,112,32,61,32,109,105,110,95,99,104,97,114,115,32,45,32,40,105,102,32,110,101,103,32,124,124,32,98,108,97,110,107,32,124,124,32,115,105,103,110,32,116,104,101,110,32,49,32,101,108,115,101,32,48,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,45,32,40,105,102,32,97,100,100,95,122,101,114,111,120,32,116,104,101,110,32,50,32,101,108,115,101,32,48,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,122,112,50,32,61,32,115,116,100,46,109,97,120,40,122,112,44,32,109,105,110,95,100,105,103,105,116,115,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,104,101,120,50,32,61,32,40,105,102,32,97,100,100,95,122,101,114,111,120,32,116,104,101,110,32,40,105,102,32,99,97,112,105,116,97,108,115,32,116,104,101,110,32,34,48,88,34,32,101,108,115,101,32,34,48,120,34,41,32,101,108,115,101,32,34,34,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,43,32,112,97,100,95,108,101,102,116,40,104,101,120,44,32,122,112,50,44,32,34,48,34,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,40,105,102,32,110,101,103,32,116,104,101,110,32,34,45,34,32,101,108,115,101,32,105,102,32,115,105,103,110,32,116,104,101,110,32,34,43,34,32,101,108,115,101,32,105,102,32,98,108,97,110,107,32,116,104,101,110,32,34,32,34,32,101,108,115,101,32,34,34,41,32,43,32,104,101,120,50,59,10,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,115,116,114,105,112,95,116,114,97,105,108,105,110,103,95,122,101,114,111,40,115,116,114,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,97,117,120,40,115,116,114,44,32,105,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,32,60,32,48,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,34,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,114,91,105,93,32,61,61,32,34,48,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,115,116,114,44,32,105,32,45,32,49,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,115,117,98,115,116,114,40,115,116,114,44,32,48,44,32,105,32,43,32,49,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,115,116,114,44,32,115,116,100,46,108,101,110,103,116,104,40,115,116,114,41,32,45,32,49,41,59,10,10,32,32,32,32,32,32,32,32,47,47,32,82,101,110,100,101,114,32,102,108,111,97,116,105,110,103,32,112,111,105,110,116,32,105,110,32,100,101,99,105,109,97,108,32,102,111,114,109,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,114,101,110,100,101,114,95,102,108,111,97,116,95,100,101,99,40,110,95,95,44,32,122,101,114,111,95,112,97,100,44,32,98,108,97,110,107,44,32,115,105,103,110,44,32,101,110,115,117,114,101,95,112,116,44,32,116,114,97,105,108,105,110,103,44,32,112,114,101,99,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,110,95,32,61,32,115,116,100,46,97,98,115,40,110,95,95,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,119,104,111,108,101,32,61,32,115,116,100,46,102,108,111,111,114,40,110,95,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,100,111,116,95,115,105,122,101,32,61,32,105,102,32,112,114,101,99,32,61,61,32,48,32,38,38,32,33,101,110,115,117,114,101,95,112,116,32,116,104,101,110,32,48,32,101,108,115,101,32,49,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,122,112,32,61,32,122,101,114,111,95,112,97,100,32,45,32,112,114,101,99,32,45,32,100,111,116,95,115,105,122,101,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,115,116,114,32,61,32,114,101,110,100,101,114,95,105,110,116,40,110,95,95,32,47,32,110,95,32,42,32,119,104,111,108,101,44,32,122,112,44,32,48,44,32,98,108,97,110,107,44,32,115,105,103,110,44,32,49,48,44,32,34,34,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,112,114,101,99,32,61,61,32,48,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,116,114,32,43,32,105,102,32,101,110,115,117,114,101,95,112,116,32,116,104,101,110,32,34,46,34,32,101,108,115,101,32,34,34,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,102,114,97,99,32,61,32,115,116,100,46,102,108,111,111,114,40,40,110,95,32,45,32,119,104,111,108,101,41,32,42,32,115,116,100,46,112,111,119,40,49,48,44,32,112,114,101,99,41,32,43,32,48,46,53,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,116,114,97,105,108,105,110,103,32,124,124,32,102,114,97,99,32,62,32,48,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,102,114,97,99,95,115,116,114,32,61,32,114,101,110,100,101,114,95,105,110,116,40,102,114,97,99,44,32,112,114,101,99,44,32,48,44,32,102,97,108,115,101,44,32,102,97,108,115,101,44,32,49,48,44,32,34,34,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,116,114,32,43,32,34,46,34,32,43,32,105,102,32,33,116,114,97,105,108,105,110,103,32,116,104,101,110,32,115,116,114,105,112,95,116,114,97,105,108,105,110,103,95,122,101,114,111,40,102,114,97,99,95,115,116,114,41,32,101,108,115,101,32,102,114,97,99,95,115,116,114,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,116,114,59,10,10,32,32,32,32,32,32,32,32,47,47,32,82,101,110,100,101,114,32,102,108,111,97,116,105,110,103,32,112,111,105,110,116,32,105,110,32,115,99,105,101,110,116,105,102,105,99,32,102,111,114,109,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,114,101,110,100,101,114,95,102,108,111,97,116,95,115,99,105,40,110,95,95,44,32,122,101,114,111,95,112,97,100,44,32,98,108,97,110,107,44,32,115,105,103,110,44,32,101,110,115,117,114,101,95,112,116,44,32,116,114,97,105,108,105,110,103,44,32,99,97,112,115,44,32,112,114,101,99,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,101,120,112,111,110,101,110,116,32,61,32,115,116,100,46,102,108,111,111,114,40,115,116,100,46,108,111,103,40,115,116,100,46,97,98,115,40,110,95,95,41,41,32,47,32,115,116,100,46,108,111,103,40,49,48,41,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,115,117,102,102,32,61,32,40,105,102,32,99,97,112,115,32,116,104,101,110,32,34,69,34,32,101,108,115,101,32,34,101,34,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,43,32,114,101,110,100,101,114,95,105,110,116,40,101,120,112,111,110,101,110,116,44,32,51,44,32,48,44,32,102,97,108,115,101,44,32,116,114,117,101,44,32,49,48,44,32,34,34,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,109,97,110,116,105,115,115,97,32,61,32,110,95,95,32,47,32,115,116,100,46,112,111,119,40,49,48,44,32,101,120,112,111,110,101,110,116,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,122,112,50,32,61,32,122,101,114,111,95,112,97,100,32,45,32,115,116,100,46,108,101,110,103,116,104,40,115,117,102,102,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,114,101,110,100,101,114,95,102,108,111,97,116,95,100,101,99,40,109,97,110,116,105,115,115,97,44,32,122,112,50,44,32,98,108,97,110,107,44,32,115,105,103,110,44,32,101,110,115,117,114,101,95,112,116,44,32,116,114,97,105,108,105,110,103,44,32,112,114,101,99,41,32,43,32,115,117,102,102,59,10,10,32,32,32,32,32,32,32,32,47,47,32,82,101,110,100,101,114,32,97,32,118,97,108,117,101,32,119,105,116,104,32,97,110,32,97,114,98,105,116,114,97,114,121,32,102,111,114,109,97,116,32,99,111,100,101,46,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,102,111,114,109,97,116,95,99,111,100,101,40,118,97,108,44,32,99,111,100,101,44,32,102,119,44,32,112,114,101,99,95,111,114,95,110,117,108,108,44,32,105,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,102,108,97,103,115,32,61,32,99,111,100,101,46,99,102,108,97,103,115,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,102,112,112,114,101,99,32,61,32,105,102,32,112,114,101,99,95,111,114,95,110,117,108,108,32,33,61,32,110,117,108,108,32,116,104,101,110,32,112,114,101,99,95,111,114,95,110,117,108,108,32,101,108,115,101,32,54,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,105,112,114,101,99,32,61,32,105,102,32,112,114,101,99,95,111,114,95,110,117,108,108,32,33,61,32,110,117,108,108,32,116,104,101,110,32,112,114,101,99,95,111,114,95,110,117,108,108,32,101,108,115,101,32,48,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,122,112,32,61,32,105,102,32,99,102,108,97,103,115,46,122,101,114,111,32,38,38,32,33,99,102,108,97,103,115,46,108,101,102,116,32,116,104,101,110,32,102,119,32,101,108,115,101,32,48,59,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,111,100,101,46,99,116,121,112,101,32,61,61,32,34,115,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,116,111,83,116,114,105,110,103,40,118,97,108,41,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,111,100,101,46,99,116,121,112,101,32,61,61,32,34,100,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,118,97,108,41,32,33,61,32,34,110,117,109,98,101,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,70,111,114,109,97,116,32,114,101,113,117,105,114,101,100,32,110,117,109,98,101,114,32,97,116,32,34,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,43,32,105,32,43,32,34,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,118,97,108,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,114,101,110,100,101,114,95,105,110,116,40,118,97,108,44,32,122,112,44,32,105,112,114,101,99,44,32,99,102,108,97,103,115,46,98,108,97,110,107,44,32,99,102,108,97,103,115,46,115,105,103,110,44,32,49,48,44,32,34,34,41,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,111,100,101,46,99,116,121,112,101,32,61,61,32,34,111,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,118,97,108,41,32,33,61,32,34,110,117,109,98,101,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,70,111,114,109,97,116,32,114,101,113,117,105,114,101,100,32,110,117,109,98,101,114,32,97,116,32,34,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,43,32,105,32,43,32,34,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,118,97,108,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,122,101,114,111,95,112,114,101,102,105,120,32,61,32,105,102,32,99,102,108,97,103,115,46,97,108,116,32,116,104,101,110,32,34,48,34,32,101,108,115,101,32,34,34,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,114,101,110,100,101,114,95,105,110,116,40,118,97,108,44,32,122,112,44,32,105,112,114,101,99,44,32,99,102,108,97,103,115,46,98,108,97,110,107,44,32,99,102,108,97,103,115,46,115,105,103,110,44,32,56,44,32,122,101,114,111,95,112,114,101,102,105,120,41,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,111,100,101,46,99,116,121,112,101,32,61,61,32,34,120,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,118,97,108,41,32,33,61,32,34,110,117,109,98,101,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,70,111,114,109,97,116,32,114,101,113,117,105,114,101,100,32,110,117,109,98,101,114,32,97,116,32,34,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,43,32,105,32,43,32,34,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,118,97,108,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,114,101,110,100,101,114,95,104,101,120,40,118,97,108,44,32,122,112,44,32,105,112,114,101,99,44,32,99,102,108,97,103,115,46,98,108,97,110,107,44,32,99,102,108,97,103,115,46,115,105,103,110,44,32,99,102,108,97,103,115,46,97,108,116,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,100,101,46,99,97,112,115,41,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,111,100,101,46,99,116,121,112,101,32,61,61,32,34,102,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,118,97,108,41,32,33,61,32,34,110,117,109,98,101,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,70,111,114,109,97,116,32,114,101,113,117,105,114,101,100,32,110,117,109,98,101,114,32,97,116,32,34,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,43,32,105,32,43,32,34,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,118,97,108,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,114,101,110,100,101,114,95,102,108,111,97,116,95,100,101,99,40,118,97,108,44,32,122,112,44,32,99,102,108,97,103,115,46,98,108,97,110,107,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,102,108,97,103,115,46,115,105,103,110,44,32,99,102,108,97,103,115,46,97,108,116,44,32,116,114,117,101,44,32,102,112,112,114,101,99,41,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,111,100,101,46,99,116,121,112,101,32,61,61,32,34,101,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,118,97,108,41,32,33,61,32,34,110,117,109,98,101,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,70,111,114,109,97,116,32,114,101,113,117,105,114,101,100,32,110,117,109,98,101,114,32,97,116,32,34,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,43,32,105,32,43,32,34,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,118,97,108,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,114,101,110,100,101,114,95,102,108,111,97,116,95,115,99,105,40,118,97,108,44,32,122,112,44,32,99,102,108,97,103,115,46,98,108,97,110,107,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,102,108,97,103,115,46,115,105,103,110,44,32,99,102,108,97,103,115,46,97,108,116,44,32,116,114,117,101,44,32,99,111,100,101,46,99,97,112,115,44,32,102,112,112,114,101,99,41,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,111,100,101,46,99,116,121,112,101,32,61,61,32,34,103,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,118,97,108,41,32,33,61,32,34,110,117,109,98,101,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,70,111,114,109,97,116,32,114,101,113,117,105,114,101,100,32,110,117,109,98,101,114,32,97,116,32,34,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,43,32,105,32,43,32,34,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,118,97,108,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,101,120,112,111,110,101,110,116,32,61,32,115,116,100,46,102,108,111,111,114,40,115,116,100,46,108,111,103,40,115,116,100,46,97,98,115,40,118,97,108,41,41,32,47,32,115,116,100,46,108,111,103,40,49,48,41,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,101,120,112,111,110,101,110,116,32,60,32,45,52,32,124,124,32,101,120,112,111,110,101,110,116,32,62,61,32,102,112,112,114,101,99,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,114,101,110,100,101,114,95,102,108,111,97,116,95,115,99,105,40,118,97,108,44,32,122,112,44,32,99,102,108,97,103,115,46,98,108,97,110,107,44,32,99,102,108,97,103,115,46,115,105,103,110,44,32,99,102,108,97,103,115,46,97,108,116,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,102,108,97,103,115,46,97,108,116,44,32,99,111,100,101,46,99,97,112,115,44,32,102,112,112,114,101,99,32,45,32,49,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,100,105,103,105,116,115,95,98,101,102,111,114,101,95,112,116,32,61,32,115,116,100,46,109,97,120,40,49,44,32,101,120,112,111,110,101,110,116,32,43,32,49,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,114,101,110,100,101,114,95,102,108,111,97,116,95,100,101,99,40,118,97,108,44,32,122,112,44,32,99,102,108,97,103,115,46,98,108,97,110,107,44,32,99,102,108,97,103,115,46,115,105,103,110,44,32,99,102,108,97,103,115,46,97,108,116,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,102,108,97,103,115,46,97,108,116,44,32,102,112,112,114,101,99,32,45,32,100,105,103,105,116,115,95,98,101,102,111,114,101,95,112,116,41,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,111,100,101,46,99,116,121,112,101,32,61,61,32,34,99,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,118,97,108,41,32,61,61,32,34,110,117,109,98,101,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,99,104,97,114,40,118,97,108,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,118,97,108,41,32,61,61,32,34,115,116,114,105,110,103,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,108,101,110,103,116,104,40,118,97,108,41,32,61,61,32,49,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,118,97,108,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,37,99,32,101,120,112,101,99,116,101,100,32,49,45,115,105,122,101,100,32,115,116,114,105,110,103,32,103,111,116,58,32,34,32,43,32,115,116,100,46,108,101,110,103,116,104,40,118,97,108,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,37,99,32,101,120,112,101,99,116,101,100,32,110,117,109,98,101,114,32,47,32,115,116,114,105,110,103,44,32,103,111,116,58,32,34,32,43,32,115,116,100,46,116,121,112,101,40,118,97,108,41,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,85,110,107,110,111,119,110,32,99,111,100,101,58,32,34,32,43,32,99,111,100,101,46,99,116,121,112,101,59,10,10,32,32,32,32,32,32,32,32,47,47,32,82,101,110,100,101,114,32,97,32,112,97,114,115,101,100,32,102,111,114,109,97,116,32,115,116,114,105,110,103,32,119,105,116,104,32,97,110,32,97,114,114,97,121,32,111,102,32,118,97,108,117,101,115,46,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,102,111,114,109,97,116,95,99,111,100,101,115,95,97,114,114,40,99,111,100,101,115,44,32,97,114,114,44,32,105,44,32,106,44,32,118,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,99,111,100,101,115,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,106,32,60,32,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,40,34,84,111,111,32,109,97,110,121,32,118,97,108,117,101,115,32,116,111,32,102,111,114,109,97,116,58,32,34,32,43,32,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,32,43,32,34,44,32,101,120,112,101,99,116,101,100,32,34,32,43,32,106,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,118,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,111,100,101,32,61,32,99,111,100,101,115,91,105,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,99,111,100,101,41,32,61,61,32,34,115,116,114,105,110,103,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,102,111,114,109,97,116,95,99,111,100,101,115,95,97,114,114,40,99,111,100,101,115,44,32,97,114,114,44,32,105,32,43,32,49,44,32,106,44,32,118,32,43,32,99,111,100,101,41,32,116,97,105,108,115,116,114,105,99,116,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,116,109,112,32,61,32,105,102,32,99,111,100,101,46,102,119,32,61,61,32,34,42,34,32,116,104,101,110,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,106,58,32,106,32,43,32,49,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,102,119,58,32,105,102,32,106,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,78,111,116,32,101,110,111,117,103,104,32,118,97,108,117,101,115,32,116,111,32,102,111,114,109,97,116,58,32,34,32,43,32,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,114,114,91,106,93,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,125,32,101,108,115,101,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,106,58,32,106,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,102,119,58,32,99,111,100,101,46,102,119,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,125,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,116,109,112,50,32,61,32,105,102,32,99,111,100,101,46,112,114,101,99,32,61,61,32,34,42,34,32,116,104,101,110,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,106,58,32,116,109,112,46,106,32,43,32,49,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,112,114,101,99,58,32,105,102,32,116,109,112,46,106,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,78,111,116,32,101,110,111,117,103,104,32,118,97,108,117,101,115,32,116,111,32,102,111,114,109,97,116,58,32,34,32,43,32,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,114,114,91,116,109,112,46,106,93,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,125,32,101,108,115,101,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,106,58,32,116,109,112,46,106,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,112,114,101,99,58,32,99,111,100,101,46,112,114,101,99,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,125,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,106,50,32,61,32,116,109,112,50,46,106,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,118,97,108,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,106,50,32,60,32,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,114,114,91,106,50,93,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,78,111,116,32,101,110,111,117,103,104,32,118,97,108,117,101,115,32,116,111,32,102,111,114,109,97,116,44,32,103,111,116,32,34,32,43,32,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,115,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,111,100,101,46,99,116,121,112,101,32,61,61,32,34,37,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,37,34,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,102,111,114,109,97,116,95,99,111,100,101,40,118,97,108,44,32,99,111,100,101,44,32,116,109,112,46,102,119,44,32,116,109,112,50,46,112,114,101,99,44,32,106,50,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,115,95,112,97,100,100,101,100,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,111,100,101,46,99,102,108,97,103,115,46,108,101,102,116,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,112,97,100,95,114,105,103,104,116,40,115,44,32,116,109,112,46,102,119,44,32,34,32,34,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,112,97,100,95,108,101,102,116,40,115,44,32,116,109,112,46,102,119,44,32,34,32,34,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,106,51,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,111,100,101,46,99,116,121,112,101,32,61,61,32,34,37,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,106,50,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,106,50,32,43,32,49,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,102,111,114,109,97,116,95,99,111,100,101,115,95,97,114,114,40,99,111,100,101,115,44,32,97,114,114,44,32,105,32,43,32,49,44,32,106,51,44,32,118,32,43,32,115,95,112,97,100,100,101,100,41,32,116,97,105,108,115,116,114,105,99,116,59,10,10,32,32,32,32,32,32,32,32,47,47,32,82,101,110,100,101,114,32,97,32,112,97,114,115,101,100,32,102,111,114,109,97,116,32,115,116,114,105,110,103,32,119,105,116,104,32,97,110,32,111,98,106,101,99,116,32,111,102,32,118,97,108,117,101,115,46,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,102,111,114,109,97,116,95,99,111,100,101,115,95,111,98,106,40,99,111,100,101,115,44,32,111,98,106,44,32,105,44,32,118,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,99,111,100,101,115,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,118,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,111,100,101,32,61,32,99,111,100,101,115,91,105,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,99,111,100,101,41,32,61,61,32,34,115,116,114,105,110,103,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,102,111,114,109,97,116,95,99,111,100,101,115,95,111,98,106,40,99,111,100,101,115,44,32,111,98,106,44,32,105,32,43,32,49,44,32,118,32,43,32,99,111,100,101,41,32,116,97,105,108,115,116,114,105,99,116,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,102,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,111,100,101,46,109,107,101,121,32,61,61,32,110,117,108,108,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,77,97,112,112,105,110,103,32,107,101,121,115,32,114,101,113,117,105,114,101,100,46,34,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,100,101,46,109,107,101,121,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,102,119,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,111,100,101,46,102,119,32,61,61,32,34,42,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,67,97,110,110,111,116,32,117,115,101,32,42,32,102,105,101,108,100,32,119,105,100,116,104,32,119,105,116,104,32,111,98,106,101,99,116,46,34,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,100,101,46,102,119,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,112,114,101,99,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,111,100,101,46,112,114,101,99,32,61,61,32,34,42,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,67,97,110,110,111,116,32,117,115,101,32,42,32,112,114,101,99,105,115,105,111,110,32,119,105,116,104,32,111,98,106,101,99,116,46,34,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,111,100,101,46,112,114,101,99,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,118,97,108,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,111,98,106,101,99,116,72,97,115,65,108,108,40,111,98,106,44,32,102,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,111,98,106,91,102,93,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,78,111,32,115,117,99,104,32,102,105,101,108,100,58,32,34,32,43,32,102,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,115,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,111,100,101,46,99,116,121,112,101,32,61,61,32,34,37,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,37,34,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,102,111,114,109,97,116,95,99,111,100,101,40,118,97,108,44,32,99,111,100,101,44,32,102,119,44,32,112,114,101,99,44,32,102,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,115,95,112,97,100,100,101,100,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,111,100,101,46,99,102,108,97,103,115,46,108,101,102,116,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,112,97,100,95,114,105,103,104,116,40,115,44,32,102,119,44,32,34,32,34,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,112,97,100,95,108,101,102,116,40,115,44,32,102,119,44,32,34,32,34,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,102,111,114,109,97,116,95,99,111,100,101,115,95,111,98,106,40,99,111,100,101,115,44,32,111,98,106,44,32,105,32,43,32,49,44,32,118,32,43,32,115,95,112,97,100,100,101,100,41,32,116,97,105,108,115,116,114,105,99,116,59,10,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,118,97,108,115,41,32,61,61,32,34,97,114,114,97,121,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,102,111,114,109,97,116,95,99,111,100,101,115,95,97,114,114,40,99,111,100,101,115,44,32,118,97,108,115,44,32,48,44,32,48,44,32,34,34,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,118,97,108,115,41,32,61,61,32,34,111,98,106,101,99,116,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,102,111,114,109,97,116,95,99,111,100,101,115,95,111,98,106,40,99,111,100,101,115,44,32,118,97,108,115,44,32,48,44,32,34,34,41,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,102,111,114,109,97,116,95,99,111,100,101,115,95,97,114,114,40,99,111,100,101,115,44,32,91,118,97,108,115,93,44,32,48,44,32,48,44,32,34,34,41,44,10,10,32,32,32,32,102,111,108,100,114,40,102,117,110,99,44,32,97,114,114,44,32,105,110,105,116,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,97,117,120,40,102,117,110,99,44,32,97,114,114,44,32,114,117,110,110,105,110,103,44,32,105,100,120,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,100,120,32,60,32,48,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,114,117,110,110,105,110,103,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,102,117,110,99,44,32,97,114,114,44,32,102,117,110,99,40,97,114,114,91,105,100,120,93,44,32,114,117,110,110,105,110,103,41,44,32,105,100,120,32,45,32,49,41,32,116,97,105,108,115,116,114,105,99,116,59,10,32,32,32,32,32,32,32,32,97,117,120,40,102,117,110,99,44,32,97,114,114,44,32,105,110,105,116,44,32,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,32,45,32,49,41,44,10,10,32,32,32,32,102,111,108,100,108,40,102,117,110,99,44,32,97,114,114,44,32,105,110,105,116,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,97,117,120,40,102,117,110,99,44,32,97,114,114,44,32,114,117,110,110,105,110,103,44,32,105,100,120,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,100,120,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,114,117,110,110,105,110,103,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,102,117,110,99,44,32,97,114,114,44,32,102,117,110,99,40,114,117,110,110,105,110,103,44,32,97,114,114,91,105,100,120,93,41,44,32,105,100,120,32,43,32,49,41,32,116,97,105,108,115,116,114,105,99,116,59,10,32,32,32,32,32,32,32,32,97,117,120,40,102,117,110,99,44,32,97,114,114,44,32,105,110,105,116,44,32,48,41,44,10,10,10,32,32,32,32,102,105,108,116,101,114,77,97,112,40,102,105,108,116,101,114,95,102,117,110,99,44,32,109,97,112,95,102,117,110,99,44,32,97,114,114,41,58,58,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,102,105,108,116,101,114,95,102,117,110,99,41,32,33,61,32,34,102,117,110,99,116,105,111,110,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,40,34,115,116,100,46,102,105,108,116,101,114,77,97,112,32,102,105,114,115,116,32,112,97,114,97,109,32,109,117,115,116,32,98,101,32,102,117,110,99,116,105,111,110,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,102,105,108,116,101,114,95,102,117,110,99,41,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,109,97,112,95,102,117,110,99,41,32,33,61,32,34,102,117,110,99,116,105,111,110,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,40,34,115,116,100,46,102,105,108,116,101,114,77,97,112,32,115,101,99,111,110,100,32,112,97,114,97,109,32,109,117,115,116,32,98,101,32,102,117,110,99,116,105,111,110,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,109,97,112,95,102,117,110,99,41,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,97,114,114,41,32,33,61,32,34,97,114,114,97,121,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,40,34,115,116,100,46,102,105,108,116,101,114,77,97,112,32,116,104,105,114,100,32,112,97,114,97,109,32,109,117,115,116,32,98,101,32,97,114,114,97,121,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,97,114,114,41,41,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,109,97,112,40,109,97,112,95,102,117,110,99,44,32,115,116,100,46,102,105,108,116,101,114,40,102,105,108,116,101,114,95,102,117,110,99,44,32,97,114,114,41,41,44,10,10,32,32,32,32,97,115,115,101,114,116,69,113,117,97,108,40,97,44,32,98,41,58,58,10,32,32,32,32,32,32,32,32,105,102,32,97,32,61,61,32,98,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,116,114,117,101,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,65,115,115,101,114,116,105,111,110,32,102,97,105,108,101,100,46,32,34,32,43,32,97,32,43,32,34,32,33,61,32,34,32,43,32,98,44,10,10,32,32,32,32,97,98,115,40,110,41,58,58,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,110,41,32,33,61,32,34,110,117,109,98,101,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,115,116,100,46,97,98,115,32,101,120,112,101,99,116,101,100,32,110,117,109,98,101,114,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,110,41,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,110,32,62,32,48,32,116,104,101,110,32,110,32,101,108,115,101,32,45,110,44,10,10,32,32,32,32,109,97,120,40,97,44,32,98,41,58,58,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,97,41,32,33,61,32,34,110,117,109,98,101,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,115,116,100,46,109,97,120,32,102,105,114,115,116,32,112,97,114,97,109,32,101,120,112,101,99,116,101,100,32,110,117,109,98,101,114,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,97,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,98,41,32,33,61,32,34,110,117,109,98,101,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,115,116,100,46,109,97,120,32,115,101,99,111,110,100,32,112,97,114,97,109,32,101,120,112,101,99,116,101,100,32,110,117,109,98,101,114,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,98,41,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,97,32,62,32,98,32,116,104,101,110,32,97,32,101,108,115,101,32,98,44,10,10,32,32,32,32,109,105,110,40,97,44,32,98,41,58,58,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,97,41,32,33,61,32,34,110,117,109,98,101,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,115,116,100,46,109,97,120,32,102,105,114,115,116,32,112,97,114,97,109,32,101,120,112,101,99,116,101,100,32,110,117,109,98,101,114,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,97,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,98,41,32,33,61,32,34,110,117,109,98,101,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,115,116,100,46,109,97,120,32,115,101,99,111,110,100,32,112,97,114,97,109,32,101,120,112,101,99,116,101,100,32,110,117,109,98,101,114,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,98,41,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,97,32,60,32,98,32,116,104,101,110,32,97,32,101,108,115,101,32,98,44,10,10,32,32,32,32,102,108,97,116,116,101,110,65,114,114,97,121,115,40,97,114,114,115,41,58,58,10,32,32,32,32,32,32,32,32,115,116,100,46,102,111,108,100,108,40,102,117,110,99,116,105,111,110,40,97,44,32,98,41,32,97,32,43,32,98,44,32,97,114,114,115,44,32,91,93,41,44,10,10,32,32,32,32,109,97,110,105,102,101,115,116,73,110,105,40,105,110,105,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,98,111,100,121,95,108,105,110,101,115,40,98,111,100,121,41,32,61,32,91,34,37,115,32,61,32,37,115,34,32,37,32,91,107,44,32,98,111,100,121,91,107,93,93,32,102,111,114,32,107,32,105,110,32,115,116,100,46,111,98,106,101,99,116,70,105,101,108,100,115,40,98,111,100,121,41,93,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,101,99,116,105,111,110,95,108,105,110,101,115,40,115,110,97,109,101,44,32,115,98,111,100,121,41,32,61,32,91,34,91,37,115,93,34,32,37,32,91,115,110,97,109,101,93,93,32,43,32,98,111,100,121,95,108,105,110,101,115,40,115,98,111,100,121,41,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,109,97,105,110,95,98,111,100,121,32,61,32,105,102,32,115,116,100,46,111,98,106,101,99,116,72,97,115,40,105,110,105,44,32,34,109,97,105,110,34,41,32,116,104,101,110,32,98,111,100,121,95,108,105,110,101,115,40,105,110,105,46,109,97,105,110,41,32,101,108,115,101,32,91,93,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,108,108,95,115,101,99,116,105,111,110,115,32,61,32,91,115,101,99,116,105,111,110,95,108,105,110,101,115,40,107,44,32,105,110,105,46,115,101,99,116,105,111,110,115,91,107,93,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,102,111,114,32,107,32,105,110,32,115,116,100,46,111,98,106,101,99,116,70,105,101,108,100,115,40,105,110,105,46,115,101,99,116,105,111,110,115,41,93,59,10,32,32,32,32,32,32,32,32,115,116,100,46,106,111,105,110,40,34,92,110,34,44,32,109,97,105,110,95,98,111,100,121,32,43,32,115,116,100,46,102,108,97,116,116,101,110,65,114,114,97,121,115,40,97,108,108,95,115,101,99,116,105,111,110,115,41,32,43,32,91,34,34,93,41,44,10,10,32,32,32,32,101,115,99,97,112,101,83,116,114,105,110,103,74,115,111,110,40,115,116,114,95,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,115,116,114,32,61,32,115,116,100,46,116,111,83,116,114,105,110,103,40,115,116,114,95,41,59,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,116,114,97,110,115,40,99,104,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,104,32,61,61,32,34,92,34,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,92,92,92,34,34,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,104,32,61,61,32,34,92,92,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,92,92,92,92,34,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,104,32,61,61,32,34,92,98,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,92,92,98,34,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,104,32,61,61,32,34,92,102,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,92,92,102,34,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,104,32,61,61,32,34,92,110,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,92,92,110,34,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,104,32,61,61,32,34,92,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,92,92,114,34,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,99,104,32,61,61,32,34,92,116,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,92,92,116,34,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,99,112,32,61,32,115,116,100,46,99,111,100,101,112,111,105,110,116,40,99,104,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,112,32,60,32,51,50,32,124,124,32,40,99,112,32,62,61,32,49,50,54,32,38,38,32,99,112,32,60,61,32,49,53,57,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,92,92,117,37,48,52,120,34,32,37,32,91,99,112,93,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,104,59,10,32,32,32,32,32,32,32,32,34,92,34,37,115,92,34,34,32,37,32,115,116,100,46,106,111,105,110,40,34,34,44,32,91,116,114,97,110,115,40,99,104,41,32,102,111,114,32,99,104,32,105,110,32,115,116,100,46,115,116,114,105,110,103,67,104,97,114,115,40,115,116,114,41,93,41,44,10,10,32,32,32,32,101,115,99,97,112,101,83,116,114,105,110,103,80,121,116,104,111,110,40,115,116,114,41,58,58,10,32,32,32,32,32,32,32,32,115,116,100,46,101,115,99,97,112,101,83,116,114,105,110,103,74,115,111,110,40,115,116,114,41,44,10,10,32,32,32,32,101,115,99,97,112,101,83,116,114,105,110,103,66,97,115,104,40,115,116,114,95,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,115,116,114,32,61,32,115,116,100,46,116,111,83,116,114,105,110,103,40,115,116,114,95,41,59,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,116,114,97,110,115,40,99,104,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,104,32,61,61,32,34,39,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,39,92,34,39,92,34,39,34,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,104,59,10,32,32,32,32,32,32,32,32,34,39,37,115,39,34,32,37,32,115,116,100,46,106,111,105,110,40,34,34,44,32,91,116,114,97,110,115,40,99,104,41,32,102,111,114,32,99,104,32,105,110,32,115,116,100,46,115,116,114,105,110,103,67,104,97,114,115,40,115,116,114,41,93,41,44,10,10,32,32,32,32,101,115,99,97,112,101,83,116,114,105,110,103,68,111,108,108,97,114,115,40,115,116,114,95,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,115,116,114,32,61,32,115,116,100,46,116,111,83,116,114,105,110,103,40,115,116,114,95,41,59,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,116,114,97,110,115,40,99,104,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,99,104,32,61,61,32,34,36,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,36,36,34,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,104,59,10,32,32,32,32,32,32,32,32,115,116,100,46,102,111,108,100,108,40,102,117,110,99,116,105,111,110,40,97,44,32,98,41,32,97,32,43,32,116,114,97,110,115,40,98,41,44,32,115,116,100,46,115,116,114,105,110,103,67,104,97,114,115,40,115,116,114,41,44,32,34,34,41,44,10,10,32,32,32,32,109,97,110,105,102,101,115,116,74,115,111,110,40,118,97,108,117,101,41,58,58,32,115,116,100,46,109,97,110,105,102,101,115,116,74,115,111,110,69,120,40,118,97,108,117,101,44,32,34,32,32,32,32,34,41,44,10,10,32,32,32,32,109,97,110,105,102,101,115,116,74,115,111,110,69,120,40,118,97,108,117,101,44,32,105,110,100,101,110,116,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,97,117,120,40,118,44,32,112,97,116,104,44,32,99,105,110,100,101,110,116,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,118,32,61,61,32,116,114,117,101,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,116,114,117,101,34,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,118,32,61,61,32,102,97,108,115,101,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,102,97,108,115,101,34,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,118,32,61,61,32,110,117,108,108,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,110,117,108,108,34,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,118,41,32,61,61,32,34,110,117,109,98,101,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,34,32,43,32,118,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,118,41,32,61,61,32,34,115,116,114,105,110,103,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,101,115,99,97,112,101,83,116,114,105,110,103,74,115,111,110,40,118,41,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,118,41,32,61,61,32,34,102,117,110,99,116,105,111,110,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,84,114,105,101,100,32,116,111,32,109,97,110,105,102,101,115,116,32,102,117,110,99,116,105,111,110,32,97,116,32,34,32,43,32,112,97,116,104,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,118,41,32,61,61,32,34,97,114,114,97,121,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,114,97,110,103,101,32,61,32,115,116,100,46,114,97,110,103,101,40,48,44,32,115,116,100,46,108,101,110,103,116,104,40,118,41,32,45,32,49,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,110,101,119,95,105,110,100,101,110,116,32,61,32,99,105,110,100,101,110,116,32,43,32,105,110,100,101,110,116,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,108,105,110,101,115,32,61,32,91,34,91,92,110,34,93,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,43,32,115,116,100,46,106,111,105,110,40,91,34,44,92,110,34,93,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,91,91,110,101,119,95,105,110,100,101,110,116,32,43,32,97,117,120,40,118,91,105,93,44,32,112,97,116,104,32,43,32,91,105,93,44,32,110,101,119,95,105,110,100,101,110,116,41,93,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,102,111,114,32,105,32,105,110,32,114,97,110,103,101,93,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,43,32,91,34,92,110,34,32,43,32,99,105,110,100,101,110,116,32,43,32,34,93,34,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,106,111,105,110,40,34,34,44,32,108,105,110,101,115,41,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,118,41,32,61,61,32,34,111,98,106,101,99,116,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,108,105,110,101,115,32,61,32,91,34,123,92,110,34,93,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,43,32,115,116,100,46,106,111,105,110,40,91,34,44,92,110,34,93,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,91,91,99,105,110,100,101,110,116,32,43,32,105,110,100,101,110,116,32,43,32,34,92,34,34,32,43,32,107,32,43,32,34,92,34,58,32,34,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,43,32,97,117,120,40,118,91,107,93,44,32,112,97,116,104,32,43,32,91,107,93,44,32,99,105,110,100,101,110,116,32,43,32,105,110,100,101,110,116,41,93,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,102,111,114,32,107,32,105,110,32,115,116,100,46,111,98,106,101,99,116,70,105,101,108,100,115,40,118,41,93,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,43,32,91,34,92,110,34,32,43,32,99,105,110,100,101,110,116,32,43,32,34,125,34,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,106,111,105,110,40,34,34,44,32,108,105,110,101,115,41,59,10,32,32,32,32,32,32,32,32,97,117,120,40,118,97,108,117,101,44,32,91,93,44,32,34,34,41,44,10,10,32,32,32,32,109,97,110,105,102,101,115,116,89,97,109,108,83,116,114,101,97,109,40,118,97,108,117,101,41,58,58,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,118,97,108,117,101,41,32,33,61,32,34,97,114,114,97,121,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,109,97,110,105,102,101,115,116,89,97,109,108,83,116,114,101,97,109,32,111,110,108,121,32,116,97,107,101,115,32,97,114,114,97,121,115,44,32,103,111,116,32,34,32,43,32,115,116,100,46,116,121,112,101,40,118,97,108,117,101,41,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,34,45,45,45,92,110,34,32,43,32,115,116,100,46,106,111,105,110,40,34,92,110,45,45,45,92,110,34,44,32,91,115,116,100,46,109,97,110,105,102,101,115,116,74,115,111,110,40,101,41,32,102,111,114,32,101,32,105,110,32,118,97,108,117,101,93,41,32,43,32,39,92,110,46,46,46,92,110,39,44,10,10,10,32,32,32,32,109,97,110,105,102,101,115,116,80,121,116,104,111,110,40,111,41,58,58,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,111,41,32,61,61,32,34,111,98,106,101,99,116,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,102,105,101,108,100,115,32,61,32,91,34,37,115,58,32,37,115,34,32,37,32,91,115,116,100,46,101,115,99,97,112,101,83,116,114,105,110,103,80,121,116,104,111,110,40,107,41,44,32,115,116,100,46,109,97,110,105,102,101,115,116,80,121,116,104,111,110,40,111,91,107,93,41,93,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,102,111,114,32,107,32,105,110,32,115,116,100,46,111,98,106,101,99,116,70,105,101,108,100,115,40,111,41,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,34,123,37,115,125,34,32,37,32,91,115,116,100,46,106,111,105,110,40,34,44,32,34,44,32,102,105,101,108,100,115,41,93,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,111,41,32,61,61,32,34,97,114,114,97,121,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,34,91,37,115,93,34,32,37,32,91,115,116,100,46,106,111,105,110,40,34,44,32,34,44,32,91,115,116,100,46,109,97,110,105,102,101,115,116,80,121,116,104,111,110,40,111,50,41,32,102,111,114,32,111,50,32,105,110,32,111,93,41,93,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,111,41,32,61,61,32,34,115,116,114,105,110,103,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,34,37,115,34,32,37,32,91,115,116,100,46,101,115,99,97,112,101,83,116,114,105,110,103,80,121,116,104,111,110,40,111,41,93,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,111,41,32,61,61,32,34,102,117,110,99,116,105,111,110,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,99,97,110,110,111,116,32,109,97,110,105,102,101,115,116,32,102,117,110,99,116,105,111,110,34,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,116,121,112,101,40,111,41,32,61,61,32,34,110,117,109,98,101,114,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,116,111,83,116,114,105,110,103,40,111,41,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,111,32,61,61,32,116,114,117,101,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,34,84,114,117,101,34,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,111,32,61,61,32,102,97,108,115,101,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,34,70,97,108,115,101,34,10,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,111,32,61,61,32,110,117,108,108,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,34,78,111,110,101,34,44,10,10,32,32,32,32,109,97,110,105,102,101,115,116,80,121,116,104,111,110,86,97,114,115,40,99,111,110,102,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,118,97,114,115,32,61,32,91,34,37,115,32,61,32,37,115,34,32,37,32,91,107,44,32,115,116,100,46,109,97,110,105,102,101,115,116,80,121,116,104,111,110,40,99,111,110,102,91,107,93,41,93,32,102,111,114,32,107,32,105,110,32,115,116,100,46,111,98,106,101,99,116,70,105,101,108,100,115,40,99,111,110,102,41,93,59,10,32,32,32,32,32,32,32,32,115,116,100,46,106,111,105,110,40,34,92,110,34,44,32,118,97,114,115,32,43,32,91,34,34,93,41,44,10,10,10,32,32,32,32,108,111,99,97,108,32,98,97,115,101,54,52,95,116,97,98,108,101,32,61,32,34,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,48,49,50,51,52,53,54,55,56,57,43,47,34,44,10,32,32,32,32,108,111,99,97,108,32,98,97,115,101,54,52,95,105,110,118,32,61,32,123,32,91,98,97,115,101,54,52,95,116,97,98,108,101,91,105,93,93,58,32,105,32,102,111,114,32,105,32,105,110,32,115,116,100,46,114,97,110,103,101,40,48,44,32,54,51,41,32,125,44,10,10,32,32,32,32,98,97,115,101,54,52,40,105,110,112,117,116,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,98,121,116,101,115,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,105,110,112,117,116,41,32,61,61,32,34,115,116,114,105,110,103,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,109,97,112,40,102,117,110,99,116,105,111,110,40,99,41,32,115,116,100,46,99,111,100,101,112,111,105,110,116,40,99,41,44,32,105,110,112,117,116,41,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,110,112,117,116,59,10,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,97,117,120,40,97,114,114,44,32,105,44,32,114,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,114,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,105,32,43,32,49,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,115,116,114,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,47,47,32,54,32,77,83,66,32,111,102,32,105,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,98,97,115,101,54,52,95,116,97,98,108,101,91,40,97,114,114,91,105,93,32,38,32,50,53,50,41,32,62,62,32,50,93,32,43,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,47,47,32,50,32,76,83,66,32,111,102,32,105,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,98,97,115,101,54,52,95,116,97,98,108,101,91,40,97,114,114,91,105,93,32,38,32,51,41,32,60,60,32,52,93,32,43,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,61,61,34,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,114,114,44,32,105,32,43,32,51,44,32,114,32,43,32,115,116,114,41,32,116,97,105,108,115,116,114,105,99,116,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,105,32,43,32,50,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,115,116,114,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,47,47,32,54,32,77,83,66,32,111,102,32,105,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,98,97,115,101,54,52,95,116,97,98,108,101,91,40,97,114,114,91,105,93,32,38,32,50,53,50,41,32,62,62,32,50,93,32,43,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,47,47,32,50,32,76,83,66,32,111,102,32,105,44,32,52,32,77,83,66,32,111,102,32,105,43,49,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,98,97,115,101,54,52,95,116,97,98,108,101,91,40,97,114,114,91,105,93,32,38,32,51,41,32,60,60,32,52,32,124,32,40,97,114,114,91,105,32,43,32,49,93,32,38,32,50,52,48,41,32,62,62,32,52,93,32,43,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,47,47,32,52,32,76,83,66,32,111,102,32,105,43,49,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,98,97,115,101,54,52,95,116,97,98,108,101,91,40,97,114,114,91,105,32,43,32,49,93,32,38,32,49,53,41,32,60,60,32,50,93,32,43,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,61,34,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,114,114,44,32,105,32,43,32,51,44,32,114,32,43,32,115,116,114,41,32,116,97,105,108,115,116,114,105,99,116,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,115,116,114,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,47,47,32,54,32,77,83,66,32,111,102,32,105,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,98,97,115,101,54,52,95,116,97,98,108,101,91,40,97,114,114,91,105,93,32,38,32,50,53,50,41,32,62,62,32,50,93,32,43,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,47,47,32,50,32,76,83,66,32,111,102,32,105,44,32,52,32,77,83,66,32,111,102,32,105,43,49,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,98,97,115,101,54,52,95,116,97,98,108,101,91,40,97,114,114,91,105,93,32,38,32,51,41,32,60,60,32,52,32,124,32,40,97,114,114,91,105,32,43,32,49,93,32,38,32,50,52,48,41,32,62,62,32,52,93,32,43,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,47,47,32,52,32,76,83,66,32,111,102,32,105,43,49,44,32,50,32,77,83,66,32,111,102,32,105,43,50,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,98,97,115,101,54,52,95,116,97,98,108,101,91,40,97,114,114,91,105,32,43,32,49,93,32,38,32,49,53,41,32,60,60,32,50,32,124,32,40,97,114,114,91,105,32,43,32,50,93,32,38,32,49,57,50,41,32,62,62,32,54,93,32,43,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,47,47,32,54,32,76,83,66,32,111,102,32,105,43,50,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,98,97,115,101,54,52,95,116,97,98,108,101,91,40,97,114,114,91,105,32,43,32,50,93,32,38,32,54,51,41,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,114,114,44,32,105,32,43,32,51,44,32,114,32,43,32,115,116,114,41,32,116,97,105,108,115,116,114,105,99,116,59,10,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,115,97,110,105,116,121,32,61,32,115,116,100,46,102,111,108,100,108,40,102,117,110,99,116,105,111,110,40,114,44,32,97,41,32,114,32,38,38,32,40,97,32,60,32,50,53,54,41,44,32,98,121,116,101,115,44,32,116,114,117,101,41,59,10,32,32,32,32,32,32,32,32,105,102,32,33,115,97,110,105,116,121,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,67,97,110,32,111,110,108,121,32,98,97,115,101,54,52,32,101,110,99,111,100,101,32,115,116,114,105,110,103,115,32,47,32,97,114,114,97,121,115,32,111,102,32,115,105,110,103,108,101,32,98,121,116,101,115,46,34,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,98,121,116,101,115,44,32,48,44,32,34,34,41,44,10,10,10,32,32,32,32,98,97,115,101,54,52,68,101,99,111,100,101,66,121,116,101,115,40,115,116,114,41,58,58,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,108,101,110,103,116,104,40,115,116,114,41,32,37,32,52,32,33,61,32,48,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,32,34,78,111,116,32,97,32,98,97,115,101,54,52,32,101,110,99,111,100,101,100,32,115,116,114,105,110,103,32,92,34,37,115,92,34,34,32,37,32,115,116,114,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,97,117,120,40,115,116,114,44,32,105,44,32,114,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,115,116,114,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,114,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,47,47,32,97,108,108,32,54,32,98,105,116,115,32,111,102,32,105,44,32,50,32,77,83,66,32,111,102,32,105,43,49,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,110,49,32,61,32,91,98,97,115,101,54,52,95,105,110,118,91,115,116,114,91,105,93,93,32,60,60,32,50,32,124,32,40,98,97,115,101,54,52,95,105,110,118,91,115,116,114,91,105,32,43,32,49,93,93,32,62,62,32,52,41,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,47,47,32,52,32,76,83,66,32,111,102,32,105,43,49,44,32,52,77,83,66,32,111,102,32,105,43,50,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,110,50,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,114,91,105,32,43,32,50,93,32,61,61,32,34,61,34,32,116,104,101,110,32,91,93,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,91,40,98,97,115,101,54,52,95,105,110,118,91,115,116,114,91,105,32,43,32,49,93,93,32,38,32,49,53,41,32,60,60,32,52,32,124,32,40,98,97,115,101,54,52,95,105,110,118,91,115,116,114,91,105,32,43,32,50,93,93,32,62,62,32,50,41,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,47,47,32,50,32,76,83,66,32,111,102,32,105,43,50,44,32,97,108,108,32,54,32,98,105,116,115,32,111,102,32,105,43,51,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,110,51,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,114,91,105,32,43,32,51,93,32,61,61,32,34,61,34,32,116,104,101,110,32,91,93,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,91,40,98,97,115,101,54,52,95,105,110,118,91,115,116,114,91,105,32,43,32,50,93,93,32,38,32,51,41,32,60,60,32,54,32,124,32,98,97,115,101,54,52,95,105,110,118,91,115,116,114,91,105,32,43,32,51,93,93,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,115,116,114,44,32,105,32,43,32,52,44,32,114,32,43,32,110,49,32,43,32,110,50,32,43,32,110,51,41,32,116,97,105,108,115,116,114,105,99,116,59,10,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,115,116,114,44,32,48,44,32,91,93,41,44,10,10,32,32,32,32,98,97,115,101,54,52,68,101,99,111,100,101,40,115,116,114,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,98,121,116,101,115,32,61,32,115,116,100,46,98,97,115,101,54,52,68,101,99,111,100,101,66,121,116,101,115,40,115,116,114,41,59,10,32,32,32,32,32,32,32,32,115,116,100,46,106,111,105,110,40,34,34,44,32,115,116,100,46,109,97,112,40,102,117,110,99,116,105,111,110,40,98,41,32,115,116,100,46,99,104,97,114,40,98,41,44,32,98,121,116,101,115,41,41,44,10,10,32,32,32,32,47,47,32,81,117,105,99,107,115,111,114,116,10,32,32,32,32,115,111,114,116,40,97,114,114,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,108,32,61,32,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,59,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,32,61,61,32,48,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,91,93,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,112,105,118,111,116,32,61,32,97,114,114,91,48,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,114,101,115,116,32,61,32,115,116,100,46,109,97,107,101,65,114,114,97,121,40,108,32,45,32,49,44,32,102,117,110,99,116,105,111,110,40,105,41,32,97,114,114,91,105,32,43,32,49,93,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,108,101,102,116,32,61,32,115,116,100,46,102,105,108,116,101,114,40,102,117,110,99,116,105,111,110,40,120,41,32,120,32,60,61,32,112,105,118,111,116,44,32,114,101,115,116,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,114,105,103,104,116,32,61,32,115,116,100,46,102,105,108,116,101,114,40,102,117,110,99,116,105,111,110,40,120,41,32,120,32,62,32,112,105,118,111,116,44,32,114,101,115,116,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,115,111,114,116,40,108,101,102,116,41,32,43,32,91,112,105,118,111,116,93,32,43,32,115,116,100,46,115,111,114,116,40,114,105,103,104,116,41,44,10,10,32,32,32,32,117,110,105,113,40,97,114,114,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,102,40,97,44,32,98,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,108,101,110,103,116,104,40,97,41,32,61,61,32,48,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,91,98,93,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,97,91,115,116,100,46,108,101,110,103,116,104,40,97,41,32,45,32,49,93,32,61,61,32,98,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,32,43,32,91,98,93,59,10,32,32,32,32,32,32,32,32,115,116,100,46,102,111,108,100,108,40,102,44,32,97,114,114,44,32,91,93,41,44,10,10,32,32,32,32,115,101,116,40,97,114,114,41,58,58,10,32,32,32,32,32,32,32,32,115,116,100,46,117,110,105,113,40,115,116,100,46,115,111,114,116,40,97,114,114,41,41,44,10,10,32,32,32,32,115,101,116,77,101,109,98,101,114,40,120,44,32,97,114,114,41,58,58,10,32,32,32,32,32,32,32,32,47,47,32,84,79,68,79,40,100,99,117,110,110,105,110,41,58,32,66,105,110,97,114,121,32,99,104,111,112,32,102,111,114,32,79,40,108,111,103,32,110,41,32,99,111,109,112,108,101,120,105,116,121,10,32,32,32,32,32,32,32,32,115,116,100,46,108,101,110,103,116,104,40,115,116,100,46,115,101,116,73,110,116,101,114,40,91,120,93,44,32,97,114,114,41,41,32,62,32,48,44,10,10,32,32,32,32,115,101,116,85,110,105,111,110,40,97,44,32,98,41,58,58,10,32,32,32,32,32,32,32,32,115,116,100,46,115,101,116,40,97,32,43,32,98,41,44,10,10,32,32,32,32,115,101,116,73,110,116,101,114,40,97,44,32,98,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,97,117,120,40,97,44,32,98,44,32,105,44,32,106,44,32,97,99,99,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,97,41,32,124,124,32,106,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,98,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,99,99,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,97,91,105,93,32,61,61,32,98,91,106,93,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,44,32,98,44,32,105,32,43,32,49,44,32,106,32,43,32,49,44,32,97,99,99,32,43,32,91,97,91,105,93,93,41,32,116,97,105,108,115,116,114,105,99,116,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,97,91,105,93,32,60,32,98,91,106,93,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,44,32,98,44,32,105,32,43,32,49,44,32,106,44,32,97,99,99,41,32,116,97,105,108,115,116,114,105,99,116,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,44,32,98,44,32,105,44,32,106,32,43,32,49,44,32,97,99,99,41,32,116,97,105,108,115,116,114,105,99,116,59,10,32,32,32,32,32,32,32,32,97,117,120,40,97,44,32,98,44,32,48,44,32,48,44,32,91,93,41,32,116,97,105,108,115,116,114,105,99,116,44,10,10,32,32,32,32,115,101,116,68,105,102,102,40,97,44,32,98,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,97,117,120,40,97,44,32,98,44,32,105,44,32,106,44,32,97,99,99,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,97,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,99,99,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,106,32,62,61,32,115,116,100,46,108,101,110,103,116,104,40,98,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,44,32,98,44,32,105,32,43,32,49,44,32,106,44,32,97,99,99,32,43,32,91,97,91,105,93,93,41,32,116,97,105,108,115,116,114,105,99,116,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,97,91,105,93,32,61,61,32,98,91,106,93,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,44,32,98,44,32,105,32,43,32,49,44,32,106,32,43,32,49,44,32,97,99,99,41,32,116,97,105,108,115,116,114,105,99,116,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,97,91,105,93,32,60,32,98,91,106,93,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,44,32,98,44,32,105,32,43,32,49,44,32,106,44,32,97,99,99,32,43,32,91,97,91,105,93,93,41,32,116,97,105,108,115,116,114,105,99,116,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,44,32,98,44,32,105,44,32,106,32,43,32,49,44,32,97,99,99,41,32,116,97,105,108,115,116,114,105,99,116,59,10,32,32,32,32,32,32,32,32,97,117,120,40,97,44,32,98,44,32,48,44,32,48,44,32,91,93,41,32,116,97,105,108,115,116,114,105,99,116,44,10,10,32,32,32,32,109,101,114,103,101,80,97,116,99,104,40,116,97,114,103,101,116,44,32,112,97,116,99,104,41,58,58,10,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,112,97,116,99,104,41,32,61,61,32,34,111,98,106,101,99,116,34,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,116,97,114,103,101,116,95,111,98,106,101,99,116,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,116,97,114,103,101,116,41,32,61,61,32,34,111,98,106,101,99,116,34,32,116,104,101,110,32,116,97,114,103,101,116,32,101,108,115,101,32,123,125,59,10,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,116,97,114,103,101,116,95,102,105,101,108,100,115,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,116,121,112,101,40,116,97,114,103,101,116,95,111,98,106,101,99,116,41,32,61,61,32,34,111,98,106,101,99,116,34,32,116,104,101,110,32,115,116,100,46,111,98,106,101,99,116,70,105,101,108,100,115,40,116,97,114,103,101,116,95,111,98,106,101,99,116,41,32,101,108,115,101,32,91,93,59,10,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,110,117,108,108,95,102,105,101,108,100,115,32,61,32,91,107,32,102,111,114,32,107,32,105,110,32,115,116,100,46,111,98,106,101,99,116,70,105,101,108,100,115,40,112,97,116,99,104,41,32,105,102,32,112,97,116,99,104,91,107,93,32,61,61,32,110,117,108,108,93,59,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,98,111,116,104,95,102,105,101,108,100,115,32,61,32,115,116,100,46,115,101,116,85,110,105,111,110,40,116,97,114,103,101,116,95,102,105,101,108,100,115,44,32,115,116,100,46,111,98,106,101,99,116,70,105,101,108,100,115,40,112,97,116,99,104,41,41,59,10,10,32,32,32,32,32,32,32,32,32,32,32,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,91,107,93,58,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,33,115,116,100,46,111,98,106,101,99,116,72,97,115,40,112,97,116,99,104,44,32,107,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,116,97,114,103,101,116,95,111,98,106,101,99,116,91,107,93,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,33,115,116,100,46,111,98,106,101,99,116,72,97,115,40,116,97,114,103,101,116,95,111,98,106,101,99,116,44,32,107,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,109,101,114,103,101,80,97,116,99,104,40,110,117,108,108,44,32,112,97,116,99,104,91,107,93,41,32,116,97,105,108,115,116,114,105,99,116,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,109,101,114,103,101,80,97,116,99,104,40,116,97,114,103,101,116,95,111,98,106,101,99,116,91,107,93,44,32,112,97,116,99,104,91,107,93,41,32,116,97,105,108,115,116,114,105,99,116,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,102,111,114,32,107,32,105,110,32,115,116,100,46,115,101,116,68,105,102,102,40,98,111,116,104,95,102,105,101,108,100,115,44,32,110,117,108,108,95,102,105,101,108,100,115,41,10,32,32,32,32,32,32,32,32,32,32,32,32,125,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,112,97,116,99,104,44,10,10,32,32,32,32,111,98,106,101,99,116,70,105,101,108,100,115,40,111,41,58,58,10,32,32,32,32,32,32,32,32,115,116,100,46,111,98,106,101,99,116,70,105,101,108,100,115,69,120,40,111,44,32,102,97,108,115,101,41,44,10,10,32,32,32,32,111,98,106,101,99,116,70,105,101,108,100,115,65,108,108,40,111,41,58,58,10,32,32,32,32,32,32,32,32,115,116,100,46,111,98,106,101,99,116,70,105,101,108,100,115,69,120,40,111,44,32,116,114,117,101,41,44,10,10,32,32,32,32,111,98,106,101,99,116,72,97,115,40,111,44,32,102,41,58,58,10,32,32,32,32,32,32,32,32,115,116,100,46,111,98,106,101,99,116,72,97,115,69,120,40,111,44,32,102,44,32,102,97,108,115,101,41,44,10,10,32,32,32,32,111,98,106,101,99,116,72,97,115,65,108,108,40,111,44,32,102,41,58,58,10,32,32,32,32,32,32,32,32,115,116,100,46,111,98,106,101,99,116,72,97,115,69,120,40,111,44,32,102,44,32,116,114,117,101,41,44,10,10,32,32,32,32,101,113,117,97,108,115,40,97,44,32,98,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,116,97,32,61,32,115,116,100,46,116,121,112,101,40,97,41,59,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,116,98,32,61,32,115,116,100,46,116,121,112,101,40,98,41,59,10,32,32,32,32,32,32,32,32,105,102,32,33,115,116,100,46,112,114,105,109,105,116,105,118,101,69,113,117,97,108,115,40,116,97,44,32,116,98,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,102,97,108,115,101,10,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,115,116,100,46,112,114,105,109,105,116,105,118,101,69,113,117,97,108,115,40,116,97,44,32,34,97,114,114,97,121,34,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,108,97,32,61,32,115,116,100,46,108,101,110,103,116,104,40,97,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,33,115,116,100,46,112,114,105,109,105,116,105,118,101,69,113,117,97,108,115,40,108,97,44,32,115,116,100,46,108,101,110,103,116,104,40,98,41,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,102,97,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,97,117,120,40,97,44,32,98,44,32,105,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,32,62,61,32,108,97,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,116,114,117,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,97,91,105,93,32,33,61,32,98,91,105,93,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,102,97,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,44,32,98,44,32,105,32,43,32,49,41,32,116,97,105,108,115,116,114,105,99,116,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,44,32,98,44,32,48,41,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,115,116,100,46,112,114,105,109,105,116,105,118,101,69,113,117,97,108,115,40,116,97,44,32,34,111,98,106,101,99,116,34,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,102,105,101,108,100,115,32,61,32,115,116,100,46,111,98,106,101,99,116,70,105,101,108,100,115,40,97,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,108,102,105,101,108,100,115,32,61,32,115,116,100,46,108,101,110,103,116,104,40,102,105,101,108,100,115,41,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,102,105,101,108,100,115,32,33,61,32,115,116,100,46,111,98,106,101,99,116,70,105,101,108,100,115,40,98,41,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,102,97,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,108,111,99,97,108,32,97,117,120,40,97,44,32,98,44,32,105,41,32,61,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,105,102,32,105,32,62,61,32,108,102,105,101,108,100,115,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,116,114,117,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,32,105,102,32,108,111,99,97,108,32,102,32,61,32,102,105,101,108,100,115,91,105,93,59,32,97,91,102,93,32,33,61,32,98,91,102,93,32,116,104,101,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,102,97,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,44,32,98,44,32,105,32,43,32,49,41,32,116,97,105,108,115,116,114,105,99,116,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,97,117,120,40,97,44,32,98,44,32,48,41,10,32,32,32,32,32,32,32,32,32,32,32,32,101,108,115,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,116,100,46,112,114,105,109,105,116,105,118,101,69,113,117,97,108,115,40,97,44,32,98,41,44,10,10,10,32,32,32,32,114,101,115,111,108,118,101,80,97,116,104,40,102,44,32,114,41,58,58,10,32,32,32,32,32,32,32,32,108,111,99,97,108,32,97,114,114,32,61,32,115,116,100,46,115,112,108,105,116,40,102,44,32,34,47,34,41,59,10,32,32,32,32,32,32,32,32,115,116,100,46,106,111,105,110,40,34,47,34,44,32,115,116,100,46,109,97,107,101,65,114,114,97,121,40,115,116,100,46,108,101,110,103,116,104,40,97,114,114,41,32,45,32,49,44,32,102,117,110,99,116,105,111,110,40,105,41,32,97,114,114,91,105,93,41,32,43,32,91,114,93,41,44,10,10,125,10,0 + diff --git a/vendor/github.com/strickyak/jsonnet_cgo/string_utils.cpp b/vendor/github.com/strickyak/jsonnet_cgo/string_utils.cpp new file mode 100644 index 00000000..03ea9e0b --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/string_utils.cpp @@ -0,0 +1,162 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include + +#include "string_utils.h" +#include "static_error.h" + +String jsonnet_string_unparse(const String &str, bool single) +{ + StringStream ss; + ss << (single ? U'\'' : U'\"'); + ss << jsonnet_string_escape(str, single); + ss << (single ? U'\'' : U'\"'); + return ss.str(); +} + +String jsonnet_string_escape(const String &str, bool single) +{ + StringStream ss; + for (std::size_t i=0 ; i= 0x7f && c <= 0x9f)) { + //Unprintable, use \u + std::stringstream ss8; + ss8 << "\\u" << std::hex << std::setfill('0') << std::setw(4) + << (unsigned long)(c); + ss << decode_utf8(ss8.str()); + } else { + // Printable, write verbatim + ss << c; + } + } + } + } + return ss.str(); +} + + +String jsonnet_string_unescape(const LocationRange &loc, const String &s) +{ + String r; + const char32_t *s_ptr = s.c_str(); + for (const char32_t *c = s_ptr; *c != U'\0' ; ++c) { + switch (*c) { + case '\\': + switch (*(++c)) { + case '"': + case '\'': + r += *c; + break; + + case '\\': + r += *c; + break; + + case '/': + r += *c; + break; + + case 'b': + r += '\b'; + break; + + case 'f': + r += '\f'; + break; + + case 'n': + r += '\n'; + break; + + case 'r': + r += '\r'; + break; + + case 't': + r += '\t'; + break; + + case 'u': { + ++c; // Consume the 'u'. + unsigned long codepoint = 0; + // Expect 4 hex digits. + for (unsigned i=0 ; i<4 ; ++i) { + auto x = (unsigned char)(c[i]); + unsigned digit; + if (x == '\0') { + auto msg = "Truncated unicode escape sequence in string literal."; + throw StaticError(loc, msg); + } else if (x >= '0' && x <= '9') { + digit = x - '0'; + } else if (x >= 'a' && x <= 'f') { + digit = x - 'a' + 10; + } else if (x >= 'A' && x <= 'F') { + digit = x - 'A' + 10; + } else { + std::stringstream ss; + ss << "Malformed unicode escape character, " + << "should be hex: '" << x << "'"; + throw StaticError(loc, ss.str()); + } + codepoint *= 16; + codepoint += digit; + } + + r += codepoint; + + // Leave us on the last char, ready for the ++c at + // the outer for loop. + c += 3; + } + break; + + case '\0': { + auto msg = "Truncated escape sequence in string literal."; + throw StaticError(loc, msg); + } + + default: { + std::stringstream ss; + std::string utf8; + encode_utf8(*c, utf8); + ss << "Unknown escape sequence in string literal: '" << utf8 << "'"; + throw StaticError(loc, ss.str()); + } + } + break; + + default: + // Just a regular letter. + r += *c; + } + } + return r; +} + + diff --git a/vendor/github.com/strickyak/jsonnet_cgo/string_utils.h b/vendor/github.com/strickyak/jsonnet_cgo/string_utils.h new file mode 100644 index 00000000..8916d5a3 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/string_utils.h @@ -0,0 +1,31 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef JSONNET_STRING_H +#define JSONNET_STRING_H + +#include "lexer.h" + +/** Unparse the string. */ +String jsonnet_string_unparse(const String &str, bool single); + +/** Escape special characters. */ +String jsonnet_string_escape(const String &str, bool single); + +/** Resolve escape chracters in the string. */ +String jsonnet_string_unescape(const LocationRange &loc, const String &s); + +#endif diff --git a/vendor/github.com/strickyak/jsonnet_cgo/test1.j b/vendor/github.com/strickyak/jsonnet_cgo/test1.j new file mode 100644 index 00000000..6b4508aa --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/test1.j @@ -0,0 +1,4 @@ +{ + shell: "/bin/sh", + awk: "/usr/bin/awk", +} diff --git a/vendor/github.com/strickyak/jsonnet_cgo/test2.j b/vendor/github.com/strickyak/jsonnet_cgo/test2.j new file mode 100644 index 00000000..dd1aec39 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/test2.j @@ -0,0 +1,5 @@ +local test1 = import "test1.j"; + +test1 { + shell: "/bin/csh", +} diff --git a/vendor/github.com/strickyak/jsonnet_cgo/unicode.h b/vendor/github.com/strickyak/jsonnet_cgo/unicode.h new file mode 100644 index 00000000..ec9596fb --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/unicode.h @@ -0,0 +1,166 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef JSONNET_UNICODE_H +#define JSONNET_UNICODE_H + +/** Substituted when a unicode translation format encoding error is encountered. */ +#define JSONNET_CODEPOINT_ERROR 0xfffd +#define JSONNET_CODEPOINT_MAX 0x110000 + +/** Convert a unicode codepoint to UTF8. + * + * \param x The unicode codepoint. + * \param s The UTF-8 string to append to. + * \returns The number of characters appended. + */ +static inline int encode_utf8(char32_t x, std::string &s) +{ + if (x >= JSONNET_CODEPOINT_MAX) + x = JSONNET_CODEPOINT_ERROR; + + // 00ZZZzzz 00zzYYYY 00Yyyyxx 00xxxxxx + long bytes = ((x & 0x1C0000) << 6) | ((x & 0x03F000) << 4) | ((x & 0x0FC0) << 2) | (x & 0x3F); + + if (x < 0x80) { + s.push_back((char)x); + return 1; + } else if (x < 0x800) { // note that capital 'Y' bits must be 0 + bytes |= 0xC080; + s.push_back((bytes >> 8) & 0xFF); + s.push_back((bytes >> 0) & 0xFF); + return 2; + } else if (x < 0x10000) { // note that 'z' bits must be 0 + bytes |= 0xE08080; + s.push_back((bytes >> 16) & 0xFF); + s.push_back((bytes >> 8) & 0xFF); + s.push_back((bytes >> 0) & 0xFF); + return 3; + } else if (x < 0x110000) { // note that capital 'Z' bits must be 0 + bytes |= 0xF0808080; + s.push_back((bytes >> 24) & 0xFF); + s.push_back((bytes >> 16) & 0xFF); + s.push_back((bytes >> 8) & 0xFF); + s.push_back((bytes >> 0) & 0xFF); + return 4; + } else { + std::cerr << "Should never get here." << std::endl; + abort(); + } +} + +/** Convert the UTF8 byte sequence in the given string to a unicode code point. + * + * \param str The string. + * \param i The index of the string from which to start decoding and returns the index of the last + * byte of the encoded codepoint. + * \returns The decoded unicode codepoint. + */ +static inline char32_t decode_utf8(const std::string &str, size_t &i) +{ + char c0 = str[i]; + if ((c0 & 0x80) == 0) { //0xxxxxxx + return c0; + } else if ((c0 & 0xE0) == 0xC0) { //110yyyxx 10xxxxxx + if (i+1 >= str.length()) { + return JSONNET_CODEPOINT_ERROR; + } + char c1 = str[++i]; + if ((c1 & 0xC0) != 0x80) { + return JSONNET_CODEPOINT_ERROR; + } + return ((c0 & 0x1F) << 6ul) | (c1 & 0x3F); + } else if ((c0 & 0xF0) == 0xE0) { //1110yyyy 10yyyyxx 10xxxxxx + if (i+2 >= str.length()) { + return JSONNET_CODEPOINT_ERROR; + } + char c1 = str[++i]; + if ((c1 & 0xC0) != 0x80) { + return JSONNET_CODEPOINT_ERROR; + } + char c2 = str[++i]; + if ((c2 & 0xC0) != 0x80) { + return JSONNET_CODEPOINT_ERROR; + } + return ((c0 & 0xF) << 12ul) | ((c1 & 0x3F) << 6) | (c2 & 0x3F); + } else if ((c0 & 0xF8) == 0xF0) { //11110zzz 10zzyyyy 10yyyyxx 10xxxxxx + if (i+3 >= str.length()) { + return JSONNET_CODEPOINT_ERROR; + } + char c1 = str[++i]; + if ((c1 & 0xC0) != 0x80) { + return JSONNET_CODEPOINT_ERROR; + } + char c2 = str[++i]; + if ((c2 & 0xC0) != 0x80) { + return JSONNET_CODEPOINT_ERROR; + } + char c3 = str[++i]; + if ((c3 & 0xC0) != 0x80) { + return JSONNET_CODEPOINT_ERROR; + } + return ((c0 & 0x7) << 24ul) | ((c1 & 0x3F) << 12ul) | ((c2 & 0x3F) << 6) | (c3 & 0x3F); + } else { + return JSONNET_CODEPOINT_ERROR; + } +} + +/** A string class capable of holding unicode codepoints. */ +typedef std::basic_string String; + + +static inline void encode_utf8(const String &s, std::string &r) +{ + for (char32_t cp : s) + encode_utf8(cp, r); +} + +static inline std::string encode_utf8(const String &s) +{ + std::string r; + encode_utf8(s, r); + return r; +} + +static inline String decode_utf8(const std::string &s) +{ + String r; + for (size_t i = 0; i < s.length(); ++i) + r.push_back(decode_utf8(s, i)); + return r; +} + +/** A stringstream-like class capable of holding unicode codepoints. + * The C++ standard does not support std::basic_stringstream StringStream &operator << (T c) + { + std::stringstream ss; + ss << c; + for (char c : ss.str()) + buf.push_back(char32_t(c)); + return *this; + } + String str() { return buf; } +}; + +#endif // JSONNET_UNICODE_H diff --git a/vendor/github.com/strickyak/jsonnet_cgo/vm.cpp b/vendor/github.com/strickyak/jsonnet_cgo/vm.cpp new file mode 100644 index 00000000..43c25dfd --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/vm.cpp @@ -0,0 +1,2750 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include +#include + +#include +#include +#include + + +#include "desugarer.h" +#include "json.h" +#include "md5.h" +#include "parser.h" +#include "state.h" +#include "static_analysis.h" +#include "string_utils.h" +#include "vm.h" + +namespace { + +/** Turn a path e.g. "/a/b/c" into a dir, e.g. "/a/b/". If there is no path returns "". + */ +std::string dir_name(const std::string &path) +{ + size_t last_slash = path.rfind('/'); + if (last_slash != std::string::npos) { + return path.substr(0, last_slash+1); + } + return ""; +} + +/** Stack frames. + * + * Of these, FRAME_CALL is the most special, as it is the only frame the stack + * trace (for errors) displays. + */ +enum FrameKind { + FRAME_APPLY_TARGET, // e in e(...) + FRAME_BINARY_LEFT, // a in a + b + FRAME_BINARY_RIGHT, // b in a + b + FRAME_BUILTIN_FILTER, // When executing std.filter, used to hold intermediate state. + FRAME_BUILTIN_FORCE_THUNKS, // When forcing builtin args, holds intermediate state. + FRAME_CALL, // Used any time we have switched location in user code. + FRAME_ERROR, // e in error e + FRAME_IF, // e in if e then a else b + FRAME_INDEX_TARGET, // e in e[x] + FRAME_INDEX_INDEX, // e in x[e] + FRAME_INVARIANTS, // Caches the thunks that need to be executed one at a time. + FRAME_LOCAL, // Stores thunk bindings as we execute e in local ...; e + FRAME_OBJECT, // Stores intermediate state as we execute es in { [e]: ..., [e]: ... } + FRAME_OBJECT_COMP_ARRAY, // e in {f:a for x in e] + FRAME_OBJECT_COMP_ELEMENT, // Stores intermediate state when building object + FRAME_STRING_CONCAT, // Stores intermediate state while co-ercing objects + FRAME_SUPER_INDEX, // e in super[e] + FRAME_UNARY, // e in -e +}; + +/** A frame on the stack. + * + * Every time a subterm is evaluated, we first push a new stack frame to + * store the continuation. + * + * The stack frame is a bit like a tagged union, except not as memory + * efficient. The set of member variables that are actually used depends on + * the value of the member varaible kind. + * + * If the stack frame is of kind FRAME_CALL, then it counts towards the + * maximum number of stack frames allowed. Other stack frames are not + * counted. This is because FRAME_CALL exists where there is a branch in + * the code, e.g. the forcing of a thunk, evaluation of a field, calling a + * function, etc. + * + * The stack is used to mark objects during garbage + * collection, so HeapObjects not referred to from the stack may be + * prematurely collected. + */ +struct Frame { + + /** Tag (tagged union). */ + FrameKind kind; + + /** The code we were executing before. */ + const AST *ast; + + /** The location of the code we were executing before. + * + * location == ast->location when ast != nullptr + */ + LocationRange location; + + /** Reuse this stack frame for the purpose of tail call optimization. */ + bool tailCall; + + /** Used for a variety of purposes. */ + Value val; + + /** Used for a variety of purposes. */ + Value val2; + + /** Used for a variety of purposes. */ + DesugaredObject::Fields::const_iterator fit; + + /** Used for a variety of purposes. */ + std::map objectFields; + + /** Used for a variety of purposes. */ + unsigned elementId; + + /** Used for a variety of purposes. */ + std::map elements; + + /** Used for a variety of purposes. */ + std::vector thunks; + + /** The context is used in error messages to attempt to find a reasonable name for the + * object, function, or thunk value being executed. If it is a thunk, it is filled + * with the value when the frame terminates. + */ + HeapEntity *context; + + /** The lexically nearest object we are in, or nullptr. Note + * that this is not the same as context, because we could be inside a function, + * inside an object and then context would be the function, but self would still point + * to the object. + */ + HeapObject *self; + + /** The "super" level of self. Sometimes, we look upwards in the + * inheritance tree, e.g. via an explicit use of super, or because a given field + * has been inherited. When evaluating a field from one of these super objects, + * we need to bind self to the concrete object (so self must point + * there) but uses of super should be resolved relative to the object whose + * field we are evaluating. Thus, we keep a second field for that. This is + * usually 0, unless we are evaluating a super object's field. + */ + unsigned offset; + + /** A set of variables introduced at this point. */ + BindingFrame bindings; + + Frame(const FrameKind &kind, const AST *ast) + : kind(kind), ast(ast), location(ast->location), tailCall(false), elementId(0), + context(NULL), self(NULL), offset(0) + { + val.t = Value::NULL_TYPE; + val2.t = Value::NULL_TYPE; + } + + Frame(const FrameKind &kind, const LocationRange &location) + : kind(kind), ast(nullptr), location(location), tailCall(false), elementId(0), + context(NULL), self(NULL), offset(0) + { + val.t = Value::NULL_TYPE; + val2.t = Value::NULL_TYPE; + } + + /** Mark everything visible from this frame. */ + void mark(Heap &heap) const + { + heap.markFrom(val); + heap.markFrom(val2); + if (context) heap.markFrom(context); + if (self) heap.markFrom(self); + for (const auto &bind : bindings) + heap.markFrom(bind.second); + for (const auto &el : elements) + heap.markFrom(el.second); + for (const auto &th : thunks) + heap.markFrom(th); + } + + bool isCall(void) const + { + return kind == FRAME_CALL; + } + +}; + +/** The stack holds all the stack frames and manages the stack frame limit. */ +class Stack { + + /** How many call frames are on the stack. */ + unsigned calls; + + /** How many call frames should be allowed before aborting the program. */ + unsigned limit; + + /** The stack frames. */ + std::vector stack; + + public: + + Stack(unsigned limit) + : calls(0), limit(limit) + { + } + + ~Stack(void) { } + + unsigned size(void) + { + return stack.size(); + } + + /** Search for the closest variable in scope that matches the given name. */ + HeapThunk *lookUpVar(const Identifier *id) + { + for (int i=stack.size()-1 ; i>=0 ; --i) { + const auto &binds = stack[i].bindings; + auto it = binds.find(id); + if (it != binds.end()) { + return it->second; + } + if (stack[i].isCall()) break; + } + return nullptr; + } + + /** Mark everything visible from the stack (any frame). */ + void mark(Heap &heap) + { + for (const auto &f : stack) { + f.mark(heap); + } + } + + Frame &top(void) + { + return stack.back(); + } + + const Frame &top(void) const + { + return stack.back(); + } + + void pop(void) + { + if (top().isCall()) calls--; + stack.pop_back(); + } + + /** Attempt to find a name for a given heap entity. This may not be possible, but we try + * reasonably hard. We look in the bindings for a variable in the closest scope that + * happens to point at the entity in question. Otherwise, the best we can do is use its + * type. + */ + std::string getName(unsigned from_here, const HeapEntity *e) + { + std::string name; + for (int i=from_here-1 ; i>=0; --i) { + const auto &f = stack[i]; + for (const auto &pair : f.bindings) { + HeapThunk *thunk = pair.second; + if (!thunk->filled) continue; + if (!thunk->content.isHeap()) continue; + if (e != thunk->content.v.h) continue; + name = encode_utf8(pair.first->name); + } + // Do not go into the next call frame, keep local reasoning. + if (f.isCall()) break; + } + + if (name == "") name = "anonymous"; + if (dynamic_cast(e)) { + return "object <" + name + ">"; + } else if (auto *thunk = dynamic_cast(e)) { + if (thunk->name == nullptr) { + return ""; // Argument of builtin, or root (since top level functions). + } else { + return "thunk <" + encode_utf8(thunk->name->name) + ">"; + } + } else { + const auto *func = static_cast(e); + if (func->body == nullptr) { + return "builtin function <" + func->builtinName + ">"; + } + return "function <" + name + ">"; + } + } + + /** Dump the stack. + * + * This is useful to help debug the VM in gdb. It is virtual to stop it + * being removed by the compiler. + */ + virtual void dump(void) + { + for (unsigned i=0 ; i stack_trace; + stack_trace.push_back(TraceFrame(loc)); + for (int i=stack.size()-1 ; i>=0 ; --i) { + const auto &f = stack[i]; + if (f.isCall()) { + if (f.context != nullptr) { + // Give the last line a name. + stack_trace[stack_trace.size()-1].name = getName(i, f.context); + } + if (f.location.isSet() || f.location.file.length() > 0) + stack_trace.push_back(TraceFrame(f.location)); + } + } + return RuntimeError(stack_trace, msg); + } + + /** New (non-call) frame. */ + template void newFrame(Args... args) + { + stack.emplace_back(args...); + } + + /** If there is a tailstrict annotated frame followed by some locals, pop them all. */ + void tailCallTrimStack (void) + { + for (int i=stack.size()-1 ; i>=0 ; --i) { + switch (stack[i].kind) { + case FRAME_CALL: { + if (!stack[i].tailCall || stack[i].thunks.size() > 0) { + return; + } + // Remove all stack frames including this one. + while (stack.size() > unsigned(i)) stack.pop_back(); + calls--; + return; + } break; + + case FRAME_LOCAL: break; + + default: return; + } + } + } + + /** New call frame. */ + void newCall(const LocationRange &loc, HeapEntity *context, HeapObject *self, + unsigned offset, const BindingFrame &up_values) + { + tailCallTrimStack(); + if (calls >= limit) { + throw makeError(loc, "Max stack frames exceeded."); + } + stack.emplace_back(FRAME_CALL, loc); + calls++; + top().context = context; + top().self = self; + top().offset = offset; + top().bindings = up_values; + top().tailCall = false; + + #ifndef NDEBUG + for (const auto &bind : up_values) { + if (bind.second == nullptr) { + std::cerr << "INTERNAL ERROR: No binding for variable " + << encode_utf8(bind.first->name) << std::endl; + std::abort(); + } + } + #endif + } + + /** Look up the stack to find the self binding. */ + void getSelfBinding(HeapObject *&self, unsigned &offset) + { + self = nullptr; + offset = 0; + for (int i=stack.size() - 1 ; i>=0 ; --i) { + if (stack[i].isCall()) { + self = stack[i].self; + offset = stack[i].offset; + return; + } + } + } + + /** Look up the stack to see if we're running assertions for this object. */ + bool alreadyExecutingInvariants(HeapObject *self) + { + for (int i=stack.size() - 1 ; i>=0 ; --i) { + if (stack[i].kind == FRAME_INVARIANTS) { + if (stack[i].self == self) return true; + } + } + return false; + } +}; + +/** Typedef to save some typing. */ +typedef std::map ExtMap; + +/** Typedef to save some typing. */ +typedef std::map StrMap; + + +class Interpreter; + +typedef const AST *(Interpreter::*BuiltinFunc)(const LocationRange &loc, + const std::vector &args); + +/** Holds the intermediate state during execution and implements the necessary functions to + * implement the semantics of the language. + * + * The garbage collector used is a simple stop-the-world mark and sweep collector. It runs upon + * memory allocation if the heap is large enough and has grown enough since the last collection. + * All reachable entities have their mark field incremented. Then all entities with the old + * mark are removed from the heap. + */ +class Interpreter { + + /** The heap. */ + Heap heap; + + /** The value last computed. */ + Value scratch; + + /** The stack. */ + Stack stack; + + /** Used to create ASTs if needed. + * + * This is used at import time, and in a few other cases. + */ + Allocator *alloc; + + /** Used to "name" thunks created to cache imports. */ + const Identifier *idImport; + + /** Used to "name" thunks created on the inside of an array. */ + const Identifier *idArrayElement; + + /** Used to "name" thunks created to execute invariants. */ + const Identifier *idInvariant; + + /** Used to "name" thunks created to convert JSON to Jsonnet objects. */ + const Identifier *idJsonObjVar; + + /** Used to refer to idJsonObjVar. */ + const AST *jsonObjVar; + + struct ImportCacheValue { + std::string foundHere; + std::string content; + /** Thunk to store cached result of execution. + * + * Null if this file was only ever successfully imported with importstr. + */ + HeapThunk *thunk; + }; + + /** Cache for imported Jsonnet files. */ + std::map, ImportCacheValue *> cachedImports; + + /** External variables for std.extVar. */ + ExtMap externalVars; + + /** The callback used for loading imported files. */ + VmNativeCallbackMap nativeCallbacks; + + /** The callback used for loading imported files. */ + JsonnetImportCallback *importCallback; + + /** User context pointer for the import callback. */ + void *importCallbackContext; + + /** Builtin functions by name. */ + typedef std::map BuiltinMap; + BuiltinMap builtins; + + RuntimeError makeError(const LocationRange &loc, const std::string &msg) + { + return stack.makeError(loc, msg); + } + + /** Create an object on the heap, maybe collect garbage. + * \param T Something under HeapEntity + * \returns The new object + */ + template T* makeHeap(Args&&... args) + { + T *r = heap.makeEntity(std::forward(args)...); + if (heap.checkHeap()) { // Do a GC cycle? + // Avoid the object we just made being collected. + heap.markFrom(r); + + // Mark from the stack. + stack.mark(heap); + + // Mark from the scratch register + heap.markFrom(scratch); + + // Mark from cached imports + for (const auto &pair : cachedImports) { + HeapThunk *thunk = pair.second->thunk; + if (thunk != nullptr) + heap.markFrom(thunk); + } + + // Delete unreachable objects. + heap.sweep(); + } + return r; + } + + Value makeBoolean(bool v) + { + Value r; + r.t = Value::BOOLEAN; + r.v.b = v; + return r; + } + + Value makeDouble(double v) + { + Value r; + r.t = Value::DOUBLE; + r.v.d = v; + return r; + } + + Value makeDoubleCheck(const LocationRange &loc, double v) + { + if (std::isnan(v)) { + throw makeError(loc, "Not a number"); + } + if (std::isinf(v)) { + throw makeError(loc, "Overflow"); + } + return makeDouble(v); + } + + Value makeNull(void) + { + Value r; + r.t = Value::NULL_TYPE; + return r; + } + + Value makeArray(const std::vector &v) + { + Value r; + r.t = Value::ARRAY; + r.v.h = makeHeap(v); + return r; + } + + Value makeClosure(const BindingFrame &env, + HeapObject *self, + unsigned offset, + const HeapClosure::Params ¶ms, + AST *body) + { + Value r; + r.t = Value::FUNCTION; + r.v.h = makeHeap(env, self, offset, params, body, ""); + return r; + } + + Value makeNativeBuiltin(const std::string &name, const std::vector ¶ms) + { + HeapClosure::Params hc_params; + for (const auto &p : params) { + hc_params.emplace_back(alloc->makeIdentifier(decode_utf8(p)), nullptr); + } + return makeBuiltin(name, hc_params); + } + + Value makeBuiltin(const std::string &name, const HeapClosure::Params ¶ms) + { + AST *body = nullptr; + Value r; + r.t = Value::FUNCTION; + r.v.h = makeHeap(BindingFrame(), nullptr, 0, params, body, name); + return r; + } + + template Value makeObject(Args... args) + { + Value r; + r.t = Value::OBJECT; + r.v.h = makeHeap(args...); + return r; + } + + Value makeString(const String &v) + { + Value r; + r.t = Value::STRING; + r.v.h = makeHeap(v); + return r; + } + + /** Auxiliary function of objectIndex. + * + * Traverse the object's tree from right to left, looking for an object + * with the given field. Call with offset initially set to 0. + * + * \param f The field we're looking for. + * \param start_from Step over this many leaves first. + * \param counter Return the level of "super" that contained the field. + * \returns The first object with the field, or nullptr if it could not be found. + */ + HeapLeafObject *findObject(const Identifier *f, HeapObject *curr, + unsigned start_from, unsigned &counter) + { + if (auto *ext = dynamic_cast(curr)) { + auto *r = findObject(f, ext->right, start_from, counter); + if (r) return r; + auto *l = findObject(f, ext->left, start_from, counter); + if (l) return l; + } else { + if (counter >= start_from) { + if (auto *simp = dynamic_cast(curr)) { + auto it = simp->fields.find(f); + if (it != simp->fields.end()) { + return simp; + } + } else if (auto *comp = dynamic_cast(curr)) { + auto it = comp->compValues.find(f); + if (it != comp->compValues.end()) { + return comp; + } + } + } + counter++; + } + return nullptr; + } + + typedef std::map IdHideMap; + + /** Auxiliary function. + */ + IdHideMap objectFieldsAux(const HeapObject *obj_) + { + IdHideMap r; + if (auto *obj = dynamic_cast(obj_)) { + for (const auto &f : obj->fields) { + r[f.first] = f.second.hide; + } + + } else if (auto *obj = dynamic_cast(obj_)) { + r = objectFieldsAux(obj->right); + for (const auto &pair : objectFieldsAux(obj->left)) { + auto it = r.find(pair.first); + if (it == r.end()) { + // First time it is seen + r[pair.first] = pair.second; + } else if (it->second == ObjectField::INHERIT) { + // Seen before, but with inherited visibility so use new visibility + r[pair.first] = pair.second; + } + } + + } else if (auto *obj = dynamic_cast(obj_)) { + for (const auto &f : obj->compValues) + r[f.first] = ObjectField::VISIBLE; + } + return r; + } + + /** Auxiliary function. + */ + std::set objectFields(const HeapObject *obj_, bool manifesting) + { + std::set r; + for (const auto &pair : objectFieldsAux(obj_)) { + if (!manifesting || pair.second != ObjectField::HIDDEN) r.insert(pair.first); + } + return r; + } + + /** Import another Jsonnet file. + * + * If the file has already been imported, then use that version. This maintains + * referential transparency in the case of writes to disk during execution. The + * cache holds a thunk in order to cache the resulting value of execution. + * + * \param loc Location of the import statement. + * \param file Path to the filename. + */ + HeapThunk *import(const LocationRange &loc, const LiteralString *file) + { + ImportCacheValue *input = importString(loc, file); + if (input->thunk == nullptr) { + Tokens tokens = jsonnet_lex(input->foundHere, input->content.c_str()); + AST *expr = jsonnet_parse(alloc, tokens); + jsonnet_desugar(alloc, expr, nullptr); + jsonnet_static_analysis(expr); + // If no errors then populate cache. + auto *thunk = makeHeap(idImport, nullptr, 0, expr); + input->thunk = thunk; + } + return input->thunk; + } + + /** Import a file as a string. + * + * If the file has already been imported, then use that version. This maintains + * referential transparency in the case of writes to disk during execution. + * + * \param loc Location of the import statement. + * \param file Path to the filename. + * \param found_here If non-null, used to store the actual path of the file + */ + ImportCacheValue *importString(const LocationRange &loc, const LiteralString *file) + { + std::string dir = dir_name(loc.file); + + const String &path = file->value; + + std::pair key(dir, path); + ImportCacheValue *cached_value = cachedImports[key]; + if (cached_value != nullptr) + return cached_value; + + int success = 0; + char *found_here_cptr; + char *content = + importCallback(importCallbackContext, dir.c_str(), encode_utf8(path).c_str(), + &found_here_cptr, &success); + + std::string input(content); + ::free(content); + + if (!success) { + std::string msg = "Couldn't open import \"" + encode_utf8(path) + "\": "; + msg += input; + throw makeError(loc, msg); + } + + auto *input_ptr = new ImportCacheValue(); + input_ptr->foundHere = found_here_cptr; + input_ptr->content = input; + input_ptr->thunk = nullptr; // May be filled in later by import(). + ::free(found_here_cptr); + cachedImports[key] = input_ptr; + return input_ptr; + } + + /** Capture the required variables from the environment. */ + BindingFrame capture(const std::vector &free_vars) + { + BindingFrame env; + for (auto fv : free_vars) { + auto *th = stack.lookUpVar(fv); + env[fv] = th; + } + return env; + } + + /** Count the number of leaves in the tree. + * + * \param obj The root of the tree. + * \param counter Initialize to 0, returns the number of leaves. + */ + unsigned countLeaves(HeapObject *obj) + { + if (auto *ext = dynamic_cast(obj)) { + return countLeaves(ext->left) + countLeaves(ext->right); + } else { + return 1; + } + } + + public: + + /** Create a new interpreter. + * + * \param loc The location range of the file to be executed. + */ + Interpreter( + Allocator *alloc, + const ExtMap &ext_vars, + unsigned max_stack, + double gc_min_objects, + double gc_growth_trigger, + const VmNativeCallbackMap &native_callbacks, + JsonnetImportCallback *import_callback, + void *import_callback_context) + + : heap(gc_min_objects, gc_growth_trigger), + stack(max_stack), + alloc(alloc), + idImport(alloc->makeIdentifier(U"import")), + idArrayElement(alloc->makeIdentifier(U"array_element")), + idInvariant(alloc->makeIdentifier(U"object_assert")), + idJsonObjVar(alloc->makeIdentifier(U"_")), + jsonObjVar(alloc->make(LocationRange(), Fodder{}, idJsonObjVar)), + externalVars(ext_vars), + nativeCallbacks(native_callbacks), + importCallback(import_callback), + importCallbackContext(import_callback_context) + { + scratch = makeNull(); + builtins["makeArray"] = &Interpreter::builtinMakeArray; + builtins["pow"] = &Interpreter::builtinPow; + builtins["floor"] = &Interpreter::builtinFloor; + builtins["ceil"] = &Interpreter::builtinCeil; + builtins["sqrt"] = &Interpreter::builtinSqrt; + builtins["sin"] = &Interpreter::builtinSin; + builtins["cos"] = &Interpreter::builtinCos; + builtins["tan"] = &Interpreter::builtinTan; + builtins["asin"] = &Interpreter::builtinAsin; + builtins["acos"] = &Interpreter::builtinAcos; + builtins["atan"] = &Interpreter::builtinAtan; + builtins["type"] = &Interpreter::builtinType; + builtins["filter"] = &Interpreter::builtinFilter; + builtins["objectHasEx"] = &Interpreter::builtinObjectHasEx; + builtins["length"] = &Interpreter::builtinLength; + builtins["objectFieldsEx"] = &Interpreter::builtinObjectFieldsEx; + builtins["codepoint"] = &Interpreter::builtinCodepoint; + builtins["char"] = &Interpreter::builtinChar; + builtins["log"] = &Interpreter::builtinLog; + builtins["exp"] = &Interpreter::builtinExp; + builtins["mantissa"] = &Interpreter::builtinMantissa; + builtins["exponent"] = &Interpreter::builtinExponent; + builtins["modulo"] = &Interpreter::builtinModulo; + builtins["extVar"] = &Interpreter::builtinExtVar; + builtins["primitiveEquals"] = &Interpreter::builtinPrimitiveEquals; + builtins["native"] = &Interpreter::builtinNative; + builtins["md5"] = &Interpreter::builtinMd5; + } + + /** Clean up the heap, stack, stash, and builtin function ASTs. */ + ~Interpreter() + { + for (const auto &pair : cachedImports) { + delete pair.second; + } + } + + const Value &getScratchRegister(void) + { + return scratch; + } + + void setScratchRegister(const Value &v) + { + scratch = v; + } + + + /** Raise an error if the arguments aren't the expected types. */ + void validateBuiltinArgs(const LocationRange &loc, + const std::string &name, + const std::vector &args, + const std::vector params) + { + if (args.size() == params.size()) { + for (unsigned i=0 ; i &args) + { + Frame &f = stack.top(); + validateBuiltinArgs(loc, "makeArray", args, + {Value::DOUBLE, Value::FUNCTION}); + long sz = long(args[0].v.d); + if (sz < 0) { + std::stringstream ss; + ss << "makeArray requires size >= 0, got " << sz; + throw makeError(loc, ss.str()); + } + auto *func = static_cast(args[1].v.h); + std::vector elements; + if (func->params.size() != 1) { + std::stringstream ss; + ss << "makeArray function must take 1 param, got: " << func->params.size(); + throw makeError(loc, ss.str()); + } + elements.resize(sz); + for (long i=0 ; i(idArrayElement, func->self, func->offset, func->body); + // The next line stops the new thunks from being GCed. + f.thunks.push_back(th); + th->upValues = func->upValues; + + auto *el = makeHeap(func->params[0].id, nullptr, 0, nullptr); + el->fill(makeDouble(i)); // i guaranteed not to be inf/NaN + th->upValues[func->params[0].id] = el; + elements[i] = th; + } + scratch = makeArray(elements); + return nullptr; + } + + const AST *builtinPow(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "pow", args, {Value::DOUBLE, Value::DOUBLE}); + scratch = makeDoubleCheck(loc, std::pow(args[0].v.d, args[1].v.d)); + return nullptr; + } + + const AST *builtinFloor(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "floor", args, {Value::DOUBLE}); + scratch = makeDoubleCheck(loc, std::floor(args[0].v.d)); + return nullptr; + } + + const AST *builtinCeil(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "ceil", args, {Value::DOUBLE}); + scratch = makeDoubleCheck(loc, std::ceil(args[0].v.d)); + return nullptr; + } + + const AST *builtinSqrt(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "sqrt", args, {Value::DOUBLE}); + scratch = makeDoubleCheck(loc, std::sqrt(args[0].v.d)); + return nullptr; + } + + const AST *builtinSin(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "sin", args, {Value::DOUBLE}); + scratch = makeDoubleCheck(loc, std::sin(args[0].v.d)); + return nullptr; + } + + const AST *builtinCos(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "cos", args, {Value::DOUBLE}); + scratch = makeDoubleCheck(loc, std::cos(args[0].v.d)); + return nullptr; + } + + const AST *builtinTan(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "tan", args, {Value::DOUBLE}); + scratch = makeDoubleCheck(loc, std::tan(args[0].v.d)); + return nullptr; + } + + const AST *builtinAsin(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "asin", args, {Value::DOUBLE}); + scratch = makeDoubleCheck(loc, std::asin(args[0].v.d)); + return nullptr; + } + + const AST *builtinAcos(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "acos", args, {Value::DOUBLE}); + scratch = makeDoubleCheck(loc, std::acos(args[0].v.d)); + return nullptr; + } + + const AST *builtinAtan(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "atan", args, {Value::DOUBLE}); + scratch = makeDoubleCheck(loc, std::atan(args[0].v.d)); + return nullptr; + } + + const AST *builtinType(const LocationRange &, const std::vector &args) + { + switch (args[0].t) { + case Value::NULL_TYPE: + scratch = makeString(U"null"); + return nullptr; + + case Value::BOOLEAN: + scratch = makeString(U"boolean"); + return nullptr; + + case Value::DOUBLE: + scratch = makeString(U"number"); + return nullptr; + + case Value::ARRAY: + scratch = makeString(U"array"); + return nullptr; + + case Value::FUNCTION: + scratch = makeString(U"function"); + return nullptr; + + case Value::OBJECT: + scratch = makeString(U"object"); + return nullptr; + + case Value::STRING: + scratch = makeString(U"string"); + return nullptr; + } + return nullptr; // Quiet, compiler. + } + + const AST *builtinFilter(const LocationRange &loc, const std::vector &args) + { + Frame &f = stack.top(); + validateBuiltinArgs(loc, "filter", args, {Value::FUNCTION, Value::ARRAY}); + auto *func = static_cast(args[0].v.h); + auto *arr = static_cast(args[1].v.h); + if (func->params.size() != 1) { + throw makeError(loc, "filter function takes 1 parameter."); + } + if (arr->elements.size() == 0) { + scratch = makeArray({}); + } else { + f.kind = FRAME_BUILTIN_FILTER; + f.val = args[0]; + f.val2 = args[1]; + f.thunks.clear(); + f.elementId = 0; + + auto *thunk = arr->elements[f.elementId]; + BindingFrame bindings = func->upValues; + bindings[func->params[0].id] = thunk; + stack.newCall(loc, func, func->self, func->offset, bindings); + return func->body; + } + return nullptr; + } + + const AST *builtinObjectHasEx(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "objectHasEx", args, + {Value::OBJECT, Value::STRING, + Value::BOOLEAN}); + const auto *obj = static_cast(args[0].v.h); + const auto *str = static_cast(args[1].v.h); + bool include_hidden = args[2].v.b; + bool found = false; + for (const auto &field : objectFields(obj, !include_hidden)) { + if (field->name == str->value) { + found = true; + break; + } + } + scratch = makeBoolean(found); + return nullptr; + } + + const AST *builtinLength(const LocationRange &loc, const std::vector &args) + { + if (args.size() != 1) { + throw makeError(loc, "length takes 1 parameter."); + } + HeapEntity *e = args[0].v.h; + switch (args[0].t) { + case Value::OBJECT: { + auto fields = objectFields(static_cast(e), true); + scratch = makeDouble(fields.size()); + } break; + + case Value::ARRAY: + scratch = makeDouble(static_cast(e)->elements.size()); + break; + + case Value::STRING: + scratch = makeDouble(static_cast(e)->value.length()); + break; + + case Value::FUNCTION: + scratch = makeDouble(static_cast(e)->params.size()); + break; + + default: + throw makeError(loc, + "length operates on strings, objects, " + "and arrays, got " + type_str(args[0])); + } + return nullptr; + } + + const AST *builtinObjectFieldsEx(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "objectFieldsEx", args, + {Value::OBJECT, Value::BOOLEAN}); + const auto *obj = static_cast(args[0].v.h); + bool include_hidden = args[1].v.b; + // Stash in a set first to sort them. + std::set fields; + for (const auto &field : objectFields(obj, !include_hidden)) { + fields.insert(field->name); + } + scratch = makeArray({}); + auto &elements = static_cast(scratch.v.h)->elements; + for (const auto &field : fields) { + auto *th = makeHeap(idArrayElement, nullptr, 0, nullptr); + elements.push_back(th); + th->fill(makeString(field)); + } + return nullptr; + } + + const AST *builtinCodepoint(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "codepoint", args, {Value::STRING}); + const String &str = + static_cast(args[0].v.h)->value; + if (str.length() != 1) { + std::stringstream ss; + ss << "codepoint takes a string of length 1, got length " + << str.length(); + throw makeError(loc, ss.str()); + } + char32_t c = static_cast(args[0].v.h)->value[0]; + scratch = makeDouble((unsigned long)(c)); + return nullptr; + } + + const AST *builtinChar(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "char", args, {Value::DOUBLE}); + long l = long(args[0].v.d); + if (l < 0) { + std::stringstream ss; + ss << "Codepoints must be >= 0, got " << l; + throw makeError(loc, ss.str()); + } + if (l >= JSONNET_CODEPOINT_MAX) { + std::stringstream ss; + ss << "Invalid unicode codepoint, got " << l; + throw makeError(loc, ss.str()); + } + char32_t c = l; + scratch = makeString(String(&c, 1)); + return nullptr; + } + + const AST *builtinLog(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "log", args, {Value::DOUBLE}); + scratch = makeDoubleCheck(loc, std::log(args[0].v.d)); + return nullptr; + } + + const AST *builtinExp(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "exp", args, {Value::DOUBLE}); + scratch = makeDoubleCheck(loc, std::exp(args[0].v.d)); + return nullptr; + } + + const AST *builtinMantissa(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "mantissa", args, {Value::DOUBLE}); + int exp; + double m = std::frexp(args[0].v.d, &exp); + scratch = makeDoubleCheck(loc, m); + return nullptr; + } + + const AST *builtinExponent(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "exponent", args, {Value::DOUBLE}); + int exp; + std::frexp(args[0].v.d, &exp); + scratch = makeDoubleCheck(loc, exp); + return nullptr; + } + + const AST *builtinModulo(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "modulo", args, {Value::DOUBLE, Value::DOUBLE}); + double a = args[0].v.d; + double b = args[1].v.d; + if (b == 0) + throw makeError(loc, "Division by zero."); + scratch = makeDoubleCheck(loc, std::fmod(a, b)); + return nullptr; + } + + const AST *builtinExtVar(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "extVar", args, {Value::STRING}); + const String &var = + static_cast(args[0].v.h)->value; + std::string var8 = encode_utf8(var); + auto it = externalVars.find(var8); + if (it == externalVars.end()) { + std::string msg = "Undefined external variable: " + var8; + throw makeError(loc, msg); + } + const VmExt &ext = it->second; + if (ext.isCode) { + std::string filename = ""; + Tokens tokens = jsonnet_lex(filename, ext.data.c_str()); + AST *expr = jsonnet_parse(alloc, tokens); + jsonnet_desugar(alloc, expr, nullptr); + jsonnet_static_analysis(expr); + stack.pop(); + return expr; + } else { + scratch = makeString(decode_utf8(ext.data)); + return nullptr; + } + } + + const AST *builtinPrimitiveEquals(const LocationRange &loc, const std::vector &args) + { + if (args.size() != 2) { + std::stringstream ss; + ss << "primitiveEquals takes 2 parameters, got " << args.size(); + throw makeError(loc, ss.str()); + } + if (args[0].t != args[1].t) { + scratch = makeBoolean(false); + return nullptr; + } + bool r; + switch (args[0].t) { + case Value::BOOLEAN: + r = args[0].v.b == args[1].v.b; + break; + + case Value::DOUBLE: + r = args[0].v.d == args[1].v.d; + break; + + case Value::STRING: + r = static_cast(args[0].v.h)->value + == static_cast(args[1].v.h)->value; + break; + + case Value::NULL_TYPE: + r = true; + break; + + case Value::FUNCTION: + throw makeError(loc, "Cannot test equality of functions"); + break; + + default: + throw makeError(loc, + "primitiveEquals operates on primitive " + "types, got " + type_str(args[0])); + } + scratch = makeBoolean(r); + return nullptr; + } + + const AST *builtinNative(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "native", args, {Value::STRING}); + + std::string builtin_name = encode_utf8(static_cast(args[0].v.h)->value); + + VmNativeCallbackMap::const_iterator nit = nativeCallbacks.find(builtin_name); + if (nit == nativeCallbacks.end()) { + throw makeError(loc, "Unrecognized native function name: " + builtin_name); + } + + const VmNativeCallback &cb = nit->second; + scratch = makeNativeBuiltin(builtin_name, cb.params); + return nullptr; + } + + const AST *builtinMd5(const LocationRange &loc, const std::vector &args) + { + validateBuiltinArgs(loc, "md5", args, {Value::STRING}); + + std::string value = encode_utf8(static_cast(args[0].v.h)->value); + + scratch = makeString(decode_utf8(md5(value))); + return nullptr; + } + + void jsonToHeap(const std::unique_ptr &v, bool &filled, Value &attach) + { + // In order to not anger the garbage collector, assign to attach immediately after + // making the heap object. + switch (v->kind) { + case JsonnetJsonValue::STRING: + attach = makeString(decode_utf8(v->string)); + filled = true; + break; + + case JsonnetJsonValue::BOOL: + attach = makeBoolean(v->number != 0.0); + filled = true; + break; + + case JsonnetJsonValue::NUMBER: + attach = makeDouble(v->number); + filled = true; + break; + + case JsonnetJsonValue::NULL_KIND: + attach = makeNull(); + filled = true; + break; + + case JsonnetJsonValue::ARRAY: { + attach = makeArray(std::vector{}); + filled = true; + auto *arr = static_cast(attach.v.h); + for (size_t i = 0; i < v->elements.size() ; ++i) { + arr->elements.push_back( + makeHeap(idArrayElement, nullptr, 0, nullptr)); + jsonToHeap(v->elements[i], arr->elements[i]->filled, arr->elements[i]->content); + } + } break; + + case JsonnetJsonValue::OBJECT: { + attach = makeObject( + BindingFrame{}, jsonObjVar, idJsonObjVar, BindingFrame{}); + filled = true; + auto *obj = static_cast(attach.v.h); + for (const auto &pair : v->fields) { + auto *thunk = makeHeap(idJsonObjVar, nullptr, 0, nullptr); + obj->compValues[alloc->makeIdentifier(decode_utf8(pair.first))] = thunk; + jsonToHeap(pair.second, thunk->filled, thunk->content); + } + } break; + } + } + + + String toString(const LocationRange &loc) + { + return manifestJson(loc, false, U""); + } + + + + /** Recursively collect an object's invariants. + * + * \param curr + * \param self + * \param offset + * \param thunks + */ + void objectInvariants(HeapObject *curr, HeapObject *self, + unsigned &counter, std::vector &thunks) + { + if (auto *ext = dynamic_cast(curr)) { + objectInvariants(ext->right, self, counter, thunks); + objectInvariants(ext->left, self, counter, thunks); + } else { + if (auto *simp = dynamic_cast(curr)) { + for (AST *assert : simp->asserts) { + auto *el_th = makeHeap(idInvariant, self, counter, assert); + el_th->upValues = simp->upValues; + thunks.push_back(el_th); + } + } + counter++; + } + } + + /** Index an object's field. + * + * \param loc Location where the e.f occured. + * \param obj The target + * \param f The field + */ + const AST *objectIndex(const LocationRange &loc, HeapObject *obj, + const Identifier *f, unsigned offset) + { + unsigned found_at = 0; + HeapObject *self = obj; + HeapLeafObject *found = findObject(f, obj, offset, found_at); + if (found == nullptr) { + throw makeError(loc, "Field does not exist: " + encode_utf8(f->name)); + } + if (auto *simp = dynamic_cast(found)) { + auto it = simp->fields.find(f); + const AST *body = it->second.body; + + stack.newCall(loc, simp, self, found_at, simp->upValues); + return body; + } else { + // If a HeapLeafObject is not HeapSimpleObject, it must be HeapComprehensionObject. + auto *comp = static_cast(found); + auto it = comp->compValues.find(f); + auto *th = it->second; + BindingFrame binds = comp->upValues; + binds[comp->id] = th; + stack.newCall(loc, comp, self, found_at, binds); + return comp->value; + } + } + + void runInvariants(const LocationRange &loc, HeapObject *self) + { + if (stack.alreadyExecutingInvariants(self)) return; + + unsigned counter = 0; + unsigned initial_stack_size = stack.size(); + stack.newFrame(FRAME_INVARIANTS, loc); + std::vector &thunks = stack.top().thunks; + objectInvariants(self, self, counter, thunks); + if (thunks.size() == 0) { + stack.pop(); + return; + } + HeapThunk *thunk = thunks[0]; + stack.top().elementId = 1; + stack.top().self = self; + stack.newCall(loc, thunk, thunk->self, thunk->offset, thunk->upValues); + evaluate(thunk->body, initial_stack_size); + } + + /** Evaluate the given AST to a value. + * + * Rather than call itself recursively, this function maintains a separate stack of + * partially-evaluated constructs. First, the AST is handled depending on its type. If + * this cannot be completed without evaluating another AST (e.g. a sub expression) then a + * frame is pushed onto the stack containing the partial state, and the code jumps back to + * the beginning of this function. Once there are no more ASTs to evaluate, the code + * executes the second part of the function to unwind the stack. If the stack cannot be + * completely unwound without evaluating an AST then it jumps back to the beginning of the + * function again. The process terminates when the AST has been processed and the stack is + * the same size it was at the beginning of the call to evaluate. + */ + void evaluate(const AST *ast_, unsigned initial_stack_size) + { + recurse: + + switch (ast_->type) { + case AST_APPLY: { + const auto &ast = *static_cast(ast_); + stack.newFrame(FRAME_APPLY_TARGET, ast_); + ast_ = ast.target; + goto recurse; + } break; + + case AST_ARRAY: { + const auto &ast = *static_cast(ast_); + HeapObject *self; + unsigned offset; + stack.getSelfBinding(self, offset); + scratch = makeArray({}); + auto &elements = static_cast(scratch.v.h)->elements; + for (const auto &el : ast.elements) { + auto *el_th = makeHeap(idArrayElement, self, offset, el.expr); + el_th->upValues = capture(el.expr->freeVariables); + elements.push_back(el_th); + } + } break; + + case AST_BINARY: { + const auto &ast = *static_cast(ast_); + stack.newFrame(FRAME_BINARY_LEFT, ast_); + ast_ = ast.left; + goto recurse; + } break; + + case AST_BUILTIN_FUNCTION: { + const auto &ast = *static_cast(ast_); + HeapClosure::Params params; + params.reserve(ast.params.size()); + for (const auto &p : ast.params) { + // None of the builtins have default args. + params.emplace_back(p, nullptr); + } + scratch = makeBuiltin(ast.name, params); + } break; + + case AST_CONDITIONAL: { + const auto &ast = *static_cast(ast_); + stack.newFrame(FRAME_IF, ast_); + ast_ = ast.cond; + goto recurse; + } break; + + case AST_ERROR: { + const auto &ast = *static_cast(ast_); + stack.newFrame(FRAME_ERROR, ast_); + ast_ = ast.expr; + goto recurse; + } break; + + case AST_FUNCTION: { + const auto &ast = *static_cast(ast_); + auto env = capture(ast.freeVariables); + HeapObject *self; + unsigned offset; + stack.getSelfBinding(self, offset); + HeapClosure::Params params; + params.reserve(ast.params.size()); + for (const auto &p : ast.params) { + params.emplace_back(p.id, p.expr); + } + scratch = makeClosure(env, self, offset, params, ast.body); + } break; + + case AST_IMPORT: { + const auto &ast = *static_cast(ast_); + HeapThunk *thunk = import(ast.location, ast.file); + if (thunk->filled) { + scratch = thunk->content; + } else { + stack.newCall(ast.location, thunk, thunk->self, thunk->offset, thunk->upValues); + ast_ = thunk->body; + goto recurse; + } + } break; + + case AST_IMPORTSTR: { + const auto &ast = *static_cast(ast_); + const ImportCacheValue *value = importString(ast.location, ast.file); + scratch = makeString(decode_utf8(value->content)); + } break; + + case AST_INDEX: { + const auto &ast = *static_cast(ast_); + stack.newFrame(FRAME_INDEX_TARGET, ast_); + ast_ = ast.target; + goto recurse; + } break; + + case AST_LOCAL: { + const auto &ast = *static_cast(ast_); + stack.newFrame(FRAME_LOCAL, ast_); + Frame &f = stack.top(); + // First build all the thunks and bind them. + HeapObject *self; + unsigned offset; + stack.getSelfBinding(self, offset); + for (const auto &bind : ast.binds) { + // Note that these 2 lines must remain separate to avoid the GC running + // when bindings has a nullptr for key bind.first. + auto *th = makeHeap(bind.var, self, offset, bind.body); + f.bindings[bind.var] = th; + } + // Now capture the environment (including the new thunks, to make cycles). + for (const auto &bind : ast.binds) { + auto *thunk = f.bindings[bind.var]; + thunk->upValues = capture(bind.body->freeVariables); + } + ast_ = ast.body; + goto recurse; + } break; + + case AST_LITERAL_BOOLEAN: { + const auto &ast = *static_cast(ast_); + scratch = makeBoolean(ast.value); + } break; + + case AST_LITERAL_NUMBER: { + const auto &ast = *static_cast(ast_); + scratch = makeDoubleCheck(ast_->location, ast.value); + } break; + + case AST_LITERAL_STRING: { + const auto &ast = *static_cast(ast_); + scratch = makeString(ast.value); + } break; + + case AST_LITERAL_NULL: { + scratch = makeNull(); + } break; + + case AST_DESUGARED_OBJECT: { + const auto &ast = *static_cast(ast_); + if (ast.fields.empty()) { + auto env = capture(ast.freeVariables); + std::map fields; + scratch = makeObject(env, fields, ast.asserts); + } else { + auto env = capture(ast.freeVariables); + stack.newFrame(FRAME_OBJECT, ast_); + auto fit = ast.fields.begin(); + stack.top().fit = fit; + ast_ = fit->name; + goto recurse; + } + } break; + + case AST_OBJECT_COMPREHENSION_SIMPLE: { + const auto &ast = *static_cast(ast_); + stack.newFrame(FRAME_OBJECT_COMP_ARRAY, ast_); + ast_ = ast.array; + goto recurse; + } break; + + case AST_SELF: { + scratch.t = Value::OBJECT; + HeapObject *self; + unsigned offset; + stack.getSelfBinding(self, offset); + scratch.v.h = self; + } break; + + case AST_SUPER_INDEX: { + const auto &ast = *static_cast(ast_); + stack.newFrame(FRAME_SUPER_INDEX, ast_); + ast_ = ast.index; + goto recurse; + } break; + + case AST_UNARY: { + const auto &ast = *static_cast(ast_); + stack.newFrame(FRAME_UNARY, ast_); + ast_ = ast.expr; + goto recurse; + } break; + + case AST_VAR: { + const auto &ast = *static_cast(ast_); + auto *thunk = stack.lookUpVar(ast.id); + if (thunk == nullptr) { + std::cerr << "INTERNAL ERROR: Could not bind variable: " + << encode_utf8(ast.id->name) << std::endl; + std::abort(); + } + if (thunk->filled) { + scratch = thunk->content; + } else { + stack.newCall(ast.location, thunk, thunk->self, thunk->offset, thunk->upValues); + ast_ = thunk->body; + goto recurse; + } + } break; + + default: + std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_->type << std::endl; + std::abort(); + } + + // To evaluate another AST, set ast to it, then goto recurse. + // To pop, exit the switch or goto popframe + // To change the frame and re-enter the switch, goto replaceframe + while (stack.size() > initial_stack_size) { + Frame &f = stack.top(); + switch (f.kind) { + case FRAME_APPLY_TARGET: { + const auto &ast = *static_cast(f.ast); + if (scratch.t != Value::FUNCTION) { + throw makeError(ast.location, + "Only functions can be called, got " + + type_str(scratch)); + } + auto *func = static_cast(scratch.v.h); + + std::set params_needed; + for (const auto ¶m : func->params) { + params_needed.insert(param.id); + } + + // Create thunks for arguments. + std::vector positional_args; + BindingFrame args; + bool got_named = false; + for (unsigned i=0 ; i= func->params.size()) { + std::stringstream ss; + ss << "Too many args, function has " << func->params.size() + << " parameter(s)"; + throw makeError(ast.location, ss.str()); + } + name = func->params[i].id; + } + // Special case for builtin functions -- leave identifier blank for + // them in the thunk. This removes the thunk frame from the stacktrace. + const Identifier *name_ = func->body == nullptr ? nullptr : name; + HeapObject *self; + unsigned offset; + stack.getSelfBinding(self, offset); + auto *thunk = makeHeap(name_, self, offset, arg.expr); + thunk->upValues = capture(arg.expr->freeVariables); + // While making the thunks, keep them in a frame to avoid premature garbage + // collection. + f.thunks.push_back(thunk); + if (args.find(name) != args.end()) { + std::stringstream ss; + ss << "Binding parameter a second time: " << encode_utf8(name->name); + throw makeError(ast.location, ss.str()); + } + args[name] = thunk; + if (params_needed.find(name) == params_needed.end()) { + std::stringstream ss; + ss << "Function has no parameter " << encode_utf8(name->name); + throw makeError(ast.location, ss.str()); + } + } + + // For any func params for which there was no arg, create a thunk for those and + // bind the default argument. Allow default thunks to see other params. If no + // default argument than raise an error. + + // Raise errors for unbound params, create thunks (but don't fill in upvalues). + // This is a subset of f.thunks, so will not get garbage collected. + std::vector def_arg_thunks; + for (const auto ¶m : func->params) { + if (args.find(param.id) != args.end()) continue; + if (param.def == nullptr) { + std::stringstream ss; + ss << "Function parameter " << encode_utf8(param.id->name) << + " not bound in call."; + throw makeError(ast.location, ss.str()); + } + + // Special case for builtin functions -- leave identifier blank for + // them in the thunk. This removes the thunk frame from the stacktrace. + const Identifier *name_ = func->body == nullptr ? nullptr : param.id; + auto *thunk = makeHeap(name_, func->self, func->offset, + param.def); + f.thunks.push_back(thunk); + def_arg_thunks.push_back(thunk); + args[param.id] = thunk; + } + + BindingFrame up_values = func->upValues; + up_values.insert(args.begin(), args.end()); + + // Fill in upvalues + for (HeapThunk *thunk : def_arg_thunks) { + thunk->upValues = up_values; + } + + // Cache these, because pop will invalidate them. + std::vector thunks_copy = f.thunks; + + stack.pop(); + + if (func->body == nullptr) { + // Built-in function. + // Give nullptr for self because noone looking at this frame will + // attempt to bind to self (it's native code). + stack.newFrame(FRAME_BUILTIN_FORCE_THUNKS, f.ast); + stack.top().thunks = thunks_copy; + stack.top().val = scratch; + goto replaceframe; + } else { + // User defined function. + stack.newCall(ast.location, func, func->self, func->offset, up_values); + if (ast.tailstrict) { + stack.top().tailCall = true; + if (thunks_copy.size() == 0) { + // No need to force thunks, proceed straight to body. + ast_ = func->body; + goto recurse; + } else { + // The check for args.size() > 0 + stack.top().thunks = thunks_copy; + stack.top().val = scratch; + goto replaceframe; + } + } else { + ast_ = func->body; + goto recurse; + } + } + } break; + + case FRAME_BINARY_LEFT: { + const auto &ast = *static_cast(f.ast); + const Value &lhs = scratch; + if (lhs.t == Value::BOOLEAN) { + // Handle short-cut semantics + switch (ast.op) { + case BOP_AND: { + if (!lhs.v.b) { + scratch = makeBoolean(false); + goto popframe; + } + } break; + + case BOP_OR: { + if (lhs.v.b) { + scratch = makeBoolean(true); + goto popframe; + } + } break; + + default:; + } + } + stack.top().kind = FRAME_BINARY_RIGHT; + stack.top().val = lhs; + ast_ = ast.right; + goto recurse; + } break; + + case FRAME_BINARY_RIGHT: { + const auto &ast = *static_cast(f.ast); + const Value &lhs = stack.top().val; + const Value &rhs = scratch; + if (lhs.t == Value::STRING || rhs.t == Value::STRING) { + if (ast.op == BOP_PLUS) { + // Handle co-ercions for string processing. + stack.top().kind = FRAME_STRING_CONCAT; + stack.top().val2 = rhs; + goto replaceframe; + } + } + // Equality can be used when the types don't match. + switch (ast.op) { + case BOP_MANIFEST_EQUAL: + std::cerr << "INTERNAL ERROR: Equals not desugared" << std::endl; + abort(); + + case BOP_MANIFEST_UNEQUAL: + std::cerr << "INTERNAL ERROR: Notequals not desugared" << std::endl; + abort(); + + default:; + } + // Everything else requires matching types. + if (lhs.t != rhs.t) { + throw makeError(ast.location, + "Binary operator " + bop_string(ast.op) + " requires " + "matching types, got " + type_str(lhs) + " and " + + type_str(rhs) + "."); + } + switch (lhs.t) { + case Value::ARRAY: + if (ast.op == BOP_PLUS) { + auto *arr_l = static_cast(lhs.v.h); + auto *arr_r = static_cast(rhs.v.h); + std::vector elements; + for (auto *el : arr_l->elements) + elements.push_back(el); + for (auto *el : arr_r->elements) + elements.push_back(el); + scratch = makeArray(elements); + } else { + throw makeError(ast.location, + "Binary operator " + bop_string(ast.op) + + " does not operate on arrays."); + } + break; + + case Value::BOOLEAN: + switch (ast.op) { + case BOP_AND: + scratch = makeBoolean(lhs.v.b && rhs.v.b); + break; + + case BOP_OR: + scratch = makeBoolean(lhs.v.b || rhs.v.b); + break; + + default: + throw makeError(ast.location, + "Binary operator " + bop_string(ast.op) + + " does not operate on booleans."); + } + break; + + case Value::DOUBLE: + switch (ast.op) { + case BOP_PLUS: + scratch = makeDoubleCheck(ast.location, lhs.v.d + rhs.v.d); + break; + + case BOP_MINUS: + scratch = makeDoubleCheck(ast.location, lhs.v.d - rhs.v.d); + break; + + case BOP_MULT: + scratch = makeDoubleCheck(ast.location, lhs.v.d * rhs.v.d); + break; + + case BOP_DIV: + if (rhs.v.d == 0) + throw makeError(ast.location, "Division by zero."); + scratch = makeDoubleCheck(ast.location, lhs.v.d / rhs.v.d); + break; + + // No need to check doubles made from longs + + case BOP_SHIFT_L: { + long long_l = lhs.v.d; + long long_r = rhs.v.d; + scratch = makeDouble(long_l << long_r); + } break; + + case BOP_SHIFT_R: { + long long_l = lhs.v.d; + long long_r = rhs.v.d; + scratch = makeDouble(long_l >> long_r); + } break; + + case BOP_BITWISE_AND: { + long long_l = lhs.v.d; + long long_r = rhs.v.d; + scratch = makeDouble(long_l & long_r); + } break; + + case BOP_BITWISE_XOR: { + long long_l = lhs.v.d; + long long_r = rhs.v.d; + scratch = makeDouble(long_l ^ long_r); + } break; + + case BOP_BITWISE_OR: { + long long_l = lhs.v.d; + long long_r = rhs.v.d; + scratch = makeDouble(long_l | long_r); + } break; + + case BOP_LESS_EQ: + scratch = makeBoolean(lhs.v.d <= rhs.v.d); + break; + + case BOP_GREATER_EQ: + scratch = makeBoolean(lhs.v.d >= rhs.v.d); + break; + + case BOP_LESS: + scratch = makeBoolean(lhs.v.d < rhs.v.d); + break; + + case BOP_GREATER: + scratch = makeBoolean(lhs.v.d > rhs.v.d); + break; + + default: + throw makeError(ast.location, + "Binary operator " + bop_string(ast.op) + + " does not operate on numbers."); + } + break; + + case Value::FUNCTION: + throw makeError(ast.location, "Binary operator " + bop_string(ast.op) + + " does not operate on functions."); + + case Value::NULL_TYPE: + throw makeError(ast.location, "Binary operator " + bop_string(ast.op) + + " does not operate on null."); + + case Value::OBJECT: { + if (ast.op != BOP_PLUS) { + throw makeError(ast.location, + "Binary operator " + bop_string(ast.op) + + " does not operate on objects."); + } + auto *lhs_obj = static_cast(lhs.v.h); + auto *rhs_obj = static_cast(rhs.v.h); + scratch = makeObject(lhs_obj, rhs_obj); + } + break; + + case Value::STRING: { + const String &lhs_str = + static_cast(lhs.v.h)->value; + const String &rhs_str = + static_cast(rhs.v.h)->value; + switch (ast.op) { + case BOP_PLUS: + scratch = makeString(lhs_str + rhs_str); + break; + + case BOP_LESS_EQ: + scratch = makeBoolean(lhs_str <= rhs_str); + break; + + case BOP_GREATER_EQ: + scratch = makeBoolean(lhs_str >= rhs_str); + break; + + case BOP_LESS: + scratch = makeBoolean(lhs_str < rhs_str); + break; + + case BOP_GREATER: + scratch = makeBoolean(lhs_str > rhs_str); + break; + + default: + throw makeError(ast.location, + "Binary operator " + bop_string(ast.op) + + " does not operate on strings."); + } + } + break; + } + } break; + + case FRAME_BUILTIN_FILTER: { + const auto &ast = *static_cast(f.ast); + auto *func = static_cast(f.val.v.h); + auto *arr = static_cast(f.val2.v.h); + if (scratch.t != Value::BOOLEAN) { + throw makeError(ast.location, + "filter function must return boolean, got: " + + type_str(scratch)); + } + if (scratch.v.b) f.thunks.push_back(arr->elements[f.elementId]); + f.elementId++; + // Iterate through arr, calling the function on each. + if (f.elementId == arr->elements.size()) { + scratch = makeArray(f.thunks); + } else { + auto *thunk = arr->elements[f.elementId]; + BindingFrame bindings = func->upValues; + bindings[func->params[0].id] = thunk; + stack.newCall(ast.location, func, func->self, func->offset, bindings); + ast_ = func->body; + goto recurse; + } + } break; + + case FRAME_BUILTIN_FORCE_THUNKS: { + const auto &ast = *static_cast(f.ast); + auto *func = static_cast(f.val.v.h); + if (f.elementId == f.thunks.size()) { + // All thunks forced, now the builtin implementations. + const LocationRange &loc = ast.location; + const std::string &builtin_name = func->builtinName; + std::vector args; + for (auto *th : f.thunks) { + args.push_back(th->content); + } + BuiltinMap::const_iterator bit = builtins.find(builtin_name); + if (bit != builtins.end()) { + const AST *new_ast = (this->*bit->second)(loc, args); + if (new_ast != nullptr) { + ast_ = new_ast; + goto recurse; + } + break; + } + VmNativeCallbackMap::const_iterator nit = + nativeCallbacks.find(builtin_name); + // TODO(dcunnin): Support arrays. + // TODO(dcunnin): Support objects. + std::vector args2; + for (const Value &arg : args) { + switch (arg.t) { + case Value::STRING: + args2.push_back(JsonnetJsonValue{ + JsonnetJsonValue::STRING, + encode_utf8(static_cast(arg.v.h)->value), + 0, + std::vector>{}, + std::map>{}, + }); + break; + + case Value::BOOLEAN: + args2.push_back(JsonnetJsonValue{ + JsonnetJsonValue::BOOL, + "", + arg.v.b ? 1.0 : 0.0, + std::vector>{}, + std::map>{}, + }); + break; + + case Value::DOUBLE: + args2.push_back(JsonnetJsonValue{ + JsonnetJsonValue::NUMBER, + "", + arg.v.d, + std::vector>{}, + std::map>{}, + }); + break; + + case Value::NULL_TYPE: + args2.push_back(JsonnetJsonValue{ + JsonnetJsonValue::NULL_KIND, + "", + 0, + std::vector>{}, + std::map>{}, + }); + break; + + default: + throw makeError(ast.location, + "Native extensions can only take primitives."); + } + + } + std::vector args3; + for (size_t i = 0; i < args2.size() ; ++i) { + args3.push_back(&args2[i]); + } + if (nit == nativeCallbacks.end()) { + throw makeError(ast.location, + "Unrecognized builtin name: " + builtin_name); + } + const VmNativeCallback &cb = nit->second; + + int succ; + std::unique_ptr r(cb.cb(cb.ctx, &args3[0], &succ)); + + if (succ) { + bool unused; + jsonToHeap(r, unused, scratch); + } else { + if (r->kind != JsonnetJsonValue::STRING) { + throw makeError( + ast.location, + "Native extension returned an error that was not a string."); + } + std::string rs = r->string; + throw makeError(ast.location, rs); + } + + } else { + // Not all arguments forced yet. + HeapThunk *th = f.thunks[f.elementId++]; + if (!th->filled) { + stack.newCall(ast.location, th, th->self, th->offset, th->upValues); + ast_ = th->body; + goto recurse; + } + } + } break; + + case FRAME_CALL: { + if (auto *thunk = dynamic_cast(f.context)) { + // If we called a thunk, cache result. + thunk->fill(scratch); + } else if (auto *closure = dynamic_cast(f.context)) { + if (f.elementId < f.thunks.size()) { + // If tailstrict, force thunks + HeapThunk *th = f.thunks[f.elementId++]; + if (!th->filled) { + stack.newCall(f.location, th, + th->self, th->offset, th->upValues); + ast_ = th->body; + goto recurse; + } + } else if (f.thunks.size() == 0) { + // Body has now been executed + } else { + // Execute the body + f.thunks.clear(); + f.elementId = 0; + ast_ = closure->body; + goto recurse; + } + } + // Result of call is in scratch, just pop. + } break; + + case FRAME_ERROR: { + const auto &ast = *static_cast(f.ast); + String msg; + if (scratch.t == Value::STRING) { + msg = static_cast(scratch.v.h)->value; + } else { + msg = toString(ast.location); + } + throw makeError(ast.location, encode_utf8(msg)); + } break; + + case FRAME_IF: { + const auto &ast = *static_cast(f.ast); + if (scratch.t != Value::BOOLEAN) { + throw makeError(ast.location, "Condition must be boolean, got " + + type_str(scratch) + "."); + } + ast_ = scratch.v.b ? ast.branchTrue : ast.branchFalse; + stack.pop(); + goto recurse; + } break; + + case FRAME_SUPER_INDEX: { + const auto &ast = *static_cast(f.ast); + HeapObject *self; + unsigned offset; + stack.getSelfBinding(self, offset); + offset++; + if (offset >= countLeaves(self)) { + throw makeError(ast.location, + "Attempt to use super when there is no super class."); + } + if (scratch.t != Value::STRING) { + throw makeError(ast.location, + "Super index must be string, got " + + type_str(scratch) + "."); + } + + const String &index_name = + static_cast(scratch.v.h)->value; + auto *fid = alloc->makeIdentifier(index_name); + stack.pop(); + ast_ = objectIndex(ast.location, self, fid, offset); + goto recurse; + } break; + + case FRAME_INDEX_INDEX: { + const auto &ast = *static_cast(f.ast); + const Value &target = f.val; + if (target.t == Value::ARRAY) { + const auto *array = static_cast(target.v.h); + if (scratch.t != Value::DOUBLE) { + throw makeError(ast.location, "Array index must be number, got " + + type_str(scratch) + "."); + } + long i = long(scratch.v.d); + long sz = array->elements.size(); + if (i < 0 || i >= sz) { + std::stringstream ss; + ss << "Array bounds error: " << i + << " not within [0, " << sz << ")"; + throw makeError(ast.location, ss.str()); + } + auto *thunk = array->elements[i]; + if (thunk->filled) { + scratch = thunk->content; + } else { + stack.pop(); + stack.newCall(ast.location, thunk, + thunk->self, thunk->offset, thunk->upValues); + ast_ = thunk->body; + goto recurse; + } + } else if (target.t == Value::OBJECT) { + auto *obj = static_cast(target.v.h); + assert(obj != nullptr); + if (scratch.t != Value::STRING) { + throw makeError(ast.location, + "Object index must be string, got " + + type_str(scratch) + "."); + } + const String &index_name = + static_cast(scratch.v.h)->value; + auto *fid = alloc->makeIdentifier(index_name); + stack.pop(); + ast_ = objectIndex(ast.location, obj, fid, 0); + goto recurse; + } else if (target.t == Value::STRING) { + auto *obj = static_cast(target.v.h); + assert(obj != nullptr); + if (scratch.t != Value::DOUBLE) { + throw makeError(ast.location, + "String index must be a number, got " + + type_str(scratch) + "."); + } + long sz = obj->value.length(); + long i = (long)scratch.v.d; + if (i < 0 || i >= sz) { + std::stringstream ss; + ss << "String bounds error: " << i + << " not within [0, " << sz << ")"; + throw makeError(ast.location, ss.str()); + } + char32_t ch[] = {obj->value[i], U'\0'}; + scratch = makeString(ch); + } else { + std::cerr << "INTERNAL ERROR: Not object / array / string." << std::endl; + abort(); + } + } break; + + case FRAME_INDEX_TARGET: { + const auto &ast = *static_cast(f.ast); + if (scratch.t != Value::ARRAY + && scratch.t != Value::OBJECT + && scratch.t != Value::STRING) { + throw makeError(ast.location, + "Can only index objects, strings, and arrays, got " + + type_str(scratch) + "."); + } + f.val = scratch; + f.kind = FRAME_INDEX_INDEX; + if (scratch.t == Value::OBJECT) { + auto *self = static_cast(scratch.v.h); + if (!stack.alreadyExecutingInvariants(self)) { + stack.newFrame(FRAME_INVARIANTS, ast.location); + Frame &f2 = stack.top(); + f2.self = self; + unsigned counter = 0; + objectInvariants(self, self, counter, f2.thunks); + if (f2.thunks.size() > 0) { + auto *thunk = f2.thunks[0]; + f2.elementId = 1; + stack.newCall(ast.location, thunk, + thunk->self, thunk->offset, thunk->upValues); + ast_ = thunk->body; + goto recurse; + } + } + } + ast_ = ast.index; + goto recurse; + } break; + + case FRAME_INVARIANTS: { + if (f.elementId >= f.thunks.size()) { + if (stack.size() == initial_stack_size + 1) { + // Just pop, evaluate was invoked by runInvariants. + break; + } + stack.pop(); + Frame &f2 = stack.top(); + const auto &ast = *static_cast(f2.ast); + ast_ = ast.index; + goto recurse; + } + auto *thunk = f.thunks[f.elementId++]; + stack.newCall(f.location, thunk, + thunk->self, thunk->offset, thunk->upValues); + ast_ = thunk->body; + goto recurse; + } break; + + case FRAME_LOCAL: { + // Result of execution is in scratch already. + } break; + + case FRAME_OBJECT: { + const auto &ast = *static_cast(f.ast); + if (scratch.t != Value::NULL_TYPE) { + if (scratch.t != Value::STRING) { + throw makeError(ast.location, "Field name was not a string."); + } + const auto &fname = static_cast(scratch.v.h)->value; + const Identifier *fid = alloc->makeIdentifier(fname); + if (f.objectFields.find(fid) != f.objectFields.end()) { + std::string msg = "Duplicate field name: \"" + + encode_utf8(fname) + "\""; + throw makeError(ast.location, msg); + } + f.objectFields[fid].hide = f.fit->hide; + f.objectFields[fid].body = f.fit->body; + } + f.fit++; + if (f.fit != ast.fields.end()) { + ast_ = f.fit->name; + goto recurse; + } else { + auto env = capture(ast.freeVariables); + scratch = makeObject(env, f.objectFields, ast.asserts); + } + } break; + + case FRAME_OBJECT_COMP_ARRAY: { + const auto &ast = *static_cast(f.ast); + const Value &arr_v = scratch; + if (scratch.t != Value::ARRAY) { + throw makeError(ast.location, + "Object comprehension needs array, got " + + type_str(arr_v)); + } + const auto *arr = static_cast(arr_v.v.h); + if (arr->elements.size() == 0) { + // Degenerate case. Just create the object now. + scratch = makeObject(BindingFrame{}, ast.value, + ast.id, BindingFrame{}); + } else { + f.kind = FRAME_OBJECT_COMP_ELEMENT; + f.val = scratch; + f.bindings[ast.id] = arr->elements[0]; + f.elementId = 0; + ast_ = ast.field; + goto recurse; + } + } break; + + case FRAME_OBJECT_COMP_ELEMENT: { + const auto &ast = *static_cast(f.ast); + const auto *arr = static_cast(f.val.v.h); + if (scratch.t != Value::STRING) { + std::stringstream ss; + ss << "field must be string, got: " << type_str(scratch); + throw makeError(ast.location, ss.str()); + } + const auto &fname = static_cast(scratch.v.h)->value; + const Identifier *fid = alloc->makeIdentifier(fname); + if (f.elements.find(fid) != f.elements.end()) { + throw makeError(ast.location, + "Duplicate field name: \"" + encode_utf8(fname) + "\""); + } + f.elements[fid] = arr->elements[f.elementId]; + f.elementId++; + + if (f.elementId == arr->elements.size()) { + auto env = capture(ast.freeVariables); + scratch = makeObject(env, ast.value, + ast.id, f.elements); + } else { + f.bindings[ast.id] = arr->elements[f.elementId]; + ast_ = ast.field; + goto recurse; + } + } break; + + case FRAME_STRING_CONCAT: { + const auto &ast = *static_cast(f.ast); + const Value &lhs = stack.top().val; + const Value &rhs = stack.top().val2; + String output; + if (lhs.t == Value::STRING) { + output.append(static_cast(lhs.v.h)->value); + } else { + scratch = lhs; + output.append(toString(ast.left->location)); + } + if (rhs.t == Value::STRING) { + output.append(static_cast(rhs.v.h)->value); + } else { + scratch = rhs; + output.append(toString(ast.right->location)); + } + scratch = makeString(output); + } break; + + case FRAME_UNARY: { + const auto &ast = *static_cast(f.ast); + switch (scratch.t) { + + case Value::BOOLEAN: + if (ast.op == UOP_NOT) { + scratch = makeBoolean(!scratch.v.b); + } else { + throw makeError(ast.location, + "Unary operator " + uop_string(ast.op) + + " does not operate on booleans."); + } + break; + + case Value::DOUBLE: + switch (ast.op) { + case UOP_PLUS: + break; + + case UOP_MINUS: + scratch = makeDouble(-scratch.v.d); + break; + + case UOP_BITWISE_NOT: + scratch = makeDouble(~(long)(scratch.v.d)); + break; + + default: + throw makeError(ast.location, + "Unary operator " + uop_string(ast.op) + + " does not operate on numbers."); + } + break; + + default: + throw makeError(ast.location, + "Unary operator " + uop_string(ast.op) + + " does not operate on type " + type_str(scratch)); + } + } break; + + default: + std::cerr << "INTERNAL ERROR: Unknown FrameKind: " << f.kind << std::endl; + std::abort(); + } + + popframe:; + + stack.pop(); + + replaceframe:; + } + } + + /** Manifest the scratch value by evaluating any remaining fields, and then convert to JSON. + * + * This can trigger a garbage collection cycle. Be sure to stash any objects that aren't + * reachable via the stack or heap. + * + * \param multiline If true, will print objects and arrays in an indented fashion. + */ + String manifestJson(const LocationRange &loc, bool multiline, const String &indent) + { + // Printing fields means evaluating and binding them, which can trigger + // garbage collection. + + StringStream ss; + switch (scratch.t) { + case Value::ARRAY: { + HeapArray *arr = static_cast(scratch.v.h); + if (arr->elements.size() == 0) { + ss << U"[ ]"; + } else { + const char32_t *prefix = multiline ? U"[\n" : U"["; + String indent2 = multiline ? indent + U" " : indent; + for (auto *thunk : arr->elements) { + LocationRange tloc = thunk->body == nullptr + ? loc + : thunk->body->location; + if (thunk->filled) { + stack.newCall(loc, thunk, nullptr, 0, BindingFrame{}); + // Keep arr alive when scratch is overwritten + stack.top().val = scratch; + scratch = thunk->content; + } else { + stack.newCall(loc, thunk, thunk->self, thunk->offset, thunk->upValues); + // Keep arr alive when scratch is overwritten + stack.top().val = scratch; + evaluate(thunk->body, stack.size()); + } + auto element = manifestJson(tloc, multiline, indent2); + // Restore scratch + scratch = stack.top().val; + stack.pop(); + ss << prefix << indent2 << element; + prefix = multiline ? U",\n" : U", "; + } + ss << (multiline ? U"\n" : U"") << indent << U"]"; + } + } + break; + + case Value::BOOLEAN: + ss << (scratch.v.b ? U"true" : U"false"); + break; + + case Value::DOUBLE: + ss << decode_utf8(jsonnet_unparse_number(scratch.v.d)); + break; + + case Value::FUNCTION: + throw makeError(loc, "Couldn't manifest function in JSON output."); + + case Value::NULL_TYPE: + ss << U"null"; + break; + + case Value::OBJECT: { + auto *obj = static_cast(scratch.v.h); + runInvariants(loc, obj); + // Using std::map has the useful side-effect of ordering the fields + // alphabetically. + std::map fields; + for (const auto &f : objectFields(obj, true)) { + fields[f->name] = f; + } + if (fields.size() == 0) { + ss << U"{ }"; + } else { + String indent2 = multiline ? indent + U" " : indent; + const char32_t *prefix = multiline ? U"{\n" : U"{"; + for (const auto &f : fields) { + // pushes FRAME_CALL + const AST *body = objectIndex(loc, obj, f.second, 0); + stack.top().val = scratch; + evaluate(body, stack.size()); + auto vstr = manifestJson(body->location, multiline, indent2); + // Reset scratch so that the object we're manifesting doesn't + // get GC'd. + scratch = stack.top().val; + stack.pop(); + ss << prefix << indent2 << jsonnet_string_unparse(f.first, false) + << U": " << vstr; + prefix = multiline ? U",\n" : U", "; + } + ss << (multiline ? U"\n" : U"") << indent << U"}"; + } + } + break; + + case Value::STRING: { + const String &str = static_cast(scratch.v.h)->value; + ss << jsonnet_string_unparse(str, false); + } + break; + } + return ss.str(); + } + + String manifestString(const LocationRange &loc) + { + if (scratch.t != Value::STRING) { + std::stringstream ss; + ss << "Expected string result, got: " << type_str(scratch.t); + throw makeError(loc, ss.str()); + } + return static_cast(scratch.v.h)->value; + } + + StrMap manifestMulti(bool string) + { + StrMap r; + LocationRange loc("During manifestation"); + if (scratch.t != Value::OBJECT) { + std::stringstream ss; + ss << "Multi mode: Top-level object was a " << type_str(scratch.t) << ", " + << "should be an object whose keys are filenames and values hold " + << "the JSON for that file."; + throw makeError(loc, ss.str()); + } + auto *obj = static_cast(scratch.v.h); + runInvariants(loc, obj); + std::map fields; + for (const auto &f : objectFields(obj, true)) { + fields[f->name] = f; + } + for (const auto &f : fields) { + // pushes FRAME_CALL + const AST *body = objectIndex(loc, obj, f.second, 0); + stack.top().val = scratch; + evaluate(body, stack.size()); + auto vstr = string ? manifestString(body->location) + : manifestJson(body->location, true, U""); + // Reset scratch so that the object we're manifesting doesn't + // get GC'd. + scratch = stack.top().val; + stack.pop(); + r[encode_utf8(f.first)] = encode_utf8(vstr); + } + return r; + } + + std::vector manifestStream(void) + { + std::vector r; + LocationRange loc("During manifestation"); + if (scratch.t != Value::ARRAY) { + std::stringstream ss; + ss << "Stream mode: Top-level object was a " << type_str(scratch.t) << ", " + << "should be an array whose elements hold " + << "the JSON for each document in the stream."; + throw makeError(loc, ss.str()); + } + auto *arr = static_cast(scratch.v.h); + for (auto *thunk : arr->elements) { + LocationRange tloc = thunk->body == nullptr + ? loc + : thunk->body->location; + if (thunk->filled) { + stack.newCall(loc, thunk, nullptr, 0, BindingFrame{}); + // Keep arr alive when scratch is overwritten + stack.top().val = scratch; + scratch = thunk->content; + } else { + stack.newCall(loc, thunk, thunk->self, thunk->offset, thunk->upValues); + // Keep arr alive when scratch is overwritten + stack.top().val = scratch; + evaluate(thunk->body, stack.size()); + } + String element = manifestJson(tloc, true, U""); + scratch = stack.top().val; + stack.pop(); + r.push_back(encode_utf8(element)); + } + return r; + } + +}; + +} // namespace + +std::string jsonnet_vm_execute( + Allocator *alloc, + const AST *ast, + const ExtMap &ext_vars, + unsigned max_stack, + double gc_min_objects, + double gc_growth_trigger, + const VmNativeCallbackMap &natives, + JsonnetImportCallback *import_callback, + void *ctx, + bool string_output) +{ + Interpreter vm(alloc, ext_vars, max_stack, gc_min_objects, gc_growth_trigger, + natives, import_callback, ctx); + vm.evaluate(ast, 0); + if (string_output) { + return encode_utf8(vm.manifestString(LocationRange("During manifestation"))); + } else { + return encode_utf8(vm.manifestJson(LocationRange("During manifestation"), true, U"")); + } +} + +StrMap jsonnet_vm_execute_multi( + Allocator *alloc, + const AST *ast, + const ExtMap &ext_vars, + unsigned max_stack, + double gc_min_objects, + double gc_growth_trigger, + const VmNativeCallbackMap &natives, + JsonnetImportCallback *import_callback, + void *ctx, + bool string_output) +{ + Interpreter vm(alloc, ext_vars, max_stack, gc_min_objects, gc_growth_trigger, + natives, import_callback, ctx); + vm.evaluate(ast, 0); + return vm.manifestMulti(string_output); +} + +std::vector jsonnet_vm_execute_stream( + Allocator *alloc, + const AST *ast, + const ExtMap &ext_vars, + unsigned max_stack, + double gc_min_objects, + double gc_growth_trigger, + const VmNativeCallbackMap &natives, + JsonnetImportCallback *import_callback, + void *ctx) +{ + Interpreter vm(alloc, ext_vars, max_stack, gc_min_objects, gc_growth_trigger, + natives, import_callback, ctx); + vm.evaluate(ast, 0); + return vm.manifestStream(); +} + + diff --git a/vendor/github.com/strickyak/jsonnet_cgo/vm.h b/vendor/github.com/strickyak/jsonnet_cgo/vm.h new file mode 100644 index 00000000..2f6f7bd7 --- /dev/null +++ b/vendor/github.com/strickyak/jsonnet_cgo/vm.h @@ -0,0 +1,148 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef JSONNET_VM_H +#define JSONNET_VM_H + +#include + +#include "ast.h" + +/** A single line of a stack trace from a runtime error. + */ +struct TraceFrame { + LocationRange location; + std::string name; + TraceFrame(const LocationRange &location, const std::string &name="") + : location(location), name(name) + { } +}; + +/** Exception that is thrown by the interpreter when it reaches an error construct, or divide by + * zero, array bounds error, dynamic type error, etc. + */ +struct RuntimeError { + std::vector stackTrace; + std::string msg; + RuntimeError(const std::vector stack_trace, const std::string &msg) + : stackTrace(stack_trace), msg(msg) + { } +}; + +/** Holds native callback and context. */ +struct VmNativeCallback { + JsonnetNativeCallback *cb; + void *ctx; + std::vector params; +}; + +typedef std::map VmNativeCallbackMap; + +/** Stores external values / code. */ +struct VmExt { + std::string data; + bool isCode; + VmExt() : isCode(false) { } + VmExt(const std::string &data, bool is_code) + : data(data), isCode(is_code) + { } +}; + + +/** Execute the program and return the value as a JSON string. + * + * \param alloc The allocator used to create the ast. + * \param ast The program to execute. + * \param ext The external vars / code. + * \param max_stack Recursion beyond this level gives an error. + * \param gc_min_objects The garbage collector does not run when the heap is this small. + * \param gc_growth_trigger Growth since last garbage collection cycle to trigger a new cycle. + * \param import_callback A callback to handle imports + * \param import_callback_ctx Context param for the import callback. + * \param output_string Whether to expect a string and output it without JSON encoding + * \throws RuntimeError reports runtime errors in the program. + * \returns The JSON result in string form. + */ +std::string jsonnet_vm_execute( + Allocator *alloc, const AST *ast, + const std::map &ext, + unsigned max_stack, + double gc_min_objects, + double gc_growth_trigger, + const VmNativeCallbackMap &natives, + JsonnetImportCallback *import_callback, + void *import_callback_ctx, + bool string_output); + +/** Execute the program and return the value as a number of named JSON files. + * + * This assumes the given program yields an object whose keys are filenames. + * + * \param alloc The allocator used to create the ast. + * \param ast The program to execute. + * \param ext The external vars / code. + * \param tla The top-level arguments (strings or code). + * \param max_stack Recursion beyond this level gives an error. + * \param gc_min_objects The garbage collector does not run when the heap is this small. + * \param gc_growth_trigger Growth since last garbage collection cycle to trigger a new cycle. + * \param import_callback A callback to handle imports + * \param import_callback_ctx Context param for the import callback. + * \param output_string Whether to expect a string and output it without JSON encoding + * \throws RuntimeError reports runtime errors in the program. + * \returns A mapping from filename to the JSON strings for that file. + */ +std::map jsonnet_vm_execute_multi( + Allocator *alloc, + const AST *ast, + const std::map &ext, + unsigned max_stack, + double gc_min_objects, + double gc_growth_trigger, + const VmNativeCallbackMap &natives, + JsonnetImportCallback *import_callback, + void *import_callback_ctx, + bool string_output); + +/** Execute the program and return the value as a stream of JSON files. + * + * This assumes the given program yields an array whose elements are individual + * JSON files. + * + * \param alloc The allocator used to create the ast. + * \param ast The program to execute. + * \param ext The external vars / code. + * \param tla The top-level arguments (strings or code). + * \param max_stack Recursion beyond this level gives an error. + * \param gc_min_objects The garbage collector does not run when the heap is this small. + * \param gc_growth_trigger Growth since last garbage collection cycle to trigger a new cycle. + * \param import_callback A callback to handle imports + * \param import_callback_ctx Context param for the import callback. + * \param output_string Whether to expect a string and output it without JSON encoding + * \throws RuntimeError reports runtime errors in the program. + * \returns A mapping from filename to the JSON strings for that file. + */ +std::vector jsonnet_vm_execute_stream( + Allocator *alloc, + const AST *ast, + const std::map &ext, + unsigned max_stack, + double gc_min_objects, + double gc_growth_trigger, + const VmNativeCallbackMap &natives, + JsonnetImportCallback *import_callback, + void *import_callback_ctx); + +#endif diff --git a/vendor/vendor.json b/vendor/vendor.json new file mode 100644 index 00000000..3bb0a498 --- /dev/null +++ b/vendor/vendor.json @@ -0,0 +1,37 @@ +{ + "comment": "", + "ignore": "test", + "package": [ + { + "checksumSHA1": "HmbftipkadrLlCfzzVQ+iFHbl6g=", + "path": "github.com/golang/glog", + "revision": "23def4e6c14b4da8ac2ed8007337bc5eb5007998", + "revisionTime": "2016-01-25T20:49:56Z" + }, + { + "checksumSHA1": "40vJyUB4ezQSn/NSadsKEOrudMc=", + "path": "github.com/inconshreveable/mousetrap", + "revision": "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75", + "revisionTime": "2014-10-17T20:07:13Z" + }, + { + "checksumSHA1": "Wgm8Y0np1Usy3+ZTTPFdHoqzed8=", + "path": "github.com/spf13/cobra", + "revision": "4673102358fdd630e3bb0eb6dee96e4b533d53ec", + "revisionTime": "2017-05-11T15:04:35Z" + }, + { + "checksumSHA1": "STxYqRb4gnlSr3mRpT+Igfdz/kM=", + "path": "github.com/spf13/pflag", + "revision": "e57e3eeb33f795204c1ca35f56c44f83227c6e66", + "revisionTime": "2017-05-08T18:43:26Z" + }, + { + "checksumSHA1": "BXgH3TNmg26Ql/fH29Yb3dR3u2g=", + "path": "github.com/strickyak/jsonnet_cgo", + "revision": "f22f0c43815490049135532023c27392536b057b", + "revisionTime": "2017-04-18T07:42:43Z" + } + ], + "rootPath": "github.com/anguslees/kubecfg" +}