Add interface method signatures
diff --git a/internal/cgen/cgen.go b/internal/cgen/cgen.go
index df2a8ac..124fac5 100644
--- a/internal/cgen/cgen.go
+++ b/internal/cgen/cgen.go
@@ -325,13 +325,30 @@
}
func insertInterfaceDeclarations(buf *buffer) error {
+ if err := parseBuiltInInterfaceMethods(); err != nil {
+ return err
+ }
+
+ g := &gen{
+ pkgPrefix: "wuffs_base__",
+ pkgName: "base",
+ tm: &builtInTokenMap,
+ }
+
buf.writes("// ---------------- Interface Declarations.\n\n")
for _, n := range builtin.Interfaces {
- buf.printf("extern const char* wuffs_base__%s__vtable_name;\n", n)
- buf.writeb('\n')
+ qid := t.QID{t.IDBase, builtInTokenMap.ByName(n)}
- buf.printf("typedef struct wuffs_base__%s__struct wuffs_base__%s;\n", n, n)
- buf.writeb('\n')
+ buf.printf("extern const char* wuffs_base__%s__vtable_name;\n\n", n)
+
+ buf.printf("typedef struct wuffs_base__%s__struct wuffs_base__%s;\n\n", n, n)
+
+ for _, f := range builtInInterfaceMethods[qid] {
+ if err := g.writeFuncSignature(buf, f, cppNone); err != nil {
+ return err
+ }
+ buf.writes(";\n\n")
+ }
buf.writes("#if defined(__cplusplus) || defined(WUFFS_IMPLEMENTATION)\n\n")
@@ -343,7 +360,20 @@
buf.writes("} private_impl;\n\n")
buf.writes("\n#ifdef __cplusplus\n\n")
- // TODO: C++ methods.
+ for _, f := range builtInInterfaceMethods[qid] {
+ if err := g.writeFuncSignature(buf, f, cppInsideStruct); err != nil {
+ return err
+ }
+ buf.writes("{ return ")
+ buf.writes(g.funcCName(f))
+ buf.writes("(this")
+ for _, o := range f.In().Fields() {
+ buf.writeb(',')
+ buf.writes(aPrefix)
+ buf.writes(o.AsField().Name().Str(g.tm))
+ }
+ buf.writes(");}\n\n")
+ }
buf.writes("#endif // __cplusplus\n\n")
buf.printf("}; // struct wuffs_base__%s__struct\n\n", n)
@@ -354,16 +384,67 @@
}
func insertInterfaceDefinitions(buf *buffer) error {
+ if err := parseBuiltInInterfaceMethods(); err != nil {
+ return err
+ }
+
+ g := &gen{
+ pkgPrefix: "wuffs_base__",
+ pkgName: "base",
+ tm: &builtInTokenMap,
+ }
+
buf.writes("// ---------------- Interface Definitions.\n\n")
for _, n := range builtin.Interfaces {
+ qid := t.QID{t.IDBase, builtInTokenMap.ByName(n)}
+
buf.printf("const char* wuffs_base__%s__vtable_name = "+
- "\"{vtable}wuffs_base__%s\";\n", n, n)
+ "\"{vtable}wuffs_base__%s\";\n\n", n, n)
+
+ for _, f := range builtInInterfaceMethods[qid] {
+ returnsStatus := f.Effect().Coroutine() ||
+ ((f.Out() != nil) && f.Out().IsStatus())
+
+ if err := g.writeFuncSignature(buf, f, cppNone); err != nil {
+ return err
+ }
+ buf.writes("{\n")
+ if err := writeFuncImplSelfMagicCheck(buf, g.tm, f); err != nil {
+ return err
+ }
+
+ // TODO.
+
+ buf.writes("return ")
+ if returnsStatus {
+ buf.writes("wuffs_base__make_status(wuffs_base__error__bad_vtable)")
+ } else if err := writeOutParamZeroValue(buf, g.tm, f.Out()); err != nil {
+ return err
+ }
+ buf.writes(";\n}\n\n")
+ }
}
- buf.writeb('\n')
return nil
}
+var (
+ builtInTokenMap = t.Map{}
+ builtInInterfaceMethods = map[t.QID][]*a.Func{}
+)
+
+func parseBuiltInInterfaceMethods() error {
+ if len(builtInInterfaceMethods) != 0 {
+ return nil
+ }
+ return builtin.ParseFuncs(&builtInTokenMap, builtin.InterfaceFuncs, false,
+ func(f *a.Func) error {
+ qid := f.Receiver()
+ builtInInterfaceMethods[qid] = append(builtInInterfaceMethods[qid], f)
+ return nil
+ })
+}
+
type gen struct {
pkgPrefix string // e.g. "wuffs_jpeg__"
pkgName string // e.g. "jpeg"
diff --git a/internal/cgen/func.go b/internal/cgen/func.go
index e754e9f..f3cf09a 100644
--- a/internal/cgen/func.go
+++ b/internal/cgen/func.go
@@ -67,7 +67,7 @@
// TODO: this isn't right if r[0] != 0, i.e. the receiver is from a
// used package. There might be similar cases elsewhere in this
// package.
- return g.pkgPrefix + r.Str(g.tm) + "__" + n.FuncName().Str(g.tm)
+ return g.pkgPrefix + r[1].Str(g.tm) + "__" + n.FuncName().Str(g.tm)
}
return g.pkgPrefix + n.FuncName().Str(g.tm)
}
@@ -121,7 +121,7 @@
if n.Effect().Pure() {
b.writes("const ")
}
- b.printf("%s%s *self", g.pkgPrefix, r.Str(g.tm))
+ b.printf("%s%s *self", g.pkgPrefix, r[1].Str(g.tm))
comma = true
}
}
@@ -217,7 +217,7 @@
return nil
}
-func (g *gen) writeOutParamZeroValue(b *buffer, typ *a.TypeExpr) error {
+func writeOutParamZeroValue(b *buffer, tm *t.Map, typ *a.TypeExpr) error {
if typ == nil {
b.writes("wuffs_base__make_empty_struct()")
return nil
@@ -251,39 +251,47 @@
return nil
}
}
- return fmt.Errorf("internal error: cannot write the zero value of type %q", typ.Str(g.tm))
+ return fmt.Errorf("internal error: cannot write the zero value of type %q", typ.Str(tm))
+}
+
+func writeFuncImplSelfMagicCheck(b *buffer, tm *t.Map, f *a.Func) error {
+ returnsStatus := f.Effect().Coroutine() ||
+ ((f.Out() != nil) && f.Out().IsStatus())
+
+ b.writes("if (!self) { return ")
+ if returnsStatus {
+ b.writes("wuffs_base__make_status(wuffs_base__error__bad_receiver)")
+ } else if err := writeOutParamZeroValue(b, tm, f.Out()); err != nil {
+ return err
+ }
+ b.writes(";}")
+
+ if f.Effect().Pure() {
+ b.writes("if ((self->private_impl.magic != WUFFS_BASE__MAGIC) &&")
+ b.writes(" (self->private_impl.magic != WUFFS_BASE__DISABLED)) {")
+ } else {
+ b.writes("if (self->private_impl.magic != WUFFS_BASE__MAGIC) {")
+ }
+ b.writes("return ")
+ if returnsStatus {
+ b.writes("wuffs_base__make_status(" +
+ "(self->private_impl.magic == WUFFS_BASE__DISABLED) " +
+ "? wuffs_base__error__disabled_by_previous_error " +
+ ": wuffs_base__error__initialize_not_called)")
+ } else if err := writeOutParamZeroValue(b, tm, f.Out()); err != nil {
+ return err
+ }
+
+ b.writes(";}\n")
+ return nil
}
func (g *gen) writeFuncImplPrologue(b *buffer) error {
// Check the initialized/disabled state and the "self" arg.
if g.currFunk.astFunc.Public() && !g.currFunk.astFunc.Receiver().IsZero() {
- out := g.currFunk.astFunc.Out()
-
- b.writes("if (!self) { return ")
- if g.currFunk.returnsStatus {
- b.writes("wuffs_base__make_status(wuffs_base__error__bad_receiver)")
- } else if err := g.writeOutParamZeroValue(b, out); err != nil {
+ if err := writeFuncImplSelfMagicCheck(b, g.tm, g.currFunk.astFunc); err != nil {
return err
}
- b.writes(";}")
-
- if g.currFunk.astFunc.Effect().Pure() {
- b.writes("if ((self->private_impl.magic != WUFFS_BASE__MAGIC) &&")
- b.writes(" (self->private_impl.magic != WUFFS_BASE__DISABLED)) {")
- } else {
- b.writes("if (self->private_impl.magic != WUFFS_BASE__MAGIC) {")
- }
- b.writes("return ")
- if g.currFunk.returnsStatus {
- b.writes("wuffs_base__make_status(" +
- "(self->private_impl.magic == WUFFS_BASE__DISABLED) " +
- "? wuffs_base__error__disabled_by_previous_error " +
- ": wuffs_base__error__initialize_not_called)")
- } else if err := g.writeOutParamZeroValue(b, out); err != nil {
- return err
- }
-
- b.writes(";}\n")
}
// For public functions, check (at runtime) the other args for bounds and
diff --git a/lang/builtin/builtin.go b/lang/builtin/builtin.go
index 5123e33..3e57af2 100644
--- a/lang/builtin/builtin.go
+++ b/lang/builtin/builtin.go
@@ -16,6 +16,11 @@
package builtin
import (
+ "fmt"
+
+ "github.com/google/wuffs/lang/parse"
+
+ a "github.com/google/wuffs/lang/ast"
t "github.com/google/wuffs/lang/token"
)
@@ -41,6 +46,7 @@
`"#bad receiver"`,
`"#bad restart"`,
`"#bad sizeof receiver"`,
+ `"#bad vtable"`,
`"#bad workbuf length"`,
`"#bad wuffs version"`,
`"#cannot return a suspension"`,
@@ -341,6 +347,12 @@
"hasher_u32",
}
+var InterfaceFuncs = []string{
+ // ---- hasher_u32
+
+ "hasher_u32.update_u32!(x: slice u8) u32",
+}
+
// The "T1" and "T2" types here are placeholders for generic "slice T" or
// "table T" types. After tokenizing (but before parsing) these XxxFunc strings
// (e.g. in the lang/check package), replace "T1" and "T2" with "†" or "‡"
@@ -367,3 +379,48 @@
"T2.row(y: u32) T1",
}
+
+func ParseFuncs(tm *t.Map, ss []string, generic bool, callback func(*a.Func) error) error {
+ buf := []byte(nil)
+ for _, s := range ss {
+ buf = buf[:0]
+ buf = append(buf, "pub func "...)
+ buf = append(buf, s...)
+ buf = append(buf, "{}\n"...)
+
+ const filename = "builtin.wuffs"
+ tokens, _, err := t.Tokenize(tm, filename, buf)
+ if err != nil {
+ return fmt.Errorf("parsing %q: could not tokenize built-in funcs: %v", s, err)
+ }
+ if generic {
+ for i := range tokens {
+ if tokens[i].ID == GenericOldName1 {
+ tokens[i].ID = GenericNewName1
+ } else if tokens[i].ID == GenericOldName2 {
+ tokens[i].ID = GenericNewName2
+ }
+ }
+ }
+ file, err := parse.Parse(tm, filename, tokens, &parse.Options{
+ AllowBuiltInNames: true,
+ })
+ if err != nil {
+ return fmt.Errorf("parsing %q: could not parse built-in funcs: %v", s, err)
+ }
+
+ tlds := file.TopLevelDecls()
+ if len(tlds) != 1 || tlds[0].Kind() != a.KFunc {
+ return fmt.Errorf("parsing %q: got %d top level decls, want %d", s, len(tlds), 1)
+ }
+ f := tlds[0].AsFunc()
+ f.AsNode().AsRaw().SetPackage(tm, t.IDBase)
+
+ if callback != nil {
+ if err := callback(f); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
diff --git a/lang/check/resolve.go b/lang/check/resolve.go
index 0b66ffa..88eeb59 100644
--- a/lang/check/resolve.go
+++ b/lang/check/resolve.go
@@ -18,7 +18,6 @@
"fmt"
"github.com/google/wuffs/lang/builtin"
- "github.com/google/wuffs/lang/parse"
a "github.com/google/wuffs/lang/ast"
t "github.com/google/wuffs/lang/token"
@@ -117,48 +116,18 @@
m = map[t.QQID]*a.Func{}
}
- buf := []byte(nil)
- for _, s := range ss {
- buf = buf[:0]
- buf = append(buf, "pub func "...)
- buf = append(buf, s...)
- buf = append(buf, "{}\n"...)
-
- const filename = "builtin.wuffs"
- tokens, _, err := t.Tokenize(c.tm, filename, buf)
- if err != nil {
- return nil, fmt.Errorf("check: parsing %q: could not tokenize built-in funcs: %v", s, err)
- }
- if generic {
- for i := range tokens {
- if tokens[i].ID == builtin.GenericOldName1 {
- tokens[i].ID = builtin.GenericNewName1
- } else if tokens[i].ID == builtin.GenericOldName2 {
- tokens[i].ID = builtin.GenericNewName2
- }
- }
- }
- file, err := parse.Parse(c.tm, filename, tokens, &parse.Options{
- AllowBuiltInNames: true,
- })
- if err != nil {
- return nil, fmt.Errorf("check: parsing %q: could not parse built-in funcs: %v", s, err)
- }
-
- tlds := file.TopLevelDecls()
- if len(tlds) != 1 || tlds[0].Kind() != a.KFunc {
- return nil, fmt.Errorf("check: parsing %q: got %d top level decls, want %d", s, len(tlds), 1)
- }
- f := tlds[0].AsFunc()
- f.AsNode().AsRaw().SetPackage(c.tm, t.IDBase)
+ if err := builtin.ParseFuncs(c.tm, ss, generic, func(f *a.Func) error {
if err := c.checkFuncSignature(f.AsNode()); err != nil {
- return nil, err
+ return err
}
-
if m != nil {
m[f.QQID()] = f
}
+ return nil
+ }); err != nil {
+ return nil, err
}
+
return m, nil
}
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 866890a..4d23d00 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -187,6 +187,7 @@
extern const char* wuffs_base__error__bad_receiver;
extern const char* wuffs_base__error__bad_restart;
extern const char* wuffs_base__error__bad_sizeof_receiver;
+extern const char* wuffs_base__error__bad_vtable;
extern const char* wuffs_base__error__bad_workbuf_length;
extern const char* wuffs_base__error__bad_wuffs_version;
extern const char* wuffs_base__error__cannot_return_a_suspension;
@@ -2569,6 +2570,10 @@
typedef struct wuffs_base__hasher_u32__struct wuffs_base__hasher_u32;
+WUFFS_BASE__MAYBE_STATIC uint32_t //
+wuffs_base__hasher_u32__update_u32(wuffs_base__hasher_u32* self,
+ wuffs_base__slice_u8 a_x);
+
#if defined(__cplusplus) || defined(WUFFS_IMPLEMENTATION)
struct wuffs_base__hasher_u32__struct {
@@ -2580,6 +2585,11 @@
#ifdef __cplusplus
+ inline uint32_t //
+ update_u32(wuffs_base__slice_u8 a_x) {
+ return wuffs_base__hasher_u32__update_u32(this, a_x);
+ }
+
#endif // __cplusplus
}; // struct wuffs_base__hasher_u32__struct
@@ -4565,6 +4575,7 @@
const char* wuffs_base__error__bad_restart = "#base: bad restart";
const char* wuffs_base__error__bad_sizeof_receiver =
"#base: bad sizeof receiver";
+const char* wuffs_base__error__bad_vtable = "#base: bad vtable";
const char* wuffs_base__error__bad_workbuf_length = "#base: bad workbuf length";
const char* wuffs_base__error__bad_wuffs_version = "#base: bad wuffs version";
const char* wuffs_base__error__cannot_return_a_suspension =
@@ -4586,6 +4597,18 @@
const char* wuffs_base__hasher_u32__vtable_name =
"{vtable}wuffs_base__hasher_u32";
+WUFFS_BASE__MAYBE_STATIC uint32_t //
+wuffs_base__hasher_u32__update_u32(wuffs_base__hasher_u32* self,
+ wuffs_base__slice_u8 a_x) {
+ if (!self) {
+ return 0;
+ }
+ if (self->private_impl.magic != WUFFS_BASE__MAGIC) {
+ return 0;
+ }
+ return 0;
+}
+
// ---------------- Images
const uint32_t wuffs_base__pixel_format__bits_per_channel[16] = {