예제 #1
0
 internal override MSAst.Expression TransformSet(SourceSpan span, MSAst.Expression right, PythonOperationKind op)
 {
     if (op == PythonOperationKind.None)
     {
         return(GlobalParent.AddDebugInfoAndVoid(
                    GlobalParent.Set(
                        _name,
                        _target,
                        right
                        ),
                    span
                    ));
     }
     else
     {
         MSAst.ParameterExpression temp = Ast.Variable(typeof(object), "inplace");
         return(GlobalParent.AddDebugInfo(
                    Ast.Block(
                        new[] { temp },
                        Ast.Assign(temp, _target),
                        SetMemberOperator(right, op, temp),
                        AstUtils.Empty()
                        ),
                    Span.Start,
                    span.End
                    ));
     }
 }
예제 #2
0
        public override MSAst.Expression Reduce()
        {
            // If debugging is off, return empty statement
            if (Optimize)
            {
                return(AstUtils.Empty());
            }

            // Transform into:
            // if (_test) {
            // } else {
            //     RaiseAssertionError(_message);
            // }
            return(GlobalParent.AddDebugInfoAndVoid(
                       AstUtils.Unless(                                     // if
                           TransformAndDynamicConvert(_test, typeof(bool)), // _test
                           Ast.Call(                                        // else branch
                               AstMethods.RaiseAssertionError,
                               Parent.LocalContext,
                               TransformOrConstantNull(_message, typeof(object))
                               )
                           ),
                       Span
                       ));
        }
예제 #3
0
        public override MSAst.Expression Reduce()
        {
            ReadOnlyCollectionBuilder <MSAst.Expression> statements = new ReadOnlyCollectionBuilder <MSAst.Expression>();

            for (int i = 0; i < _names.Length; i++)
            {
                statements.Add(
                    // _references[i] = PythonOps.Import(<code context>, _names[i])
                    GlobalParent.AddDebugInfoAndVoid(
                        AssignValue(
                            Parent.GetVariableExpression(_variables[i]),
                            LightExceptions.CheckAndThrow(
                                Expression.Call(
                                    _asNames[i] == null ? AstMethods.ImportTop : AstMethods.ImportBottom,
                                    Parent.LocalContext,                                     // 1st arg - code context
                                    AstUtils.Constant(_names[i].MakeString()),               // 2nd arg - module name
                                    AstUtils.Constant(_forceAbsolute ? 0 : -1)               // 3rd arg - absolute or relative imports
                                    )
                                )
                            ),
                        _names[i].Span
                        )
                    );
            }

            statements.Add(AstUtils.Empty());
            return(GlobalParent.AddDebugInfo(Ast.Block(statements.ToReadOnlyCollection()), Span));
        }
예제 #4
0
        public override MSAst.Expression Reduce()
        {
            if (_statements.Length == 0)
            {
                return(GlobalParent.AddDebugInfoAndVoid(AstUtils.Empty(), Span));
            }

            ReadOnlyCollectionBuilder <MSAst.Expression> statements = new ReadOnlyCollectionBuilder <MSAst.Expression>();

            int curStart = -1;

            foreach (var statement in _statements)
            {
                // CPython debugging treats multiple statements on the same line as a single step, we
                // match that behavior here.
                int newline = GlobalParent.IndexToLocation(statement.StartIndex).Line;
                if (newline == curStart)
                {
                    statements.Add(new DebugInfoRemovalExpression(statement, curStart));
                }
                else
                {
                    if (statement.CanThrow && newline != -1)
                    {
                        statements.Add(UpdateLineNumber(newline));
                    }

                    statements.Add(statement);
                }
                curStart = newline;
            }

            return(Ast.Block(statements.ToReadOnlyCollection()));
        }
예제 #5
0
        private MSAst.Expression ReduceWorker(bool optimizeDynamicConvert)
        {
            MSAst.Expression result;

            if (_else != null)
            {
                result = _else;
            }
            else
            {
                result = AstUtils.Empty();
            }

            // Now build from the inside out
            int i = _tests.Length;

            while (i-- > 0)
            {
                IfStatementTest ist = _tests[i];

                result = GlobalParent.AddDebugInfoAndVoid(
                    Ast.Condition(
                        optimizeDynamicConvert ?
                        TransformAndDynamicConvert(ist.Test, typeof(bool)) :
                        GlobalParent.Convert(typeof(bool), Microsoft.Scripting.Actions.ConversionResultKind.ExplicitCast, ist.Test),
                        TransformMaybeSingleLineSuite(ist.Body, ist.Test.Start),
                        result
                        ),
                    new SourceSpan(ist.Start, ist.Header)
                    );
            }

            return(result);
        }
