Пример #1
0
 protected ScriptVariable(string name, ScriptVariableScope scope)
 {
     Name  = name;
     Scope = scope;
     unchecked {
         _hashCode = (Name.GetHashCode() * 397) ^ (int)Scope;
     }
 }
Пример #2
0
        private void PushVariableScope(ScriptVariableScope scope)
        {
            Debug.Assert(scope != ScriptVariableScope.Global);
            var store = _availableStores.Count > 0 ? _availableStores.Pop() : new ScriptObject();

            if (scope == ScriptVariableScope.Local)
            {
                PushLocalContext(store);
            }
            else
            {
                _currentLocalContext.Loops.Push(store);
            }
        }
Пример #3
0
        public static ScriptVariable Create(string name, ScriptVariableScope scope)
        {
            switch (scope)
            {
            case ScriptVariableScope.Global:
                return(new ScriptVariableGlobal(name));

            case ScriptVariableScope.Local:
                return(new ScriptVariableLocal(name));

            default:
                throw new InvalidOperationException($"Scope `{scope}` is not supported");
            }
        }
Пример #4
0
        /// <summary>
        /// Push a new <see cref="ScriptVariableScope"/> for variables
        /// </summary>
        /// <param name="scope"></param>
        internal void PushVariableScope(ScriptVariableScope scope)
        {
            var store = _availableStores.Count > 0 ? _availableStores.Pop() : new ScriptObject();
            var tags  = _availableTags.Count > 0 ? _availableTags.Pop() : new Dictionary <object, object>();

            if (scope == ScriptVariableScope.Local)
            {
                _localStores.Push(store);
                _localTagsStack.Push(tags);
            }
            else
            {
                _loopStores.Push(store);
                _loopTagsStack.Push(tags);
            }
        }
Пример #5
0
        /// <summary>
        /// Pops a previous <see cref="ScriptVariableScope"/>.
        /// </summary>
        /// <param name="scope"></param>
        internal void PopVariableScope(ScriptVariableScope scope)
        {
            var stores = (scope == ScriptVariableScope.Local ? _localStores : _loopStores);

            if (stores.Count == 0)
            {
                // Should not happen at runtime
                throw new InvalidOperationException("Invalid number of matching push/pop VariableScope.");
            }

            var store = stores.Pop();

            // The store is cleanup once it is pushed back
            store.Clear();

            _availableStores.Push(store);
        }
Пример #6
0
        /// <summary>
        /// Creates a <see cref="ScriptVariable"/> according to the specified name and <see cref="ScriptVariableScope"/>
        /// </summary>
        /// <param name="name">Name of the variable</param>
        /// <param name="scope">Scope of the variable</param>
        /// <returns>The script variable</returns>
        public static ScriptVariable Create(string name, ScriptVariableScope scope)
        {
            switch (scope)
            {
            case ScriptVariableScope.Global:
                return(new ScriptVariableGlobal(name));

            case ScriptVariableScope.Local:
                return(new ScriptVariableLocal(name));

            case ScriptVariableScope.Loop:
                return(new ScriptVariableLoop(name));

            default:
                throw new InvalidOperationException(string.Format(RS.UnsupportedScope, scope));
            }
        }
Пример #7
0
        /// <summary>
        /// Pops a previous <see cref="ScriptVariableScope"/>.
        /// </summary>
        /// <param name="scope"></param>
        internal void PopVariableScope(ScriptVariableScope scope)
        {
            Dictionary <object, object> tags;

            if (scope == ScriptVariableScope.Local)
            {
                PopVariableScope(ref _localStores);
                tags = _localTagsStack.Pop();
            }
            else
            {
                PopVariableScope(ref _loopStores);
                tags = _loopTagsStack.Pop();
            }
            // Make sure that tags are clear
            tags.Clear();
            _availableTags.Push(tags);
        }
