// ex: set sts=4 sw=4 expandtab:
/**
* Yeti type pretty-printer.
*
* Copyright (c) 2010-2013 Madis Janson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package yeti.lang.compiler;
import java.util.*;
import yeti.lang.*;
class ShowTypeFun extends Fun2 {
Fun showType;
Fun formatDoc;
String indentStep = " ";
ShowTypeFun() {
showType = this;
}
private void hstr(StringBuffer to, boolean variant,
AList fields, String indent) {
boolean useNL = false;
AIter i = fields;
for (int n = 0; i != null; i = i.next())
if (++n >= 3 || formatDoc != null && ((String) ((Struct)
i.first()).get("description")).length() > 0) {
useNL = true;
break;
}
String indent_ = indent, oldIndent = indent;
if (useNL) {
if (!variant)
indent = indent.concat(indentStep);
indent_ = indent.concat(indentStep);
}
String sep = variant
? useNL ? "\n" + indent + "| " : " | "
: useNL ? ",\n".concat(indent) : ", ";
Struct field = null;
for (i = fields; i != null; i = i.next()) {
field = (Struct) i.first();
if (i != fields) // not first
to.append(sep);
else if (useNL && !variant)
to.append('\n').append(indent);
if (formatDoc != null) {
String doc = (String) field.get("description");
if (formatDoc != this) {
to.append(formatDoc.apply(indent, doc));
} else if (useNL && doc.length() > 0) {
to.append("// ")
.append(Core.replace("\n", "\n" + indent + "//", doc))
.append('\n')
.append(indent);
}
}
if (!variant) {
if (field.get("mutable") == Boolean.TRUE)
to.append("var ");
to.append(field.get("tag"));
}
to.append(field.get("name"));
if (variant)
to.append(field.get("tag"));
to.append(variant ? " " : " is ");
Tag fieldType = (Tag) field.get("type");
Object tstr = showType.apply(indent_, fieldType);
if (variant && (fieldType.name == "Function" ||
fieldType.name == "Variant"))
to.append('(').append(tstr).append(')');
else
to.append(tstr);
}
try {
if (field != null && field.get("strip") != null)
to.append(sep).append("...");
} catch (Exception ex) {
}
if (useNL && !variant)
to.append("\n").append(oldIndent);
}
public Object apply(Object indent, Object typeObj) {
Tag type = (Tag) typeObj;
String typeTag = type.name;
if (typeTag == "Simple")
return type.value;
if (typeTag == "Alias") {
Struct t = (Struct) type.value;
return '(' + (String) t.get("alias") + " is " +
showType.apply(indent, t.get("type")) + ')';
}
AList typeList;
String typeName = null;
if (typeTag == "Parametric") {
Struct t = (Struct) type.value;
typeName = (String) t.get("type");
typeList = (AList) t.get("params");
} else {
typeList = (AList) type.value;
}
if (typeList != null && typeList.isEmpty())
typeList = null;
AIter i = typeList;
StringBuffer to = new StringBuffer();
if (typeName != null) {
to.append(typeName).append('<');
for (; i != null; i = i.next()) {
if (i != typeList)
to.append(", ");
to.append(showType.apply(indent, i.first()));
}
to.append('>');
} else if (typeTag == "Function") {
while (i != null) {
Tag t = (Tag) i.first();
if (i != typeList)
to.append(" -> ");
i = i.next();
if (i != null && t.name == "Function")
to.append('(')
.append(showType.apply(indent, t))
.append(')');
else
to.append(showType.apply(indent, t));
}
} else if (typeTag == "Struct") {
to.append('{');
hstr(to, false, typeList, (String) indent);
to.append('}');
} else if (typeTag == "Variant") {
hstr(to, true, typeList, (String) indent);
} else {
throw new IllegalArgumentException("Unknown type kind: " + typeTag);
}
return to.toString();
}
}
class DescrCtx {
TypePattern defs;
Map vars = new HashMap();
Map refs = new HashMap();
List trace;
String getVarName(YType t) {
String v = (String) vars.get(t);
if (v == null) {
// 26^7 > 2^32, should be enough ;)
char[] buf = new char[10];
int p = buf.length;
if ((t.flags & YetiType.FL_ERROR_IS_HERE) != 0)
buf[--p] = '*';
int n = vars.size() + 1;
while (n > 26) {
buf[--p] = (char) ('a' + n % 26);
n /= 26;
}
buf[--p] = (char) (96 + n);
if ((t.flags & YetiType.FL_TAINTED_VAR) != 0)
buf[--p] = '_';
buf[--p] =
(t.flags & YetiType.FL_ORDERED_REQUIRED) == 0 ? '\'' : '^';
v = new String(buf, p, buf.length - p);
vars.put(t, v);
}
return v;
}
}
class TypeDescr extends YetiType {
private int type;
private String name;
private TypeDescr value;
private TypeDescr prev;
private String alias;
private Map properties;
TypeDescr(String name_) {
name = name_;
}
static Struct pair(String name1, Object value1,
String name2, Object value2) {
// low-level implementation-specific struct, don't do that ;)
Struct3 result = new Struct3(new String[] { name1, name2 }, null);
result._0 = value1;
result._1 = value2;
return result;
}
Tag force() {
if (type == 0)
return new Tag(name, "Simple");
AList l = null;
for (TypeDescr i = value; i != null; i = i.prev)
if (i.properties != null) {
i.properties.put("type", i.force());
l = new LList(new GenericStruct(i.properties), l);
} else {
l = new LList(i.force(), l);
}
Object val = l;
String tag = null;
switch (type) {
case FUN:
tag = "Function"; break;
case MAP:
val = pair("params", l, "type", name);
tag = "Parametric"; break;
case STRUCT:
tag = "Struct"; break;
case VARIANT:
tag = "Variant"; break;
}
Tag res = new Tag(val, tag);
if (alias == null)
return res;
return new Tag(pair("alias", alias, "type", res), "Alias");
}
static Tag yetiType(YType t, TypePattern defs, TypeException path) {
DescrCtx ctx = new DescrCtx();
ctx.defs = defs;
if (path != null)
ctx.trace = path.trace;
return prepare(t, ctx).force();
}
static Tag typeDef(YType[] def, MList param, TypePattern defs) {
DescrCtx ctx = new DescrCtx();
ctx.defs = defs;
for (int i = 0, n = 0; i < def.length - 1; ++i) {
// the .doc don't work
//String name = def[i].doc instanceof String
// ? (String) def[i].doc : "t" + ++n;
String name = "t" + ++n;
ctx.vars.put(def[i].deref(), name);
param.add(name);
}
return prepare(def[def.length - 1], ctx).force();
}
private static void hdescr(TypeDescr descr, YType tt, DescrCtx ctx) {
Map m = new java.util.TreeMap();
if (tt.requiredMembers != null)
m.putAll(tt.requiredMembers);
if (tt.allowedMembers != null) {
Iterator i = tt.allowedMembers.entrySet().iterator();
while (i.hasNext()) {
Map.Entry e = (Map.Entry) i.next();
YType t = (YType) e.getValue();
Object v = m.put(e.getKey(), t);
if (v != null && t.doc == null)
t.doc = v;
}
}
Object name;
// Stupid list is used, because normally it shouldn't ever contain
// over 1 or 2 elements, and it's faster than hash in this case.
List strip = null;
if (ctx.trace != null)
for (int i = 0, last = ctx.trace.size() - 3; i <= last; i += 3)
if (ctx.trace.get(i + 1) == tt || ctx.trace.get(i + 2) == tt) {
if (strip == null)
strip = new ArrayList();
if (m.containsKey(name = ctx.trace.get(i)) &&
!strip.contains(name))
strip.add(name);
}
if (strip != null && strip.size() >= m.size())
strip = null; // everything is included, no stripping actually
for (Iterator i = m.entrySet().iterator(); i.hasNext(); ) {
Map.Entry e = (Map.Entry) i.next();
name = e.getKey();
if (strip != null && !strip.contains(name))
continue;
YType t = (YType) e.getValue();
Map it = new IdentityHashMap(5);
String doc = t.doc();
it.put("name", name);
it.put("description", doc == null ? Core.UNDEF_STR : doc);
it.put("mutable", Boolean.valueOf(t.field == FIELD_MUTABLE));
it.put("tag",
tt.allowedMembers == null || !tt.allowedMembers.containsKey(name)
? tt.type == STRUCT ? "." : "" :
tt.requiredMembers != null && tt.requiredMembers.containsKey(name)
? "`" : tt.type == STRUCT ? "" : ".");
it.put("strip", strip);
TypeDescr field = prepare(t, ctx);
field.properties = it;
field.prev = descr.value;
descr.value = field;
}
}
private static boolean match(TypeDescr descr, YType t, DescrCtx ctx) {
Map defVars = null;
TypePattern def = null;
if (ctx.defs == null ||
(def = ctx.defs.match(t, defVars = new IdentityHashMap())) == null
|| def.end == null)
return false;
descr.name = def.end.typename;
if (def.end.defvars.length == 0) {
descr.type = 0;
return true;
}
ctx.refs.put(t, descr); // to avoid infinite recursion
descr.type = MAP; // Parametric
Map param = new HashMap();
for (Iterator i = defVars.entrySet().iterator(); i.hasNext();) {
Map.Entry e = (Map.Entry) i.next();
param.put(e.getValue(), e.getKey());
}
for (int i = def.end.defvars.length; --i >= 0; ) {
YType tp = (YType) param.get(new Integer(def.end.defvars[i]));
TypeDescr item = tp != null ? prepare(tp, ctx) : new TypeDescr("?");
item.prev = descr.value;
descr.value = item;
}
if (descr.alias == null) // no recursive refs in parameters?
ctx.refs.remove(t);
return true;
}
private static TypeDescr prepare(YType t, DescrCtx ctx) {
final int type = t.type;
if (type == VAR) {
if (t.ref != null)
return prepare(t.ref, ctx);
return new TypeDescr(ctx.getVarName(t));
}
if (type < PRIMITIVES.length)
return new TypeDescr(TYPE_NAMES[type]);
if (type == JAVA)
return new TypeDescr(t.javaType.str());
if (type == JAVA_ARRAY)
return new TypeDescr(prepare(t.param[0], ctx).name.concat("[]"));
TypeDescr descr = (TypeDescr) ctx.refs.get(t), item, tmp;
if (descr != null) {
if (descr.alias == null)
descr.alias = ctx.getVarName(t);
return new TypeDescr(descr.alias);
}
final YType tt = t;
descr = new TypeDescr(null);
int varcount = ctx.vars.size();
if (match(descr, tt, ctx))
return descr;
ctx.refs.put(tt, descr);
descr.type = type;
YType[] param = t.param;
int n = 1;
switch (type) {
case FUN:
tmp = new TypeDescr(null);
do {
param = t.param;
item = prepare(param[0], ctx);
item.prev = descr.value;
descr.value = item;
t = param[1].deref();
} while (t.type == FUN ? !match(tmp, t, ctx)
: (tmp = prepare(t, ctx)) == null);
tmp.prev = descr.value;
descr.value = tmp;
break;
case STRUCT:
case VARIANT:
hdescr(descr, t, ctx);
t = t.param[0].deref();
if ((t.flags & FL_ERROR_IS_HERE) != 0)
descr.alias = ctx.getVarName(t);
break;
case MAP:
YType p1 = param[1].deref();
YType p2 = param[2].deref();
if (p2.type == LIST_MARKER) {
descr.name = p1.type == NONE ? "list" : p1.type == NUM
? "array" : "list?";
if ((p1.flags & FL_ERROR_IS_HERE) != 0)
descr.name = descr.name.concat("*");
} else {
descr.name = p2.type == MAP_MARKER || p1.type != NUM
&& p1.type != VAR ? "hash" : "map";
if ((p2.flags & FL_ERROR_IS_HERE) != 0)
descr.name = descr.name.concat("*");
n = 2;
}
while (--n >= 0) {
item = prepare(param[n], ctx);
item.prev = descr.value;
descr.value = item;
}
break;
default:
if (type < OPAQUE_TYPES) {
descr.name = "?" + type + '?';
break;
}
descr.type = MAP;
descr.name = t.requiredMembers.keySet().toString();
for (n = -1; ++n < param.length; ) {
item = prepare(param[n], ctx);
item.prev = descr.value;
descr.value = item;
}
}
// don't create ('foo is ...) when there is no free variables in ...
if (varcount == ctx.vars.size() && descr.alias == null)
ctx.refs.remove(tt);
return descr;
}
}
class TypeWalk implements Comparable {
int id;
private YType type;
private int st;
private TypeWalk parent;
private String[] fields;
private Map fieldMap;
String field;
TypePattern pattern;
String typename;
YType[] def;
int[] defvars;
TypeWalk(YType t, TypeWalk parent, Map tvars, TypePattern p) {
pattern = p;
this.parent = parent;
type = t = t.deref();
TypePattern tvar = (TypePattern) tvars.get(t);
if (tvar != null) {
id = tvar.var;
if (id > 0)
tvar.var = id = -id; // mark used
return;
}
id = t.type;
if (id == YetiType.VAR) {
if (tvars.containsKey(t)) {
id = Integer.MAX_VALUE; // typedef parameter - match anything
if (p != null && p.var >= 0)
p.var = -p.var; // parameters must be saved
} else if (parent != null && parent.type.type == YetiType.MAP &&
parent.st > 1 && (parent.st > 2 ||
parent.type.param[2] == YetiType.LIST_TYPE)) {
id = Integer.MAX_VALUE; // map kind - match anything
return; // and don't associate
}
tvars.put(t, p);
} else if (id >= YetiType.PRIMITIVES.length) {
tvars.put(t, p);
}
if (id == YetiType.STRUCT || id == YetiType.VARIANT) {
fieldMap = t.allowedMembers != null ? t.allowedMembers
: t.requiredMembers;
fields = (String[])
fieldMap.keySet().toArray(new String[fieldMap.size()]);
Arrays.sort(fields);
}
}
TypeWalk next(Map tvars, TypePattern pattern) {
if (id < 0 || id == Integer.MAX_VALUE) {
if (parent != null)
return parent.next(tvars, pattern);
if (def != null) {
pattern.end = this;
defvars = new int[def.length - 1];
for (int i = 0; i < defvars.length; ++i)
if ((pattern = (TypePattern) tvars.get(def[i])) != null)
defvars[i] = pattern.var;
}
return null;
}
if (fields == null) {
if (type.param != null && st < type.param.length)
return new TypeWalk(type.param[st++], this, tvars, pattern);
} else if (st < fields.length) {
YType t = (YType) fieldMap.get(fields[st]);
TypeWalk res = new TypeWalk(t, this, tvars, pattern);
res.field = fields[st++];
if (t.field == YetiType.FIELD_MUTABLE)
res.field = ";".concat(res.field);
return res;
}
field = null;
id = Integer.MIN_VALUE;
return this;
}
public int compareTo(Object o) {
TypeWalk tw = (TypeWalk) o;
if (field == null)
return tw.field == null ? id - tw.id : 1;
if (tw.field == null)
return -1;
int cmp = field.compareTo(tw.field);
return cmp == 0 ? id - tw.id : cmp;
}
}
class TypePattern {
// Integer.MIN_VALUE is type end marker
// Integer.MAX_VALUE matches any type
private int[] idx;
private TypePattern[] next;
// struct/variant field match, next[idx.length] when no such field
private String field;
private boolean mutable;
int var; // if var < 0 then match stores type in typeVars as var
TypeWalk end; // end result
TypePattern(int var) {
this.var = var;
}
TypePattern match(YType type, Map typeVars) {
int i;
type = type.deref();
Object tv = typeVars.get(type);
if (tv != null) {
i = Arrays.binarySearch(idx, ((Integer) tv).intValue());
if (i >= 0)
return next[i];
}
i = Arrays.binarySearch(idx, type.type);
if (i < 0) {
if (idx[i = idx.length - 1] != Integer.MAX_VALUE)
return null;
if (var < 0)
typeVars.put(type, new Integer(var));
return next[i];
}
if (var < 0)
typeVars.put(type, new Integer(var));
TypePattern pat = next[i];
if (pat.field == null) {
YType[] param = type.param;
if (param != null)
for (i = 0; i < param.length && pat != null; ++i)
pat = pat.match(param[i], typeVars);
} else {
// TODO check final/partial if necessary
Map m = type.allowedMembers;
if (m == null)
m = type.requiredMembers;
i = m.size();
while (--i >= 0 && pat != null) {
if (pat.field == null)
return null;
type = (YType) m.get(pat.field);
if (type != null &&
type.field == YetiType.FIELD_MUTABLE == pat.mutable) {
pat = pat.match(type, typeVars);
} else {
pat = pat.next[pat.idx.length];
++i; // was not matched
}
}
}
// go for type end marker
if (pat != null && pat.idx[0] == Integer.MIN_VALUE)
return pat.next[0];
return null;
}
static TypePattern toPattern(Map typedefs) {
int j = 0, varAlloc = 1;
TypePattern presult = new TypePattern(varAlloc);
TypeWalk[] w = new TypeWalk[typedefs.size()];
Map tvars = new IdentityHashMap();
for (Iterator i = typedefs.entrySet().iterator(); i.hasNext(); ) {
Map.Entry e = (Map.Entry) i.next();
YType[] def = (YType[]) e.getValue();
YType t = def[def.length - 1].deref();
if (t.type < YetiType.PRIMITIVES.length)
continue;
for (int k = def.length - 1; --k >= 0; )
tvars.put(def[k].deref(), null); // mark as param
w[j] = new TypeWalk(t, null, tvars, presult);
w[j].typename = (String) e.getKey();
w[j++].def = def;
}
if (j == 0)
return null;
TypeWalk[] wg = new TypeWalk[j];
System.arraycopy(w, 0, wg, 0, j);
int[] ids = new int[j];
TypePattern[] patterns = new TypePattern[j];
List walkers = new ArrayList();
walkers.add(wg); // types
walkers.add(presult); // resulting pattern
walkers.add(tvars);
while (walkers.size() > 0) {
List current = walkers;
walkers = new ArrayList();
for (int i = 0, cnt = current.size(); i < cnt; i += 3) {
w = (TypeWalk[]) current.get(i);
Arrays.sort(w);
// group by different types
// next - target for group in next cycle
TypePattern next = new TypePattern(++varAlloc),
target = (TypePattern) current.get(i + 1);
String field = w.length != 0 ? w[0].field : null;
int start = 0, n = 0, e;
for (j = 1; j <= w.length; ++j) {
if (j < w.length && w[j].id == w[j - 1].id &&
(field == w[j].field || field.equals(w[j].field)))
continue; // skip until same
// add branch
tvars = new IdentityHashMap((Map) current.get(i + 2));
ids[n] = w[j - 1].id;
for (int k = e = start; k < j; ++k)
if ((w[e] = w[k].next(tvars, next)) != null)
++e;
wg = new TypeWalk[e - start];
System.arraycopy(w, start, wg, 0, wg.length);
walkers.add(wg);
walkers.add(patterns[n++] = next);
walkers.add(tvars);
next = new TypePattern(++varAlloc);
start = j;
if (j < w.length &&
(field == w[j].field || field.equals(w[j].field)))
continue; // continue same pattern
target.idx = new int[n];
System.arraycopy(ids, 0, target.idx, 0, n);
if (field != null) {
if (field.charAt(0) == ';') {
field = field.substring(1).intern();
target.mutable = true;
}
target.field = field;
target.next = new TypePattern[n + 1];
System.arraycopy(patterns, 0, target.next, 0, n);
if (j < w.length) {
field = w[j].field;
target.next[n] = next;
target = next;
next = new TypePattern(++varAlloc);
}
} else {
target.next = new TypePattern[n];
System.arraycopy(patterns, 0, target.next, 0, n);
}
n = 0;
}
}
}
return presult;
}
static TypePattern toPattern(Scope scope, boolean ignoreLocal) {
Map typedefs = new HashMap();
for (; scope != null; scope = scope.outer) {
YType[] def = scope.typedef(false);
if (def != null && (!ignoreLocal ||
scope.name.charAt(0) != '_')) {
Object old = typedefs.put(scope.name, def);
if (old != null)
typedefs.put(scope.name, old);
}
}
return toPattern(typedefs);
}
/*
public String toString() {
StringBuffer sb = new StringBuffer();
if (var < 0)
sb.append(var).append(':');
if (field != null)
sb.append(field).append(' ');
sb.append('{');
if (next == null)
sb.append('-');
else for (int i = 0; i < next.length; ++i) {
if (i != 0)
sb.append(", ");
if (i >= idx.length) {
sb.append('!');
} else if (idx[i] == Integer.MIN_VALUE) {
sb.append('.');
} else if (idx[i] == Integer.MAX_VALUE) {
sb.append('_');
} else {
sb.append(idx[i]);
}
sb.append(" => ").append(next[i]);
}
sb.append('}');
if (end != null) {
sb.append(':').append(end.typename).append('<');
for (int i = 0; i < end.defvars.length; ++i) {
if (i != 0)
sb.append(',');
sb.append(end.defvars[i]);
}
sb.append('>');
}
return sb.toString();
}
static String showres(TypePattern res, Map vars) {
if (res == null)
return "FAIL";
Map rvars = new HashMap();
for (Iterator i = vars.entrySet().iterator(); i.hasNext();) {
Map.Entry e = (Map.Entry) i.next();
rvars.put(e.getValue(), e.getKey());
}
StringBuffer r = new StringBuffer(res.end.typename).append('<');
for (int i = 0; i < res.end.defvars.length; ++i) {
if (i != 0)
r.append(", ");
YType t = (YType) rvars.get(Integer.valueOf(res.end.defvars[i]));
if (t != null)
r.append(t);
else
r.append("t" + i);
}
return r + ">";
}
public static void main(String[] _) {
YType st = new YType(YetiType.STRUCT, null);
st.allowedMembers = new HashMap();
st.allowedMembers.put("close", YetiType.fun(YetiType.UNIT_TYPE, YetiType.UNIT_TYPE));
st.allowedMembers.put("read", YetiType.fun(YetiType.A, YetiType.STR_TYPE));
YType st2 = new YType(YetiType.STRUCT, null);
st2.allowedMembers = new HashMap();
st2.allowedMembers.put("close", YetiType.fun(YetiType.UNIT_TYPE, YetiType.UNIT_TYPE));
st2.allowedMembers.put("write", YetiType.fun(YetiType.STR_TYPE, YetiType.UNIT_TYPE));
//YType[] types = {YetiType.CONS_TYPE, st};
Map defs = new HashMap();
defs.put("cons", new YType[] { YetiType.A, YetiType.CONS_TYPE });
defs.put("str_pred", new YType[] { YetiType.STR2_PRED_TYPE });
defs.put("str_array", new YType[] { YetiType.STRING_ARRAY });
defs.put("my_struct", new YType[] { YetiType.A, st });
defs.put("a_struct", new YType[] { st2 });
TypePattern res, pat = toPattern(defs);
System.err.println(pat);
for (Iterator i = defs.values().iterator(); i.hasNext(); ) {
YType[] def = (YType[]) i.next();
YType t = def[def.length - 1];
Map vars = new IdentityHashMap();
System.out.println(t + " " + showres(pat.match(t, vars), vars));
}
YType intlist = new YType(YetiType.MAP, new YType[] {
YetiType.NUM_TYPE, YetiType.NO_TYPE, YetiType.LIST_TYPE });
YType il2il = YetiType.fun2Arg(YetiType.NUM_TYPE, intlist, intlist);
Map vars = new IdentityHashMap();
res = pat.match(il2il, vars);
System.out.println(il2il + " " + showres(pat.match(il2il, vars), vars));
}*/
}