예제 #6
0
        public override MSAst.Expression Reduce()
        {
            Debug.Assert(_variable != null, "Shouldn't be called by lambda expression");

            MSAst.Expression function = MakeFunctionExpression();
            return(GlobalParent.AddDebugInfoAndVoid(AssignValue(Parent.GetVariableExpression(_variable), function), new SourceSpan(Start, Header)));
        }
예제 #7
0
 internal override MSAst.Expression Transform(MSAst.Expression body)
 {
     return(GlobalParent.AddDebugInfoAndVoid(
                AstUtils.If(
                    GlobalParent.Convert(typeof(bool), ConversionResultKind.ExplicitCast, _test),
                    body
                    ),
                Span
                ));
 }
예제 #8
0
        private MSAst.Expression ReduceWorker(bool optimizeDynamicConvert)
        {
            // Only the body is "in the loop" for the purposes of break/continue
            // The "else" clause is outside

            ConstantExpression constTest = _test as ConstantExpression;

            if (constTest != null && constTest.Value is int)
            {
                // while 0: / while 1:
                int val = (int)constTest.Value;
                if (val == 0)
                {
                    // completely optimize the loop away
                    if (_else == null)
                    {
                        return(MSAst.Expression.Empty());
                    }
                    else
                    {
                        return(_else);
                    }
                }

                MSAst.Expression test = MSAst.Expression.Constant(true);
                MSAst.Expression res  = AstUtils.While(
                    test,
                    _body,
                    _else,
                    _break,
                    _continue
                    );

                if (GlobalParent.IndexToLocation(_test.StartIndex).Line != GlobalParent.IndexToLocation(_body.StartIndex).Line)
                {
                    res = GlobalParent.AddDebugInfoAndVoid(res, _test.Span);
                }

                return(res);
            }

            return(AstUtils.While(
                       GlobalParent.AddDebugInfo(
                           optimizeDynamicConvert ?
                           TransformAndDynamicConvert(_test, typeof(bool)) :
                           GlobalParent.Convert(typeof(bool), Microsoft.Scripting.Actions.ConversionResultKind.ExplicitCast, _test),
                           Header
                           ),
                       _body,
                       _else,
                       _break,
                       _continue
                       ));
        }
예제 #9
0
        private MSAst.Expression ReduceWorker(MSAst.Expression expression)
        {
            if (Parent.PrintExpressions)
            {
                expression = Ast.Call(
                    AstMethods.PrintExpressionValue,
                    Parent.LocalContext,
                    ConvertIfNeeded(expression, typeof(object))
                    );
            }

            return(GlobalParent.AddDebugInfoAndVoid(expression, _expression.Span));
        }
예제 #10
0
        internal override MSAst.Expression TransformDelete()
        {
            MSAst.Expression index;
            if (IsSlice)
            {
                index = GlobalParent.DeleteSlice(GetActionArgumentsForGetOrDelete());
            }
            else
            {
                index = GlobalParent.DeleteIndex(GetActionArgumentsForGetOrDelete());
            }

            return(GlobalParent.AddDebugInfoAndVoid(index, Span));
        }