Пример #8
0
        protected ScriptVariable(string name, ScriptVariableScope scope)
        {
            BaseName = name;
            Scope    = scope;
            switch (scope)
            {
            case ScriptVariableScope.Global:
                Name = name;
                break;

            case ScriptVariableScope.Local:
                Name = $"${name}";
                break;
            }
            unchecked
            {
                _hashCode = (BaseName.GetHashCode() * 397) ^ (int)Scope;
            }
        }
Пример #9
0
        /// <summary>
        /// Returns the list of <see cref="ScriptObject"/> depending on the scope of the variable.
        /// </summary>
        /// <param name="variable"></param>
        /// <exception cref="NotImplementedException"></exception>
        /// <returns>The list of script objects valid for the specified variable scope</returns>
        private IEnumerable <IScriptObject> GetStoreForSet(ScriptVariable variable)
        {
            ScriptVariableScope scope = variable.Scope;

            switch (scope)
            {
            case ScriptVariableScope.Global:
                for (int i = _globalStores.Count - 1; i >= 0; i--)
                {
                    yield return(_globalStores.Items[i]);
                }
                break;

            case ScriptVariableScope.Local:
                if (_localStores.Count > 0)
                {
                    yield return(_localStores.Peek());
                }
                else
                {
                    throw new ScriptRuntimeException(variable.Span, string.Format(RS.InvalidLocalVariableInContext, variable));
                }

                break;

            case ScriptVariableScope.Loop:
                if (_loopStores.Count > 0)
                {
                    yield return(_loopStores.Peek());
                }
                else
                {
                    // unit test: 215-for-special-var-error1.txt
                    throw new ScriptRuntimeException(variable.Span, string.Format(RS.InvalidLoopVariableOutsideLoop, variable));
                }
                break;

            default:
                throw new NotImplementedException(string.Format(RS.InvalidVariableScope, scope));
            }
        }
Пример #10
0
        private void PopVariableScope(ScriptVariableScope scope)
        {
            Debug.Assert(scope != ScriptVariableScope.Global);
            if (scope == ScriptVariableScope.Local)
            {
                var local = PopLocalContext();
                local.Clear();
                _availableStores.Push(local);
            }
            else
            {
                if (_currentLocalContext.Loops.Count == 0)
                {
                    // Should not happen at runtime
                    throw new InvalidOperationException("Invalid number of matching push/pop VariableScope.");
                }

                var store = _currentLocalContext.Loops.Pop();
                // The store is cleanup once it is pushed back
                store.Clear();

                _availableStores.Push(store);
            }
        }
