text: #include <stdio.h>
  #include <stdlib.h>
  #include <inttypes.h>
  #include <stdbool.h>
  #include <stdarg.h>
  #include <ctype.h>
  #include <string.h>
  #include <assert.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <fcntl.h>
  #include <unistd.h>
  
  #include "util.h"
  #include "parse.h"
  #include "mi.h"
  
  #define V1
  /**
   * TODO
   * Recursively check the types of the pattern and the subject tree.
   *
   */
  
  File file;
  char debugopt[128];
  
  typedef struct Dtree Dtree;
  extern Dtree *gendtree(Node *m, Node *val, Node **lbl, size_t nlbl);
  extern void dtreedump(FILE *fd, Dtree *dt);
  
  
  static char *
  errorf(char *fmt, ...)
  {
  	va_list ap;
  	char *p;
  	size_t n;
  
  	p = malloc(2048);
  	if (p == NULL)
  		return "(NULL)";
  
  	va_start(ap, fmt);
  	n = vsnprintf(p, 2048, fmt, ap);
  	va_end(ap);
  	if (n > 0) {
  		p = realloc(p, n+1);
  	} else {
  		free(p);
  		p = "(NULL)";
  	}
  	return p;
  }
  
  static Type *
  installucons(Type *t)
  {
  	Type *b;
  	size_t i;
  
  	if (!t)
  		return NULL;
  	b = tybase(t);
  	switch (b->type) {
  	case Tystruct:
  		for (i = 0; i < b->nmemb; i++)
  			installucons(b->sdecls[i]->decl.type);
  		break;
  	case Tyunion:
  		for (i = 0; i < b->nmemb; i++) {
  			if (!b->udecls[i]->utype)
  				b->udecls[i]->utype = b;
  			b->udecls[i]->id = i;
  		}
  		break;
  	default:
  		break;
  	}
  	return t;
  }
  
  static Node *
  mkdummymatch(Node *p)
  {
  	Node *b;
  
  	b = mkblock(Zloc, mkstab(0));
  	b->block.stmts = NULL;
  	b->block.nstmts = 0;
  
  	return mkmatch(Zloc, p, b);
  }
  
  static Node *
  ty(Node *n, Type *t)
  {
  	switch (n->type) {
  	case Nlit:
  		n->lit.type = t;
  		break;
  	case Nexpr:
  		n->expr.type = t;
  	default:
  		;
  	}
  	return n;
  }
  
  static char *
  exprequal(Node *a, Node *b, int depth)
  {
  	size_t i;
  	char *err;
  
  	if (a == NULL && b == NULL)
  		return NULL;
  
  	if (a == NULL || b == NULL)
  		return "either one is null";
  
  	if (false && a->nid != b->nid)
  		return errorf("nid is not matched. (%d) want %d, got %d", depth, a->nid, b->nid);
  
  	if (a->type != b->type)
  		return errorf("ntype is not matched. (%d) want %s, got %s", depth, nodestr[a->type], nodestr[b->type]);
  
  	switch (a->type) {
  	case Nexpr:
  		if (exprop(a) != exprop(b))
  			return errorf("op is not matched. (%d) want %s, got %s", depth, opstr[exprop(a)], opstr[exprop(b)]);
  
  		if (a->expr.nargs != b->expr.nargs) {
  			fprintf(stderr, "op:%s\n", opstr[exprop(a)]);
  			return errorf("nargs is not matched. (%d) want %d, got %d", depth, a->expr.nargs, b->expr.nargs);
  		}
  
  		for (i = 0; i < a->expr.nargs; i++) {
  			err = exprequal(a->expr.args[i], b->expr.args[i], depth+1);
  			if (err != NULL)
  				return err;
  		}
  		break;
  	case Nlit:
  		switch (a->lit.littype) {
  		case Lint:
  			if (a->lit.intval != b->lit.intval)
  				return errorf("lit.intval is not matched. (%d) want %d, got %d", depth, a->lit.intval, b->lit.intval);
  			break;
  		default:
  		return errorf("unexpected littype: %s", nodestr[a->type]);
  		}
  		break;
  	case Nname:
  		break;
  	default:
  		return errorf("unexpected ntype: %s", nodestr[a->type]);
  	}
  
  	return NULL;
  }
  
  static char *
  dtequal(Dtree *a, Dtree *b, int depth)
  {
  	size_t i;
  	char *err;
  
  	if (a == NULL && b == NULL)
  		return NULL;
  	if (a == NULL || b == NULL)
  		return "either one is null";
  
  	if (a->id != b->id)
  		return errorf("id is not matched. (depth:%d) want %d, got %d", depth, a->id, b->id);
  
  	if (a->nconstructors != b->nconstructors)
  		return errorf("nconstructors is not matched. (depth:%d id:%d) want %ld, got %ld", depth, a->id, a->nconstructors, b->nconstructors);
  
  	if (a->accept != b->accept)
  		return errorf("accept is not matched. (depth:%d id:%d) want %ld, got %ld", depth, a->id, a->accept, b->accept);
  
  	if (a->emitted != b->emitted)
  		return errorf("emitted is not matched. (depth:%d id:%d) want %ld, got %ld", depth, a->id, a->emitted, b->emitted);
  
  	err = exprequal(a->load, b->load, 0);
  	if (err != NULL) {
  		fprintf(stderr, "WANT:\n");
  		dumpn(a->load, stderr);
  		fprintf(stderr, "GOT:\n");
  		dumpn(b->load, stderr);
  		return errorf("load is not matched. (depth:%d id:%d) want %p, got %p, %s", depth, a->id, a->load, b->load, err);
  	}
  
  	if (a->nnext != b->nnext)
  		return errorf("nnext is not matched. (depth:%d id:%d) want %d, got %d", depth, a->id, a->nnext, b->nnext);
  
  	for (i = 0; i < a->npat; i++) {
  		err = exprequal(a->pat[i], b->pat[i], 0);
  		if (err != NULL) {
  			fprintf(stderr, "WANT:\n");
  			dumpn(a->pat[i], stderr);
  			fprintf(stderr, "GOT:\n");
  			dumpn(b->pat[i], stderr);
  			return errorf("pat is not matched. (depth:%d id:%d) want %p, got %p, %s", depth, a->id, a->pat[i], b->pat[i], err);
  		}
  	}
  	for (i = 0; i < a->nnext; i++) {
  		err = dtequal(a->next[i], b->next[i], depth+1);
  		if (err != NULL)
  			return errorf("next[%d] is not matched. (depth:%d id:%d) want %p, got %p, %s", i, depth, a->id, a->next[i], b->next[i], err);
  	}
  	err = dtequal(a->any, b->any, depth+1);
  	if (err != NULL)
  		return errorf("any is not matched. (depth:%d id:%d) want %p, got %p, %s", depth, a->id, a->any, b->any, err);
  
  	return NULL;
  }
  
  
  
  static char *
  test_match(int idx, Node *val, Node **pat, Dtree *want)
  {
  	Dtree *dt;
  	Node *m, *v, *r, **lbl, **matches;
  	size_t i, nlbl, npat, nmatches;
  	char *err;
  
  	matches = NULL;
  	nmatches = 0;
  	for (npat = 0; pat[npat] != NULL; npat++) {
  		lappend(&matches, &nmatches, mkdummymatch(pat[npat]));
  	}
  
  	m = mkmatchstmt(Zloc, val, matches, nmatches);
  	r = val;
  	v = gentemp(r->loc, r->expr.type, NULL);
  
  
  	if (getenv("D")) {
  		fprintf(stderr, "[%.3d]>\n", idx);
  		dumpn(m, stdout);
  	}
  
  	if (1) {
  		lbl = NULL;
  		nlbl = 0;
  		for (i = 0; i < nmatches; i++) {
  			lappend(&lbl, &nlbl, genlbl(pat[i]->match.block->loc));
  		}
  
  		dt = gendtree(m, v, lbl, nlbl);
  		if (getenv("d")) {
  			fprintf(stderr, "dtree >>\n");
  			dtreedump(stderr, dt);
  		}
  
  		err = dtequal(want, dt, 0);
  		if (err)
  			return err;
  	}
  
  	if (getenv("G")) {
  		Node **matches = NULL;
  		size_t nmatches = 0;
  		genmatch(m, v, &matches, &nmatches);
  
  		fprintf(stdout, "===========\n");
  		for (i = 0; i < nmatches; i++) {
  			dumpn(matches[i], stdout);
  		}
  	}
  
  	return NULL;
  }
  
  typedef struct Test {
  	char *name;
  	char *desc;
  	Node *val;
  	Node **pats;
  	Dtree *dt;
  } Test;
  
  inline static Node *
  setnode(Node **dst, Node *src)
  {
  	*dst = src;
  	return *dst;
  }
  
  inline static Node *
  getnode(Node *n)
  {
  	return n;
  }
  
  int
  main(int argc, char **argv)
  {
  	size_t i;
  	char *err;
  	Node *t, *p_, *p0, *p1, *p2;
  
  #define P(x) getnode(p##x)
  
  #define InitP0(p) setnode(&p0, p)
  #define InitP1(p) setnode(&p1, p)
  #define InitP2(p) setnode(&p2, p)
  #define InitP_(p) setnode(&p_, p)
  
  
  #define InitT(v) setnode(&t, v)
  #define T getnode(t)
  
  
  	Type *_int32 = mktype(Zloc, Tyint32);
  	Type *_int64 = mktype(Zloc, Tyint64);
  
  	Type *_int32t1 = mktytuple(Zloc, (Type*[]){_int32}, 1);
  	Type *_int32t2 = mktytuple(Zloc, (Type*[]){_int32, _int32}, 2);
  	Type *_int32t3 = mktytuple(Zloc, (Type*[]){_int32, _int32, _int32}, 3);
  
  	Type *_int32s1 = mktystruct(Zloc, (Node*[]){mkdecl(Zloc, mkname(Zloc, "foo"), _int32)}, 1);
  	Type *_enum1 = installucons(mktyunion(Zloc, (Ucon*[]){mkucon(Zloc, mkname(Zloc, "Foo"), NULL, NULL)}, 1));
  	Type *_enum2 = installucons(mktyunion(Zloc,
  					      (Ucon*[]){
  						      mkucon(Zloc, mkname(Zloc, "Foo"), NULL, NULL),
  						      mkucon(Zloc, mkname(Zloc, "Bar"), NULL, NULL)},
  						      2));
  	Type *_enum3 = installucons(mktyunion(Zloc,
  					      (Ucon*[]){
  						      mkucon(Zloc, mkname(Zloc, "Foo"), NULL, NULL),
  						      mkucon(Zloc, mkname(Zloc, "Bar"), NULL, NULL),
  						      mkucon(Zloc, mkname(Zloc, "Baz"), NULL, NULL)},
  						      3));
  
  	Type *_int32u1 = mktyunion(Zloc, (Ucon*[]){
  		mkucon(Zloc, mkname(Zloc, "Foo"), NULL, _int32t1),
  	}, 1);
  
  	Type *_int32a1 = mktyslice(Zloc, _int32);
  
  
  	Type *_bug001u = installucons(mktyunion(Zloc, (Ucon*[]){
  			mkucon(Zloc, mkname(Zloc, "Foo"), NULL, _int32t1),
  			mkucon(Zloc, mkname(Zloc, "Bar"), NULL, NULL)
  		}, 2));
  	Type *_bug001s = mktystruct(Zloc, (Node*[]){
  		mkdecl(Zloc, mkname(Zloc, "s1_slice"), _int32a1),
  		mkdecl(Zloc, mkname(Zloc, "s1_int32"), _int32),
  	}, 2);
  
  	Type *_bug002s = mktystruct(Zloc, (Node*[]){
  		mkdecl(Zloc, mkname(Zloc, "s2_ufoo"), _bug001u),
  		mkdecl(Zloc, mkname(Zloc, "s2_sbar"), _bug001s),
  		mkdecl(Zloc, mkname(Zloc, "s2_int32"), _int32),
  	}, 3);
  
  
  	Dtree *dt11 = &(Dtree){
  		.id = 11,
  		.any = NULL,
  	};
  	Dtree *dt8 = &(Dtree){
  		.id = 8,
  		.any =dt11,
  	};
  	dt11->any = dt8;
  
  	Test tests[] = {
  		{
  			.name = "int32 matched by 1 wildcard",
  			.val  = InitT(gentemp(Zloc, _int32, NULL)),
  			.pats = (Node*[]){
  				ty(mkexpr(Zloc, Ogap, NULL), _int32),
  				NULL,
  			},
  			.dt = &(Dtree){
  				.id = 0,
  				.accept = 1,
  			},
  		},
  		{
  			.name = "int32 matched by 1 capture variable",
  			.val = InitT(gentemp(Zloc, _int32, NULL)),
  			.pats = (Node*[]){
  				InitP0(ty(mkexpr(Zloc, Ovar, mkname(Zloc, "foovar"), NULL), _int32)),
  				NULL,
  			},
  			.dt = &(Dtree){
  				.id = 0,
  				.accept = 1,
  			},
  		},
  		{
  			.name = "int32 matched by 1 literals",
  			.val = InitT(gentemp(Zloc, _int32, NULL)),
  			.pats = (Node*[]){
  				InitP0(ty(mkexpr(Zloc, Olit, mkint(Zloc, 123), NULL), _int32)),
  				InitP_(ty(mkexpr(Zloc, Ogap, NULL), _int32)),
  				NULL,
  			},
  			.dt = &(Dtree){
  				.id = 2,
  				.load = gentemp(Zloc, _int32, NULL),
  				.nconstructors = 4294967296,
  				.nnext = 1,
  				.npat = 1,
  				.pat = (Node*[]){
  					[0] = p0,
  				},
  				.next = (Dtree*[]){
  					[0] = &(Dtree){
  						.id = 0,
  						.accept = 1,
  					},
  				},
  				.any = &(Dtree){
  					.id = 1,
  					.accept = 1,
  				},
  			},
  		},
  		{
  			.name = "int32 matched by 2 literals",
  			.val = InitT(gentemp(Zloc, _int32, NULL)),
  			.pats = (Node*[]){
  				InitP0(ty(mkexpr(Zloc, Olit, mkint(Zloc, 123), NULL), _int32)),
  				InitP1(ty(mkexpr(Zloc, Olit, mkint(Zloc, 456), NULL), _int32)),
  				InitP_(ty(mkexpr(Zloc, Ogap, NULL), _int32)),
  				NULL,
  			},
  			.dt = &(Dtree){
  				.id = 3,
  				.load = gentemp(Zloc, _int32, NULL),
  				.nconstructors = 4294967296,
  				.npat = 2,
  				.nnext = 2,
  				.pat = (Node*[]){
  					[0] = P(0),
  					[1] = P(1),
  				},
  				.next = (Dtree*[]){
  					[0] = &(Dtree){
  						.id = 0,
  						.accept = 1,
  					},
  					[1] = &(Dtree){
  						.id = 1,
  						.accept = 1,
  					},
  				},
  				.any = &(Dtree){
  					.id = 2,
  					.accept = 1,
  				},
  			},
  		},
  		{
  			.name = "1-tuple, matched by wildcard only",
  			.val = InitT(gentemp(Zloc, _int32t1, NULL)),
  			.pats = (Node*[]){
  				ty(mkexpr(Zloc, Otup, ty(mkexpr(Zloc, Ogap, NULL), _int32), NULL), _int32t1),
  				NULL,
  			},
  			.dt = &(Dtree){
  				.id = 0,
  				.accept = 1,
  				.nnext = 0,
  				.npat = 0,
  				.any = NULL,
  			},
  		},
  		{
  			.name = "1-tuple",
  			.val = InitT(gentemp(Zloc, _int32t1, NULL)),
  			.pats = (Node *[]){
  				InitP0(ty(mkexpr(Zloc, Otup, ty(mkexpr(Zloc, Olit, mkint(Zloc, 123), NULL), _int32), NULL), _int32t1)),
  				InitP1(ty(mkexpr(Zloc, Ogap, NULL), _int32t1)),
  				NULL,
  			},
  			.dt = &(Dtree){
  				.id = 2,
  				.load = ty(mkexpr(Zloc, Otupget, T, mkintlit(Zloc, 0), NULL), _int32),
  				.nconstructors = 4294967296,
  				.nnext = 1,
  				.npat = 1,
  				.pat =  (Node*[]){
  					P(0)->expr.args[0],
  				},
  				.next = (Dtree*[]){
  					[0] = &(Dtree){
  						.id = 0,
  						.accept = 1,
  					},
  				},
  				.any = &(Dtree){
  					.id = 1,
  					.accept = 1
  				},
  			},
  		},
  		{
  			.name = "2-tuple",
  			.val = InitT(gentemp(Zloc, _int32t2, NULL)),
  			.pats = (Node *[]){
  				/**
  				 * | (123, 456):
  				 */
  				InitP0(ty(mkexpr(Zloc, Otup,
  					     ty(mkexpr(Zloc, Olit, mkint(Zloc, 123), NULL), _int32),
  					     ty(mkexpr(Zloc, Olit, mkint(Zloc, 456), NULL), _int32),
  					     NULL), _int32t2)),
  				/**
  				 * | (_, _):
  				 */
  				InitP1(ty(mkexpr(Zloc, Ogap, NULL), _int32t2)),
  				NULL,
  			},
  			.dt = &(Dtree){
  				.id = 3,
  				.load = ty(mkexpr(Zloc, Otupget, T, mkintlit(Zloc, 0), NULL), _int32),
  				.nconstructors = 4294967296,
  				.nnext = 1,
  				.npat = 1,
  				.pat = (Node*[]){
  					P(0)->expr.args[0],
  				},
  				.next = (Dtree*[]){
  					[0] = &(Dtree){
  						.id = 2,
  						.load =ty(mkexpr(Zloc, Otupget, T, mkintlit(Zloc, 1), NULL), _int32),
  						.nconstructors = 4294967296,
  						.nnext = 1,
  						.npat = 1,
  						.pat = (Node*[]){
  							P(0)->expr.args[1],
  						},
  						.next = (Dtree*[]){
  							[0] = &(Dtree){
  								.id = 0,
  								.accept = 1,
  							},
  						},
  						.any = &(Dtree){
  							.id = 1,
  							.accept = 1,
  						},
  					},
  				},
  				.any = &(Dtree){
  					.id = 1,
  					.accept = 1,
  				}
  			},
  		},
  		{
  			.name = "3-tuple",
  			.val = InitT(gentemp(Zloc, _int32t3, NULL)),
  			.pats = (Node *[]){
  				/**
  				 * | (123, 456):
  				 */
  				InitP0(ty(mkexpr(Zloc, Otup,
  					     ty(mkexpr(Zloc, Olit, mkint(Zloc, 123), NULL), _int32),
  					     ty(mkexpr(Zloc, Olit, mkint(Zloc, 456), NULL), _int32),
  					     ty(mkexpr(Zloc, Olit, mkint(Zloc, 789), NULL), _int32),
  					     NULL), _int32t3)),
  				/**
  				 * | (_, _):
  				 */
  				InitP1(ty(mkexpr(Zloc, Ogap, NULL), _int32t3)),
  				NULL,
  			},
  			.dt = &(Dtree){
  				.id = 4,
  				.load = ty(mkexpr(Zloc, Otupget, T, mkintlit(Zloc, 0), NULL), _int32),
  				.nconstructors = 4294967296,
  				.nnext = 1,
  				.npat = 1,
  				.pat = (Node*[]){
  					P(0)->expr.args[0],
  				},
  				.next = (Dtree*[]){
  					[0] = &(Dtree){
  						.id = 3,
  						.load = ty(mkexpr(Zloc, Otupget, T, mkintlit(Zloc, 1), NULL), _int32),
  						.nconstructors = 4294967296,
  						.nnext = 1,
  						.npat = 1,
  						.pat = (Node*[]){
  							P(0)->expr.args[1],
  						},
  						.next = (Dtree*[]){
  							[0] = &(Dtree){
  								.id = 2,
  								.load = ty(mkexpr(Zloc, Otupget, T, mkintlit(Zloc, 2), NULL), _int32),
  								.nconstructors = 4294967296,
  								.nnext = 1,
  								.npat = 1,
  								.pat = (Node*[]){
  									P(0)->expr.args[2],
  								},
  								.next = (Dtree*[]){
  									[0] = &(Dtree){
  										.id = 0,
  										.accept = 1,
  									}
  								},
  								.any = &(Dtree){
  									.id = 1,
  									.accept = 1,
  								},
  							},
  						},
  						.any = &(Dtree){
  							.id = 1,
  							.accept = 1,
  						},
  					},
  				},
  				.any = &(Dtree){
  					.id = 1,
  					.accept =1,
  				},
  			},
  		},
  		{
  			.name = "3-tuple-3-pat",
  			.val = InitT(gentemp(Zloc, _int32t3, NULL)),
  			.pats = (Node *[]){
  				/**
  				 * | (123, 456):
  				 */
  				InitP0(ty(mkexpr(Zloc, Otup,
  					     ty(mkexpr(Zloc, Olit, mkint(Zloc, 101), NULL), _int32),
  					     ty(mkexpr(Zloc, Olit, mkint(Zloc, 102), NULL), _int32),
  					     ty(mkexpr(Zloc, Olit, mkint(Zloc, 103), NULL), _int32),
  					     NULL), _int32t3)),
  				InitP1(ty(mkexpr(Zloc, Otup,
  					       ty(mkexpr(Zloc, Olit, mkint(Zloc, 201), NULL), _int32),
  					       ty(mkexpr(Zloc, Olit, mkint(Zloc, 202), NULL), _int32),
  					       ty(mkexpr(Zloc, Olit, mkint(Zloc, 203), NULL), _int32),
  					       NULL), _int32t3)),
  				InitP2(ty(mkexpr(Zloc, Otup,
  					       ty(mkexpr(Zloc, Olit, mkint(Zloc, 301), NULL), _int32),
  					       ty(mkexpr(Zloc, Olit, mkint(Zloc, 302), NULL), _int32),
  					       ty(mkexpr(Zloc, Olit, mkint(Zloc, 303), NULL), _int32),
  					       NULL), _int32t3)),
  
  				/**
  				 * | (_, _):
  				 */
  				InitP_(ty(mkexpr(Zloc, Ogap, NULL), _int32t3)),
  				NULL,
  			},
  			.dt = &(Dtree){
  				.id = 10,
  				.load = ty(mkexpr(Zloc, Otupget, T, mkintlit(Zloc, 0), NULL), _int32),
  				.nconstructors = 4294967296,
  				.nnext = 3,
  				.npat = 3,
  				.pat = (Node*[]){
  					P(0)->expr.args[0],
  					P(1)->expr.args[0],
  					P(2)->expr.args[0],
  				},
  				.next = (Dtree*[]){
  					[0] = &(Dtree){
  						.id = 5,
  						.load = ty(mkexpr(Zloc, Otupget, T, mkintlit(Zloc, 1), NULL), _int32),
  						.nconstructors = 4294967296,
  						.nnext = 1,
  						.npat = 1,
  						.pat = (Node*[]){
  							P(0)->expr.args[1],
  						},
  						.next = (Dtree*[]){
  							[0] = &(Dtree){
  								.id = 4,
  								.load = ty(mkexpr(Zloc, Otupget, T, mkintlit(Zloc, 2), NULL), _int32),
  								.nconstructors = 4294967296,
  								.nnext = 1,
  								.npat = 1,
  								.pat = (Node*[]){
  									P(0)->expr.args[2],
  								},
  								.next = (Dtree*[]){
  									[0] = &(Dtree){
  										.id = 0,
  										.accept = 1,
  									},
  								},
  								.any = &(Dtree){
  									.id = 3,
  									.accept = 1,
  								},
  							},
  						},
  						.any = &(Dtree){
  							.id = 3,
  							.accept = 1,
  						},
  					},
  					[1] = &(Dtree){
  						.id = 7,
  						.load = ty(mkexpr(Zloc, Otupget, T, mkintlit(Zloc, 1), NULL), _int32),
  						.nconstructors = 4294967296,
  						.nnext = 1,
  						.npat = 1,
  						.pat = (Node*[]){
  							P(1)->expr.args[1],
  						},
  						.next = (Dtree*[]){
  							[0] = &(Dtree){
  								.id = 6,
  								.load = ty(mkexpr(Zloc, Otupget, T, mkintlit(Zloc, 2), NULL), _int32),
  								.nconstructors = 4294967296,
  								.nnext = 1,
  								.npat = 1,
  								.pat = (Node*[]){
  									P(1)->expr.args[2],
  								},
  								.next = (Dtree*[]){
  									[0] = &(Dtree){
  										.id = 1,
  										.accept = 1,
  									},
  								},
  								.any = &(Dtree){
  									.id = 3,
  									.accept = 1,
  								},
  							},
  						},
  						.any = &(Dtree){
  							.id = 3,
  							.accept = 1,
  						},
  					},
  					[2] = &(Dtree){
  						.id = 9,
  						.load = ty(mkexpr(Zloc, Otupget, T, mkintlit(Zloc, 1), NULL), _int32),
  						.nconstructors = 4294967296,
  						.nnext = 1,
  						.npat = 1,
  						.pat = (Node*[]){
  							P(2)->expr.args[1],
  						},
  						.next = (Dtree*[]){
  							[0] = &(Dtree){
  								.id = 8,
  								.load = ty(mkexpr(Zloc, Otupget, T, mkintlit(Zloc, 2), NULL), _int32),
  								.nconstructors = 4294967296,
  								.nnext = 1,
  								.npat = 1,
  								.pat = (Node*[]){
  									P(2)->expr.args[2],
  								},
  								.next = (Dtree*[]){
  									[0] = &(Dtree){
  										.id = 2,
  										.accept = 1,
  									},
  								},
  								.any = &(Dtree){
  									.id = 3,
  									.accept = 1,
  								},
  							},
  						},
  						.any = &(Dtree){
  							.id = 3,
  							.accept = 1,
  						},
  					},
  				},
  				.any = &(Dtree){
  					.id = 3,
  					.accept = 1,
  				},
  			},
  		},
  
  		{
  			.name = "1-int32-struct",
  			.val = InitT(gentemp(Zloc, _int32s1, NULL)),
  			.pats = (Node*[]){
  				InitP0(ty(mkexprl(Zloc, Ostruct, (Node*[]){mkidxinit(Zloc, mkname(Zloc, "foo"), mkintlit(Zloc, 123))}, 1), _int32s1)),
  				InitP_(ty(mkexpr(Zloc, Ogap, NULL), _int32s1)),
  				NULL,
  			},
  			.dt = &(Dtree){
  				.id = 2,
  				.load = ty(mkexpr(Zloc, Omemb, T, tybase(exprtype(P(0)))->sdecls[0]->decl.name, NULL), _int32),
  				.nconstructors = 4294967296,
  				.nnext = 1,
  				.npat = 1,
  				.pat = (Node*[]){
  					P(0)->expr.args[0],
  				},
  				.next = (Dtree*[]){
  					[0] = &(Dtree){
  						.id = 0,
  						.accept = 1,
  					},
  				},
  				.any = &(Dtree){
  					.id = 1,
  					.accept = 1,
  				},
  			},
  		},
  		{
  			.name = "1-enum, matched by wildcard only",
  			.val = InitT(gentemp(Zloc, _enum1, NULL)),
  			.pats = (Node*[]){
  				InitP_( ty(mkexpr(Zloc, Ogap, NULL), _enum1)),
  				NULL,
  			},
  			.dt = &(Dtree){
  				.id = 0,
  				.accept = 1,
  			},
  		},
  		{
  			.name = "1-enum, matched by a valid constructor",
  			.val = InitT(gentemp(Zloc, _enum1, NULL)),
  			.pats = (Node*[]){
  				InitP0(ty(mkexpr(Zloc, Oucon, mkname(Zloc, "Foo"), NULL), _enum1)),
  				InitP_(ty(mkexpr(Zloc, Ogap, NULL), _enum1)),
  				NULL,
  			},
  			.dt = &(Dtree){
  				.id = 2,
  				.nconstructors = 1,
  				.load = ty(mkexpr(Zloc, Outag, T, NULL), _int32),
  				.nnext = 1,
  				.npat = 1,
  				.pat = (Node*[]){
  					/*
  					 * the matcher will convert the Oucon expr to an Nlit for the Dtree
  					 */
  					ty(mkintlit(Zloc, finducon(_enum1, P(0)->expr.args[0])->id), _int32),
  				},
  				.next = (Dtree*[]){
  					[0] = &(Dtree){
  						.id = 0,
  						.accept = 1,
  					},
  				},
  				.any = &(Dtree){
  					.id = 1,
  					.accept = 1,
  				},
  			},
  		},
  		/**
  		 * match v : _enum2
  		 * | `Foo
  		 * | `Bar
  		 * ;;
  		 *
  		 */
  		{
  			.name = "2-enum, matched by 2 valid constructors",
  			.val = InitT(gentemp(Zloc, _enum2, NULL)),
  			.pats = (Node*[]) {
  				InitP0(ty(mkexpr(Zloc, Oucon, mkname(Zloc, "Foo"), NULL), _enum2)),
  				InitP1(ty(mkexpr(Zloc, Oucon, mkname(Zloc, "Bar"), NULL), _enum2)),
  
  				NULL,
  			},
  			.dt = &(Dtree){
  				.id = 2,
  				.load = ty(mkexpr(Zloc, Outag, T, NULL), _int32),
  				.nconstructors = 2,
  				.nnext = 2,
  				.npat = 2,
  				.pat = (Node*[]){
  					ty(mkintlit(Zloc, finducon(_enum2, P(0)->expr.args[0])->id), _int32),
  					ty(mkintlit(Zloc, finducon(_enum2, P(1)->expr.args[0])->id), _int32),
  				},
  				.next = (Dtree*[]){
  					[0] = &(Dtree){
  						.id = 0,
  						.accept = 1,
  					},
  					[1] = &(Dtree){
  						.id = 1,
  						.accept = 1,
  					},
  				},
  				.any = NULL,
  			},
  		},
  		{
  			.name = "3-enum, matched by 3 valid constructors",
  			.val = InitT(gentemp(Zloc, _enum3, NULL)),
  			.pats = (Node*[]) {
  				InitP0(ty(mkexpr(Zloc, Oucon, mkname(Zloc, "Foo"), NULL), _enum3)),
  				InitP1(ty(mkexpr(Zloc, Oucon, mkname(Zloc, "Bar"), NULL), _enum3)),
  				InitP2(ty(mkexpr(Zloc, Oucon, mkname(Zloc, "Baz"), NULL), _enum3)),
  				NULL,
  			},
  			.dt = &(Dtree){
  				.id = 3,
  				.load = ty(mkexpr(Zloc, Outag, T, NULL), _int32),
  				.nconstructors = 3,
  				.nnext = 3,
  				.npat = 3,
  				.pat = (Node*[]){
  					ty(mkintlit(Zloc, finducon(_enum3, P(0)->expr.args[0])->id), _int32),
  					ty(mkintlit(Zloc, finducon(_enum3, P(1)->expr.args[0])->id), _int32),
  					ty(mkintlit(Zloc, finducon(_enum3, P(2)->expr.args[0])->id), _int32),
  				},
  				.next = (Dtree*[]){
  					[0] = &(Dtree){
  						.id = 0,
  						.accept = 1,
  					},
  					[1] = &(Dtree){
  						.id = 1,
  						.accept = 1,
  					},
  					[2] = &(Dtree){
  						.id = 2,
  						.accept = 1,
  					},
  				},
  				.any = NULL,
  			},
  		},
  		{
  			.name = "1-int32-array, matched by an element",
  			.val = InitT(gentemp(Zloc, _int32a1, NULL)),
  			.pats = (Node*[]) {
  				InitP0(ty(mkexpr(Zloc, Oarr,
  						/**
  						 * {.[0] = 123}
  						 */
  						mkidxinit(Zloc, mkintlit(Zloc, 0), mkintlit(Zloc, 123)),
  						NULL),
  					_int32s1)),
  				InitP_(ty(mkexpr(Zloc, Ogap, NULL), _int32a1)),
  				NULL,
  			},
  			.dt = &(Dtree){
  				.id = 2,
  				.nconstructors = 4294967296,
  				.load = ty(mkexpr(Zloc, Oidx, T, ty(mkintlit(Zloc, 0), _int64), NULL), _int32),
  				.nnext = 1,
  				.npat = 1,
  				.pat = (Node*[]){
  					P(0)->expr.args[0],
  				},
  				.next = (Dtree*[]){
  					[0] = &(Dtree){
  						.id = 0,
  						.accept = 1,
  					},
  				},
  				.any = &(Dtree){
  					.id = 1,
  					.accept = 1,
  				},
  			},
  		},
  		/**
  		 * | `Foo (int32)
  		 */
  		{
  			.name = "1-union of 1-tuple, matched by wildcard only",
  			.val = InitT(gentemp(Zloc, _int32u1, NULL)),
  			.pats = (Node*[]){
  				InitP_(ty(mkexpr(Zloc, Ogap, NULL), _int32u1)),
  				NULL,
  			},
  			.dt = &(Dtree){
  				.id = 0,
  				.accept = 1,
  			},
  		},
  		{
  			.name = "1-union of 1-tuple",
  			.val = InitT(gentemp(Zloc, _int32u1, NULL)),
  			.pats = (Node*[]){
  				/**
  				 * `Foo (123)
  				 */
  				InitP0(ty(mkexpr(Zloc, Oucon, mkname(Zloc, "Foo"),
  					       ty(mkexpr(Zloc, Otup, ty(mkexpr(Zloc, Olit, mkint(Zloc, 123), NULL), _int32), NULL), _int32t1), NULL), _int32u1)),
  				InitP_(ty(mkexpr(Zloc, Ogap, NULL), _int32u1)),
  				NULL,
  			},
  			.dt = &(Dtree){
  				.id = 3,
  				.load = ty(mkexpr(Zloc, Outag, T, NULL), _int32),
  				.nconstructors = 1,
  				.nnext = 1,
  				.npat = 1,
  				.pat = (Node*[]){
  					/*
  					 * the matcher will convert the Oucon expr to an Nlit for the Dtree
  					 */
  					ty(mkintlit(Zloc, finducon(_enum1, P(0)->expr.args[0])->id), _int32),
  				},
  				.next = (Dtree*[]){
  					[0] = &(Dtree){
  						.id = 2,
  						.load = ty(mkexpr(Zloc, Otupget,
  								  ty(mkexpr(Zloc, Oudata, T, NULL), _int32t1),
  								  mkintlit(Zloc, 0),
  								  NULL), _int32),
  						.nconstructors = 4294967296,
  						.nnext = 1,
  						.npat = 1,
  						.pat = (Node*[]){
  							P(0)->expr.args[1]->expr.args[0],
  						},
  						.next = (Dtree*[]){
  							&(Dtree){
  								.id = 0,
  								.accept = 1,
  							},
  						},
  						.any = &(Dtree){
  							.id = 1,
  							.accept = 1,
  						},
  					},
  				},
  				.any = &(Dtree){
  					.id = 1,
  					.accept = 1,
  				},
  			},
  		},
  		{
  			.name = "bug1",
  			.val = InitT(gentemp(Zloc, _bug002s, NULL)),
  			.pats = (Node*[]){
  				InitP0(ty(mkexprl(Zloc, Ostruct, (Node*[]){
  					mkidxinit(Zloc, mkname(Zloc, "s2_ufoo"),
  						  ty(mkexpr(Zloc, Oucon, mkname(Zloc, "Foo"),
  							    mkintlit(Zloc, 123), NULL), _int32u1)
  						 )}, 1), _bug002s)),
  				InitP_(ty(mkexpr(Zloc, Ogap, NULL), _bug002s)),
  				NULL,
  			},
  			.dt = &(Dtree){
  				.id = 3,
  				.load = ty(mkexpr(Zloc, Outag,
  						  ty(mkexpr(Zloc, Omemb, T, tybase(exprtype(P(0)))->sdecls[0]->decl.name, NULL), _bug001u),
  						  NULL), _int32),
  				.nconstructors = 2,
  				.nnext = 1,
  				.npat = 1,
  				.pat = (Node*[]){
  					ty(mkintlit(Zloc, finducon(_bug001u, P(0)->expr.args[0]->expr.args[0])->id), _int32),
  				},
  				.next = (Dtree*[]){
  					[0] = &(Dtree){
  						.id = 2,
  						.load = ty(mkexpr(Zloc, Oudata, ty(mkexpr(Zloc, Omemb, T, tybase(exprtype(P(0)))->sdecls[0]->decl.name, NULL), _int32), NULL), _int32t1),
  						.nconstructors = 1,
  						.nnext = 1,
  						.npat = 1,
  						.pat = (Node*[]){
  							P(0)->expr.args[0]->expr.args[1],
  						},
  						.next = (Dtree*[]){
  							[0] = &(Dtree){
  								.id = 0,
  								.accept = 1,
  							},
  						},
  						.any = &(Dtree){
  							.id = 1,
  							.accept = 1,
  						}
  					},
  				},
  				.any = &(Dtree){
  					.id = 1,
  					.accept = 1,
  				},
  			},
  		},
  
  	};
  
  	for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
  		Test *t = &tests[i];
  		char *name = t->name;
  		char *filter = getenv("N");
  		if (filter && !strstr(name, filter))
  			continue;
  
  		initfile(&file, errorf("(test-%d-%s)", i, name));
  		fprintf(stderr, "[%03lu]------ %s ##\n", i, name);
  		err = test_match(i, t->val, t->pats, t->dt);
  		if (err) {
  			fprintf(stderr, "FAILED id: %ld name: %s\n", i, name);
  			fprintf(stderr, "%s\r\n", err);
  			break;
  		}
  	}
  	return 0;
  }
  
  