예제 #11
0
        private MSAst.Expression AssignOne()
        {
            Debug.Assert(_left.Length == 1);

            SequenceExpression seLeft  = _left[0] as SequenceExpression;
            SequenceExpression seRight = _right as SequenceExpression;

            bool isStarred = seLeft != null && seLeft.Items.OfType <StarredExpression>().Any();

            if (!isStarred && seLeft != null && seRight != null && seLeft.Items.Count == seRight.Items.Count)
            {
                int cnt = seLeft.Items.Count;

                // a, b = 1, 2, or [a,b] = 1,2 - not something like a, b = range(2)
                // we can do a fast parallel assignment
                MSAst.ParameterExpression[] tmps = new MSAst.ParameterExpression[cnt];
                MSAst.Expression[]          body = new MSAst.Expression[cnt * 2 + 1];

                // generate the body, the 1st n are the temporary assigns, the
                // last n are the assignments to the left hand side
                // 0: tmp0 = right[0]
                // ...
                // n-1: tmpn-1 = right[n-1]
                // n: right[0] = tmp0
                // ...
                // n+n-1: right[n-1] = tmpn-1

                // allocate the temps first before transforming so we don't pick up a bad temp...
                for (int i = 0; i < cnt; i++)
                {
                    MSAst.Expression tmpVal = seRight.Items[i];
                    tmps[i] = Ast.Variable(tmpVal.Type, "parallelAssign");

                    body[i] = Ast.Assign(tmps[i], tmpVal);
                }

                // then transform which can allocate more temps
                for (int i = 0; i < cnt; i++)
                {
                    body[i + cnt] = seLeft.Items[i].TransformSet(SourceSpan.None, tmps[i], PythonOperationKind.None);
                }

                // 4. Create and return the resulting suite
                body[cnt * 2] = AstUtils.Empty();
                return(GlobalParent.AddDebugInfoAndVoid(Ast.Block(tmps, body), Span));
            }

            return(_left[0].TransformSet(Span, _right, PythonOperationKind.None));
        }
예제 #12
0
        public override MSAst.Expression Reduce()
        {
            var codeObj  = GetOrMakeFunctionCode();
            var funcCode = GlobalParent.Constant(codeObj);

            FuncCodeExpr = funcCode;

            MSAst.Expression lambda;
            if (EmitDebugSymbols)
            {
                lambda = GetLambda();
            }
            else
            {
                lambda = NullLambda;
                ThreadPool.QueueUserWorkItem((x) => {
                    // class defs are almost always run, so start
                    // compiling the code now so it might be ready
                    // when we actually go and execute it
                    codeObj.UpdateDelegate(PyContext, true);
                });
            }

            MSAst.Expression classDef = Ast.Call(
                AstMethods.MakeClass,
                funcCode,
                lambda,
                Parent.LocalContext,
                AstUtils.Constant(_name),
                Ast.NewArrayInit(
                    typeof(object),
                    ToObjectArray(_bases)
                    ),
                Metaclass is null ? AstUtils.Constant(null, typeof(object)) : AstUtils.Convert(Metaclass, typeof(object)),
                AstUtils.Constant(FindSelfNames())
                );

            classDef = AddDecorators(classDef, Decorators);

            return(GlobalParent.AddDebugInfoAndVoid(
                       AssignValue(Parent.GetVariableExpression(PythonVariable), classDef),
                       new SourceSpan(
                           GlobalParent.IndexToLocation(StartIndex),
                           GlobalParent.IndexToLocation(HeaderIndex)
                           )
                       ));
        }
예제 #13
0
        internal override MSAst.Expression TransformSet(SourceSpan span, MSAst.Expression right, PythonOperationKind op)
        {
            if (op != PythonOperationKind.None)
            {
                right = GlobalParent.Operation(
                    typeof(object),
                    op,
                    this,
                    right
                    );
            }

            MSAst.Expression index = IsSlice
                ? GlobalParent.SetSlice(GetActionArgumentsForSet(right))
                : GlobalParent.SetIndex(GetActionArgumentsForSet(right));

            return(GlobalParent.AddDebugInfoAndVoid(index, Span));
        }
예제 #14
0
        private MSAst.Expression AssignComplex(MSAst.Expression right)
        {
            // Python assignment semantics:
            // - only evaluate RHS once.
            // - evaluates assignment from left to right
            // - does not evaluate getters.
            //
            // So
            //   a=b[c]=d=f()
            // should be:
            //   $temp = f()
            //   a = $temp
            //   b[c] = $temp
            //   d = $temp

            List <MSAst.Expression> statements = new List <MSAst.Expression>();

            // 1. Create temp variable for the right value
            MSAst.ParameterExpression right_temp = Expression.Variable(typeof(object), "assignment");

            // 2. right_temp = right
            statements.Add(MakeAssignment(right_temp, right));

            // Do left to right assignment
            foreach (Expression e in _left)
            {
                if (e == null)
                {
                    continue;
                }

                // 3. e = right_temp
                MSAst.Expression transformed = e.TransformSet(Span, right_temp, PythonOperationKind.None);

                statements.Add(transformed);
            }

            // 4. Create and return the resulting suite
            statements.Add(AstUtils.Empty());
            return(GlobalParent.AddDebugInfoAndVoid(
                       Ast.Block(new[] { right_temp }, statements.ToArray()),
                       Span
                       ));
        }
