summaryrefslogtreecommitdiffhomepage
path: root/tools/go_generics/defs.bzl
diff options
context:
space:
mode:
Diffstat (limited to 'tools/go_generics/defs.bzl')
-rw-r--r--tools/go_generics/defs.bzl152
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,
+)