public virtual int Write(ITemplateWriter @out, CultureInfo culture, ITemplateErrorListener listener) { Interpreter interp = new Interpreter(Group, culture, new ErrorManager(listener), false); TemplateFrame frame = new TemplateFrame(this, null); return(interp.Execute(@out, frame)); }
public virtual List<InterpEvent> GetEvents(CultureInfo culture, ITemplateWriter writer) { Interpreter interp = new Interpreter(Group, culture, true); TemplateFrame frame = new TemplateFrame(this, null); interp.Execute(writer, frame); // Render and track events return interp.GetEvents(); }
public virtual int Write(ITemplateWriter @out, CultureInfo culture) { Interpreter interp = new Interpreter(Group, culture, impl.NativeGroup.ErrorManager, false); TemplateFrame frame = new TemplateFrame(this, null); return(interp.Execute(@out, frame)); }
public object GetProperty(Interpreter interpreter, TemplateFrame frame, object o, object property, string propertyName) { if (propertyName.Equals("id")) return "const id value"; if (propertyName.Equals("name")) return "const name value"; throw new TemplateNoSuchPropertyException(null, "User." + propertyName); }
public TemplateFrame(Template template, TemplateFrame parent) { _template = template; _parent = parent; _depth = (parent != null) ? parent._depth + 1 : 1; if (parent != null && parent._debugState != null && parent._debugState.IsEarlyEval) GetDebugState().IsEarlyEval = true; }
public TemplateFrame(Template template, TemplateFrame parent) { _template = template; _parent = parent; _depth = (parent != null) ? parent._depth + 1 : 1; if (parent != null && parent._debugState != null && parent._debugState.IsEarlyEval) { GetDebugState().IsEarlyEval = true; } }
public List <TemplateFrame> GetFrameStack(bool topdown) { List <TemplateFrame> stack = new List <TemplateFrame>(); for (TemplateFrame p = this; p != null; p = p.Parent) { stack.Add(p); } if (topdown) { stack.Reverse(); } return(stack); }
public List <EvalTemplateEvent> GetEvalTemplateEventStack(bool topdown) { List <EvalTemplateEvent> stack = new List <EvalTemplateEvent>(); for (TemplateFrame p = this; p != null; p = p.Parent) { EvalTemplateEvent eval = (EvalTemplateEvent)p.GetDebugState().Events[p.GetDebugState().Events.Count - 1]; stack.Add(eval); } if (topdown) { stack.Reverse(); } return(stack); }
public List <Template> GetEnclosingInstanceStack(bool topdown) { List <Template> stack = new List <Template>(); TemplateFrame p = this; while (p != null) { if (topdown) { stack.Insert(0, p.Template); } else { stack.Add(p.Template); } p = p.Parent; } return(stack); }
/** Return a list with the same elements as v but in reverse order. null * values are NOT stripped out. use Reverse(Strip(v)) to do that. */ public virtual object Reverse(TemplateFrame frame, object v) { if (v == null) return null; v = ConvertAnythingIteratableToIterator(frame, v); IEnumerator it = v as IEnumerator; if (it != null) { List<object> a = new List<object>(); while (it.MoveNext()) a.Add(it.Current); a.Reverse(); return a; } return v; }
/** Return the last attribute if multiple valued or the attribute * itself if single-valued. Unless it's a list or array, this is pretty * slow as it iterates until the last element. */ public virtual object Last(TemplateFrame frame, object v) { if (v == null) return null; IList list = v as IList; if (list != null) return list[list.Count - 1]; object last = v; v = ConvertAnythingIteratableToIterator(frame, v); IEnumerator it = v as IEnumerator; if (it != null) { while (it.MoveNext()) last = it.Current; } return last; }
/** Return everything but the first attribute if multiple valued * or null if single-valued. */ public virtual object Rest(TemplateFrame frame, object v) { if (v == null) return null; v = ConvertAnythingIteratableToIterator(frame, v); IEnumerator it = v as IEnumerator; if (it != null) { if (!it.MoveNext()) return null; // if not even one value return null List<object> a = new List<object>(); // first value is ignored above while (it.MoveNext()) { object o = it.Current; a.Add(o); } return a; } // rest of single-valued attribute is null return null; }
protected virtual void AddToList(List<object> list, TemplateFrame frame, object o) { o = Interpreter.ConvertAnythingIteratableToIterator(frame, o); if (o is IEnumerator) { // copy of elements into our temp list IEnumerator it = (IEnumerator)o; while (it.MoveNext()) list.Add(it.Current); } else { list.Add(o); } }
/** For every event, we track in overall list and in self's * event list so that each template has a list of events used to * create it. If EvalTemplateEvent, store in parent's * childEvalTemplateEvents list for STViz tree view. */ protected void TrackDebugEvent(TemplateFrame frame, InterpEvent e) { // System.out.println(e); this.events.Add(e); // if ( self.debugState==null ) self.debugState = new ST.DebugState(); // self.debugState.events.add(e); frame.GetDebugState().Events.Add(e); if (e is EvalTemplateEvent) { //ST parent = getDebugState(self).interpEnclosingInstance; TemplateFrame parent = frame.Parent; if (parent != null) { // System.out.println("add eval "+e.self.getName()+" to children of "+parent.getName()); // if ( parent.debugState==null ) parent.debugState = new ST.DebugState(); // parent.debugState.childEvalTemplateEvents.add((EvalTemplateEvent)e); parent.GetDebugState().ChildEvalTemplateEvents.Add((EvalTemplateEvent)e); } } }
internal virtual void PassThrough(TemplateFrame frame, string templateName, IDictionary<string, object> attrs) { CompiledTemplate c = group.LookupTemplate(templateName); if (c == null) return; // will get error later if (c.FormalArguments == null) return; foreach (FormalArgument arg in c.FormalArguments) { // if not already set by user, set to value from outer scope if (!attrs.ContainsKey(arg.Name)) { //System.out.println("arg "+arg.name+" missing"); try { object o = GetAttribute(frame, arg.Name); // If the attribute exists but there is no value and // the formal argument has no default value, make it null. if (o == Template.EmptyAttribute && arg.DefaultValueToken == null) { attrs[arg.Name] = null; } // Else, the attribute has an existing value, set arg. else if (o != Template.EmptyAttribute) { attrs[arg.Name] = o; } } catch (AttributeNotFoundException) { // if no such attribute exists for arg.name, set parameter // if no default value if (arg.DefaultValueToken == null) { _errorManager.RuntimeError(frame, ErrorType.NO_SUCH_ATTRIBUTE_PASS_THROUGH, arg.Name); attrs[arg.Name] = null; } } } } }
internal virtual void StoreArguments(TemplateFrame frame, int nargs, Template st) { if (nargs > 0 && !st.impl.HasFormalArgs && st.impl.FormalArguments == null) { st.Add(Template.ImplicitArgumentName, null); // pretend we have "it" arg } int nformalArgs = 0; if (st.impl.FormalArguments != null) nformalArgs = st.impl.FormalArguments.Count; int firstArg = sp - (nargs - 1); int numToStore = Math.Min(nargs, nformalArgs); if (st.impl.IsAnonSubtemplate) nformalArgs -= predefinedAnonSubtemplateAttributes.Length; if (nargs < (nformalArgs - st.impl.NumberOfArgsWithDefaultValues) || nargs > nformalArgs) { _errorManager.RuntimeError(frame, ErrorType.ARGUMENT_COUNT_MISMATCH, nargs, st.impl.Name, nformalArgs); } if (st.impl.FormalArguments == null) return; for (int i = 0; i < numToStore; i++) { object o = operands[firstArg + i]; string argName = st.impl.FormalArguments[i].Name; st.RawSetAttribute(argName, o); } }
// <names,phones:{n,p | ...}> or <a,b:t()> // todo: i, i0 not set unless mentioned? map:{k,v | ..}? protected virtual Template.AttributeList ZipMap(TemplateFrame frame, List<object> exprs, Template prototype) { Template self = frame.Template; if (exprs == null || prototype == null || exprs.Count == 0) { return null; // do not apply if missing templates or empty values } // make everything iterable for (int i = 0; i < exprs.Count; i++) { object attr = exprs[i]; if (attr != null) exprs[i] = ConvertAnythingToIterator(frame, attr); } // ensure arguments line up int numExprs = exprs.Count; CompiledTemplate code = prototype.impl; List<FormalArgument> formalArguments = code.FormalArguments; if (!code.HasFormalArgs || formalArguments == null) { _errorManager.RuntimeError(frame, ErrorType.MISSING_FORMAL_ARGUMENTS); return null; } // todo: track formal args not names for efficient filling of locals object[] formalArgumentNames = formalArguments.Select(i => i.Name).ToArray(); int nformalArgs = formalArgumentNames.Length; if (prototype.IsAnonymousSubtemplate) nformalArgs -= predefinedAnonSubtemplateAttributes.Length; if (nformalArgs != numExprs) { _errorManager.RuntimeError(frame, ErrorType.MAP_ARGUMENT_COUNT_MISMATCH, numExprs, nformalArgs); // TODO just fill first n // truncate arg list to match smaller size int shorterSize = Math.Min(formalArgumentNames.Length, numExprs); numExprs = shorterSize; Array.Resize(ref formalArgumentNames, shorterSize); } // keep walking while at least one attribute has values Template.AttributeList results = new Template.AttributeList(); int i2 = 0; // iteration number from 0 while (true) { // get a value for each attribute in list; put into Template instance int numEmpty = 0; Template embedded = group.CreateStringTemplateInternally(prototype); embedded.RawSetAttribute("i0", i2); embedded.RawSetAttribute("i", i2 + 1); for (int a = 0; a < numExprs; a++) { IEnumerator it = (IEnumerator)exprs[a]; if (it != null && it.MoveNext()) { string argName = (string)formalArgumentNames[a]; object iteratedValue = it.Current; embedded.RawSetAttribute(argName, iteratedValue); } else { numEmpty++; } } if (numEmpty == numExprs) break; results.Add(embedded); i2++; } return results; }
public static object ConvertAnythingIteratableToIterator(TemplateFrame frame, object o) { if (o == null) return null; string str = o as string; if (str != null) return str; IDictionary dictionary = o as IDictionary; if (dictionary != null) { if (frame.Template.Group.IterateAcrossValues) return dictionary.Values.GetEnumerator(); return dictionary.Keys.GetEnumerator(); } ICollection collection = o as ICollection; if (collection != null) return collection.GetEnumerator(); IEnumerable enumerable = o as IEnumerable; if (enumerable != null) return enumerable.GetEnumerator(); //// This code is implied in the last line //Iterator iterator = o as Iterator; //if ( iterator != null ) // return iterator; return o; }
/** Write out an expression result that uses expression options. * E.g., <names; separator=", "> */ protected virtual int WriteObjectWithOptions(ITemplateWriter @out, TemplateFrame frame, object o, object[] options) { int start = @out.Index; // track char we're about to Write // precompute all option values (Render all the way to strings) string[] optionStrings = null; if (options != null) { optionStrings = new string[options.Length]; for (int i = 0; i < Compiler.TemplateCompiler.NUM_OPTIONS; i++) { optionStrings[i] = ToString(frame, options[i]); } } if (options != null && options[(int)RenderOption.Anchor] != null) { @out.PushAnchorPoint(); } int n = WriteObject(@out, frame, o, optionStrings); if (options != null && options[(int)RenderOption.Anchor] != null) { @out.PopAnchorPoint(); } if (_debug) { Interval templateLocation = frame.Template.impl.sourceMap[frame.InstructionPointer]; EvalExprEvent e = new EvalExprEvent(frame, Interval.FromBounds(start, @out.Index), templateLocation); TrackDebugEvent(frame, e); } return n; }
protected virtual int WritePlainObject(ITemplateWriter @out, TemplateFrame frame, object o, string[] options) { string formatString = null; if (options != null) formatString = options[(int)RenderOption.Format]; IAttributeRenderer r = frame.Template.impl.NativeGroup.GetAttributeRenderer(o.GetType()); string v; if (r != null) { v = r.ToString(o, formatString, culture); } else { if (o is bool) v = (bool)o ? "true" : "false"; else if (o is bool? && ((bool?)o).HasValue) v = ((bool?)o).Value ? "true" : "false"; else v = o.ToString(); } int n; if (options != null && options[(int)RenderOption.Wrap] != null) { n = @out.Write(v, options[(int)RenderOption.Wrap]); } else { n = @out.Write(v); } return n; }
/** Write out an expression result that doesn't use expression options. * E.g., <name> */ protected virtual int WriteObjectNoOptions(ITemplateWriter @out, TemplateFrame frame, object o) { int start = @out.Index; // track char we're about to Write int n = WriteObject(@out, frame, o, null); if (_debug) { Interval templateLocation = frame.Template.impl.sourceMap[frame.InstructionPointer]; EvalExprEvent e = new EvalExprEvent(frame, Interval.FromBounds(start, @out.Index), templateLocation); TrackDebugEvent(frame, e); } return n; }
/** Generic method to emit text for an object. It differentiates * between templates, iterable objects, and plain old Java objects (POJOs) */ protected virtual int WriteObject(ITemplateWriter @out, TemplateFrame frame, object o, string[] options) { int n = 0; if (o == null) { if (options != null && options[(int)RenderOption.Null] != null) o = options[(int)RenderOption.Null]; else return 0; } ITypeProxyFactory proxyFactory = frame.Template.Group.GetTypeProxyFactory(o.GetType()); if (proxyFactory != null) o = proxyFactory.CreateProxy(frame, o); System.Diagnostics.Debug.Assert(!(o is TemplateFrame)); Template template = o as Template; if (template != null) { frame = new TemplateFrame(template, frame); if (options != null && options[(int)RenderOption.Wrap] != null) { // if we have a wrap string, then inform writer it // might need to wrap try { @out.WriteWrap(options[(int)RenderOption.Wrap]); } catch (IOException ioe) { _errorManager.IOError(template, ErrorType.WRITE_IO_ERROR, ioe); } } n = Execute(@out, frame); } else { o = ConvertAnythingIteratableToIterator(frame, o); // normalize try { if (o is IEnumerator) n = WriteIterator(@out, frame, o, options); else n = WritePlainObject(@out, frame, o, options); } catch (IOException ioe) { _errorManager.IOError(frame.Template, ErrorType.WRITE_IO_ERROR, ioe, o); } } return n; }
protected virtual int WriteIterator(ITemplateWriter @out, TemplateFrame frame, object o, string[] options) { if (o == null) return 0; int n = 0; IEnumerator it = (IEnumerator)o; string separator = null; if (options != null) separator = options[(int)RenderOption.Separator]; bool seenAValue = false; while (it.MoveNext()) { object iterValue = it.Current; // Emit separator if we're beyond first value bool needSeparator = seenAValue && separator != null && // we have a separator and (iterValue != null || // either we have a value options[(int)RenderOption.Null] != null); // or no value but null option if (needSeparator) n += @out.WriteSeparator(separator); int nw = WriteObject(@out, frame, iterValue, options); if (nw > 0) seenAValue = true; n += nw; } return n; }
/** Return a new list w/o null values. */ public virtual object Strip(TemplateFrame frame, object v) { if (v == null) return null; v = ConvertAnythingIteratableToIterator(frame, v); if (v is IEnumerator) { List<object> a = new List<object>(); IEnumerator it = (IEnumerator)v; while (it.MoveNext()) { object o = it.Current; if (o != null) a.Add(o); } return a; } return v; // Strip(x)==x when x single-valued attribute }
protected virtual string ToString(TemplateFrame frame, object value) { if (value != null) { if (value.GetType() == typeof(string)) return (string)value; // if not string already, must evaluate it StringWriter sw = new StringWriter(); /* Interpreter interp = new Interpreter(group, new NoIndentWriter(sw), culture); interp.WriteObjectNoOptions(self, value, -1, -1); */ if (_debug && !frame.GetDebugState().IsEarlyEval) { frame = new TemplateFrame(frame.Template, frame); frame.GetDebugState().IsEarlyEval = true; } WriteObjectNoOptions(new NoIndentWriter(sw), frame, value); return sw.ToString(); } return null; }
/** Return all but the last element. Trunc(x)=null if x is single-valued. */ public virtual object Trunc(TemplateFrame frame, object v) { if (v == null) return null; v = ConvertAnythingIteratableToIterator(frame, v); if (v is IEnumerator) { List<object> a = new List<object>(); IEnumerator it = (IEnumerator)v; while (it.MoveNext()) a.Add(it.Current); // remove the last item a.RemoveAt(a.Count - 1); return a; } // Trunc(x)==null when x single-valued attribute return null; }
public object CreateProxy(TemplateFrame frame, object obj) { if (frame.Template.Name == "dictionaryTemplate") return obj; Template template = GetDictionaryRendererTemplate(); template.Add("dict", obj); return template; }
internal virtual void StoreArguments(TemplateFrame frame, IDictionary<string, object> attrs, Template st) { if (attrs != null && attrs.Count > 0 && !st.impl.HasFormalArgs && st.impl.FormalArguments == null) { st.Add(Template.ImplicitArgumentName, null); // pretend we have "it" arg } int nformalArgs = 0; if (st.impl.FormalArguments != null) nformalArgs = st.impl.FormalArguments.Count; int nargs = 0; if (attrs != null) nargs = attrs.Count; if (nargs < (nformalArgs - st.impl.NumberOfArgsWithDefaultValues) || nargs > nformalArgs) { _errorManager.RuntimeError(frame, ErrorType.ARGUMENT_COUNT_MISMATCH, nargs, st.impl.Name, nformalArgs); } foreach (string argName in attrs.Keys) { // don't let it throw an exception in RawSetAttribute if (st.impl.FormalArguments == null || !st.impl.FormalArguments.Exists(i => i.Name == argName)) { _errorManager.RuntimeError(frame, ErrorType.NO_SUCH_ATTRIBUTE, argName); continue; } object o = attrs[argName]; st.RawSetAttribute(argName, o); } }
protected virtual void SetFirstArgument(TemplateFrame frame, Template st, object attr) { if (!st.impl.HasFormalArgs) { if (st.impl.FormalArguments == null) { st.Add(Template.ImplicitArgumentName, attr); return; } // else fall thru to set locals[0] } if (st.impl.FormalArguments == null) { _errorManager.RuntimeError(frame, ErrorType.ARGUMENT_COUNT_MISMATCH, 1, st.impl.Name, 0); return; } st.locals[0] = attr; }
internal virtual void SuperNew(TemplateFrame frame, string name, IDictionary<string, object> attrs) { Template self = frame.Template; Template st = null; CompiledTemplate imported = self.impl.NativeGroup.LookupImportedTemplate(name); if (imported == null) { _errorManager.RuntimeError(frame, ErrorType.NO_IMPORTED_TEMPLATE, name); st = self.Group.CreateStringTemplateInternally(new CompiledTemplate()); } else { st = imported.NativeGroup.CreateStringTemplateInternally(imported); st.Group = group; } // get n args and store into st's attr list StoreArguments(frame, attrs, st); operands[++sp] = st; }
/** Find an attr via dynamic scoping up enclosing scope chain. * If not found, look for a map. So attributes sent in to a template * override dictionary names. */ public virtual object GetAttribute(TemplateFrame frame, string name) { TemplateFrame scope = frame; while (scope != null) { Template template = scope.Template; FormalArgument arg = template.impl.TryGetFormalArgument(name); if (arg != null) { object o = template.locals[arg.Index]; return o; } scope = scope.Parent; } // got to root template and no definition, try dictionaries in group Template self = frame.Template; if (self.impl.NativeGroup.IsDictionary(name)) return self.impl.NativeGroup.RawGetDictionary(name); // not found, report unknown attr throw new AttributeNotFoundException(frame, name); }
protected virtual int ExecuteImpl(ITemplateWriter @out, TemplateFrame frame) { Template self = frame.Template; int start = @out.Index; // track char we're about to Write Bytecode prevOpcode = Bytecode.Invalid; int n = 0; // how many char we Write out int nargs; int nameIndex; int addr; string name; object o, left, right; Template st; object[] options; byte[] code = self.impl.instrs; // which code block are we executing int ip = 0; while (ip < self.impl.codeSize) { if (trace || _debug) Trace(frame, ip); Bytecode opcode = (Bytecode)code[ip]; frame.InstructionPointer = ip; ip++; //jump to next instruction or first byte of operand switch (opcode) { case Bytecode.INSTR_LOAD_STR: int strIndex = GetShort(code, ip); ip += Instruction.OperandSizeInBytes; operands[++sp] = self.impl.strings[strIndex]; break; case Bytecode.INSTR_LOAD_ATTR: nameIndex = GetShort(code, ip); ip += Instruction.OperandSizeInBytes; name = self.impl.strings[nameIndex]; try { o = GetAttribute(frame, name); if (o == Template.EmptyAttribute) o = null; } catch (AttributeNotFoundException) { _errorManager.RuntimeError(frame, ErrorType.NO_SUCH_ATTRIBUTE, name); o = null; } operands[++sp] = o; break; case Bytecode.INSTR_LOAD_LOCAL: int valueIndex = GetShort(code, ip); ip += Instruction.OperandSizeInBytes; o = self.locals[valueIndex]; if (o == Template.EmptyAttribute) o = null; operands[++sp] = o; break; case Bytecode.INSTR_LOAD_PROP: nameIndex = GetShort(code, ip); ip += Instruction.OperandSizeInBytes; o = operands[sp--]; name = self.impl.strings[nameIndex]; operands[++sp] = GetObjectProperty(frame, o, name); break; case Bytecode.INSTR_LOAD_PROP_IND: object propName = operands[sp--]; o = operands[sp]; operands[sp] = GetObjectProperty(frame, o, propName); break; case Bytecode.INSTR_NEW: nameIndex = GetShort(code, ip); ip += Instruction.OperandSizeInBytes; name = self.impl.strings[nameIndex]; nargs = GetShort(code, ip); ip += Instruction.OperandSizeInBytes; // look up in original hierarchy not enclosing template (variable group) // see TestSubtemplates.testEvalSTFromAnotherGroup() st = self.Group.GetEmbeddedInstanceOf(frame, name); // get n args and store into st's attr list StoreArguments(frame, nargs, st); sp -= nargs; operands[++sp] = st; break; case Bytecode.INSTR_NEW_IND: nargs = GetShort(code, ip); ip += Instruction.OperandSizeInBytes; name = (string)operands[sp - nargs]; st = self.Group.GetEmbeddedInstanceOf(frame, name); StoreArguments(frame, nargs, st); sp -= nargs; sp--; // pop template name operands[++sp] = st; break; case Bytecode.INSTR_NEW_BOX_ARGS: nameIndex = GetShort(code, ip); ip += Instruction.OperandSizeInBytes; name = self.impl.strings[nameIndex]; IDictionary<string, object> attrs = (IDictionary<string, object>)operands[sp--]; // look up in original hierarchy not enclosing template (variable group) // see TestSubtemplates.testEvalSTFromAnotherGroup() st = self.Group.GetEmbeddedInstanceOf(frame, name); // get n args and store into st's attr list StoreArguments(frame, attrs, st); operands[++sp] = st; break; case Bytecode.INSTR_SUPER_NEW: nameIndex = GetShort(code, ip); ip += Instruction.OperandSizeInBytes; name = self.impl.strings[nameIndex]; nargs = GetShort(code, ip); ip += Instruction.OperandSizeInBytes; SuperNew(frame, name, nargs); break; case Bytecode.INSTR_SUPER_NEW_BOX_ARGS: nameIndex = GetShort(code, ip); ip += Instruction.OperandSizeInBytes; name = self.impl.strings[nameIndex]; attrs = (IDictionary<string, object>)operands[sp--]; SuperNew(frame, name, attrs); break; case Bytecode.INSTR_STORE_OPTION: int optionIndex = GetShort(code, ip); ip += Instruction.OperandSizeInBytes; o = operands[sp--]; // value to store options = (object[])operands[sp]; // get options options[optionIndex] = o; // store value into options on stack break; case Bytecode.INSTR_STORE_ARG: nameIndex = GetShort(code, ip); name = self.impl.strings[nameIndex]; ip += Instruction.OperandSizeInBytes; o = operands[sp--]; attrs = (IDictionary<string, object>)operands[sp]; attrs[name] = o; // leave attrs on stack break; case Bytecode.INSTR_WRITE: o = operands[sp--]; int n1 = WriteObjectNoOptions(@out, frame, o); n += n1; nwline += n1; break; case Bytecode.INSTR_WRITE_OPT: options = (object[])operands[sp--]; // get options o = operands[sp--]; // get option to Write int n2 = WriteObjectWithOptions(@out, frame, o, options); n += n2; nwline += n2; break; case Bytecode.INSTR_MAP: st = (Template)operands[sp--]; // get prototype off stack o = operands[sp--]; // get object to map prototype across Map(frame, o, st); break; case Bytecode.INSTR_ROT_MAP: int nmaps = GetShort(code, ip); ip += Instruction.OperandSizeInBytes; List<Template> templates = new List<Template>(); for (int i = nmaps - 1; i >= 0; i--) templates.Add((Template)operands[sp - i]); sp -= nmaps; o = operands[sp--]; if (o != null) RotateMap(frame, o, templates); break; case Bytecode.INSTR_ZIP_MAP: st = (Template)operands[sp--]; nmaps = GetShort(code, ip); ip += Instruction.OperandSizeInBytes; List<object> exprs = new List<object>(); for (int i = nmaps - 1; i >= 0; i--) exprs.Add(operands[sp - i]); sp -= nmaps; operands[++sp] = ZipMap(frame, exprs, st); break; case Bytecode.INSTR_BR: ip = GetShort(code, ip); break; case Bytecode.INSTR_BRF: addr = GetShort(code, ip); ip += Instruction.OperandSizeInBytes; o = operands[sp--]; // <if(expr)>...<endif> if (!TestAttributeTrue(o)) ip = addr; // jump break; case Bytecode.INSTR_OPTIONS: operands[++sp] = new object[Compiler.TemplateCompiler.NUM_OPTIONS]; break; case Bytecode.INSTR_ARGS: operands[++sp] = new Dictionary<string, object>(); break; case Bytecode.INSTR_PASSTHRU: nameIndex = GetShort(code, ip); ip += Instruction.OperandSizeInBytes; name = self.impl.strings[nameIndex]; attrs = (IDictionary<string, object>)operands[sp]; PassThrough(frame, name, attrs); break; case Bytecode.INSTR_LIST: operands[++sp] = new List<object>(); break; case Bytecode.INSTR_ADD: o = operands[sp--]; // pop value List<object> list = (List<object>)operands[sp]; // don't pop list AddToList(list, frame, o); break; case Bytecode.INSTR_TOSTR: // replace with string value; early eval operands[sp] = ToString(frame, operands[sp]); break; case Bytecode.INSTR_FIRST: operands[sp] = First(frame, operands[sp]); break; case Bytecode.INSTR_LAST: operands[sp] = Last(frame, operands[sp]); break; case Bytecode.INSTR_REST: operands[sp] = Rest(frame, operands[sp]); break; case Bytecode.INSTR_TRUNC: operands[sp] = Trunc(frame, operands[sp]); break; case Bytecode.INSTR_STRIP: operands[sp] = Strip(frame, operands[sp]); break; case Bytecode.INSTR_TRIM: o = operands[sp--]; if (o.GetType() == typeof(string)) { operands[++sp] = ((string)o).Trim(); } else { _errorManager.RuntimeError(frame, ErrorType.EXPECTING_STRING, "trim", o.GetType()); operands[++sp] = o; } break; case Bytecode.INSTR_LENGTH: operands[sp] = Length(operands[sp]); break; case Bytecode.INSTR_STRLEN: o = operands[sp--]; if (o.GetType() == typeof(string)) { operands[++sp] = ((string)o).Length; } else { _errorManager.RuntimeError(frame, ErrorType.EXPECTING_STRING, "strlen", o.GetType()); operands[++sp] = 0; } break; case Bytecode.INSTR_REVERSE: operands[sp] = Reverse(frame, operands[sp]); break; case Bytecode.INSTR_NOT: operands[sp] = !TestAttributeTrue(operands[sp]); break; case Bytecode.INSTR_OR: right = operands[sp--]; left = operands[sp--]; operands[++sp] = TestAttributeTrue(left) || TestAttributeTrue(right); break; case Bytecode.INSTR_AND: right = operands[sp--]; left = operands[sp--]; operands[++sp] = TestAttributeTrue(left) && TestAttributeTrue(right); break; case Bytecode.INSTR_INDENT: strIndex = GetShort(code, ip); ip += Instruction.OperandSizeInBytes; Indent(@out, frame, strIndex); break; case Bytecode.INSTR_DEDENT: @out.PopIndentation(); break; case Bytecode.INSTR_NEWLINE: try { if (prevOpcode == Bytecode.INSTR_NEWLINE || prevOpcode == Bytecode.INSTR_INDENT || nwline > 0) { @out.Write(Environment.NewLine); } nwline = 0; } catch (IOException ioe) { _errorManager.IOError(self, ErrorType.WRITE_IO_ERROR, ioe); } break; case Bytecode.INSTR_NOOP: break; case Bytecode.INSTR_POP: sp--; // throw away top of stack break; case Bytecode.INSTR_NULL: operands[++sp] = null; break; case Bytecode.INSTR_TRUE: operands[++sp] = true; break; case Bytecode.INSTR_FALSE: operands[++sp] = false; break; case Bytecode.INSTR_WRITE_STR: strIndex = GetShort(code, ip); ip += Instruction.OperandSizeInBytes; o = self.impl.strings[strIndex]; n1 = WriteObjectNoOptions(@out, frame, o); n += n1; nwline += n1; break; // TODO: generate this optimization //case Bytecode.INSTR_WRITE_LOCAL: // valueIndex = GetShort(code, ip); // ip += Instruction.OperandSizeInBytes; // o = self.locals[valueIndex]; // if (o == Template.EmptyAttribute) // o = null; // n1 = WriteObjectNoOptions(@out, frame, o); // n += n1; // nwline += n1; // break; default: _errorManager.InternalError(self, "invalid bytecode @ " + (ip - 1) + ": " + opcode, null); self.impl.Dump(); break; } prevOpcode = opcode; } if (_debug) { EvalTemplateEvent e = new EvalTemplateEvent(frame, Interval.FromBounds(start, @out.Index)); TrackDebugEvent(frame, e); } return n; }
protected virtual void Trace(TemplateFrame frame, int ip) { Template self = frame.Template; StringBuilder tr = new StringBuilder(); BytecodeDisassembler dis = new BytecodeDisassembler(self.impl); StringBuilder buf = new StringBuilder(); dis.DisassembleInstruction(buf, ip); string name = self.impl.Name + ":"; if (object.ReferenceEquals(self.impl.Name, Template.UnknownName)) name = string.Empty; tr.Append(string.Format("{0,-40}", name + buf)); tr.Append("\tstack=["); for (int i = 0; i <= sp; i++) { object o = operands[i]; PrintForTrace(tr, frame, o); } tr.Append(" ], calls="); tr.Append(frame.GetEnclosingInstanceStackString()); tr.Append(", sp=" + sp + ", nw=" + nwline); string s = tr.ToString(); if (_debug) executeTrace.Add(s); if (trace) Console.WriteLine(s); }
public object CreateProxy(TemplateFrame frame, object obj) { Template template = obj as Template; if (template != null && template.Group != _ignoreGroup) return new TemplateProxy(template); return obj; }
/** Return the first attribute if multiple valued or the attribute * itself if single-valued. Used in <names:First()> */ public virtual object First(TemplateFrame frame, object v) { if (v == null) return null; object r = v; v = ConvertAnythingIteratableToIterator(frame, v); if (v is IEnumerator) { IEnumerator it = (IEnumerator)v; if (it.MoveNext()) { r = it.Current; } } return r; }
public static IEnumerator ConvertAnythingToIterator(TemplateFrame frame, object o) { o = ConvertAnythingIteratableToIterator(frame, o); IEnumerator iter = o as IEnumerator; if (iter != null) return iter; Template.AttributeList singleton = new Template.AttributeList(1); singleton.Add(o); return singleton.GetEnumerator(); }
/** Execute template self and return how many characters it wrote to out */ public virtual int Execute(ITemplateWriter @out, TemplateFrame frame) { try { if (frame.StackDepth > 200) throw new TemplateException("Template stack overflow.", null); if (trace) Console.Out.WriteLine("Execute({0})", frame.Template.Name); SetDefaultArguments(frame); return ExecuteImpl(@out, frame); } catch (Exception e) { if (e.IsCritical()) { e.PreserveStackTrace(); throw; } StringBuilder builder = new StringBuilder(); builder.AppendLine(e.ToString()); builder.AppendLine(e.StackTrace); _errorManager.RuntimeError(frame, ErrorType.INTERNAL_ERROR, "internal error: " + builder); return 0; } }