class CodeGenRunner {

  public ExpressionMetadata buildCodeGenFromParseTree(
      final Expression expression
  ) throws Exception {
    Map<String, Class> parameterMap = getParameterInfo(expression);

    String[] parameterNames = new String[parameterMap.size()];
    Class[] parameterTypes = new Class[parameterMap.size()];
    int[] columnIndexes = new int[parameterMap.size()];
    Kudf[] kudfObjects = new Kudf[parameterMap.size()];

    int index = 0;
    for (Map.Entry<String, Class> entry : parameterMap.entrySet()) {
      parameterNames[index] = entry.getKey();
      parameterTypes[index] = entry.getValue();
      columnIndexes[index] = SchemaUtil.getFieldIndexByName(schema, entry.getKey());
      if (columnIndexes[index] < 0) {
        kudfObjects[index] = (Kudf) entry.getValue().newInstance();
      } else {
        kudfObjects[index] = null;
      }
      index++;
    }

    String javaCode = new SqlToJavaVisitor(schema, functionRegistry).process(expression);

    IExpressionEvaluator ee =
        CompilerFactoryFactory.getDefaultCompilerFactory().newExpressionEvaluator();

    // The expression will have two "int" parameters: "a" and "b".
    ee.setParameters(parameterNames, parameterTypes);

    // And the expression (i.e. "result") type is also "int".
    ExpressionTypeManager expressionTypeManager = new ExpressionTypeManager(
        schema,
        functionRegistry
    );
    Schema expressionType = expressionTypeManager.getExpressionType(expression);

    ee.setExpressionType(SchemaUtil.getJavaType(expressionType));

    // And now we "cook" (scan, parse, compile and load) the fabulous expression.
    ee.cook(javaCode);

    return new ExpressionMetadata(ee, columnIndexes, kudfObjects, expressionType);
  }

  public  CodeGenRunner(Schema schema, FunctionRegistry functionRegistry);

}