this.loader = Thread.currentThread().getContextClassLoader();
// this maps the Java types in protocol buffers into Sizzle types
this.protomap = new HashMap<Class<?>, SizzleType>();
this.protomap.put(int.class, new SizzleInt());
this.protomap.put(long.class, new SizzleInt());
this.protomap.put(float.class, new SizzleFloat());
this.protomap.put(double.class, new SizzleFloat());
this.protomap.put(boolean.class, new SizzleBool());
this.protomap.put(byte[].class, new SizzleBytes());
this.protomap.put(String.class, new SizzleString());
// this maps scalar Sizzle scalar types names to their classes
// TODO: do this via reflection
this.idmap = new HashMap<String, SizzleType>();
this.idmap.put("any", new SizzleAny());
this.idmap.put("none", null);
this.idmap.put("bool", new SizzleBool());
this.idmap.put("int", new SizzleInt());
this.idmap.put("float", new SizzleFloat());
this.idmap.put("time", new SizzleTime());
this.idmap.put("fingerprint", new SizzleFingerprint());
this.idmap.put("string", new SizzleString());
this.idmap.put("bytes", new SizzleBytes());
// does the same for arrays
// for (final String key : new HashSet<String>(this.idmap.keySet())) {
// final SizzleType value = this.idmap.get(key);
// if (value instanceof SizzleScalar)
// this.idmap.put("array of " + key, new SizzleArray((SizzleScalar)
// value));
// }
// variables with a global scope
this.globals = new HashMap<String, SizzleType>();
// set the type of the input
this.globals.put("input", input);
this.globals.put("true", new SizzleBool());
this.globals.put("false", new SizzleBool());
this.globals.put("PI", new SizzleFloat());
this.globals.put("Inf", new SizzleFloat());
this.globals.put("inf", new SizzleFloat());
this.globals.put("NaN", new SizzleFloat());
this.globals.put("nan", new SizzleFloat());
// variables with a local scope
this.locals = new HashMap<String, SizzleType>();
this.aggregators = new HashMap<String, Class<?>>();
this.functions = new FunctionTrie();
// these generic functions require more finagling than can currently be
// (easily) done with a static method, so they are handled with macros
this.setFunction("def", new SizzleFunction(new SizzleBool(), new SizzleType[] { new SizzleAny() }, "${0} != null"));
this.setFunction("len", new SizzleFunction(new SizzleInt(), new SizzleType[] { new SizzleArray(new SizzleScalar()) }, "${0}.length"));
this.setFunction("len", new SizzleFunction(new SizzleInt(), new SizzleType[] { new SizzleString() }, "${0}.length()"));
this.setFunction("len", new SizzleFunction(new SizzleInt(), new SizzleType[] { new SizzleBytes() }, "${0}.length"));
this.setFunction("len", new SizzleFunction(new SizzleInt(), new SizzleType[] { new SizzleMap(new SizzleScalar(), new SizzleScalar()) },
"${0}.keySet().size()"));
this.setFunction("haskey", new SizzleFunction(new SizzleBool(), new SizzleType[] { new SizzleMap(new SizzleScalar(), new SizzleScalar()),
new SizzleScalar() }, "${0}.containsKey(${1})"));
this.setFunction("keys", new SizzleFunction(new SizzleArray(new SizzleScalar()), new SizzleType[] { new SizzleMap(new SizzleScalar(),
new SizzleScalar()) }, "${0}.keySet().toArray()"));
this.setFunction("lookup", new SizzleFunction(new SizzleScalar(), new SizzleType[] { new SizzleMap(new SizzleScalar(), new SizzleScalar()),
new SizzleScalar(), new SizzleScalar() }, "(${0}.containsKey(${1}) ? ${0}.get(${1}) : ${2})"));
this.setFunction("regex", new SizzleFunction(new SizzleString(), new SizzleType[] { new SizzleName(new SizzleScalar()), new SizzleInt() },
"sizzle.functions.SizzleSpecialIntrinsics.regex(\"${0}\", ${1})"));
this.setFunction("regex", new SizzleFunction(new SizzleString(), new SizzleType[] { new SizzleName(new SizzleScalar()) },
"sizzle.functions.SizzleSpecialIntrinsics.regex(\"${0}\")"));
// these fingerprints are identity functions
this.setFunction("fingerprintof", new SizzleFunction(new SizzleFingerprint(), new SizzleScalar[] { new SizzleInt() }));
this.setFunction("fingerprintof", new SizzleFunction(new SizzleFingerprint(), new SizzleScalar[] { new SizzleTime() }));
/* expose all the casting constructors to Sawzall */
// string to bool
this.setFunction("bool",
new SizzleFunction("sizzle.functions.SizzleCasts.stringToBoolean", new SizzleBool(), new SizzleScalar[] { new SizzleString() }));
// bool to int
this.setFunction("int", new SizzleFunction("sizzle.functions.SizzleCasts.booleanToLong", new SizzleInt(), new SizzleScalar[] { new SizzleBool() }));
// float to int
this.setFunction("int", new SizzleFunction(new SizzleInt(), new SizzleScalar[] { new SizzleFloat() }, "(long)${0}"));
// time to int
this.setFunction("int", new SizzleFunction(new SizzleInt(), new SizzleScalar[] { new SizzleTime() }));
// fingerprint to int
this.setFunction("int", new SizzleFunction(new SizzleInt(), new SizzleScalar[] { new SizzleFingerprint() }));
// string to int
this.setFunction("int", new SizzleFunction("java.lang.Long.decode", new SizzleInt(), new SizzleScalar[] { new SizzleString() }));
// string to int with param base
this.setFunction("int", new SizzleFunction(new SizzleInt(), new SizzleScalar[] { new SizzleString(), new SizzleInt() },
"java.lang.Long.parseLong(${0}, (int)${1})"));
// bytes to int with param encoding format
this.setFunction("int", new SizzleFunction("sizzle.functions.SizzleCasts.bytesToLong", new SizzleInt(), new SizzleScalar[] { new SizzleBytes(),
new SizzleString() }));
// int to float
this.setFunction("float", new SizzleFunction(new SizzleFloat(), new SizzleScalar[] { new SizzleInt() }, "(double)${0}"));
// string to float
this.setFunction("float", new SizzleFunction("java.lang.Double.parseDouble", new SizzleFloat(), new SizzleScalar[] { new SizzleString() }));
// int to time
this.setFunction("time", new SizzleFunction(new SizzleTime(), new SizzleScalar[] { new SizzleInt() }));
// string to time
this.setFunction("time", new SizzleFunction("sizzle.functions.SizzleCasts.stringToTime", new SizzleTime(), new SizzleScalar[] { new SizzleString() }));
// string to time
this.setFunction("time", new SizzleFunction("sizzle.functions.SizzleCasts.stringToTime", new SizzleTime(), new SizzleScalar[] { new SizzleString(),
new SizzleString() }));
// int to fingerprint
this.setFunction("fingerprint", new SizzleFunction(new SizzleFingerprint(), new SizzleScalar[] { new SizzleInt() }));
// string to fingerprint
this.setFunction("fingerprint", new SizzleFunction("java.lang.Long.parseLong", new SizzleInt(), new SizzleScalar[] { new SizzleString() }));
// string to fingerprint with param base
this.setFunction("fingerprint", new SizzleFunction("java.lang.Long.parseLong", new SizzleInt(), new SizzleScalar[] { new SizzleString(),
new SizzleInt() }));
// bytes to fingerprint
this.setFunction("fingerprint", new SizzleFunction("sizzle.functions.SizzleCasts.bytesToFingerprint", new SizzleFingerprint(),
new SizzleScalar[] { new SizzleBytes() }));
// bool to string
this.setFunction("string", new SizzleFunction("java.lang.Boolean.toString", new SizzleString(), new SizzleScalar[] { new SizzleBool() }));
// int to string
this.setFunction("string", new SizzleFunction("java.lang.Long.toString", new SizzleString(), new SizzleScalar[] { new SizzleInt() }));
// int to string with parameter base
this.setFunction("string", new SizzleFunction("sizzle.functions.SizzleCasts.longToString", new SizzleString(), new SizzleScalar[] { new SizzleInt(),
new SizzleInt() }));
// float to string
this.setFunction("string", new SizzleFunction("java.lang.Double.toString", new SizzleString(), new SizzleScalar[] { new SizzleFloat() }));
// time to string
this.setFunction("string", new SizzleFunction("sizzle.functions.SizzleCasts.timeToString", new SizzleString(), new SizzleScalar[] { new SizzleTime() }));
// fingerprint to string
this.setFunction("string", new SizzleFunction("java.lang.Long.toHexString", new SizzleString(), new SizzleScalar[] { new SizzleFingerprint() }));
// bytes to string
this.setFunction("string", new SizzleFunction("new java.lang.String", new SizzleString(), new SizzleScalar[] { new SizzleBytes() }));
// bytes to string
this.setFunction("string", new SizzleFunction("new java.lang.String", new SizzleString(), new SizzleScalar[] { new SizzleBytes(), new SizzleString() }));
// int to bytes with param encoding format
this.setFunction("bytes", new SizzleFunction("sizzle.functions.SizzleCasts.longToBytes", new SizzleInt(), new SizzleScalar[] { new SizzleInt(),
new SizzleString() }));
// fingerprint to bytes
this.setFunction("bytes", new SizzleFunction("sizzle.functions.SizzleCasts.fingerprintToBytes", new SizzleBytes(),
new SizzleScalar[] { new SizzleFingerprint() }));
// string to bytes
this.setFunction("bytes",
new SizzleFunction("sizzle.functions.SizzleCasts.stringToBytes", new SizzleBytes(), new SizzleScalar[] { new SizzleString() }));
/* expose the java.lang.Math class to Sawzall */
this.setFunction("highbit", new SizzleFunction("java.lang.Long.highestOneBit", new SizzleInt(), new SizzleScalar[] { new SizzleInt() }));
// abs just needs to be overloaded
this.setFunction("abs", new SizzleFunction("java.lang.Math.abs", new SizzleFloat(), new SizzleScalar[] { new SizzleInt() }));
this.setFunction("abs", new SizzleFunction("java.lang.Math.abs", new SizzleFloat(), new SizzleScalar[] { new SizzleFloat() }));
// abs is also named fabs in Sawzall
this.setFunction("fabs", new SizzleFunction("java.lang.Math.abs", new SizzleFloat(), new SizzleScalar[] { new SizzleFloat() }));
// log is named ln in Sawzall
this.setFunction("ln", new SizzleFunction("java.lang.Math.log", new SizzleFloat(), new SizzleScalar[] { new SizzleFloat() }));
// expose the rest of the unary functions
for (final String s : Arrays.asList("log10", "exp", "sqrt", "sin", "cos", "tan", "asin", "acos", "atan", "cosh", "sinh", "tanh", "ceil", "floor",
"round"))
this.setFunction(s, new SizzleFunction("java.lang.Math." + s, new SizzleFloat(), new SizzleScalar[] { new SizzleFloat() }));
// expose the binary functions
for (final String s : Arrays.asList("pow", "atan2"))
this.setFunction(s, new SizzleFunction("java.lang.Math." + s, new SizzleFloat(), new SizzleScalar[] { new SizzleFloat(), new SizzleFloat() }));
for (final String s : Arrays.asList("max", "min"))
for (final SizzleScalar t : Arrays.asList(new SizzleInt(), new SizzleFloat()))
this.setFunction(s, new SizzleFunction("java.lang.Math." + s, new SizzleFloat(), new SizzleScalar[] { t, t }));
this.setFunction("max", new SizzleFunction(new SizzleFloat(), new SizzleScalar[] { new SizzleTime(), new SizzleTime() }, "(${0} > ${1} ? ${0} : ${1})"));
this.setFunction("min", new SizzleFunction(new SizzleFloat(), new SizzleScalar[] { new SizzleTime(), new SizzleTime() }, "(${0} < ${1} ? ${0} : ${1})"));