1// Copyright 2017 The Wuffs Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package cgen
16
17import (
18	"errors"
19	"flag"
20	"fmt"
21	"math/big"
22	"sort"
23	"strings"
24
25	"github.com/google/wuffs/internal/cgen/data"
26	"github.com/google/wuffs/lang/builtin"
27	"github.com/google/wuffs/lang/generate"
28	"github.com/google/wuffs/lib/dumbindent"
29
30	cf "github.com/google/wuffs/cmd/commonflags"
31
32	a "github.com/google/wuffs/lang/ast"
33	t "github.com/google/wuffs/lang/token"
34)
35
36var (
37	zero      = big.NewInt(0)
38	one       = big.NewInt(1)
39	eight     = big.NewInt(8)
40	sixtyFour = big.NewInt(64)
41
42	mibi = big.NewInt(1 << 20)
43
44	maxInt64 = big.NewInt((1 << 63) - 1)
45
46	typeExprUtility = a.NewTypeExpr(0, t.IDBase, t.IDUtility, nil, nil, nil)
47)
48
49// Prefixes are prepended to names to form a namespace and to avoid e.g.
50// "double" being a valid Wuffs variable name but not a valid C one.
51const (
52	aPrefix = "a_" // Function argument.
53	fPrefix = "f_" // Struct field.
54	iPrefix = "i_" // Iterate variable.
55	oPrefix = "o_" // Temporary io_bind variable.
56	pPrefix = "p_" // Coroutine suspension point (program counter).
57	sPrefix = "s_" // Coroutine stack (saved local variables).
58	tPrefix = "t_" // Temporary local variable.
59	uPrefix = "u_" // Derived from a local variable.
60	vPrefix = "v_" // Local variable.
61)
62
63// I/O (reader/writer) prefixes. In the generated C code, the variables with
64// these prefixes all have type uint8_t*. The iop_etc variables are the key
65// ones. For an io_reader or io_writer function argument a_src or a_dst,
66// reading or writing the next byte (and advancing the stream) is essentially
67// "etc = *iop_a_src++" or "*io_a_dst++ = etc".
68//
69// The other two prefixes, giving names like io1_etc and io2_etc, are
70// auxilliary pointers: lower and upper inclusive bounds. As an iop_etc pointer
71// advances, it cannot advance past io2_etc. In the rarer case that an iop_etc
72// pointer retreats, undoing a read or write, it cannot retreat past io1_etc.
73//
74// The iop_etc pointer can change over the lifetime of a function. The ioN_etc
75// pointers, for numeric N, cannot.
76//
77// At the start of a function, these pointers are initialized from an
78// io_buffer's fields (ptr, ri, wi, len). For an io_reader:
79//  - io0_etc = ptr
80//  - io1_etc = ptr + ri
81//  - iop_etc = ptr + ri
82//  - io2_etc = ptr + wi
83// and for an io_writer:
84//  - io0_etc = ptr
85//  - io1_etc = ptr + wi
86//  - iop_etc = ptr + wi
87//  - io2_etc = ptr + len
88const (
89	io0Prefix = "io0_" // Base.
90	io1Prefix = "io1_" // Lower bound.
91	io2Prefix = "io2_" // Upper bound.
92	iopPrefix = "iop_" // Pointer.
93)
94
95// BaseSubModules is the list of lower-cased XXX's in the base module's
96// WUFFS_CONFIG__MODULE__BASE__XXX sub-modules.
97var BaseSubModules = []string{
98	"core",
99	"floatconv",
100	"intconv",
101	"interfaces",
102	"pixconv",
103	"utf8",
104}
105
106// Do transpiles a Wuffs program to a C program.
107//
108// The arguments list the source Wuffs files. If no arguments are given, it
109// reads from stdin.
110//
111// The generated program is written to stdout.
112func Do(args []string) error {
113	flags := flag.FlagSet{}
114	genlinenumFlag := flags.Bool("genlinenum", cf.GenlinenumDefault, cf.GenlinenumUsage)
115
116	return generate.Do(&flags, args, func(pkgName string, tm *t.Map, files []*a.File) ([]byte, error) {
117		unformatted := []byte(nil)
118		if pkgName == "base" {
119			if len(files) != 0 {
120				return nil, fmt.Errorf("base package shouldn't have any .wuffs files")
121			}
122			buf := make(buffer, 0, 128*1024)
123			if err := expandBangBangInsert(&buf, data.BaseAllImplC, map[string]func(*buffer) error{
124				"// !! INSERT InterfaceDeclarations.\n":      insertInterfaceDeclarations,
125				"// !! INSERT InterfaceDefinitions.\n":       insertInterfaceDefinitions,
126				"// !! INSERT base/all-private.h.\n":         insertBaseAllPrivateH,
127				"// !! INSERT base/all-public.h.\n":          insertBaseAllPublicH,
128				"// !! INSERT base/copyright\n":              insertBaseCopyright,
129				"// !! INSERT base/floatconv-submodule.c.\n": insertBaseFloatConvSubmoduleC,
130				"// !! INSERT base/intconv-submodule.c.\n":   insertBaseIntConvSubmoduleC,
131				"// !! INSERT base/pixconv-submodule.c.\n":   insertBasePixConvSubmoduleC,
132				"// !! INSERT base/utf8-submodule.c.\n":      insertBaseUTF8SubmoduleC,
133				"// !! INSERT vtable names.\n": func(b *buffer) error {
134					for _, n := range builtin.Interfaces {
135						buf.printf("const char wuffs_base__%s__vtable_name[] = "+
136							"\"{vtable}wuffs_base__%s\";\n", n, n)
137					}
138					return nil
139				},
140				"// !! INSERT wuffs_base__status strings.\n": func(b *buffer) error {
141					for _, z := range builtin.Statuses {
142						msg, _ := t.Unescape(z)
143						if msg == "" {
144							continue
145						}
146						pre := "note"
147						if msg[0] == '$' {
148							pre = "suspension"
149						} else if msg[0] == '#' {
150							pre = "error"
151						}
152						b.printf("const char wuffs_base__%s__%s[] = \"%sbase: %s\";\n",
153							pre, cName(msg, ""), msg[:1], msg[1:])
154					}
155					return nil
156				},
157			}); err != nil {
158				return nil, err
159			}
160			unformatted = []byte(buf)
161
162		} else {
163			g := &gen{
164				PKGPREFIX:  "WUFFS_" + strings.ToUpper(pkgName) + "__",
165				PKGNAME:    strings.ToUpper(pkgName),
166				pkgPrefix:  "wuffs_" + pkgName + "__",
167				pkgName:    pkgName,
168				tm:         tm,
169				files:      files,
170				genlinenum: *genlinenumFlag,
171			}
172			var err error
173			unformatted, err = g.generate()
174			if err != nil {
175				return nil, err
176			}
177		}
178
179		// The base package is largely hand-written C, not transpiled from
180		// Wuffs, and that part is presumably already formatted. The rest is
181		// generated by this package. We take care here to print well indented
182		// C code, so further C formatting is unnecessary.
183		if pkgName == "base" {
184			return unformatted, nil
185		}
186
187		return dumbindent.FormatBytes(nil, unformatted, nil), nil
188	})
189}
190
191type visibility uint32
192
193const (
194	bothPubPri = visibility(iota)
195	pubOnly
196	priOnly
197)
198
199const (
200	maxIOBinds = 100
201	maxTemp    = 10000
202)
203
204type status struct {
205	cName       string
206	msg         string
207	fromThisPkg bool
208	public      bool
209}
210
211func statusMsgIsError(msg string) bool {
212	return (len(msg) != 0) && (msg[0] == '#')
213}
214
215func statusMsgIsNote(msg string) bool {
216	return (len(msg) == 0) || (msg[0] != '$' && msg[0] != '#')
217}
218
219func statusMsgIsSuspension(msg string) bool {
220	return (len(msg) != 0) && (msg[0] == '$')
221}
222
223type buffer []byte
224
225func (b *buffer) Write(p []byte) (int, error) {
226	*b = append(*b, p...)
227	return len(p), nil
228}
229
230func (b *buffer) printf(format string, args ...interface{}) { fmt.Fprintf(b, format, args...) }
231func (b *buffer) writeb(x byte)                             { *b = append(*b, x) }
232func (b *buffer) writes(s string)                           { *b = append(*b, s...) }
233func (b *buffer) writex(s []byte)                           { *b = append(*b, s...) }
234
235func expandBangBangInsert(b *buffer, s string, m map[string]func(*buffer) error) error {
236	for {
237		remaining := ""
238		if i := strings.IndexByte(s, '\n'); i >= 0 {
239			s, remaining = s[:i+1], s[i+1:]
240		}
241
242		const prefix = "// !! INSERT "
243		if !strings.HasPrefix(s, prefix) {
244			b.writes(s)
245		} else if f := m[s]; f == nil {
246			msg := []byte(fmt.Sprintf("unrecognized line %q, want one of:\n", s))
247			keys := []string(nil)
248			for k := range m {
249				keys = append(keys, k)
250			}
251			sort.Strings(keys)
252			for _, k := range keys {
253				msg = append(msg, '\t')
254				msg = append(msg, k...)
255			}
256			return errors.New(string(msg))
257		} else if err := f(b); err != nil {
258			return err
259		}
260
261		if remaining == "" {
262			break
263		}
264		s = remaining
265	}
266	return nil
267}
268
269func insertBaseAllPrivateH(buf *buffer) error {
270	buf.writes(data.BaseFundamentalPrivateH)
271	buf.writeb('\n')
272	buf.writes(data.BaseRangePrivateH)
273	buf.writeb('\n')
274	buf.writes(data.BaseIOPrivateH)
275	buf.writeb('\n')
276	buf.writes(data.BaseTokenPrivateH)
277	buf.writeb('\n')
278	buf.writes(data.BaseMemoryPrivateH)
279	buf.writeb('\n')
280	buf.writes(data.BaseImagePrivateH)
281	buf.writeb('\n')
282	buf.writes(data.BaseStrConvPrivateH)
283	return nil
284}
285
286func insertBaseAllPublicH(buf *buffer) error {
287	if err := expandBangBangInsert(buf, data.BaseFundamentalPublicH, map[string]func(*buffer) error{
288		"// !! INSERT FourCCs.\n": func(b *buffer) error {
289			for i, z := range builtin.FourCCs {
290				if i != 0 {
291					b.writeb('\n')
292				}
293				b.printf("// %s.\n#define WUFFS_BASE__FOURCC__%s 0x%02X%02X%02X%02X\n",
294					z[1],
295					strings.ToUpper(strings.TrimSpace(z[0])),
296					z[0][0],
297					z[0][1],
298					z[0][2],
299					z[0][3],
300				)
301			}
302			return nil
303		},
304		"// !! INSERT wuffs_base__status names.\n": func(b *buffer) error {
305			for _, z := range builtin.Statuses {
306				msg, _ := t.Unescape(z)
307				if msg == "" {
308					return fmt.Errorf("bad built-in status %q", z)
309				}
310				pre := "note"
311				if statusMsgIsError(msg) {
312					pre = "error"
313				} else if statusMsgIsSuspension(msg) {
314					pre = "suspension"
315				}
316				b.printf("extern const char wuffs_base__%s__%s[];\n", pre, cName(msg, ""))
317			}
318			return nil
319		},
320	}); err != nil {
321		return err
322	}
323	buf.writeb('\n')
324
325	buf.writes(data.BaseRangePublicH)
326	buf.writeb('\n')
327	buf.writes(data.BaseIOPublicH)
328	buf.writeb('\n')
329	buf.writes(data.BaseTokenPublicH)
330	buf.writeb('\n')
331	buf.writes(data.BaseMemoryPublicH)
332	buf.writeb('\n')
333	buf.writes(data.BaseImagePublicH)
334	buf.writeb('\n')
335	buf.writes(data.BaseStrConvPublicH)
336	return nil
337}
338
339func insertBaseCopyright(buf *buffer) error {
340	buf.writes(data.BaseCopyright)
341	return nil
342}
343
344func insertBaseFloatConvSubmoduleC(buf *buffer) error {
345	buf.writes(data.BaseFloatConvSubmoduleDataC)
346	buf.writeb('\n')
347	buf.writes(data.BaseFloatConvSubmoduleCodeC)
348	return nil
349}
350
351func insertBaseIntConvSubmoduleC(buf *buffer) error {
352	buf.writes(data.BaseIntConvSubmoduleC)
353	return nil
354}
355
356func insertBasePixConvSubmoduleC(buf *buffer) error {
357	buf.writes(data.BasePixConvSubmoduleC)
358	return nil
359}
360
361func insertBaseUTF8SubmoduleC(buf *buffer) error {
362	buf.writes(data.BaseUTF8SubmoduleC)
363	return nil
364}
365
366func insertInterfaceDeclarations(buf *buffer) error {
367	if err := parseBuiltInInterfaceMethods(); err != nil {
368		return err
369	}
370
371	g := &gen{
372		pkgPrefix: "wuffs_base__",
373		pkgName:   "base",
374		tm:        &builtInTokenMap,
375	}
376
377	buf.writes("// ---------------- Interface Declarations.\n\n")
378
379	buf.writes("// For modular builds that divide the base module into sub-modules, using these\n")
380	buf.writes("// functions require the WUFFS_CONFIG__MODULE__BASE__INTERFACES sub-module, not\n")
381	buf.writes("// just WUFFS_CONFIG__MODULE__BASE__CORE.\n")
382
383	for _, n := range builtin.Interfaces {
384		buf.writes("\n// --------\n\n")
385
386		qid := t.QID{t.IDBase, builtInTokenMap.ByName(n)}
387
388		buf.printf("extern const char wuffs_base__%s__vtable_name[];\n\n", n)
389
390		buf.writes("typedef struct {\n")
391		for _, f := range builtInInterfaceMethods[qid] {
392			buf.writes("  ")
393			if err := g.writeFuncSignature(buf, f, wfsCFuncPtrField); err != nil {
394				return err
395			}
396			buf.writes(";\n")
397		}
398		buf.printf("} wuffs_base__%s__func_ptrs;\n\n", n)
399
400		buf.printf("typedef struct wuffs_base__%s__struct wuffs_base__%s;\n\n", n, n)
401
402		for _, f := range builtInInterfaceMethods[qid] {
403			if err := g.writeFuncSignature(buf, f, wfsCDecl); err != nil {
404				return err
405			}
406			buf.writes(";\n\n")
407		}
408
409		buf.writes("#if defined(__cplusplus) || defined(WUFFS_IMPLEMENTATION)\n\n")
410
411		buf.printf("struct wuffs_base__%s__struct {\n", n)
412		buf.writes("  struct {\n")
413		buf.writes("    uint32_t magic;\n")
414		buf.writes("    uint32_t active_coroutine;\n")
415		buf.writes("    wuffs_base__vtable first_vtable;\n")
416		buf.writes("  } private_impl;\n\n")
417
418		buf.writes("#ifdef __cplusplus\n")
419		buf.writes("#if (__cplusplus >= 201103L)\n")
420		buf.printf("  using unique_ptr = std::unique_ptr<wuffs_base__%s, decltype(&free)>;\n", n)
421		buf.writes("#endif\n\n")
422
423		for _, f := range builtInInterfaceMethods[qid] {
424			if err := g.writeFuncSignature(buf, f, wfsCppDecl); err != nil {
425				return err
426			}
427			buf.writes(" {\n    return ")
428			buf.writes(g.funcCName(f))
429			if len(f.In().Fields()) == 0 {
430				buf.writes("(this")
431			} else {
432				buf.writes("(\n        this")
433				for _, o := range f.In().Fields() {
434					buf.writes(", ")
435					buf.writes(aPrefix)
436					buf.writes(o.AsField().Name().Str(g.tm))
437				}
438			}
439			buf.writes(");\n  }\n\n")
440		}
441		buf.writes("#endif  // __cplusplus\n")
442		buf.printf("};  // struct wuffs_base__%s__struct\n\n", n)
443
444		buf.writes("#endif  // defined(__cplusplus) || defined(WUFFS_IMPLEMENTATION)\n")
445	}
446	return nil
447}
448
449func insertInterfaceDefinitions(buf *buffer) error {
450	if err := parseBuiltInInterfaceMethods(); err != nil {
451		return err
452	}
453
454	g := &gen{
455		pkgPrefix: "wuffs_base__",
456		pkgName:   "base",
457		tm:        &builtInTokenMap,
458	}
459
460	buf.writes("// ---------------- Interface Definitions.\n")
461	for i, n := range builtin.Interfaces {
462		if i > 0 {
463			buf.writes("// --------\n")
464		}
465
466		qid := t.QID{t.IDBase, builtInTokenMap.ByName(n)}
467
468		for _, f := range builtInInterfaceMethods[qid] {
469			returnsStatus := f.Effect().Coroutine() ||
470				((f.Out() != nil) && f.Out().IsStatus())
471
472			buf.writeb('\n')
473			if err := g.writeFuncSignature(buf, f, wfsCDecl); err != nil {
474				return err
475			}
476			buf.writes(" {\n")
477			if err := writeFuncImplSelfMagicCheck(buf, g.tm, f); err != nil {
478				return err
479			}
480
481			buf.writes("\n  const wuffs_base__vtable* v = &self->private_impl.first_vtable;\n")
482			buf.writes("  int i;\n")
483			buf.printf("  for (i = 0; i < %d; i++) {\n", a.MaxImplements)
484			buf.printf("    if (v->vtable_name == wuffs_base__%s__vtable_name) {\n", n)
485			buf.printf("      const wuffs_base__%s__func_ptrs* func_ptrs =\n"+
486				"          (const wuffs_base__%s__func_ptrs*)(v->function_pointers);\n", n, n)
487			buf.printf("      return (*func_ptrs->%s)(self", f.FuncName().Str(g.tm))
488			for _, o := range f.In().Fields() {
489				buf.writes(", ")
490				buf.writes(aPrefix)
491				buf.writes(o.AsField().Name().Str(g.tm))
492			}
493			buf.writes(");\n")
494			buf.writes("    } else if (v->vtable_name == NULL) {\n")
495			buf.writes("      break;\n")
496			buf.writes("    }\n")
497			buf.writes("    v++;\n")
498			buf.writes("  }\n\n")
499
500			buf.writes("  return ")
501			if returnsStatus {
502				buf.writes("wuffs_base__make_status(wuffs_base__error__bad_vtable)")
503			} else if err := writeOutParamZeroValue(buf, g.tm, f.Out()); err != nil {
504				return err
505			}
506			buf.writes(";\n}\n")
507		}
508		if (i + 1) < len(builtin.Interfaces) {
509			buf.writeb('\n')
510		}
511	}
512
513	return nil
514}
515
516var (
517	builtInTokenMap         = t.Map{}
518	builtInInterfaceMethods = map[t.QID][]*a.Func{}
519)
520
521func parseBuiltInInterfaceMethods() error {
522	if len(builtInInterfaceMethods) != 0 {
523		return nil
524	}
525	return builtin.ParseFuncs(&builtInTokenMap, builtin.InterfaceFuncs, func(f *a.Func) error {
526		qid := f.Receiver()
527		builtInInterfaceMethods[qid] = append(builtInInterfaceMethods[qid], f)
528		return nil
529	})
530}
531
532type gen struct {
533	PKGPREFIX string // e.g. "WUFFS_JPEG__"
534	PKGNAME   string // e.g. "JPEG"
535	pkgPrefix string // e.g. "wuffs_jpeg__"
536	pkgName   string // e.g. "jpeg"
537
538	tm    *t.Map
539	files []*a.File
540
541	// genlinenum is whether to print "// foo.wuffs:123" comments in the
542	// generated C code. This can be useful for debugging, although it is not
543	// enabled by default as it can lead to many spurious changes in the
544	// generated C code (due to line numbers changing) when editing Wuffs code.
545	genlinenum bool
546
547	privateDataFields map[t.QQID]struct{}
548	scalarConstsMap   map[t.QID]*a.Const
549	statusList        []status
550	statusMap         map[t.QID]status
551	structList        []*a.Struct
552	structMap         map[t.QID]*a.Struct
553
554	currFunk funk
555	funks    map[t.QQID]funk
556
557	numPublicCoroutines map[t.QID]uint32
558}
559
560func (g *gen) generate() ([]byte, error) {
561	b := new(buffer)
562
563	g.statusMap = map[t.QID]status{}
564	if err := g.forEachStatus(b, bothPubPri, (*gen).gatherStatuses); err != nil {
565		return nil, err
566	}
567	for _, z := range builtin.Statuses {
568		id, err := g.tm.Insert(z)
569		if err != nil {
570			return nil, err
571		}
572		msg, _ := t.Unescape(z)
573		if msg == "" {
574			return nil, fmt.Errorf("bad built-in status %q", z)
575		}
576		if err := g.addStatus(t.QID{t.IDBase, id}, msg, true); err != nil {
577			return nil, err
578		}
579	}
580
581	g.scalarConstsMap = map[t.QID]*a.Const{}
582	if err := g.forEachConst(b, bothPubPri, (*gen).gatherScalarConsts); err != nil {
583		return nil, err
584	}
585
586	// Make a topologically sorted list of structs.
587	unsortedStructs := []*a.Struct(nil)
588	for _, file := range g.files {
589		for _, tld := range file.TopLevelDecls() {
590			if tld.Kind() == a.KStruct {
591				unsortedStructs = append(unsortedStructs, tld.AsStruct())
592			}
593		}
594	}
595	var ok bool
596	g.structList, ok = a.TopologicalSortStructs(unsortedStructs)
597	if !ok {
598		return nil, fmt.Errorf("cyclical struct definitions")
599	}
600	g.structMap = map[t.QID]*a.Struct{}
601	g.privateDataFields = map[t.QQID]struct{}{}
602	g.numPublicCoroutines = map[t.QID]uint32{}
603	for _, n := range g.structList {
604		qid := n.QID()
605		g.structMap[qid] = n
606		for _, f := range n.Fields() {
607			f := f.AsField()
608			if f.PrivateData() {
609				g.privateDataFields[t.QQID{qid[0], qid[1], f.Name()}] = struct{}{}
610			}
611		}
612	}
613
614	g.funks = map[t.QQID]funk{}
615	if err := g.forEachFunc(nil, bothPubPri, (*gen).gatherFuncImpl); err != nil {
616		return nil, err
617	}
618
619	includeGuard := "WUFFS_INCLUDE_GUARD__" + g.PKGNAME
620	b.printf("#ifndef %s\n#define %s\n\n", includeGuard, includeGuard)
621
622	if err := g.genIncludes(b); err != nil {
623		return nil, err
624	}
625
626	b.writes("// !! WUFFS MONOLITHIC RELEASE DISCARDS EVERYTHING ABOVE.\n\n")
627
628	if err := g.genHeader(b); err != nil {
629		return nil, err
630	}
631	b.writex(wiStartImpl)
632	if err := g.genImpl(b); err != nil {
633		return nil, err
634	}
635	b.writex(wiEnd)
636
637	b.writes("// !! WUFFS MONOLITHIC RELEASE DISCARDS EVERYTHING BELOW.\n\n")
638
639	b.printf("#endif  // %s\n\n", includeGuard)
640	return *b, nil
641}
642
643var (
644	wiStartImpl = []byte("\n// WUFFS C HEADER ENDS HERE.\n#ifdef WUFFS_IMPLEMENTATION\n\n")
645	wiEnd       = []byte("\n#endif  // WUFFS_IMPLEMENTATION\n\n")
646)
647
648func (g *gen) genIncludes(b *buffer) error {
649	b.writes("#if defined(WUFFS_IMPLEMENTATION) && !defined(WUFFS_CONFIG__MODULES)\n")
650	b.writes("#define WUFFS_CONFIG__MODULES\n")
651	b.printf("#define WUFFS_CONFIG__MODULE__%s\n", g.PKGNAME)
652	b.writes("#endif\n\n")
653
654	usesList := []string(nil)
655	usesMap := map[string]struct{}{}
656
657	for _, file := range g.files {
658		for _, tld := range file.TopLevelDecls() {
659			if tld.Kind() != a.KUse {
660				continue
661			}
662			useDirname := g.tm.ByID(tld.AsUse().Path())
663			useDirname, _ = t.Unescape(useDirname)
664
665			// TODO: sanity check useDirname via commonflags.IsValidUsePath?
666
667			if _, ok := usesMap[useDirname]; ok {
668				continue
669			}
670			usesMap[useDirname] = struct{}{}
671			usesList = append(usesList, useDirname)
672		}
673	}
674	sort.Strings(usesList)
675
676	b.writes("#include \"./wuffs-base.c\"\n")
677	for _, use := range usesList {
678		b.printf("#include \"./wuffs-%s.c\"\n",
679			strings.Replace(use, "/", "-", -1))
680	}
681
682	b.writeb('\n')
683	return nil
684}
685
686func (g *gen) genHeader(b *buffer) error {
687	b.writes("\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n")
688
689	b.writes("// ---------------- Status Codes\n\n")
690
691	wroteStatus := false
692	for _, z := range g.statusList {
693		if !z.fromThisPkg || !z.public {
694			continue
695		}
696		b.printf("extern const char %s[];\n", z.cName)
697		wroteStatus = true
698	}
699	if wroteStatus {
700		b.writes("\n")
701	}
702
703	b.writes("// ---------------- Public Consts\n\n")
704	if err := g.forEachConst(b, pubOnly, (*gen).writeConst); err != nil {
705		return err
706	}
707
708	b.writes("// ---------------- Struct Declarations\n\n")
709	for _, n := range g.structList {
710		structName := n.QID().Str(g.tm)
711		b.printf("typedef struct %s%s__struct %s%s;\n\n", g.pkgPrefix, structName, g.pkgPrefix, structName)
712	}
713
714	b.writes("// ---------------- Public Initializer Prototypes\n\n")
715	b.writes("// For any given \"wuffs_foo__bar* self\", \"wuffs_foo__bar__initialize(self,\n")
716	b.writes("// etc)\" should be called before any other \"wuffs_foo__bar__xxx(self, etc)\".\n")
717	b.writes("//\n")
718	b.writes("// Pass sizeof(*self) and WUFFS_VERSION for sizeof_star_self and wuffs_version.\n")
719	b.writes("// Pass 0 (or some combination of WUFFS_INITIALIZE__XXX) for options.\n\n")
720	for _, n := range g.structList {
721		if n.Public() {
722			if err := g.writeInitializerPrototype(b, n); err != nil {
723				return err
724			}
725		}
726	}
727
728	b.writes("// ---------------- Allocs\n\n")
729
730	b.writes("// These functions allocate and initialize Wuffs structs. They return NULL if\n")
731	b.writes("// memory allocation fails. If they return non-NULL, there is no need to call\n")
732	b.writes("// wuffs_foo__bar__initialize, but the caller is responsible for eventually\n")
733	b.writes("// calling free on the returned pointer. That pointer is effectively a C++\n")
734	b.writes("// std::unique_ptr<T, decltype(&free)>.\n\n")
735
736	for _, n := range g.structList {
737		if !n.Public() {
738			continue
739		}
740		if err := g.writeAllocSignature(b, n); err != nil {
741			return err
742		}
743		b.writes(";\n\n")
744		structName := n.QID().Str(g.tm)
745		for _, impl := range n.Implements() {
746			iQID := impl.AsTypeExpr().QID()
747			iName := fmt.Sprintf("wuffs_%s__%s", iQID[0].Str(g.tm), iQID[1].Str(g.tm))
748			b.printf("static inline %s*\n", iName)
749			b.printf("%s%s__alloc_as__%s() {\n", g.pkgPrefix, structName, iName)
750			b.printf("return (%s*)(%s%s__alloc());\n", iName, g.pkgPrefix, structName)
751			b.printf("}\n\n")
752		}
753	}
754
755	b.writes("// ---------------- Upcasts\n\n")
756	for _, n := range g.structList {
757		structName := n.QID().Str(g.tm)
758		for _, impl := range n.Implements() {
759			iQID := impl.AsTypeExpr().QID()
760			iName := fmt.Sprintf("wuffs_%s__%s", iQID[0].Str(g.tm), iQID[1].Str(g.tm))
761			b.printf("static inline %s*\n", iName)
762			b.printf("%s%s__upcast_as__%s(\n    %s%s* p) {\n",
763				g.pkgPrefix, structName, iName, g.pkgPrefix, structName)
764			b.printf("return (%s*)p;\n", iName)
765			b.printf("}\n\n")
766		}
767	}
768
769	b.writes("// ---------------- Public Function Prototypes\n\n")
770	if err := g.forEachFunc(b, pubOnly, (*gen).writeFuncPrototype); err != nil {
771		return err
772	}
773
774	b.writes("// ---------------- Struct Definitions\n\n")
775	b.writes("// These structs' fields, and the sizeof them, are private implementation\n")
776	b.writes("// details that aren't guaranteed to be stable across Wuffs versions.\n")
777	b.writes("//\n")
778	b.writes("// See https://en.wikipedia.org/wiki/Opaque_pointer#C\n\n")
779	b.writes("#if defined(__cplusplus) || defined(WUFFS_IMPLEMENTATION)\n\n")
780
781	for _, n := range g.structList {
782		if err := g.writeStruct(b, n); err != nil {
783			return err
784		}
785	}
786	b.writes("#endif  // defined(__cplusplus) || defined(WUFFS_IMPLEMENTATION)\n")
787
788	b.writes("\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif\n\n")
789	return nil
790}
791
792func (g *gen) genImpl(b *buffer) error {
793	module := "!defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__" + g.PKGNAME + ")"
794	b.printf("#if %s\n\n", module)
795
796	b.writes("// ---------------- Status Codes Implementations\n\n")
797
798	wroteStatus := false
799	for _, z := range g.statusList {
800		if !z.fromThisPkg || z.msg == "" {
801			continue
802		}
803		b.printf("const char %s[] = \"%s%s: %s\";\n", z.cName, z.msg[:1], g.pkgName, z.msg[1:])
804		wroteStatus = true
805	}
806	if wroteStatus {
807		b.writes("\n")
808	}
809
810	b.writes("// ---------------- Private Consts\n\n")
811	if err := g.forEachConst(b, priOnly, (*gen).writeConst); err != nil {
812		return err
813	}
814
815	b.writes("// ---------------- Private Initializer Prototypes\n\n")
816	for _, n := range g.structList {
817		if !n.Public() {
818			if err := g.writeInitializerPrototype(b, n); err != nil {
819				return err
820			}
821		}
822	}
823
824	b.writes("// ---------------- Private Function Prototypes\n\n")
825	if err := g.forEachFunc(b, priOnly, (*gen).writeFuncPrototype); err != nil {
826		return err
827	}
828
829	b.writes("// ---------------- VTables\n\n")
830	for _, n := range g.structList {
831		if err := g.writeVTableImpl(b, n); err != nil {
832			return err
833		}
834	}
835
836	b.writes("// ---------------- Initializer Implementations\n\n")
837	for _, n := range g.structList {
838		if err := g.writeInitializerImpl(b, n); err != nil {
839			return err
840		}
841	}
842
843	b.writes("// ---------------- Function Implementations\n\n")
844	if err := g.forEachFunc(b, bothPubPri, (*gen).writeFuncImpl); err != nil {
845		return err
846	}
847
848	b.printf("#endif  // %s\n\n", module)
849	return nil
850}
851
852func (g *gen) forEachConst(b *buffer, v visibility, f func(*gen, *buffer, *a.Const) error) error {
853	for _, file := range g.files {
854		for _, tld := range file.TopLevelDecls() {
855			if tld.Kind() != a.KConst ||
856				(v == pubOnly && tld.AsRaw().Flags()&a.FlagsPublic == 0) ||
857				(v == priOnly && tld.AsRaw().Flags()&a.FlagsPublic != 0) {
858				continue
859			}
860			if err := f(g, b, tld.AsConst()); err != nil {
861				return err
862			}
863		}
864	}
865	return nil
866}
867
868func (g *gen) forEachFunc(b *buffer, v visibility, f func(*gen, *buffer, *a.Func) error) error {
869	for _, file := range g.files {
870		for _, tld := range file.TopLevelDecls() {
871			if tld.Kind() != a.KFunc ||
872				(v == pubOnly && tld.AsRaw().Flags()&a.FlagsPublic == 0) ||
873				(v == priOnly && tld.AsRaw().Flags()&a.FlagsPublic != 0) {
874				continue
875			}
876			if err := f(g, b, tld.AsFunc()); err != nil {
877				return err
878			}
879		}
880	}
881	return nil
882}
883
884func (g *gen) forEachStatus(b *buffer, v visibility, f func(*gen, *buffer, *a.Status) error) error {
885	for _, file := range g.files {
886		for _, tld := range file.TopLevelDecls() {
887			if tld.Kind() != a.KStatus ||
888				(v == pubOnly && tld.AsRaw().Flags()&a.FlagsPublic == 0) ||
889				(v == priOnly && tld.AsRaw().Flags()&a.FlagsPublic != 0) {
890				continue
891			}
892			if err := f(g, b, tld.AsStatus()); err != nil {
893				return err
894			}
895		}
896	}
897	return nil
898}
899
900func (g *gen) cName(name string) string {
901	return cName(name, g.pkgPrefix)
902}
903
904func cName(name string, pkgPrefix string) string {
905	s := []byte(pkgPrefix)
906	underscore := true
907	for _, r := range name {
908		if 'A' <= r && r <= 'Z' {
909			s = append(s, byte(r+'a'-'A'))
910			underscore = false
911		} else if ('a' <= r && r <= 'z') || ('0' <= r && r <= '9') {
912			s = append(s, byte(r))
913			underscore = false
914		} else if !underscore {
915			s = append(s, '_')
916			underscore = true
917		}
918	}
919	if underscore {
920		s = s[:len(s)-1]
921	}
922	return string(s)
923}
924
925func uintBits(qid t.QID) uint32 {
926	if qid[0] == t.IDBase {
927		switch qid[1] {
928		case t.IDU8:
929			return 8
930		case t.IDU16:
931			return 16
932		case t.IDU32:
933			return 32
934		case t.IDU64:
935			return 64
936		}
937	}
938	return 0
939}
940
941func (g *gen) sizeof(typ *a.TypeExpr) (uint32, error) {
942	if typ.Decorator() == 0 {
943		if n := uintBits(typ.QID()); n != 0 {
944			return n / 8, nil
945		}
946	}
947	return 0, fmt.Errorf("unknown sizeof for %q", typ.Str(g.tm))
948}
949
950func (g *gen) gatherStatuses(b *buffer, n *a.Status) error {
951	raw := n.QID()[1].Str(g.tm)
952	msg, ok := t.Unescape(raw)
953	if !ok || msg == "" {
954		return fmt.Errorf("bad status message %q", raw)
955	}
956	return g.addStatus(n.QID(), msg, n.Public())
957}
958
959func (g *gen) addStatus(qid t.QID, msg string, public bool) error {
960	category := "note__"
961	if msg[0] == '$' {
962		category = "suspension__"
963	} else if msg[0] == '#' {
964		category = "error__"
965	}
966	z := status{
967		cName:       g.packagePrefix(qid) + category + cName(msg, ""),
968		msg:         msg,
969		fromThisPkg: qid[0] == 0,
970		public:      public,
971	}
972	g.statusList = append(g.statusList, z)
973	g.statusMap[qid] = z
974	return nil
975}
976
977func (g *gen) gatherScalarConsts(b *buffer, n *a.Const) error {
978	if cv := n.Value().ConstValue(); cv != nil {
979		g.scalarConstsMap[n.QID()] = n
980	}
981	return nil
982}
983
984func (g *gen) writeConst(b *buffer, n *a.Const) error {
985	if cv := n.Value().ConstValue(); cv != nil {
986		b.printf("#define %s%s %v\n\n", g.PKGPREFIX, n.QID()[1].Str(g.tm), cv)
987	} else {
988		b.writes("static const ")
989		if err := g.writeCTypeName(b, n.XType(), "\n"+g.PKGPREFIX, n.QID()[1].Str(g.tm)); err != nil {
990			return err
991		}
992		b.writes("WUFFS_BASE__POTENTIALLY_UNUSED = ")
993		if err := g.writeConstList(b, n.Value()); err != nil {
994			return err
995		}
996		b.writes(";\n\n")
997	}
998	return nil
999}
1000
1001func (g *gen) writeConstList(b *buffer, n *a.Expr) error {
1002	if n.Operator() == t.IDComma {
1003		b.writeb('{')
1004		for i, o := range n.Args() {
1005			if i&7 == 0 {
1006				b.writeb('\n')
1007			}
1008			if err := g.writeConstList(b, o.AsExpr()); err != nil {
1009				return err
1010			}
1011			b.writes(", ")
1012		}
1013		b.writes("\n}")
1014	} else if cv := n.ConstValue(); cv != nil {
1015		b.writes(cv.String())
1016	} else {
1017		return fmt.Errorf("invalid const value %q", n.Str(g.tm))
1018	}
1019	return nil
1020}
1021
1022func (g *gen) writeStructPrivateImpl(b *buffer, n *a.Struct) error {
1023	// TODO: allow max depth > 1 for recursive coroutines.
1024	const maxDepth = 1
1025
1026	b.writes("// Do not access the private_impl's or private_data's fields directly. There\n")
1027	b.writes("// is no API/ABI compatibility or safety guarantee if you do so. Instead, use\n")
1028	b.writes("// the wuffs_foo__bar__baz functions.\n")
1029	b.writes("//\n")
1030	b.writes("// It is a struct, not a struct*, so that the outermost wuffs_foo__bar struct\n")
1031	b.writes("// can be stack allocated when WUFFS_IMPLEMENTATION is defined.\n\n")
1032
1033	b.writes("struct {\n")
1034	if n.Classy() {
1035		b.writes("uint32_t magic;\n")
1036		b.writes("uint32_t active_coroutine;\n")
1037		for _, impl := range n.Implements() {
1038			qid := impl.AsTypeExpr().QID()
1039			b.printf("wuffs_base__vtable vtable_for__wuffs_%s__%s;\n",
1040				qid[0].Str(g.tm), qid[1].Str(g.tm))
1041		}
1042		b.writes("wuffs_base__vtable null_vtable;\n")
1043		b.writes("\n")
1044	}
1045
1046	for _, o := range n.Fields() {
1047		o := o.AsField()
1048		if o.PrivateData() || o.XType().Eq(typeExprUtility) {
1049			continue
1050		}
1051		if err := g.writeCTypeName(b, o.XType(), fPrefix, o.Name().Str(g.tm)); err != nil {
1052			return err
1053		}
1054		b.writes(";\n")
1055	}
1056
1057	if n.Classy() {
1058		needEmptyLine := true
1059		for _, file := range g.files {
1060			for _, tld := range file.TopLevelDecls() {
1061				if tld.Kind() != a.KFunc {
1062					continue
1063				}
1064				o := tld.AsFunc()
1065				if o.Receiver() != n.QID() || !o.Effect().Coroutine() {
1066					continue
1067				}
1068				k := g.funks[o.QQID()]
1069				if k.coroSuspPoint == 0 {
1070					continue
1071				}
1072
1073				if needEmptyLine {
1074					needEmptyLine = false
1075					b.writeb('\n')
1076				}
1077				b.printf("uint32_t %s%s[%d];\n", pPrefix, o.FuncName().Str(g.tm), maxDepth)
1078			}
1079		}
1080
1081	}
1082	b.writes("} private_impl;\n\n")
1083
1084	{
1085		oldOuterLenB0 := len(*b)
1086		b.writes("struct {\n")
1087		oldOuterLenB1 := len(*b)
1088
1089		for _, o := range n.Fields() {
1090			o := o.AsField()
1091			if !o.PrivateData() || o.XType().Eq(typeExprUtility) {
1092				continue
1093			}
1094			if err := g.writeCTypeName(b, o.XType(), fPrefix, o.Name().Str(g.tm)); err != nil {
1095				return err
1096			}
1097			b.writes(";\n")
1098		}
1099
1100		needEmptyLine := oldOuterLenB1 != len(*b)
1101		for _, file := range g.files {
1102			for _, tld := range file.TopLevelDecls() {
1103				if tld.Kind() != a.KFunc {
1104					continue
1105				}
1106				o := tld.AsFunc()
1107				if o.Receiver() != n.QID() || !o.Effect().Coroutine() {
1108					continue
1109				}
1110				k := g.funks[o.QQID()]
1111				if k.coroSuspPoint == 0 && !k.usesScratch {
1112					continue
1113				}
1114
1115				oldInnerLenB0 := len(*b)
1116				oldNeedEmptyLine := needEmptyLine
1117				if needEmptyLine {
1118					needEmptyLine = false
1119					b.writeb('\n')
1120				}
1121				b.writes("struct {\n")
1122				oldInnerLenB1 := len(*b)
1123				if k.coroSuspPoint != 0 {
1124					if err := g.writeVars(b, &k, true); err != nil {
1125						return err
1126					}
1127				}
1128				if k.usesScratch {
1129					b.writes("uint64_t scratch;\n")
1130				}
1131				if oldInnerLenB1 != len(*b) {
1132					b.printf("} %s%s[%d];\n", sPrefix, o.FuncName().Str(g.tm), maxDepth)
1133				} else {
1134					*b = (*b)[:oldInnerLenB0]
1135					needEmptyLine = oldNeedEmptyLine
1136				}
1137			}
1138		}
1139
1140		if oldOuterLenB1 != len(*b) {
1141			b.writes("} private_data;\n\n")
1142		} else {
1143			*b = (*b)[:oldOuterLenB0]
1144		}
1145	}
1146
1147	return nil
1148}
1149
1150func (g *gen) writeStruct(b *buffer, n *a.Struct) error {
1151	structName := n.QID().Str(g.tm)
1152	fullStructName := g.pkgPrefix + structName + "__struct"
1153	b.printf("struct %s {\n", fullStructName)
1154
1155	if err := g.writeStructPrivateImpl(b, n); err != nil {
1156		return err
1157	}
1158
1159	if n.AsNode().AsRaw().Flags()&a.FlagsPublic != 0 {
1160		if err := g.writeCppMethods(b, n); err != nil {
1161			return err
1162		}
1163	}
1164
1165	b.printf("};  // struct %s\n\n", fullStructName)
1166	return nil
1167}
1168
1169func (g *gen) writeCppMethods(b *buffer, n *a.Struct) error {
1170	structName := n.QID().Str(g.tm)
1171	fullStructName := g.pkgPrefix + structName + "__struct"
1172	b.writes("#ifdef __cplusplus\n")
1173
1174	b.writes("#if (__cplusplus >= 201103L)\n")
1175	b.printf("using unique_ptr = std::unique_ptr<%s%s, decltype(&free)>;\n\n", g.pkgPrefix, structName)
1176	b.writes("// On failure, the alloc_etc functions return nullptr. They don't throw.\n\n")
1177	b.writes("static inline unique_ptr\n")
1178	b.writes("alloc() {\n")
1179	b.printf("return unique_ptr(%s%s__alloc(), &free);\n", g.pkgPrefix, structName)
1180	b.writes("}\n")
1181	for _, impl := range n.Implements() {
1182		iQID := impl.AsTypeExpr().QID()
1183		iName := fmt.Sprintf("wuffs_%s__%s", iQID[0].Str(g.tm), iQID[1].Str(g.tm))
1184		b.printf("\nstatic inline %s::unique_ptr\n", iName)
1185		b.printf("alloc_as__%s() {\n", iName)
1186		b.printf("return %s::unique_ptr(\n%s%s__alloc_as__%s(), &free);\n",
1187			iName, g.pkgPrefix, structName, iName)
1188		b.printf("}\n")
1189	}
1190	b.writes("#endif  // (__cplusplus >= 201103L)\n\n")
1191
1192	b.writes("#if (__cplusplus >= 201103L) && !defined(WUFFS_IMPLEMENTATION)\n")
1193	b.writes("// Disallow constructing or copying an object via standard C++ mechanisms,\n")
1194	b.writes("// e.g. the \"new\" operator, as this struct is intentionally opaque. Its total\n")
1195	b.writes("// size and field layout is not part of the public, stable, memory-safe API.\n")
1196	b.writes("// Use malloc or memcpy and the sizeof__wuffs_foo__bar function instead, and\n")
1197	b.writes("// call wuffs_foo__bar__baz methods (which all take a \"this\"-like pointer as\n")
1198	b.writes("// their first argument) rather than tweaking bar.private_impl.qux fields.\n")
1199	b.writes("//\n")
1200	b.writes("// In C, we can just leave wuffs_foo__bar as an incomplete type (unless\n")
1201	b.writes("// WUFFS_IMPLEMENTATION is #define'd). In C++, we define a complete type in\n")
1202	b.writes("// order to provide convenience methods. These forward on \"this\", so that you\n")
1203	b.writes("// can write \"bar->baz(etc)\" instead of \"wuffs_foo__bar__baz(bar, etc)\".\n")
1204	b.printf("%s() = delete;\n", fullStructName)
1205	b.printf("%s(const %s&) = delete;\n", fullStructName, fullStructName)
1206	b.printf("%s& operator=(\nconst %s&) = delete;\n", fullStructName, fullStructName)
1207	b.writes("\n")
1208	b.writes("// As above, the size of the struct is not part of the public API, and unless\n")
1209	b.writes("// WUFFS_IMPLEMENTATION is #define'd, this struct type T should be heap\n")
1210	b.writes("// allocated, not stack allocated. Its size is not intended to be known at\n")
1211	b.writes("// compile time, but it is unfortunately divulged as a side effect of\n")
1212	b.writes("// defining C++ convenience methods. Use \"sizeof__T()\", calling the function,\n")
1213	b.writes("// instead of \"sizeof T\", invoking the operator. To make the two values\n")
1214	b.writes("// different, so that passing the latter will be rejected by the initialize\n")
1215	b.writes("// function, we add an arbitrary amount of dead weight.\n")
1216	b.writes("uint8_t dead_weight[123000000];  // 123 MB.\n")
1217	b.writes("#endif  // (__cplusplus >= 201103L) && !defined(WUFFS_IMPLEMENTATION)\n\n")
1218
1219	b.writes("inline wuffs_base__status WUFFS_BASE__WARN_UNUSED_RESULT\n" +
1220		"initialize(\nsize_t sizeof_star_self,\nuint64_t wuffs_version,\nuint32_t options) {\n")
1221	b.printf("return %s%s__initialize(\nthis, sizeof_star_self, wuffs_version, options);\n}\n\n",
1222		g.pkgPrefix, structName)
1223
1224	for _, impl := range n.Implements() {
1225		iQID := impl.AsTypeExpr().QID()
1226		iName := fmt.Sprintf("wuffs_%s__%s", iQID[0].Str(g.tm), iQID[1].Str(g.tm))
1227		b.printf("inline %s*\n", iName)
1228		b.printf("upcast_as__%s() {\n", iName)
1229		b.printf("return (%s*)this;\n", iName)
1230		b.printf("}\n\n")
1231	}
1232
1233	structID := n.QID()[1]
1234	for _, file := range g.files {
1235		for _, tld := range file.TopLevelDecls() {
1236			if (tld.Kind() != a.KFunc) || (tld.AsRaw().Flags()&a.FlagsPublic == 0) {
1237				continue
1238			}
1239			f := tld.AsFunc()
1240			qqid := f.QQID()
1241			if qqid[1] != structID {
1242				continue
1243			}
1244
1245			if err := g.writeFuncSignature(b, f, wfsCppDecl); err != nil {
1246				return err
1247			}
1248			b.writes(" {\n    return ")
1249			b.writes(g.funcCName(f))
1250			b.writes("(this")
1251			for _, o := range f.In().Fields() {
1252				b.writes(", ")
1253				b.writes(aPrefix)
1254				b.writes(o.AsField().Name().Str(g.tm))
1255			}
1256			b.writes(");\n  }\n\n")
1257		}
1258	}
1259
1260	b.writes("#endif  // __cplusplus\n")
1261	return nil
1262}
1263
1264func (g *gen) writeVTableImpl(b *buffer, n *a.Struct) error {
1265	impls := n.Implements()
1266	if len(impls) == 0 {
1267		return nil
1268	}
1269
1270	if err := parseBuiltInInterfaceMethods(); err != nil {
1271		return err
1272	}
1273
1274	nQID := n.QID()
1275	for _, impl := range impls {
1276		iQID := impl.AsTypeExpr().QID()
1277		b.printf("const wuffs_%s__%s__func_ptrs\n%s%s__func_ptrs_for__wuffs_%s__%s = {\n",
1278			iQID[0].Str(g.tm), iQID[1].Str(g.tm),
1279			g.pkgPrefix, nQID[1].Str(g.tm),
1280			iQID[0].Str(g.tm), iQID[1].Str(g.tm),
1281		)
1282
1283		// Note the two t.Map values: g.tm and builtInTokenMap.
1284		altQID := t.QID{
1285			builtInTokenMap.ByName(iQID[0].Str(g.tm)),
1286			builtInTokenMap.ByName(iQID[1].Str(g.tm)),
1287		}
1288		for _, f := range builtInInterfaceMethods[altQID] {
1289			b.writeb('(')
1290			if err := g.writeFuncSignature(b, f, wfsCFuncPtrType); err != nil {
1291				return err
1292			}
1293			b.printf(")(&%s%s__%s),\n",
1294				g.pkgPrefix, nQID[1].Str(g.tm),
1295				f.FuncName().Str(&builtInTokenMap),
1296			)
1297		}
1298		b.writes("};\n\n")
1299	}
1300	return nil
1301}
1302
1303func (g *gen) writeInitializerSignature(b *buffer, n *a.Struct, public bool) error {
1304	structName := n.QID().Str(g.tm)
1305	b.printf("wuffs_base__status WUFFS_BASE__WARN_UNUSED_RESULT\n"+
1306		"%s%s__initialize(\n"+
1307		"    %s%s* self,\n"+
1308		"    size_t sizeof_star_self,\n"+
1309		"    uint64_t wuffs_version,\n"+
1310		"    uint32_t options)",
1311		g.pkgPrefix, structName, g.pkgPrefix, structName)
1312	return nil
1313}
1314
1315func (g *gen) writeAllocSignature(b *buffer, n *a.Struct) error {
1316	structName := n.QID().Str(g.tm)
1317	b.printf("%s%s*\n%s%s__alloc()", g.pkgPrefix, structName, g.pkgPrefix, structName)
1318	return nil
1319}
1320
1321func (g *gen) writeSizeofSignature(b *buffer, n *a.Struct) error {
1322	structName := n.QID().Str(g.tm)
1323	b.printf("size_t\nsizeof__%s%s()", g.pkgPrefix, structName)
1324	return nil
1325}
1326
1327func (g *gen) writeInitializerPrototype(b *buffer, n *a.Struct) error {
1328	if !n.Classy() {
1329		return nil
1330	}
1331	if err := g.writeInitializerSignature(b, n, n.Public()); err != nil {
1332		return err
1333	}
1334	b.writes(";\n\n")
1335
1336	if n.Public() {
1337		if err := g.writeSizeofSignature(b, n); err != nil {
1338			return err
1339		}
1340		b.writes(";\n\n")
1341	}
1342	return nil
1343}
1344
1345func (g *gen) writeInitializerImpl(b *buffer, n *a.Struct) error {
1346	if !n.Classy() {
1347		return nil
1348	}
1349	if err := g.writeInitializerSignature(b, n, false); err != nil {
1350		return err
1351	}
1352	b.writes("{\n")
1353	b.writes("if (!self) {\n")
1354	b.writes("  return wuffs_base__make_status(wuffs_base__error__bad_receiver);\n")
1355	b.writes("}\n")
1356
1357	b.writes("if (sizeof(*self) != sizeof_star_self) {\n")
1358	b.writes("  return wuffs_base__make_status(wuffs_base__error__bad_sizeof_receiver);\n")
1359	b.writes("}\n")
1360	b.writes("if (((wuffs_version >> 32) != WUFFS_VERSION_MAJOR) ||\n" +
1361		"(((wuffs_version >> 16) & 0xFFFF) > WUFFS_VERSION_MINOR)) {\n")
1362	b.writes("  return wuffs_base__make_status(wuffs_base__error__bad_wuffs_version);\n")
1363	b.writes("}\n\n")
1364
1365	b.writes("if ((options & WUFFS_INITIALIZE__ALREADY_ZEROED) != 0) {\n")
1366	b.writes("  // The whole point of this if-check is to detect an uninitialized *self.\n")
1367	b.writes("  // We disable the warning on GCC. Clang-5.0 does not have this warning.\n")
1368	b.writes("  #if !defined(__clang__) && defined(__GNUC__)\n")
1369	b.writes("  #pragma GCC diagnostic push\n")
1370	b.writes("  #pragma GCC diagnostic ignored \"-Wmaybe-uninitialized\"\n")
1371	b.writes("  #endif\n")
1372	b.writes("  if (self->private_impl.magic != 0) {\n")
1373	b.writes("    return wuffs_base__make_status(wuffs_base__error__initialize_falsely_claimed_already_zeroed);\n")
1374	b.writes("  }\n")
1375	b.writes("  #if !defined(__clang__) && defined(__GNUC__)\n")
1376	b.writes("  #pragma GCC diagnostic pop\n")
1377	b.writes("  #endif\n")
1378	b.writes("} else {\n")
1379	b.writes("  if ((options & WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED) == 0) {\n")
1380	b.writes("    memset(self, 0, sizeof(*self));\n")
1381	b.writes("    options |= WUFFS_INITIALIZE__ALREADY_ZEROED;\n")
1382	b.writes("  } else {\n")
1383	b.writes("    memset(&(self->private_impl), 0, sizeof(self->private_impl));\n")
1384	b.writes("  }\n")
1385	b.writes("}\n\n")
1386
1387	// Call any ctors on sub-structs.
1388	for _, f := range n.Fields() {
1389		f := f.AsField()
1390		x := f.XType()
1391		if x != x.Innermost() {
1392			// TODO: arrays of sub-structs.
1393			continue
1394		}
1395
1396		prefix := g.pkgPrefix
1397		qid := x.QID()
1398		if qid[0] == t.IDBase {
1399			// Base types don't need further initialization.
1400			continue
1401		} else if qid[0] != 0 {
1402			// See gen.packagePrefix for a related TODO with otherPkg.
1403			otherPkg := g.tm.ByID(qid[0])
1404			prefix = "wuffs_" + otherPkg + "__"
1405		} else if g.structMap[qid] == nil {
1406			continue
1407		}
1408
1409		b.printf("{\n")
1410		b.printf("wuffs_base__status z = %s%s__initialize(\n"+
1411			"&self->private_data.%s%s, sizeof(self->private_data.%s%s), WUFFS_VERSION, options);\n",
1412			prefix, qid[1].Str(g.tm), fPrefix, f.Name().Str(g.tm), fPrefix, f.Name().Str(g.tm))
1413		b.printf("if (z.repr) {\nreturn z;\n}\n")
1414		b.printf("}\n")
1415	}
1416
1417	b.writes("self->private_impl.magic = WUFFS_BASE__MAGIC;\n")
1418	for _, impl := range n.Implements() {
1419		qid := impl.AsTypeExpr().QID()
1420		iName := fmt.Sprintf("wuffs_%s__%s", qid[0].Str(g.tm), qid[1].Str(g.tm))
1421		b.printf("self->private_impl.vtable_for__%s.vtable_name =\n"+
1422			"%s__vtable_name;\n", iName, iName)
1423		b.printf("self->private_impl.vtable_for__%s.function_pointers =\n"+
1424			"(const void*)(&%s%s__func_ptrs_for__%s);\n",
1425			iName, g.pkgPrefix, n.QID().Str(g.tm), iName)
1426	}
1427	b.writes("return wuffs_base__make_status(NULL);\n")
1428	b.writes("}\n\n")
1429
1430	if n.Public() {
1431		structName := n.QID().Str(g.tm)
1432		if err := g.writeAllocSignature(b, n); err != nil {
1433			return err
1434		}
1435		b.writes(" {\n")
1436		b.printf("%s%s* x =\n(%s%s*)(calloc(sizeof(%s%s), 1));\n",
1437			g.pkgPrefix, structName, g.pkgPrefix, structName, g.pkgPrefix, structName)
1438		b.writes("if (!x) {\nreturn NULL;\n}\n")
1439		b.printf("if (%s%s__initialize(\nx, sizeof(%s%s), "+
1440			"WUFFS_VERSION, WUFFS_INITIALIZE__ALREADY_ZEROED).repr) {\n",
1441			g.pkgPrefix, structName, g.pkgPrefix, structName)
1442		b.writes("free(x);\nreturn NULL;\n}\n")
1443		b.writes("return x;\n")
1444		b.writes("}\n\n")
1445
1446		if err := g.writeSizeofSignature(b, n); err != nil {
1447			return err
1448		}
1449		b.printf(" {\nreturn sizeof(%s%s);\n}\n\n", g.pkgPrefix, structName)
1450	}
1451	return nil
1452}
1453