text: "use strict"
  
  // The function below is called when constructing a cwise function object, and does the following:
  // A function object is constructed which accepts as argument a compilation function and returns another function.
  // It is this other function that is eventually returned by createThunk, and this function is the one that actually
  // checks whether a certain pattern of arguments has already been used before and compiles new loops as needed.
  // The compilation passed to the first function object is used for compiling new functions.
  // Once this function object is created, it is called with compile as argument, where the first argument of compile
  // is bound to "proc" (essentially containing a preprocessed version of the user arguments to cwise).
  // So createThunk roughly works like this:
  // function createThunk(proc) {
  //   var thunk = function(compileBound) {
  //     var CACHED = {}
  //     return function(arrays and scalars) {
  //       if (dtype and order of arrays in CACHED) {
  //         var func = CACHED[dtype and order of arrays]
  //       } else {
  //         var func = CACHED[dtype and order of arrays] = compileBound(dtype and order of arrays)
  //       }
  //       return func(arrays and scalars)
  //     }
  //   }
  //   return thunk(compile.bind1(proc))
  // }
  
  var compile = require("./compile.js")
  
  function createThunk(proc) {
    var code = ["'use strict'", "var CACHED={}"]
    var vars = []
    var thunkName = proc.funcName + "_cwise_thunk"
    
    //Build thunk
    code.push(["return function ", thunkName, "(", proc.shimArgs.join(","), "){"].join(""))
    var typesig = []
    var string_typesig = []
    var proc_args = [["array",proc.arrayArgs[0],".shape.slice(", // Slice shape so that we only retain the shape over which we iterate (which gets passed to the cwise operator as SS).
                      Math.max(0,proc.arrayBlockIndices[i]),proc.arrayBlockIndices[i]<0?(","+proc.arrayBlockIndices[i]+")"):")"].join("")]
    for(var i=0; i<proc.arrayArgs.length; ++i) {
      var j = proc.arrayArgs[i]
      vars.push(["t", j, "=array", j, ".dtype,",
                 "r", j, "=array", j, ".order"].join(""))
      typesig.push("t" + j)
      typesig.push("r" + j)
      string_typesig.push("t"+j)
      string_typesig.push("r"+j+".join()")
      proc_args.push("array" + j + ".data")
      proc_args.push("array" + j + ".stride")
      proc_args.push("array" + j + ".offset|0")
    }
    for(var i=0; i<proc.scalarArgs.length; ++i) {
      proc_args.push("scalar" + proc.scalarArgs[i])
    }
    vars.push(["type=[", string_typesig.join(","), "].join()"].join(""))
    vars.push("proc=CACHED[type]")
    code.push("var " + vars.join(","))
    
    code.push(["if(!proc){",
               "CACHED[type]=proc=compile([", typesig.join(","), "])}",
               "return proc(", proc_args.join(","), ")}"].join(""))
  
    if(proc.debug) {
      console.log("-----Generated thunk:\n" + code.join("\n") + "\n----------")
    }
    
    //Compile thunk
    var thunk = new Function("compile", code.join("\n"))
    return thunk(compile.bind(undefined, proc))
  }
  
  module.exports = createThunk
  