Пример #11
0
        private static void ParseHeaderNodeDefNode(ScriptProgram program, ScriptNode root, TokenStream stream)
        {
            string              variablename  = "";
            string              defaultValue  = ""; // To be converted later
            Guid                variableId    = Guid.Empty;
            ScriptVariableType  variableType  = ScriptVariableType.Unknown;
            ScriptVariableScope variableScope = ScriptVariableScope.Unknown;

            var parameter = stream.Pop();

            while (parameter.TokenType == SemanticTokenType.NodeParameter)
            {
                //var argumentValue = stream.Pop();
                if (parameter.TokenValue == "name:")
                {
                    var value = stream.Pop();
                    variablename = value.TokenValue;
                }
                else if (parameter.TokenValue == "type:")
                {
                    var value = stream.Pop();
                    if (value.TokenValue == "flag")
                    {
                        variableType = ScriptVariableType.Flag;
                    }
                    else if (value.TokenValue == "int")
                    {
                        variableType = ScriptVariableType.Integer;
                    }
                    else
                    {
                        throw new Exception("Unsupported variable type:" + value.TokenValue);
                    }
                }
                else if (parameter.TokenValue == "scope:")
                {
                    var value = stream.Pop();
                    if (value.TokenValue == "global")
                    {
                        variableScope = ScriptVariableScope.Global;
                    }
                    else if (value.TokenValue == "local")
                    {
                        variableScope = ScriptVariableScope.Local;
                    }
                    else
                    {
                        throw new Exception("Unsupported scope:" + value);
                    }
                }
                else if (parameter.TokenValue == "default:")
                {
                    var value = stream.Pop();
                    defaultValue = value.TokenValue;
                }
                else
                {
                    throw new Exception("Unknown parameter:" + parameter.TokenValue);
                }


                var nexttype = stream.GetCurrent().TokenType;
                if (nexttype != SemanticTokenType.NodeParameter)
                {
                    break;
                }
                parameter = stream.Pop();
            }

            // TODO Look up guid properly
            Console.WriteLine("TODO Look up guid for variable name");
            if (variableId == Guid.Empty)
            {
                variableId = Guid.NewGuid();
            }

            switch (variableType)
            {
            case ScriptVariableType.Integer:
            {
                var value = int.Parse(defaultValue);
                if (variableScope == ScriptVariableScope.Global)
                {
                    program.GlobalVariables.AddVariable(variableId, variableType, value, variablename);
                }
                else if (variableScope == ScriptVariableScope.Local)
                {
                    root.LocalVariables.AddVariable(variableId, variableType, value, variablename);
                }
                break;
            }

            case ScriptVariableType.Flag:
            {
                var value = bool.Parse(defaultValue);
                if (variableScope == ScriptVariableScope.Global)
                {
                    program.GlobalVariables.AddVariable(variableId, variableType, value, variablename);
                }
                else if (variableScope == ScriptVariableScope.Local)
                {
                    root.LocalVariables.AddVariable(variableId, variableType, value, variablename);
                }
                else
                {
                    throw new Exception("Unsupported Variable");
                }
                break;
            }

            default:
                throw new Exception("Unsupported VariableType:" + variableType);
            }
        }
Пример #12
0
        /// <summary>
        /// Push a new <see cref="ScriptVariableScope"/> for variables
        /// </summary>
        /// <param name="scope"></param>
        internal void PushVariableScope(ScriptVariableScope scope)
        {
            var store = _availableStores.Count > 0 ? _availableStores.Pop() : new ScriptObject();

            (scope == ScriptVariableScope.Local ? _localStores : _loopStores).Push(store);
        }
