/* ************************************************************************ # # DivConq # # http://divconq.com/ # # Copyright: # Copyright 2014 eTimeline, LLC. All rights reserved. # # License: # See the license.txt file in the project's top-level directory for details. # # Authors: # * Andy White # ************************************************************************ */ package divconq.script; import divconq.lang.op.FuncResult; import divconq.lang.op.OperationContext; import divconq.struct.CompositeStruct; import divconq.struct.RecordStruct; import divconq.struct.Struct; import divconq.struct.scalar.IntegerStruct; import divconq.util.StringUtil; import divconq.work.TaskRun; public class StackFunctionEntry extends StackBlockEntry { // result/state about the last command executed protected Struct lastResult = null; protected IntegerStruct lastCode = null; // parameter into function, make sure this is not disposed directly as the caller // does not want the param disposed protected Struct param = null; protected String pname = null; public StackFunctionEntry(Activity act, StackEntry parent, Instruction inst) { super(act, parent, inst); this.lastCode = new IntegerStruct(); this.lastCode.setValue((long) 0); } @Override public Struct getLastResult() { return this.lastResult; } @Override public void setLastResult(Struct v) { this.lastResult = v; // if this is the Main function then the last result is also the task result if (this.parent == null) { TaskRun run = OperationContext.get().getTaskRun(); if (run != null) run.setResult(v); } } @Override public Long getLastCode() { return this.lastCode.getValue(); } @Override public void setLastCode(Long v) { // won't overwrite the existing code with 1 if ((v != null) && (v == 1) && (this.lastCode.getValue() > 1)) return; this.lastCode.setValue(v); } public Struct getParameter() { return this.param; } public void setParameter(Struct v) { this.param = v; } public String getParameterName() { return this.pname; } public void setParameterName(String v) { this.pname = v; } @Override public void collectDebugRecord(RecordStruct rec) { super.collectDebugRecord(rec); RecordStruct dumpVariables = rec.getFieldAsRecord("Variables"); if (StringUtil.isNotEmpty(this.pname)) dumpVariables.setField(this.pname, (this.param != null) ? this.param : null); else dumpVariables.setField("_Param", (this.param != null) ? this.param : null); dumpVariables.setField("_LastResult", this.lastResult); dumpVariables.setField("_LastCode", this.lastCode); } @Override public Struct queryVariable(String name) { if (StringUtil.isEmpty(name)) return null; //if (name.equals(this.pname) || "_Param".equals(this.pname)) // return this.param; if ("_LastResult".equals(name) || "_".equals(name)) return this.lastResult; if ("_LastCode".equals(name) || "__".equals(name)) return this.lastCode; // needed to copy all of StackBlock here, except remove the query for parent vars - replace with check for global vars // do not call super - that would expose vars outside of the function int dotpos = name.indexOf("."); if (dotpos > -1) { String oname = name.substring(0, dotpos); Struct ov = null; if (oname.equals(this.pname) || oname.equals("_Param")) ov = this.param; if (ov == null) ov = this.variables.containsKey(oname) ? this.variables.get(oname) : null; // support global variables if (ov == null) ov = this.activity.queryVariable(oname); if (ov == null) { OperationContext.get().errorTr(515, oname); return null; } if (!(ov instanceof CompositeStruct)){ OperationContext.get().errorTr(516, oname); return null; } FuncResult<Struct> sres = ((CompositeStruct)ov).select(name.substring(dotpos + 1)); return sres.getResult(); } else if (name.equals(this.pname) || name.equals("_Param")) { return this.param; } else if (this.variables.containsKey(name)) { return this.variables.get(name); } // if nothing else, try globals return this.activity.queryVariable(name); } @Override public StackFunctionEntry queryFunctionStack() { return this; } }