Exemplo n.º 1
0
        public static T EvaluateBindingAs <T>(TemplateScopeContext scope, JsBinding binding)
        {
            var result    = EvaluateBinding(scope, binding);
            var converted = result.ConvertTo <T>();

            return(converted);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Creates a new <see cref="JsExecutionContext"/> instance.
        /// </summary>
        public JsExecutionContext(JavaScriptRuntime runtime)
        {
            _runtime = runtime;
            _scope   = new JsContextScope(_runtime.CreateContext());
            _binder  = new JsBinder(_scope);
            _interop = new JsInterop(this, _scope, _binder);

            _scope.Run(() =>
            {
                _global = new JsBinding(_scope, _binder, _interop, JavaScriptValue.GlobalObject);
            });
        }
        public void Does_parse_linq_examples()
        {
            ConditionExpression expr;
            var it = new JsBinding("it");

            "it < 5".ParseConditionExpression(out expr);
            Assert.That(expr,
                        Is.EqualTo(new BinaryExpression(it, JsLessThan.Operand, new JsConstant(5))));

            "it.UnitsInStock > 0 and it.UnitPrice > 3".ParseConditionExpression(out expr);
            Assert.That(expr, Is.EqualTo(
                            new AndExpression(
                                new BinaryExpression(new JsExpression("it.UnitsInStock"), JsGreaterThan.Operand, new JsConstant(0)),
                                new BinaryExpression(new JsExpression("it.UnitPrice"), JsGreaterThan.Operand, new JsConstant(3))
                                )
                            ));
        }
Exemplo n.º 4
0
        /// <summary>
        /// Creates a new <see cref="JsModule"/> instance.
        /// </summary>
        public JsModule(JsContextScope scope, JsBinder binder, JsInterop interop, string moduleId)
        {
            _scope   = scope;
            _binder  = binder;
            _interop = interop;

            ModuleId = moduleId;

            // Create JS Representation
            Module = _scope.Run(() =>
            {
                var jsValue = JavaScriptValue.CreateObject();
                jsValue.AddRef();

                return(new JsBinding(_scope, _binder, _interop, jsValue));
            });
        }
Exemplo n.º 5
0
        private static Expression CreateStringIndexExpression(Expression body, JsBinding binding, ParameterExpression scope,
                                                              Expression valueExpr, ref Type currType)
        {
            body     = Expression.Call(body, typeof(string).GetMethod("ToCharArray", Type.EmptyTypes));
            currType = typeof(char[]);

            if (binding != null)
            {
                var evalAsInt = typeof(TemplatePageUtils).GetStaticMethod(nameof(EvaluateBindingAs))
                                .MakeGenericMethod(typeof(int));
                body = Expression.ArrayIndex(body, Expression.Call(evalAsInt, scope, Expression.Constant(binding)));
            }
            else
            {
                body = Expression.ArrayIndex(body, valueExpr);
            }
            return(body);
        }
Exemplo n.º 6
0
        /// <inheritdoc/>
        public T GetExportedValue <T>(string name)
        {
            return(_scope.Run(() =>
            {
                if (null == _exports)
                {
                    if (!Module.HasValue("exports"))
                    {
                        return default(T);
                    }

                    var exports = Module.GetValue("exports");
                    _exports = new JsBinding(_scope, _binder, _interop, exports);
                }

                return _exports.GetValue <T>(name);
            }));
        }
Exemplo n.º 7
0
        public void Does_parse_not_unary_expression()
        {
            ConditionExpression expr;
            var it = new JsBinding("it");

            "!it".ParseConditionExpression(out expr);
            Assert.That(expr,
                        Is.EqualTo(new BinaryExpression(
                                       new UnaryExpression(JsNot.Operator, it),
                                       JsEquals.Operand,
                                       JsConstant.True)));

            "!contains(items, it)".ParseConditionExpression(out expr);
            Assert.That(expr,
                        Is.EqualTo(new BinaryExpression(
                                       new UnaryExpression(JsNot.Operator,
                                                           new JsExpression("contains")
            {
                Args = { "items".ToStringSegment(), "it".ToStringSegment() }
            }),
                                       JsEquals.Operand,
                                       JsConstant.True)));
        }
Exemplo n.º 8
0
        public static StringSegment ParseNextToken(this StringSegment literal, out object value, out JsBinding binding, bool allowWhitespaceSyntax)
        {
            binding = null;
            value   = null;
            var c = (char)0;

            if (literal.IsNullOrEmpty())
            {
                return(TypeConstants.EmptyStringSegment);
            }

            var i = 0;

            literal = literal.AdvancePastWhitespace();

            var firstChar = literal.GetChar(0);

            if (firstChar == '\'' || firstChar == '"' || firstChar == '`')
            {
                i = 1;
                var hasEscapeChar = false;
                while (i < literal.Length && ((c = literal.GetChar(i)) != firstChar || literal.GetChar(i - 1) == '\\'))
                {
                    i++;
                    if (!hasEscapeChar)
                    {
                        hasEscapeChar = c == '\\';
                    }
                }

                if (i >= literal.Length || literal.GetChar(i) != firstChar)
                {
                    throw new ArgumentException($"Unterminated string literal: {literal}");
                }

                var str = literal.Substring(1, i - 1);
                value = str;

                if (hasEscapeChar)
                {
                    var sb = StringBuilderCache.Allocate();
                    for (var j = 0; j < str.Length; j++)
                    {
                        // strip the back-slash used to escape quote char in strings
                        var ch = str[j];
                        if (ch != '\\' || (j + 1 >= str.Length || str[j + 1] != firstChar))
                        {
                            sb.Append(ch);
                        }
                    }
                    value = StringBuilderCache.ReturnAndFree(sb);
                }

                return(literal.Advance(i + 1));
            }
            if (firstChar >= '0' && firstChar <= '9' || (literal.Length >= 2 && (firstChar == '-' || firstChar == '+') && literal.GetChar(1).IsNumericChar()))
            {
                i = 1;
                var hasExponent = false;
                var hasDecimal  = false;

                while (i < literal.Length && IsNumericChar(c = literal.GetChar(i)) ||
                       (hasExponent = (c == 'e' || c == 'E')))
                {
                    if (c == '.')
                    {
                        hasDecimal = true;
                    }

                    i++;

                    if (hasExponent)
                    {
                        i += 2; // [e+1]0

                        while (i < literal.Length && IsNumericChar(literal.GetChar(i)))
                        {
                            i++;
                        }

                        break;
                    }
                }

                var numLiteral = literal.Subsegment(0, i);

                //don't convert into ternary to avoid Type coercion
                if (hasDecimal || hasExponent)
                {
                    value = numLiteral.TryParseDouble(out double d) ? d : default(double);
                }
                else
                {
                    value = numLiteral.ParseSignedInteger();
                }

                return(literal.Advance(i));
            }
            if (firstChar == '{')
            {
                var map = new Dictionary <string, object>();

                literal = literal.Advance(1);
                while (!literal.IsNullOrEmpty())
                {
                    literal = literal.AdvancePastWhitespace();
                    if (literal.GetChar(0) == '}')
                    {
                        literal = literal.Advance(1);
                        break;
                    }

                    literal = literal.ParseNextToken(out object mapKeyString, out JsBinding mapKeyVar);

                    if (mapKeyVar is JsExpression)
                    {
                        throw new NotSupportedException($"JsExpression '{mapKeyVar?.Binding}' is not a valid Object key.");
                    }

                    var mapKey = mapKeyVar != null
                        ? mapKeyVar.Binding.Value
                        : (string)mapKeyString;

                    if (mapKey != null)
                    {
                        literal = literal.AdvancePastWhitespace();
                        if (literal.Length > 0 && literal.GetChar(0) == ':')
                        {
                            literal     = literal.Advance(1);
                            literal     = literal.ParseNextToken(out object mapValue, out JsBinding mapValueBinding);
                            map[mapKey] = mapValue ?? mapValueBinding;
                        }
                        else //shorthand notation
                        {
                            if (literal.Length == 0 || (c = literal.GetChar(0)) != ',' && c != '}')
                            {
                                throw new ArgumentException($"Unterminated object literal near: {literal.SubstringWithElipsis(0, 50)}");
                            }

                            map[mapKey] = new JsBinding(mapKey);
                        }
                    }

                    literal = literal.AdvancePastWhitespace();
                    if (literal.IsNullOrEmpty())
                    {
                        break;
                    }

                    if (literal.GetChar(0) == '}')
                    {
                        literal = literal.Advance(1);
                        break;
                    }

                    literal = literal.AdvancePastChar(',');
                    literal = literal.AdvancePastWhitespace();
                }

                value = map;
                return(literal);
            }
            if (firstChar == '[')
            {
                var list = new List <object>();

                literal = literal.Advance(1);
                while (!literal.IsNullOrEmpty())
                {
                    literal = literal.AdvancePastWhitespace();
                    if (literal.GetChar(0) == ']')
                    {
                        literal = literal.Advance(1);
                        break;
                    }

                    literal = literal.ParseNextToken(out object mapValue, out JsBinding mapVarRef);
                    list.Add(mapVarRef ?? mapValue);

                    literal = literal.AdvancePastWhitespace();
                    if (literal.IsNullOrEmpty())
                    {
                        break;
                    }

                    if (literal.GetChar(0) == ']')
                    {
                        literal = literal.Advance(1);
                        break;
                    }

                    literal = literal.AdvancePastWhitespace();
                    c       = literal.GetChar(0);
                    if (c == ']')
                    {
                        literal = literal.Advance(1);
                        break;
                    }

                    if (c != ',')
                    {
                        throw new ArgumentException($"Unterminated array literal near: {literal.SubstringWithElipsis(0, 50)}");
                    }

                    literal = literal.Advance(1);
                    literal = literal.AdvancePastWhitespace();
                }

                literal = literal.AdvancePastWhitespace();

                value = list;
                return(literal);
            }
            if (literal.StartsWith("true") && (literal.Length == 4 || !IsValidVarNameChar(literal.GetChar(4))))
            {
                value = true;
                return(literal.Advance(4));
            }
            if (literal.StartsWith("false") && (literal.Length == 5 || !IsValidVarNameChar(literal.GetChar(5))))
            {
                value = false;
                return(literal.Advance(5));
            }
            if (literal.StartsWith("null") && (literal.Length == 4 || !IsValidVarNameChar(literal.GetChar(4))))
            {
                value = JsNull.Value;
                return(literal.Advance(4));
            }
            if (firstChar.IsOperatorChar())
            {
                if (literal.StartsWith(">="))
                {
                    binding = JsGreaterThanEqual.Operand;
                    return(literal.Advance(2));
                }
                if (literal.StartsWith("<="))
                {
                    binding = JsLessThanEqual.Operand;
                    return(literal.Advance(2));
                }
                if (literal.StartsWith("!=="))
                {
                    binding = JsStrictNotEquals.Operand;
                    return(literal.Advance(3));
                }
                if (literal.StartsWith("!="))
                {
                    binding = JsNotEquals.Operand;
                    return(literal.Advance(2));
                }
                if (literal.StartsWith("==="))
                {
                    binding = JsStrictEquals.Operand;
                    return(literal.Advance(3));
                }
                if (literal.StartsWith("=="))
                {
                    binding = JsEquals.Operand;
                    return(literal.Advance(2));
                }
                if (literal.StartsWith("||"))
                {
                    binding = JsOr.Operator;
                    return(literal.Advance(2));
                }
                if (literal.StartsWith("&&"))
                {
                    binding = JsAnd.Operator;
                    return(literal.Advance(2));
                }

                switch (firstChar)
                {
                case '>':
                    binding = JsGreaterThan.Operand;
                    return(literal.Advance(1));

                case '<':
                    binding = JsLessThan.Operand;
                    return(literal.Advance(1));

                case '=':
                    binding = JsAssignment.Operator;
                    return(literal.Advance(1));

                case '!':
                    binding = JsNot.Operator;
                    return(literal.Advance(1));

                case '+':
                    binding = JsAddition.Operator;
                    return(literal.Advance(1));

                case '-':
                    binding = JsSubtraction.Operator;
                    return(literal.Advance(1));

                case '*':
                    binding = JsMultiplication.Operator;
                    return(literal.Advance(1));

                case '\\':
                    binding = JsDivision.Operator;
                    return(literal.Advance(1));

                case '|':
                    binding = JsBitwiseOr.Operator;
                    return(literal.Advance(1));

                case '&':
                    binding = JsBitwiseAnd.Operator;
                    return(literal.Advance(1));

                default:
                    throw new NotSupportedException($"Invalid Operator found near: '{literal.SubstringWithElipsis(0, 50)}'");
                }
            }

            // name
            i = 1;
            var isExpression  = false;
            var hadWhitespace = false;

            while (i < literal.Length && IsValidVarNameChar(c = literal.GetChar(i)) ||
                   (isExpression = c.IsBindingExpressionChar() || (allowWhitespaceSyntax && c == ':')))
            {
                if (isExpression)
                {
                    literal = literal.ParseNextExpression(out JsExpression expr);
                    binding = expr;
                    return(literal);
                }

                i++;

                while (i < literal.Length && literal.GetChar(i).IsWhiteSpace()) // advance past whitespace
                {
                    i++;
                    hadWhitespace = true;
                }

                if (hadWhitespace && (i >= literal.Length || !literal.GetChar(i).IsBindingExpressionChar()))
                {
                    break;
                }
            }

            binding = new JsBinding(literal.Subsegment(0, i).TrimEnd());
            return(literal.Advance(i));
        }
Exemplo n.º 9
0
 public static StringSegment ParseNextToken(this StringSegment literal, out object value, out JsBinding binding) => ParseNextToken(literal, out value, out binding, false);
Exemplo n.º 10
0
 public static JsUnaryOperator GetUnaryOperator(JsBinding op) =>
 (JsUnaryOperator)(
     op == JsSubtraction.Operator
         ? JsMinus.Operator
         : op == JsNot.Operator
         ? op : null);
Exemplo n.º 11
0
        public static object EvaluateBinding(TemplateScopeContext scope, JsBinding binding)
        {
            var result = scope.EvaluateToken(binding);

            return(result);
        }
Exemplo n.º 12
0
 public static JsUnaryOperator GetUnaryOperator(JsBinding op) =>
 op == JsSubtraction.Operator ? JsMinus.Operator : null;
Exemplo n.º 13
0
        public static StringSegment ParseNextToken(this StringSegment literal, out object value, out JsBinding binding)
        {
            binding = null;
            value   = null;
            var c = (char)0;

            if (literal.IsNullOrEmpty())
            {
                return(TypeConstants.EmptyStringSegment);
            }

            var i = 0;

            literal = literal.AdvancePastWhitespace();

            var firstChar = literal.GetChar(0);

            if (firstChar == '\'' || firstChar == '"')
            {
                i = 1;
                while (i < literal.Length && (literal.GetChar(i) != firstChar || literal.GetChar(i - 1) == '\\'))
                {
                    i++;
                }

                if (i >= literal.Length || literal.GetChar(i) != firstChar)
                {
                    throw new ArgumentException($"Unterminated string literal: {literal}");
                }

                value = literal.Substring(1, i - 1);
                return(literal.Advance(i));
            }
            if (firstChar >= '0' && firstChar <= '9' || firstChar == '-' || firstChar == '+')
            {
                i = 1;
                var hasExponent = false;
                var hasDecimal  = false;

                while (i < literal.Length && IsValidNumericChar(c = literal.GetChar(i)) ||
                       (hasExponent = (c == 'e' || c == 'E')))
                {
                    if (c == '.')
                    {
                        hasDecimal = true;
                    }

                    i++;

                    if (hasExponent)
                    {
                        i += 2; // [e+1]0

                        while (i < literal.Length && IsValidNumericChar(literal.GetChar(i)))
                        {
                            i++;
                        }

                        break;
                    }
                }

                var numLiteral = literal.Subsegment(0, i);

                //don't convert into ternary to avoid Type coercion
                if (hasDecimal || hasExponent)
                {
                    value = numLiteral.TryParseDouble(out double d) ? d : default(double);
                }
                else
                {
                    value = numLiteral.ParseSignedInteger();
                }

                return(literal.Advance(i));
            }
            if (firstChar == '{')
            {
                var map = new Dictionary <string, object>();

                literal = literal.Advance(1);
                while (!literal.IsNullOrEmpty())
                {
                    literal = literal.ParseNextToken(out object mapKeyString, out JsBinding mapKeyVar);

                    if (mapKeyVar is JsExpression)
                    {
                        throw new NotSupportedException($"JsExpression '{mapKeyVar?.Binding}' is not a valid Object key.");
                    }

                    var mapKey = mapKeyVar != null
                        ? mapKeyVar.Binding.Value
                        : (string)mapKeyString;

                    if (mapKey != null)
                    {
                        literal     = literal.AdvancePastChar(':');
                        literal     = literal.ParseNextToken(out object mapValue, out JsBinding mapValueBinding);
                        map[mapKey] = mapValue ?? mapValueBinding;
                    }

                    literal = literal.AdvancePastWhitespace();
                    if (literal.IsNullOrEmpty())
                    {
                        break;
                    }

                    if (literal.GetChar(0) == '}')
                    {
                        literal = literal.Advance(1);
                        break;
                    }

                    literal = literal.AdvancePastChar(',');
                    literal = literal.AdvancePastWhitespace();
                }

                value = map;
                return(literal);
            }
            if (firstChar == '[')
            {
                var list = new List <object>();

                literal = literal.Advance(1);
                while (!literal.IsNullOrEmpty() && literal.GetChar(0) != ']')
                {
                    literal = literal.ParseNextToken(out object mapValue, out JsBinding mapVarRef);
                    list.Add(mapVarRef ?? mapValue);

                    literal = literal.AdvancePastWhitespace();
                    if (literal.IsNullOrEmpty())
                    {
                        break;
                    }

                    if (literal.GetChar(0) == ']')
                    {
                        literal = literal.Advance(1);
                        break;
                    }

                    literal = literal.AdvancePastChar(',');
                    literal = literal.AdvancePastWhitespace();
                }

                value = list;
                return(literal);
            }
            if (literal.StartsWith("true") && (literal.Length == 4 || !IsValidVarNameChar(literal.GetChar(4))))
            {
                value = true;
                return(literal.Advance(4));
            }
            if (literal.StartsWith("false") && (literal.Length == 5 || !IsValidVarNameChar(literal.GetChar(5))))
            {
                value = false;
                return(literal.Advance(5));
            }
            if (literal.StartsWith("null") && (literal.Length == 4 || !IsValidVarNameChar(literal.GetChar(4))))
            {
                value = JsNull.Value;
                return(literal.Advance(4));
            }

            // name
            i = 1;
            var isExpression = false;

            while (i < literal.Length && IsValidVarNameChar(c = literal.GetChar(i)) ||
                   (isExpression = (c == '.' || c == '(' || c == '[')))
            {
                if (isExpression)
                {
                    binding = literal.ParseJsExpression(out int pos).FirstOrDefault();
                    return(literal.Advance(pos));
                }

                i++;

                while (i < literal.Length && literal.GetChar(i).IsWhiteSpace()) // advance past whitespace
                {
                    i++;
                }
            }

            binding = new JsBinding(literal.Subsegment(0, i).TrimEnd());
            return(literal.Advance(i));
        }