dgotemplate is a D implementation of Go text/template.
Initial scope targets text/template behavior only. Go html/template is out
of scope.
- Primary verified compiler:
ldc2 - Secondary verified compiler:
dmd(current local matrix runs with--temp-build)
dub test --compiler=ldc2tests/fixtures/go-template/go1.26.1/ contains fixture data derived from Go
standard library tests in text/template/parse and text/template.
The full conformance helper currently passes the generated Go 1.26.1 fixture corpus:
lexTests: 40/40
parseTests: 108/108
errorTests: 32/32
execTests: 356/356
Regenerate fixtures with:
GO111MODULE=off go run ./tools/go-template-fixtures \
-goroot "$(go env GOROOT)" \
-out tests/fixtures/go-template/go1.26.1 \
-package text/template/parse \
-table lexTests \
-table parseTests \
-table errorTests
GO111MODULE=off go run ./tools/go-template-fixtures \
-goroot "$(go env GOROOT)" \
-out tests/fixtures/go-template/go1.26.1 \
-package text/template \
-table execTests \
-exec-limit 356Run the full generated corpus in an isolated helper worktree with:
tools/check-go-template-conformance.shDerived fixture data is covered by
tests/fixtures/go-template/go1.26.1/LICENSE.go.
The public facade exports parse, render, parseFiles, and
parseGlob.
import dgotemplate;
import std.string : toLower;
void main()
{
struct Data
{
string Name;
}
auto data = Data("D");
auto output = render("hello {{.Name}}", data);
auto funcs = FunctionRegistry()
.add("lower", (string value) => value.toLower);
auto typed = parse("typed", "{{lower .Name}}");
typed.funcs(funcs);
auto lowered = typed.execute(data);
auto templateValue = parseFiles(["layout.tmpl", "content.tmpl"]);
auto mergedOutput = templateValue.execute(data);
}Typed function registration keeps Go template call syntax unchanged while providing D-friendly overload helpers:
auto funcs = FunctionRegistry()
.add("lower", (string value) => value.toLower) // replaces "lower"
.addOverload("format", cast(string function(int)) &formatInt)
.addOverload("format", cast(string function(string)) &formatString)
.addOverloads!(__traits(getOverloads, mymodule, "formatAuto"))("format");add registers one typed callable and replaces any prior entry for that name.
addOverload appends one typed overload candidate, and addOverloads appends
an alias sequence of D overloads. This is a D host-language convenience and
does not change Go template syntax.
Passing the generated Go fixture corpus does not mean dgotemplate is a full
Go runtime or reflection model. The public API accepts native D data, while
Go's template executor relies heavily on reflection,
method sets, pointer/interface identity, typed nils, callable values,
iterators, complex numbers, exact integer types, and fmt behavior.
The conformance fixtures include a small internal schema for Go-only concepts that plain D values do not naturally carry. Fixture decoding translates that schema into internal runtime values before execution. This is test infrastructure, not a supported input format for application code. Examples include projected methods, typed nils, typed integer metadata, complex values, slice capacity, typed maps, display overrides, and iterator/range-function sources.
Current compatibility boundaries:
html/templatecontextual escaping is not implemented.- Native data is adapted into template values before execution:
- Structs and classes expose fields as template maps.
- Arrays expose template arrays.
- Associative-array keys are converted to strings for selector lookup.
- Pointers are dereferenced when possible.
- Pointer identity, interface metadata, inherited field projection, and arbitrary callable object identity are not preserved as live reflection state.
- Field lookup:
- D member names are used directly.
- A trailing underscore is stripped, so
name_is visible as.name. - Custom field rename/ignore attributes are deferred and not currently supported.
- Fields take precedence over same-visible-name methods and properties.
- Compiler support:
ldc2is the primary validated compiler anddmdis covered by the local temp-build matrix.- Broader D compiler/version range guarantees are deferred until after the pre-1.0 API and behavior surface is finalized.
- Native methods:
- Struct and non-null class instance methods are projected as bound template methods.
- Supported D overloads for one visible name are projected as one template selector and resolved during execution by explicit command arity plus supported template-to-D argument conversions.
- Niladic methods work in selector position, e.g.
{{.displayName}}. - Methods with arguments work as command heads, e.g.
{{.greet "Ada"}}. - Pipeline values are passed as the final method argument.
- Unsupported overload candidates are omitted without hiding supported overloads for the same visible name.
- Ambiguous runtime matches fail with a template execution error.
- Statically typed interface receivers use the same method path.
- Inherited base-class methods and implemented interface methods are supported when they pass native method filters.
- Null class/interface references remain nil/null and do not dispatch methods.
- D method forms not exposed:
- Static, template, or variadic methods.
- Methods with
ref,out, orlazyparameters. - Setter-only properties and getter/setter property overload pairs.
- Reserved
Objectnames on class/interface receivers:toString,toHash,opCmp,opEquals, andfactory.
- Method conversion rules:
- Supported method parameters are
bool,string, signed/unsigned integers, and floating point values. - Unsupported argument or return conversions make the method unavailable or produce a template execution error.
- Const-qualified aggregate receivers expose only const-callable methods and properties.
- Template-callable behavior outside this supported method subset should be supplied through registered template functions.
- Supported method parameters are
print,printf, andprintlnare backed by the standalonedgo.fmtsubpackage. The formatter has its own lifted Gofmtfixture corpus and currently covers the scalar subset needed by the template builtins: booleans, strings, signed/unsigned integers, floating point values, complex display values, Go-style type names supplied by internal adapters, quoted strings/runes, selected static width/precision forms, and string byte hexadecimal output.dgo.fmtis not a complete clone of Go'sfmtpackage. Composite Go reflection formatting, dynamic width/precision with*, argument indexing, Formatter/Stringer/GoStringer-style interfaces, broad float flag coverage, and Go pointer/map/slice/struct identity formatting remain outside the supported subset. Unsupported forms produce template or formatter errors rather than approximate output.- Fixture-only values model Go runtime details for conformance tests. Their shape and behavior are intentionally not a stable application API; user data should be passed as native D values and registered functions.