예제 #15
0
        internal override MSAst.Expression TransformSet(SourceSpan span, MSAst.Expression right, PythonOperationKind op)
        {
            MSAst.Expression assignment;

            if (op != PythonOperationKind.None)
            {
                right = GlobalParent.Operation(
                    typeof(object),
                    op,
                    this,
                    right
                    );
            }

            SourceSpan aspan = span.IsValid ? new SourceSpan(Span.Start, span.End) : SourceSpan.None;

            if (Reference.PythonVariable != null)
            {
                assignment = AssignValue(
                    Parent.GetVariableExpression(Reference.PythonVariable),
                    ConvertIfNeeded(right, typeof(object))
                    );
            }
            else
            {
                assignment = Ast.Call(
                    null,
                    AstMethods.SetName,
                    Parent.LocalContext,
                    Ast.Constant(Name),
                    AstUtils.Convert(right, typeof(object))
                    );
            }

            return(GlobalParent.AddDebugInfoAndVoid(assignment, aspan));
        }
예제 #16
0
        private MSAst.Expression ReduceWorker(bool optimizeDynamicConvert)
        {
            MSAst.Expression result;

            if (_tests.Length > 100)
            {
                // generate:
                // if(x) {
                //   body
                //   goto end
                // } else {
                // }
                // elseBody
                // end:
                //
                // to avoid deeply recursive trees which can stack overflow.
                var builder = new ReadOnlyCollectionBuilder <MSAst.Expression>();
                var label   = Ast.Label();
                for (int i = 0; i < _tests.Length; i++)
                {
                    IfStatementTest ist = _tests[i];

                    builder.Add(
                        Ast.Condition(
                            optimizeDynamicConvert ?
                            TransformAndDynamicConvert(ist.Test, typeof(bool)) :
                            GlobalParent.Convert(typeof(bool), Microsoft.Scripting.Actions.ConversionResultKind.ExplicitCast, ist.Test),
                            Ast.Block(
                                TransformMaybeSingleLineSuite(ist.Body, ist.Test.Start),
                                Ast.Goto(label)
                                ),
                            AstUtils.Empty()
                            )
                        );
                }

                if (_else != null)
                {
                    builder.Add(_else);
                }

                builder.Add(Ast.Label(label));
                result = Ast.Block(builder);
            }
            else
            {
                // Now build from the inside out
                if (_else != null)
                {
                    result = _else;
                }
                else
                {
                    result = AstUtils.Empty();
                }

                int i = _tests.Length;
                while (i-- > 0)
                {
                    IfStatementTest ist = _tests[i];

                    result = GlobalParent.AddDebugInfoAndVoid(
                        Ast.Condition(
                            optimizeDynamicConvert ?
                            TransformAndDynamicConvert(ist.Test, typeof(bool)) :
                            GlobalParent.Convert(typeof(bool), Microsoft.Scripting.Actions.ConversionResultKind.ExplicitCast, ist.Test),
                            TransformMaybeSingleLineSuite(ist.Body, ist.Test.Start),
                            result
                            ),
                        new SourceSpan(ist.Start, ist.Header)

                        );
                }
            }

            return(result);
        }
