public TemplateFrameAttributeViewModel(EvalTemplateEvent @event, HashSet<string> hiddenAttributes)
        {
            if (@event == null)
                throw new ArgumentNullException("event");

            this._event = @event;

            Template template = _event.Frame.Template;
            IDictionary<string, object> attributes = template.GetAttributes();
            if (attributes != null)
            {
                List<AttributeViewModel> attributesList = new List<AttributeViewModel>();
                foreach (var attribute in attributes)
                {
                    bool hidden = !hiddenAttributes.Add(attribute.Key);
                    attributesList.Add(new AttributeViewModel(attribute.Key, attribute.Value, hidden, GetAttributeEvents(template, attribute.Key)));
                }

                _attributes = attributesList.AsReadOnly();
            }
        }
Beispiel #2
0
        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;
        }
        private int GetIndexOfChild(EvalTemplateEvent parent, EvalTemplateEvent child)
        {
            if (parent == null)
                throw new ArgumentNullException("parent");
            if (child == null)
                throw new ArgumentNullException("child");

            TemplateCallHierarchyViewModel hierarchy = new TemplateCallHierarchyViewModel(ViewModel.Visualizer.Interpreter, parent);
            List<TemplateCallHierarchyViewModel> children = hierarchy.Children;
            return children.FindIndex(i => i.Event == child);
        }