diff options
Diffstat (limited to 'tools/go_generics/defs.bzl')
-rw-r--r-- | tools/go_generics/defs.bzl | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/tools/go_generics/defs.bzl b/tools/go_generics/defs.bzl new file mode 100644 index 000000000..0b2467805 --- /dev/null +++ b/tools/go_generics/defs.bzl @@ -0,0 +1,152 @@ +def _go_template_impl(ctx): + input = ctx.files.srcs + output = ctx.outputs.out + + args = ["-o=%s" % output.path] + [f.path for f in input] + + ctx.actions.run( + inputs = input, + outputs = [output], + mnemonic = "GoGenericsTemplate", + progress_message = "Building Go template %s" % ctx.label, + arguments = args, + executable = ctx.executable._tool, + ) + + return struct( + types = ctx.attr.types, + opt_types = ctx.attr.opt_types, + consts = ctx.attr.consts, + opt_consts = ctx.attr.opt_consts, + deps = ctx.attr.deps, + file = output, + ) + +""" +Generates a Go template from a set of Go files. + +A Go template is similar to a go library, except that it has certain types that +can be replaced before usage. For example, one could define a templatized List +struct, whose elements are of type T, then instantiate that template for +T=segment, where "segment" is the concrete type. + +Args: + name: the name of the template. + srcs: the list of source files that comprise the template. + types: the list of generic types in the template that are required to be specified. + opt_types: the list of generic types in the template that can but aren't required to be specified. + consts: the list of constants in the template that are required to be specified. + opt_consts: the list of constants in the template that can but aren't required to be specified. + deps: the list of dependencies. +""" + +go_template = rule( + attrs = { + "srcs": attr.label_list( + mandatory = True, + allow_files = True, + ), + "deps": attr.label_list(allow_files = True), + "types": attr.string_list(), + "opt_types": attr.string_list(), + "consts": attr.string_list(), + "opt_consts": attr.string_list(), + "_tool": attr.label( + executable = True, + cfg = "host", + default = Label("//tools/go_generics:go_merge"), + ), + }, + outputs = { + "out": "%{name}_template.go", + }, + implementation = _go_template_impl, +) + +def _go_template_instance_impl(ctx): + template = ctx.attr.template + output = ctx.outputs.out + + # Check that all required types are defined. + for t in template.types: + if t not in ctx.attr.types: + fail("Missing value for type %s in %s" % (t, ctx.attr.template.label)) + + # Check that all defined types are expected by the template. + for t in ctx.attr.types: + if (t not in template.types) and (t not in template.opt_types): + fail("Type %s it not a parameter to %s" % (t, ctx.attr.template.label)) + + # Check that all required consts are defined. + for t in template.consts: + if t not in ctx.attr.consts: + fail("Missing value for constant %s in %s" % (t, ctx.attr.template.label)) + + # Check that all defined consts are expected by the template. + for t in ctx.attr.consts: + if (t not in template.consts) and (t not in template.opt_consts): + fail("Const %s it not a parameter to %s" % (t, ctx.attr.template.label)) + + # Build the argument list. + args = ["-i=%s" % template.file.path, "-o=%s" % output.path] + args += ["-p=%s" % ctx.attr.package] + + if len(ctx.attr.prefix) > 0: + args += ["-prefix=%s" % ctx.attr.prefix] + + if len(ctx.attr.suffix) > 0: + args += ["-suffix=%s" % ctx.attr.suffix] + + args += [("-t=%s=%s" % (p[0], p[1])) for p in ctx.attr.types.items()] + args += [("-c=%s=%s" % (p[0], p[1])) for p in ctx.attr.consts.items()] + args += [("-import=%s=%s" % (p[0], p[1])) for p in ctx.attr.imports.items()] + + ctx.actions.run( + inputs = [template.file], + outputs = [output], + mnemonic = "GoGenericsInstance", + progress_message = "Building Go template instance %s" % ctx.label, + arguments = args, + executable = ctx.executable._tool, + ) + + # TODO: How can we get the dependencies out? + return struct( + files = depset([output]) + ) + +""" +Instantiates a Go template by replacing all generic types with concrete ones. + +Args: + name: the name of the template instance. + template: the label of the template to be instatiated. + prefix: a prefix to be added to globals in the template. + suffix: a suffix to be added to global in the template. + types: the map from generic type names to concrete ones. + consts: the map from constant names to their values. + imports: the map from imports used in types/consts to their import paths. + package: the name of the package the instantiated template will be compiled into. +""" + +go_template_instance = rule( + attrs = { + "template": attr.label( + mandatory = True, + providers = ["types"], + ), + "prefix": attr.string(), + "suffix": attr.string(), + "types": attr.string_dict(), + "consts": attr.string_dict(), + "imports": attr.string_dict(), + "package": attr.string(mandatory = True), + "out": attr.output(mandatory = True), + "_tool": attr.label( + executable = True, + cfg = "host", + default = Label("//tools/go_generics"), + ), + }, + implementation = _go_template_instance_impl, +) |