예제 #17
0
        /// <summary>
        /// WithStatement is translated to the DLR AST equivalent to
        /// the following Python code snippet (from with statement spec):
        ///
        /// mgr = (EXPR)
        /// exit = mgr.__exit__  # Not calling it yet
        /// value = mgr.__enter__()
        /// exc = True
        /// try:
        ///     VAR = value  # Only if "as VAR" is present
        ///     BLOCK
        /// except:
        ///     # The exceptional case is handled here
        ///     exc = False
        ///     if not exit(*sys.exc_info()):
        ///         raise
        ///     # The exception is swallowed if exit() returns true
        /// finally:
        ///     # The normal and non-local-goto cases are handled here
        ///     if exc:
        ///         exit(None, None, None)
        ///
        /// </summary>
        public override MSAst.Expression Reduce()
        {
            // Five statements in the result...
            ReadOnlyCollectionBuilder <MSAst.Expression>          statements = new ReadOnlyCollectionBuilder <MSAst.Expression>(6);
            ReadOnlyCollectionBuilder <MSAst.ParameterExpression> variables  = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression>(6);

            MSAst.ParameterExpression lineUpdated = Ast.Variable(typeof(bool), "$lineUpdated_with");
            variables.Add(lineUpdated);

            //******************************************************************
            // 1. mgr = (EXPR)
            //******************************************************************
            MSAst.ParameterExpression manager = Ast.Variable(typeof(object), "with_manager");
            variables.Add(manager);
            statements.Add(
                GlobalParent.AddDebugInfo(
                    Ast.Assign(
                        manager,
                        _contextManager
                        ),
                    new SourceSpan(Start, _header)
                    )
                );

            //******************************************************************
            // 2. exit = mgr.__exit__  # Not calling it yet
            //******************************************************************
            MSAst.ParameterExpression exit = Ast.Variable(typeof(object), "with_exit");
            variables.Add(exit);
            statements.Add(
                MakeAssignment(
                    exit,
                    GlobalParent.Get(
                        "__exit__",
                        manager
                        )
                    )
                );

            //******************************************************************
            // 3. value = mgr.__enter__()
            //******************************************************************
            MSAst.ParameterExpression value = Ast.Variable(typeof(object), "with_value");
            variables.Add(value);
            statements.Add(
                GlobalParent.AddDebugInfoAndVoid(
                    MakeAssignment(
                        value,
                        Parent.Invoke(
                            new CallSignature(0),
                            Parent.LocalContext,
                            GlobalParent.Get(
                                "__enter__",
                                manager
                                )
                            )
                        ),
                    new SourceSpan(Start, _header)
                    )
                );

            //******************************************************************
            // 4. exc = True
            //******************************************************************
            MSAst.ParameterExpression exc = Ast.Variable(typeof(bool), "with_exc");
            variables.Add(exc);
            statements.Add(
                MakeAssignment(
                    exc,
                    AstUtils.Constant(true)
                    )
                );

            //******************************************************************
            //  5. The final try statement:
            //
            //  try:
            //      VAR = value  # Only if "as VAR" is present
            //      BLOCK
            //  except:
            //      # The exceptional case is handled here
            //      exc = False
            //      if not exit(*sys.exc_info()):
            //          raise
            //      # The exception is swallowed if exit() returns true
            //  finally:
            //      # The normal and non-local-goto cases are handled here
            //      if exc:
            //          exit(None, None, None)
            //******************************************************************

            MSAst.ParameterExpression exception;
            MSAst.ParameterExpression nestedFrames = Ast.Variable(typeof(List <DynamicStackFrame>), "$nestedFrames");
            variables.Add(nestedFrames);
            statements.Add(
                // try:
                AstUtils.Try(
                    AstUtils.Try(// try statement body
                        PushLineUpdated(false, lineUpdated),
                        _var != null ?
                        (MSAst.Expression)Ast.Block(
                            // VAR = value
                            _var.TransformSet(SourceSpan.None, value, PythonOperationKind.None),
                            // BLOCK
                            _body,
                            AstUtils.Empty()
                            ) :
                        // BLOCK
                        (MSAst.Expression)_body // except:, // try statement location
                        ).Catch(exception = Ast.Variable(typeof(Exception), "exception"),
                                                // Python specific exception handling code
                                TryStatement.GetTracebackHeader(
                                    this,
                                    exception,
                                    GlobalParent.AddDebugInfoAndVoid(
                                        Ast.Block(
                                            // exc = False
                                            MakeAssignment(
                                                exc,
                                                AstUtils.Constant(false)
                                                ),
                                            Ast.Assign(
                                                nestedFrames,
                                                Ast.Call(AstMethods.GetAndClearDynamicStackFrames)
                                                ),
                                            //  if not exit(*sys.exc_info()):
                                            //      raise
                                            AstUtils.IfThen(
                                                GlobalParent.Convert(
                                                    typeof(bool),
                                                    ConversionResultKind.ExplicitCast,
                                                    GlobalParent.Operation(
                                                        typeof(bool),
                                                        PythonOperationKind.IsFalse,
                                                        MakeExitCall(exit, exception)
                                                        )
                                                    ),
                                                UpdateLineUpdated(true),
                                                Ast.Call(
                                                    AstMethods.SetDynamicStackFrames,
                                                    nestedFrames
                                                    ),
                                                Ast.Throw(
                                                    Ast.Call(
                                                        AstMethods.MakeRethrowExceptionWorker,
                                                        exception
                                                        )
                                                    )
                                                )
                                            ),
                                        _body.Span
                                        )
                                    ),
                                Ast.Call(
                                    AstMethods.SetDynamicStackFrames,
                                    nestedFrames
                                    ),
                                PopLineUpdated(lineUpdated),
                                Ast.Empty()
                                )
                    // finally:
                    ).Finally(
                    //  if exc:
                    //      exit(None, None, None)
                    AstUtils.IfThen(
                        exc,
                        GlobalParent.AddDebugInfoAndVoid(
                            Ast.Block(
                                Ast.Dynamic(
                                    GlobalParent.PyContext.Invoke(
                                        new CallSignature(3)        // signature doesn't include function
                                        ),
                                    typeof(object),
                                    new MSAst.Expression[] {
                Parent.LocalContext,
                exit,
                AstUtils.Constant(null),
                AstUtils.Constant(null),
                AstUtils.Constant(null)
            }
                                    ),
                                Ast.Empty()
                                ),
                            _contextManager.Span
                            )
                        )
                    )
                );

            statements.Add(AstUtils.Empty());
            return(Ast.Block(variables.ToReadOnlyCollection(), statements.ToReadOnlyCollection()));
        }