Пример #13
0
        private ScriptExpression ParseVariable()
        {
            Token      currentToken = Current;
            SourceSpan currentSpan  = CurrentSpan;
            SourceSpan endSpan      = currentSpan;
            string     text         = GetAsText(currentToken);

            // Return ScriptLiteral for null, true, false
            // Return ScriptAnonymousFunction
            switch (text)
            {
            case "null":
                ScriptLiteral nullValue = Open <ScriptLiteral>();
                NextToken();
                return(Close(nullValue));

            case "true":
                ScriptLiteral trueValue = Open <ScriptLiteral>();
                trueValue.Value = true;
                NextToken();
                return(Close(trueValue));

            case "false":
                ScriptLiteral falseValue = Open <ScriptLiteral>();
                falseValue.Value = false;
                NextToken();
                return(Close(falseValue));

            case "do":
                ScriptAnonymousFunction functionExp = Open <ScriptAnonymousFunction>();
                functionExp.Function = ParseFunctionStatement(true);
                ScriptAnonymousFunction func = Close(functionExp);
                return(func);

            case "this":
                if (!_isLiquid)
                {
                    ScriptThisExpression thisExp = Open <ScriptThisExpression>();
                    NextToken();
                    return(Close(thisExp));
                }
                break;
            }

            // Keeps trivia before this token
            List <ScriptTrivia> triviasBefore = null;

            if (_isKeepTrivia && _trivias.Count > 0)
            {
                triviasBefore = new List <ScriptTrivia>();
                triviasBefore.AddRange(_trivias);
                _trivias.Clear();
            }

            NextToken();
            ScriptVariableScope scope = ScriptVariableScope.Global;

            if (text.StartsWith("$"))
            {
                scope = ScriptVariableScope.Local;
                text  = text.Substring(1);

                // Convert $0, $1... $n variable into $[0] $[1]...$[n] variables
                int index;
                if (int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out index))
                {
                    ScriptIndexerExpression indexerExpression = new ScriptIndexerExpression
                    {
                        Span = currentSpan,

                        Target = new ScriptVariableLocal(ScriptVariable.Arguments.Name)
                        {
                            Span = currentSpan
                        },

                        Index = new ScriptLiteral()
                        {
                            Span = currentSpan, Value = index
                        }
                    };

                    if (_isKeepTrivia)
                    {
                        if (triviasBefore != null)
                        {
                            indexerExpression.Target.AddTrivias(triviasBefore, true);
                        }

                        FlushTrivias(indexerExpression.Index, false);
                    }

                    return(indexerExpression);
                }
            }
            else if (text == "for" || text == "while" || text == "tablerow" || (_isLiquid && (text == "forloop" || text == "tablerowloop")))
            {
                if (Current.Type == TokenType.Dot)
                {
                    NextToken();
                    if (Current.Type == TokenType.Identifier)
                    {
                        endSpan = CurrentSpan;
                        string loopVariableText = GetAsText(Current);
                        NextToken();

                        scope = ScriptVariableScope.Loop;
                        if (_isLiquid)
                        {
                            switch (loopVariableText)
                            {
                            case "first":
                                text = ScriptVariable.LoopFirst.Name;
                                break;

                            case "last":
                                text = ScriptVariable.LoopLast.Name;
                                break;

                            case "index0":
                                text = ScriptVariable.LoopIndex.Name;
                                break;

                            case "rindex0":
                                text = ScriptVariable.LoopRIndex.Name;
                                break;

                            case "rindex":
                            case "index":
                                // Because forloop.index is 1 based index, we need to create a binary expression
                                // to support it here
                                bool isrindex = loopVariableText == "rindex";

                                ScriptNestedExpression nested = new ScriptNestedExpression()
                                {
                                    Expression = new ScriptBinaryExpression()
                                    {
                                        Operator = ScriptBinaryOperator.Add,
                                        Left     = new ScriptVariableLoop(isrindex ? ScriptVariable.LoopRIndex.Name : ScriptVariable.LoopIndex.Name)
                                        {
                                            Span = currentSpan
                                        },
                                        Right = new ScriptLiteral(1)
                                        {
                                            Span = currentSpan
                                        },
                                        Span = currentSpan
                                    },
                                    Span = currentSpan
                                };

                                if (_isKeepTrivia)
                                {
                                    if (triviasBefore != null)
                                    {
                                        nested.AddTrivias(triviasBefore, true);
                                    }

                                    FlushTrivias(nested, false);
                                }
                                return(nested);

                            case "length":
                                text = ScriptVariable.LoopLength.Name;
                                break;

                            case "col":
                                if (text != "tablerowloop")
                                {
                                    // unit test: 108-variable-loop-error2.txt
                                    LogError(currentToken, string.Format(RS.InvalidLoopVariable, text + ".col"));
                                }
                                text = ScriptVariable.TableRowCol.Name;
                                break;

                            default:
                                text = text + "." + loopVariableText;
                                LogError(currentToken, string.Format(RS.InvalidLiquidLoopVariable, text));
                                break;
                            }
                        }
                        else
                        {
                            switch (loopVariableText)
                            {
                            case "first":
                                text = ScriptVariable.LoopFirst.Name;
                                break;

                            case "last":
                                if (text == "while")
                                {
                                    // unit test: 108-variable-loop-error2.txt
                                    LogError(currentToken, string.Format(RS.InvalidLoopVariable, "while.last"));
                                }
                                text = ScriptVariable.LoopLast.Name;
                                break;

                            case "changed":
                                if (text == "while")
                                {
                                    // unit test: 108-variable-loop-error2.txt
                                    LogError(currentToken, string.Format(RS.InvalidLoopVariable, "while.changed"));
                                }
                                text = ScriptVariable.LoopChanged.Name;
                                break;

                            case "length":
                                if (text == "while")
                                {
                                    // unit test: 108-variable-loop-error2.txt
                                    LogError(currentToken, string.Format(RS.InvalidLoopVariable, "while.length"));
                                }
                                text = ScriptVariable.LoopLength.Name;
                                break;

                            case "even":
                                text = ScriptVariable.LoopEven.Name;
                                break;

                            case "odd":
                                text = ScriptVariable.LoopOdd.Name;
                                break;

                            case "index":
                                text = ScriptVariable.LoopIndex.Name;
                                break;

                            case "rindex":
                                if (text == "while")
                                {
                                    // unit test: 108-variable-loop-error2.txt
                                    LogError(currentToken, string.Format(RS.InvalidLoopVariable, "while.rindex"));
                                }
                                text = ScriptVariable.LoopRIndex.Name;
                                break;

                            case "col":
                                if (text != "tablerow")
                                {
                                    // unit test: 108-variable-loop-error2.txt
                                    LogError(currentToken, string.Format(RS.InvalidLoopVariable, text + ".col"));
                                }
                                text = ScriptVariable.TableRowCol.Name;
                                break;

                            default:
                                text = text + "." + loopVariableText;
                                // unit test: 108-variable-loop-error1.txt
                                LogError(currentToken, string.Format(RS.InvalidLoopVariable, text));
                                break;
                            }
                        }

                        // We no longer checks at parse time usage of loop variables, as they can be used in a wrap context
                        //if (!IsInLoop())
                        //{
                        //    LogError(currentToken, string.Format(RS.InvalidLoopVariableOutsideLoop, text));
                        //}
                    }
                    else
                    {
                        LogError(currentToken, string.Format(RS.LoopVariableDotRequireIdentifier, Current.Type, text));
                    }
                }
            }
            else if (_isLiquid && text == "continue")
            {
                scope = ScriptVariableScope.Local;
            }

            ScriptVariable result = ScriptVariable.Create(text, scope);

            result.Span = new SourceSpan
            {
                FileName = currentSpan.FileName,
                Start    = currentSpan.Start,
                End      = endSpan.End
            };

            // A liquid variable can have `-` in its identifier
            // If this is the case, we need to translate it to `this["this"]` instead
            if (_isLiquid && text.IndexOf('-') >= 0)
            {
                ScriptIndexerExpression newExp = new ScriptIndexerExpression
                {
                    Target = new ScriptThisExpression()
                    {
                        Span = result.Span
                    },
                    Index = new ScriptLiteral(text)
                    {
                        Span = result.Span
                    },
                    Span = result.Span
                };

                // Flush any trivias after
                if (_isKeepTrivia)
                {
                    if (triviasBefore != null)
                    {
                        newExp.Target.AddTrivias(triviasBefore, true);
                    }

                    FlushTrivias(newExp, false);
                }
                // Return the expression
                return(newExp);
            }

            if (_isKeepTrivia)
            {
                // Flush any trivias after
                if (triviasBefore != null)
                {
                    result.AddTrivias(triviasBefore, true);
                }


                FlushTrivias(result, false);
            }
            return(result);
        }
Пример #14
0
        internal void PopVariableScope(ScriptVariableScope scope)
        {
            var stores = (scope == ScriptVariableScope.Local ? localStores : loopStores);
            if (stores.Count == 0)
            {
                // Should not happen at runtime
                throw new InvalidOperationException("Invalid number of matching push/pop VariableScope.");
            }

            var store = stores.Pop();
            // The store is cleanup once it is pushed back
            store.Clear();

            availableStores.Push(store);
        }
Пример #15
0
 internal void PushVariableScope(ScriptVariableScope scope)
 {
     var store = availableStores.Count > 0 ? availableStores.Pop() : new ScriptObject();
     (scope == ScriptVariableScope.Local ? localStores : loopStores).Push(store);
 }