 
   return false
 
-# Catches all errors in the function 
-# The signals parameter is only used in the "handleSignals" call
-GE.sandboxActionCall = (node, constants, bindings, methodName, signals = [], activeChildren = []) ->
-  action = constants.actions[node.action]
-  childNames = if node.children? then (child.name ? index.toString()) for index, child of node.children else []
-
-  # TODO: compile expressions ahead of time
-  evaluationContext = new GE.EvaluationContext(constants, bindings)
-
-  # Set default paramOptions
+# Set default values in paramDefs
+GE.fillParamDefDefaults = (paramDefs) ->
   # Cannot use normal "for key, value of" loop because cannot handle replace null values
-  for paramName of action.paramDefs
-    if not action.paramDefs[paramName]? then action.paramDefs[paramName] = {}
-    _.defaults action.paramDefs[paramName], 
+  for paramName of paramDefs
+    if not paramDefs[paramName]? then paramDefs[paramName] = {}
+    _.defaults paramDefs[paramName], 
       direction: "in"
-
+  return paramDefs
+
+# Returns an object mapping parameter namaes to their values 
+# Param expressions is an object that contains 'in' and 'out' attributes
+GE.evaluateInputParameters = (evaluationContext, paramDefs, paramExpressions) ->
   evaluatedParams = {}
 
-  for paramName, paramOptions of action.paramDefs
+  # TODO: don't evaluate output parameters here!
+  for paramName, paramOptions of paramDefs
     # Resolve parameter value. If the layout doesn't specify a value, use the default, it it exists. Otherwise, throw exception for input values
-    if paramOptions.direction in ["in", "inout"] and node.params?.in?[paramName] 
-      paramValue = node.params.in[paramName]
-    else if paramOptions.direction in ["out", "inout"] and node.params?.out?[paramName] 
-      paramValue = node.params.out[paramName]
+    if paramOptions.direction in ["in", "inout"] and paramExpressions.in?[paramName] 
+      paramValue = paramExpressions.in[paramName]
+    else if paramOptions.direction in ["out", "inout"] and paramExpressions.out?[paramName] 
+      paramValue = paramExpressions.out[paramName]
     else if paramOptions.default? 
       paramValue = paramOptions.default
     else if paramOptions.direction in ["in", "inout"]
-      throw new Error("Missing input parameter value for action: #{node.action}")
+      throw new Error("Missing input parameter value for parameter '#{paramName}'")
 
     try
       evaluatedParams[paramName] = evaluationContext.evaluateExpression(paramValue)
     catch error
-      throw new Error("Error evaluating the input parameter expression '#{paramValue}' for node '#{node.action}':\n#{error.stack}")
-
-  locals = 
-    params: evaluatedParams
-    children: childNames
-    signals: signals
-    activeChildren: activeChildren
-    assets: constants.assets
-    tools: constants.tools
-    log: constants.log
-  try
-    methodResult = action[methodName].apply(locals)
-  catch e
-    # TODO: convert exceptions to error sigals that do not create patches
-    constants.log(GE.logLevels.ERROR, "Calling action #{node.action}.#{methodName} raised an exception #{e}. Input params were #{JSON.stringify(locals.params)}. Children are #{JSON.stringify(locals.children)}.\n#{e.stack}")
-
-  result = new GE.NodeVisitorResult(methodResult)
-
+      throw new Error("Error evaluating the input parameter expression '#{paramValue}' for parameter '#{paramName}':\n#{error.stack}")
+  return evaluatedParams
+
+# Updates the evaluation context by evaluating the output parameter expressions
+# Param expressions is an object that contains 'in' and 'out' attributes
+GE.evaluateOutputParameters = (evaluationContext, paramDefs, paramExpressions, evaluatedParams) ->
   # Only output parameters should be accessible
-  outParams = _.pick(evaluatedParams, (paramName for paramName, paramOptions of action.paramDefs when paramOptions.direction in ["out", "inout"]))
-
-  for paramName, paramValue of node.params.out
+  outParams = _.pick(evaluatedParams, (paramName for paramName, paramOptions of paramDefs when paramOptions.direction in ["out", "inout"]))
+
+  for paramName, paramValue of paramExpressions.out
     try
       outputValue = evaluationContext.evaluateExpression(paramValue, outParams)
     catch error
-      throw new Error("Error evaluating the output parameter value expression '#{paramValue}' for node '#{node.action}':\n#{error.stack}\nOutput params were #{JSON.stringify(outputParams)}.")
+      throw new Error("Error evaluating the output parameter value expression '#{paramValue}' for parameter '#{paramName}':\n#{error.stack}\nOutput params were #{JSON.stringify(outParams)}.")
 
     [parent, key] = GE.getParentAndKey(evaluationContext, paramName.split("."))
     parent[key] = outputValue
-
-  result.modelPatches = GE.makePatches(constants.modelData, evaluationContext.model)
-  result.servicePatches = GE.makePatches(constants.serviceData, evaluationContext.services)
-
-  return result
 
 GE.calculateBindingSet = (node, constants, oldBindings) ->
   bindingSet = []


GE.nodeVisitors =
  "action": GE.visitActionNode
  "foreach": GE.visitForeachNode
  "send": GE.visitSendNode

# Constants are modelData, assets, actions, and serviceData
GE.visitNode = (node, constants, bindings = {}) ->
  # TODO: defer action and call execution until whole tree is evaluated?
  # TODO: handle children as object in addition to array

  for nodeType, visitor of GE.nodeVisitors
    if nodeType of node
      return visitor(node, constants, bindings)

      serviceData: options.inputServiceData
      assets: options.assets
      actions: options.actions
      processes: options.processes
      tools: options.tools
      evaluator: options.evaluator
      log: options.log