예제 #18
0
        public override MSAst.Expression Reduce()
        {
            if (_names == _star)
            {
                // from a[.b] import *
                return(GlobalParent.AddDebugInfo(
                           Ast.Call(
                               AstMethods.ImportStar,
                               Parent.LocalContext,
                               AstUtils.Constant(_root.MakeString()),
                               AstUtils.Constant(GetLevel())
                               ),
                           Span
                           ));
            }
            else
            {
                // from a[.b] import x [as xx], [ y [ as yy] ] [ , ... ]

                ReadOnlyCollectionBuilder <MSAst.Expression> statements = new ReadOnlyCollectionBuilder <MSAst.Expression>();
                MSAst.ParameterExpression module = Ast.Variable(typeof(object), "module");

                // Create initializer of the array of names being passed to ImportWithNames
                MSAst.Expression[] names = new MSAst.Expression[_names.Length];
                for (int i = 0; i < names.Length; i++)
                {
                    names[i] = AstUtils.Constant(_names[i]);
                }

                // module = PythonOps.ImportWithNames(<context>, _root, make_array(_names))
                statements.Add(
                    GlobalParent.AddDebugInfoAndVoid(
                        AssignValue(
                            module,
                            LightExceptions.CheckAndThrow(
                                Expression.Call(
                                    AstMethods.ImportWithNames,
                                    Parent.LocalContext,
                                    AstUtils.Constant(_root.MakeString()),
                                    Ast.NewArrayInit(typeof(string), names),
                                    AstUtils.Constant(GetLevel())
                                    )
                                )
                            ),
                        _root.Span
                        )
                    );

                // now load all the names being imported and assign the variables
                for (int i = 0; i < names.Length; i++)
                {
                    statements.Add(
                        GlobalParent.AddDebugInfoAndVoid(
                            AssignValue(
                                Parent.GetVariableExpression(_variables[i]),
                                Ast.Call(
                                    AstMethods.ImportFrom,
                                    Parent.LocalContext,
                                    module,
                                    names[i]
                                    )
                                ),
                            Span
                            )
                        );
                }

                statements.Add(AstUtils.Empty());
                return(GlobalParent.AddDebugInfo(Ast.Block(new[] { module }, statements.ToArray()), Span));
            }
        }
예제 #19
0
 public override MSAst.Expression Reduce()
 {
     return(GlobalParent.AddDebugInfoAndVoid(AstUtils.Empty(), Span));
 }
예제 #20
0
 internal MSAst.Expression MakeAssignment(MSAst.ParameterExpression variable, MSAst.Expression right, SourceSpan span)
 {
     return(GlobalParent.AddDebugInfoAndVoid(Ast.Assign(variable, AstUtils.Convert(right, variable.Type)), span));
 }