Пример #1
0
 public void Append(IOperationCollection collection)
 {
     if (collection == null)
     {
         throw new ArgumentNullException("collection");
     }
     if (collection is OperationCollection)
     {
         var c = (OperationCollection)collection;
         if (this._count == 0)
         {
             this._first = c._first;
             this._last  = c._last;
             this._count = c._count;
         }
         else if (c._count != 0)
         {
             this._last.Next = c._first;
             c._first.Prev   = this._last;
             this._last      = c._last;
             this._count    += c._count;
         }
     }
     else
     {
         OperationCollection o = new OperationCollection();
         collection.ForEach(o.Append); // leave order as it is
         this.Append(o);
     }
 }
Пример #2
0
        private IOperationCollection pushGenericBinaryLeftToRightOperation(Scope scope, Func <Scope, IOperationCollection> nextLevel, Dictionary <TokenType, Func <long, IOperationCollection> > operationConverters)
        {
            // left-to-right
            IOperationCollection operations = new OperationCollection();

            // Get allowed operations
            TokenType[] allOperationTokens = operationConverters.Keys.ToArray();

            // Push first value
            operations.Append(nextLevel(scope));
            while (_iterator.Is(allOperationTokens))
            {
                var operation = _iterator.Current.Type;
                var position  = _iterator.Position;
                _iterator.Next();

                // Push next value ...
                operations.Append(nextLevel(scope));

                // ... and the operation
                operations.Append(operationConverters[operation](position));
            }

            return(operations);
        }
Пример #3
0
        private IOperationCollection pushScopeBlock(Scope scope, bool forceScoping)
        {
            if (_iterator.Is(TokenType.CurlyBracketLeft))
            {
                IOperationCollection operations = new OperationCollection();
                operations.Append(new SimpleOperation(OperationType.BeginScope, _iterator.Position));

                _iterator.Next();

                while (!_iterator.Is(TokenType.CurlyBracketRight))
                {
                    operations.Append(pushScopeBlock(scope, false));
                }

                operations.Append(new SimpleOperation(OperationType.EndScope, _iterator.Position));

                _iterator.Next();
                return(operations);
            }
            else
            {
                IOperationCollection operations = new OperationCollection();
                if (forceScoping)
                {
                    operations.Append(new SimpleOperation(OperationType.BeginScope, -1));
                }
                operations.Append(pushLoop(scope));
                if (forceScoping)
                {
                    operations.Append(new SimpleOperation(OperationType.EndScope, -1));
                }
                return(operations);
            }
        }
Пример #4
0
        private IOperationCollection pushTerminatedInstruction_return(Scope scope)
        {
            long positionReturn = _iterator.Position;

            _iterator.Next();

            // Read what shall be returned
            IOperationCollection operations;

            if (_iterator.Is(TokenType.EndOfInstruction))
            {
                operations = new OperationCollection();
                operations.Append(new SimpleOperation(OperationType.Return, positionReturn));
            }
            else
            {
                operations = pushAssign(scope);
                operations.Append(new SimpleOperation(OperationType.ReturnValue, positionReturn));
            }

            if (!_iterator.Is(TokenType.EndOfInstruction))
            {
                throw new SyntaxException(_iterator.Position, "Expected ';'");
            }
            _iterator.Next();

            return(operations);
        }
Пример #5
0
        private IOperationCollection pushGenericBinaryRightToLeftOperation(Scope scope, Func <Scope, IOperationCollection> nextLevel, Dictionary <TokenType, Func <long, IOperationCollection> > operationConverters)
        {
            // right-to-left
            IOperationCollection operations = new OperationCollection();

            // Get allowed operations
            TokenType[] allOperationTokens = operationConverters.Keys.ToArray();

            // Store first value
            var value = nextLevel(scope);

            // Check if there is an operation
            while (_iterator.Is(allOperationTokens))
            {
                // Push operation
                operations.Prepend(operationConverters[_iterator.Current.Type](_iterator.Position));
                _iterator.Next();

                // Push value
                operations.Prepend(value);

                // Read next value
                value = nextLevel(scope);
            }

            // Push last value
            operations.Prepend(value);

            return(operations);
        }
Пример #6
0
 public _Iterator(OperationCollection op)
 {
     _op      = op;
     _first   = op._first;
     _last    = op._last;
     _current = null;
     _state   = State.BeforeBeginning;
 }
Пример #7
0
        private IOperationCollection pushTerminatedInstruction_async(Scope scope)
        {
            long asyncPosition = _iterator.Position;

            // The syntax is 'async(name) instr;'
            _iterator.Next();
            // We expect a '('
            if (!_iterator.Is(TokenType.BracketLeft))
            {
                throw new SyntaxException(_iterator.Position, "Expected '(' after 'async'.");
            }
            _iterator.Next();
            // Read name
            IOperationCollection operations_name = pushAssign(scope);

            // We expect a ')'
            if (!_iterator.Is(TokenType.BracketRight))
            {
                throw new SyntaxException(_iterator.Position, "Expected ')' after 'async('.");
            }
            _iterator.Next();

            // Handle 'wait' instruction
            if (_iterator.Is(TokenType.Name) && _iterator.GetValue <string>() == "wait")
            {
                _iterator.Next();

                // Read expression which evaluates to the wait time
                IOperationCollection operations_waitTime = pushAssign(scope);

                if (!_iterator.Is(TokenType.EndOfInstruction))
                {
                    throw new SyntaxException(_iterator.Position, "Expected ';'");
                }
                _iterator.Next();

                IOperationCollection operations = new OperationCollection();
                operations.Append(operations_name);
                operations.Append(operations_waitTime);
                operations.Append(new SimpleOperation(OperationType.AsyncWait, asyncPosition));
                return(operations);
            }
            else
            {
                IOperationCollection operations = new OperationCollection();
                operations.Append(operations_name);
                operations.Append(new SimpleOperation(OperationType.Async, asyncPosition));
                operations.Append(pushScopeBlock(scope, true));
                return(operations);
            }
        }
Пример #8
0
        private IOperationCollection pushSingleInstruction_if(Scope scope)
        {
            long ifPosition = _iterator.Position;

            // We assume that the current token is the "if" keyword
            // Proceed to next token
            _iterator.Next();

            // 'if' must be followed by '('
            if (!_iterator.Is(TokenType.BracketLeft))
            {
                throw new SyntaxException(_iterator.Position, "Expected '(' after 'if'.");
            }
            _iterator.Next();

            // Read the condition
            IOperationCollection operations_condition = pushAssign(scope);

            // Condition must be followed by ')'
            if (!_iterator.Is(TokenType.BracketRight))
            {
                throw new SyntaxException(_iterator.Position, "Expected ')' after 'if('.");
            }
            _iterator.Next();

            // ')' must be followed by an instruction
            IOperationCollection operations_if = pushScopeBlock(scope, true);

            // Look for 'else'
            IOperationCollection operations_else;

            if (_iterator.Is(TokenType.Name) && _iterator.GetValue <string>() == "else")
            {
                _iterator.Next();
                operations_else = pushScopeBlock(scope, true);
            }
            else
            {
                operations_else = new OperationCollection();
                operations_else.Append(new SimpleOperation(OperationType.NoOperation, -1));
            }

            // Put everything together
            operations_condition.Append(new SimpleOperation(OperationType.If, ifPosition));
            operations_condition.Append(operations_if);
            operations_condition.Append(operations_else);
            return(operations_condition);
        }
Пример #9
0
        private IOperationCollection pushSingleInstruction_while(Scope scope)
        {
            IOperationCollection operations_condition;
            long whilePosition = _iterator.Position;

            // We assume that the current token is the "while" keyword
            // Proceed to next token
            _iterator.Next();

            // 'while' must be followed by '('
            if (!_iterator.Is(TokenType.BracketLeft))
            {
                throw new SyntaxException(_iterator.Position, "Expected '(' after 'while'.");
            }
            _iterator.Next();

            // Read the condition part
            if (_iterator.Is(TokenType.EndOfInstruction))
            {
                operations_condition = new OperationCollection();
            }
            else
            {
                operations_condition = pushVariableAssignment(scope);
            }

            // Condition must be followed by ')'
            if (!_iterator.Is(TokenType.BracketRight))
            {
                throw new SyntaxException(_iterator.Position, "Expected ')' after 'while('.");
            }
            _iterator.Next();

            // ')' must be followed by an instruction
            IOperationCollection operations_body = pushScopeBlock(scope, true);

            // Put everything together
            IOperationCollection operations = new OperationCollection();

            operations.Append(new SimpleOperation(OperationType.While, whilePosition));
            operations.Append(new SimpleOperation(OperationType.BeginOpBlock, -1));
            operations.Append(operations_condition);
            operations.Append(new SimpleOperation(OperationType.EndOpBlock, -1));
            operations.Append(operations_body);
            return(operations);
        }
Пример #10
0
        private IOperationCollection pushTerminatedInstruction_import(Scope scope)
        {
            long positionImport = _iterator.Position;

            _iterator.Next();

            // Read what shall be imported
            string[] importedNamespace = readNamespacePath(false).ToArray();

            if (!_iterator.Is(TokenType.EndOfInstruction))
            {
                throw new SyntaxException(_iterator.Position, "Expected ';'");
            }
            _iterator.Next();

            IOperationCollection operations = new OperationCollection();

            operations.Append(new ParametrizedOperation <string[]>(OperationType.Import, positionImport, importedNamespace));
            return(operations);
        }
Пример #11
0
        private IOperationCollection pushGenericUnaryLeftToRightOperation(Scope scope, Func <Scope, IOperationCollection> nextLevel, Dictionary <TokenType, Func <long, IOperationCollection> > operationConverters)
        {
            // left-to-right
            IOperationCollection operations = new OperationCollection();

            // Get allowed operations
            TokenType[] allOperationTokens = operationConverters.Keys.ToArray();

            // Push value itself
            operations.Append(nextLevel(scope));

            while (_iterator.Is(allOperationTokens))
            {
                // Push the operation
                operations.Append(operationConverters[_iterator.Current.Type](_iterator.Position));
                _iterator.Next();
            }

            return(operations);
        }
Пример #12
0
        private IOperationCollection pushCommaSeparated(Scope scope, Func <Scope, IOperationCollection> customCallback, out int count)
        {
            // Note: this method assumes that there is AT LEAST ONE argument
            // to be parsed. You have to make sure BEFORE calling this method
            // that there is such a value

            IOperationCollection operations = new OperationCollection();

            count = 0;
            do
            {
                operations.Append(customCallback(scope)); // left-to-right
                count++;

                if (!_iterator.Is(TokenType.Comma))
                {
                    return(operations);
                }
                _iterator.Next();
            }while (true);
        }
Пример #13
0
        private IOperationCollection pushSingleInstruction_do_repeat(Scope scope, bool trueForDo_falseForRepeat)
        {
            IOperationCollection operations_condition;
            long whilePosition = _iterator.Position;

            // We assume that the current token is the "do" keyword
            // Proceed to next token
            _iterator.Next();

            // 'do' must be followed by an instruction
            IOperationCollection operations_body = pushScopeBlock(scope, true);

            string matchingKeyword = trueForDo_falseForRepeat ? "while" : "until";

            // We expect the 'while' resp. 'until' keyword ...
            if (!_iterator.Is(TokenType.Name) || _iterator.GetValue <string>() != matchingKeyword)
            {
                throw new SyntaxException(_iterator.Position, "Expected '" + matchingKeyword + "' statement.");
            }
            _iterator.Next();

            // ... which must be followed by '('
            if (!_iterator.Is(TokenType.BracketLeft))
            {
                throw new SyntaxException(_iterator.Position, "Expected '(' after '" + matchingKeyword + "'.");
            }
            _iterator.Next();

            // Read the condition part
            long conditionPosition = _iterator.Position;

            if (_iterator.Is(TokenType.EndOfInstruction))
            {
                operations_condition = new OperationCollection();
            }
            else
            {
                operations_condition = pushVariableAssignment(scope);
            }

            // repeat..until is the same as do..while, but the condition is negated
            if (!trueForDo_falseForRepeat)
            {
                operations_condition.Append(new SimpleOperation(OperationType.LogicalNot, conditionPosition));
            }

            // Condition must be followed by ');'
            if (!_iterator.Is(TokenType.BracketRight))
            {
                throw new SyntaxException(_iterator.Position, "Expected ')' after '" + matchingKeyword + "('.");
            }
            _iterator.Next();
            if (!_iterator.Is(TokenType.EndOfInstruction))
            {
                throw new SyntaxException(_iterator.Position, "Expected ';' after '" + matchingKeyword + "()'.");
            }
            _iterator.Next();

            // Put everything together
            IOperationCollection operations = new OperationCollection();

            operations.Append(new SimpleOperation(OperationType.DoWhile, whilePosition));
            operations.Append(operations_body);
            operations.Append(new SimpleOperation(OperationType.BeginOpBlock, -1));
            operations.Append(operations_condition);
            operations.Append(new SimpleOperation(OperationType.EndOpBlock, -1));
            return(operations);
        }
Пример #14
0
        private IOperationCollection pushSingleInstruction_for(Scope scope)
        {
            IOperationCollection operations_assignment;
            IOperationCollection operations_condition;
            IOperationCollection operations_init;
            long forPosition = _iterator.Position;

            // We assume that the current token is the "for" keyword
            // Proceed to next token
            _iterator.Next();

            // 'for' must be followed by '('
            if (!_iterator.Is(TokenType.BracketLeft))
            {
                throw new SyntaxException(_iterator.Position, "Expected '(' after 'for'.");
            }
            _iterator.Next();

            {
                // Read the initialization part
                // In contrast to the other parts, this also allows creation of new variables,
                // so we use pushTerminatedInstruction() here. Note that the latter also
                // reads the terminating ';' so that we don't have to do this by our own.
                if (_iterator.Is(TokenType.EndOfInstruction))
                {
                    operations_init = new OperationCollection();
                    _iterator.Next();
                }
                else
                {
                    operations_init = pushTerminatedInstruction(scope);
                }
            }
            {
                // Read the condition part
                if (_iterator.Is(TokenType.EndOfInstruction))
                {
                    operations_condition = new OperationCollection();
                }
                else
                {
                    operations_condition = pushVariableAssignment(scope);
                }

                // Condition must be followed by ';'
                if (!_iterator.Is(TokenType.EndOfInstruction))
                {
                    throw new SyntaxException(_iterator.Position, "Expected ';' in 'for('.");
                }
                _iterator.Next();
            }
            {
                // Read the condition part
                if (_iterator.Is(TokenType.BracketRight))
                {
                    operations_assignment = new OperationCollection();
                }
                else
                {
                    operations_assignment = pushVariableAssignment(scope);
                }

                // 'for' must be ended by ')'
                if (!_iterator.Is(TokenType.BracketRight))
                {
                    throw new SyntaxException(_iterator.Position, "Expected ')' after 'for('.");
                }
                _iterator.Next();
            }

            // ')' must be followed by an instruction
            IOperationCollection operations_body = pushScopeBlock(scope, true);

            // Put everything together
            IOperationCollection operations = new OperationCollection();

            operations.Append(new SimpleOperation(OperationType.For, forPosition));
            operations.Append(new SimpleOperation(OperationType.BeginScope, -1));
            operations.Append(operations_init);
            operations.Append(new SimpleOperation(OperationType.EndScope, -1));
            operations.Append(new SimpleOperation(OperationType.BeginOpBlock, -1));
            operations.Append(operations_condition);
            operations.Append(new SimpleOperation(OperationType.EndOpBlock, -1));
            operations.Append(new SimpleOperation(OperationType.BeginOpBlock, -1));
            operations.Append(operations_assignment);
            operations.Append(new SimpleOperation(OperationType.EndOpBlock, -1));
            operations.Append(operations_body);
            return(operations);
        }
Пример #15
0
        private IOperationCollection pushObject(Scope scope)
        {
            IOperationCollection operations = new OperationCollection();

            switch (_iterator.Current.Type)
            {
            case TokenType.EndOfDocument:
                throw new SyntaxException(_iterator.Position, "Unexpected end of document");

            case TokenType.EndOfInstruction:
                throw new SyntaxException(_iterator.Position, "Unexpected instruction delimiter");

            default:
                throw new SyntaxException(_iterator.Position, "Unexpected token: " + _iterator.Current.Type);

            case TokenType.DecInt:
            case TokenType.HexInt:
            case TokenType.BinInt:
                operations.Append(new ParametrizedOperation <RawInt>(OperationType.LoadConstant, _iterator.Position, _iterator.GetValue <RawInt>()));
                _iterator.Next();
                break;

            case TokenType.Float:
                operations.Append(new ParametrizedOperation <RawFloat>(OperationType.LoadConstant, _iterator.Position, _iterator.GetValue <RawFloat>()));
                _iterator.Next();
                break;

            case TokenType.String:
                operations.Append(new ParametrizedOperation <string>(OperationType.LoadConstant, _iterator.Position, _iterator.GetValue <string>()));
                _iterator.Next();
                break;

            case TokenType.Name:
            case TokenType.ReservedName:
                long posFirstNamespace = _iterator.Position;
                bool isReserved        = _iterator.Is(TokenType.ReservedName);
                // Read keyword, possibly with namespace prefix
                var keyword = readNamespacePath(true);

                // Check if we are dealing with a function
                if (_iterator.Is(TokenType.BracketLeft))
                {
                    operations.Append(new ParametrizedOperation <string[]>(OperationType.LoadFunction, posFirstNamespace, keyword.ToArray()));
                    break;
                }

                // In all other cases namespaces make no sense and are, hence, forbidden
                // Moreover, reserved names are forbidden
                if (keyword.Count != 1)
                {
                    throw new SyntaxException(posFirstNamespace, "Unexpected namespace");
                }
                if (isReserved)
                {
                    throw new SyntaxException(posFirstNamespace, "Illegal variable name: '$' characters not allowed");
                }

                // Otherwise we are dealing with a special value or with a variable
                switch (keyword[0])
                {
                case "true":
                    operations.Append(new ParametrizedOperation <bool>(OperationType.LoadConstant, posFirstNamespace, true));
                    break;

                case "false":
                    operations.Append(new ParametrizedOperation <bool>(OperationType.LoadConstant, posFirstNamespace, false));
                    break;

                default:
                    operations.Append(new ParametrizedOperation <string>(OperationType.LoadSymbol, posFirstNamespace, keyword[0]));
                    break;
                }
                break;

            case TokenType.SquareBracketLeft:
                long sqBrPosition = _iterator.Position;
                _iterator.Next();
                int listLength;
                if (_iterator.Is(TokenType.SquareBracketRight))
                {
                    listLength = 0;
                }
                else
                {
                    operations.Append(pushCommaSeparated(scope, out listLength));
                }
                operations.Append(new ParametrizedOperation <int>(OperationType.MakeList, sqBrPosition, listLength));
                if (!_iterator.Is(TokenType.SquareBracketRight))
                {
                    throw new SyntaxException(_iterator.Position, "Expected ']'");
                }
                _iterator.Next();
                break;

            case TokenType.OperatorLessThan:
                long vecPosition = _iterator.Position;
                _iterator.Next();
                int vectorDim;
                operations.Append(pushCommaSeparated(scope, pushObject, out vectorDim));
                operations.Append(new ParametrizedOperation <int>(OperationType.MakeVector, vecPosition, vectorDim));
                if (!_iterator.Is(TokenType.OperatorMoreThan))
                {
                    throw new SyntaxException(_iterator.Position, "Expected '>'. Expressions in vector definitions have to be bracketed.");
                }
                _iterator.Next();
                break;

            case TokenType.BracketLeft:
                _iterator.Next();
                operations.Append(pushAssign(scope));
                if (!_iterator.Is(TokenType.BracketRight))
                {
                    throw new SyntaxException(_iterator.Position, "Expected ')'");
                }
                _iterator.Next();
                break;
            }

            return(operations);
        }
Пример #16
0
        /// <summary>
        /// Reads a function from the tokenizer.
        /// </summary>
        /// <param name="parentNamespaces">The parts of the namespace which this definition is contained in.</param>
        /// <returns>the function which has been read.</returns>
        private UserFunction ReadFunction(List <string> parentNamespace, Dictionary <string, int> functionNameCounters)
        {
            // Read return type
            if (!_iterator.Is(TokenType.Name))
            {
                throw new SyntaxException(_iterator.Position, "Expected function return type");
            }
            string returnTypeIdentifier = _iterator.GetValue <string>();

            // Look up return type
            long  returnTypePosition = _iterator.Position;
            IType returnType;

            if (_iterator.Is(TokenType.Name) && _iterator.GetValue <string>() == "void")
            {
                returnType = null;
            }
            else
            {
                returnType = LookupType(returnTypeIdentifier, parentNamespace, parentNamespace.Count);
                if (object.ReferenceEquals(null, returnType))
                {
                    throw new SyntaxException(returnTypePosition, "Unrecognized type: " + returnTypeIdentifier);
                }
            }

            _iterator.Next();

            // Read function name
            if (!_iterator.Is(TokenType.Name))
            {
                throw new SyntaxException(_iterator.Position, "Expected function name");
            }
            string funcName = _iterator.GetValue <string>();

            _iterator.Next();

            // There should be a bracket now
            if (!_iterator.Is(TokenType.BracketLeft))
            {
                throw new SyntaxException(_iterator.Position, "Expected '('");
            }
            _iterator.Next();

            // Read arguments (as dictionary 'name=>type')
            Dictionary <string, IType> funcArgs = new Dictionary <string, IType>();

            if (!_iterator.Is(TokenType.BracketRight))
            {
                while (true)
                {
                    // Read argument type
                    if (!_iterator.Is(TokenType.Name))
                    {
                        throw new SyntaxException(_iterator.Position, "Expected argument type");
                    }
                    string argTypeIdentifier = _iterator.GetValue <string>();

                    // Look up return type
                    long  argTypePosition = _iterator.Position;
                    IType argType         = LookupType(argTypeIdentifier, parentNamespace, parentNamespace.Count);
                    if (object.ReferenceEquals(null, argType))
                    {
                        throw new SyntaxException(argTypePosition, "Unrecognized type: " + argTypeIdentifier);
                    }

                    _iterator.Next();

                    // Read argument name
                    if (!_iterator.Is(TokenType.Name))
                    {
                        throw new SyntaxException(_iterator.Position, "Expected argument name");
                    }
                    string argName = _iterator.GetValue <string>();

                    // Add to dictionary
                    if (funcArgs.ContainsKey(argName))
                    {
                        throw new SyntaxException(_iterator.Position, "Duplicate argument name '" + argName + "'.");
                    }
                    funcArgs.Add(argName, argType);

                    _iterator.Next();

                    // Check if this is the last argument
                    // and if not, read the separating comma.
                    if (_iterator.Is(TokenType.BracketRight))
                    {
                        break;
                    }
                    if (!_iterator.Is(TokenType.Comma))
                    {
                        throw new SyntaxException(_iterator.Position, "Expected ',' or ')'");
                    }
                    _iterator.Next();
                }
            }

            // The iterator must be pointing at a bracket ')' at this point
            _iterator.Next();

            // There should be a curly bracket now
            if (!_iterator.Is(TokenType.CurlyBracketLeft))
            {
                throw new SyntaxException(_iterator.Position, "Expected '{'");
            }
            _iterator.Next();

            // Read function body
            FunctionContext functionHeader;

            functionHeader.Signature.Arguments = funcArgs.Select(x => new Variable {
                Name = x.Key, Type = x.Value
            }).ToArray();
            functionHeader.Signature.Name       = funcName;
            functionHeader.Signature.Namespace  = parentNamespace.ToArray();
            functionHeader.Signature.ReturnType = returnType;
            if (!functionNameCounters.ContainsKey(funcName))
            {
                functionHeader.Signature.Index = 0;
                functionNameCounters[funcName] = 1;
            }
            else
            {
                functionHeader.Signature.Index = functionNameCounters[funcName]++;
            }
            functionHeader.Signature.IsBuiltin = false;
            functionHeader.TypeTable           = _typeTable;
            var ii       = _instructionInterpreterFactory.Create(functionHeader, _iterator);
            var funcBody = new OperationCollection();

            while (!_iterator.Is(TokenType.EndOfDocument, TokenType.CurlyBracketRight))
            {
                funcBody.Append(ii.InterpreteNext());
            }

            // There should be a curly bracket now
            if (!_iterator.Is(TokenType.CurlyBracketRight))
            {
                throw new SyntaxException(_iterator.Position, "Expected '}'");
            }
            _iterator.Next();

            UserFunction f;

            f.Signature      = functionHeader.Signature;
            f.Body           = funcBody;
            f.SourcePosition = returnTypePosition;
            return(f);
        }
Пример #17
0
        private IOperationCollection pushSuffixIncDec(Scope scope)
        {
            Func <long, bool, IOperationCollection> functionCallHandler = (bracketPosition, isImplicit) =>
            {
                IOperationCollection operations = new OperationCollection();
                int argCount = 0;

                _iterator.Next();
                if (!_iterator.Is(TokenType.BracketRight))
                {
                    // Push the loading instructions of the arguments after the
                    // ones of the function itself
                    operations.Append(pushCommaSeparated(scope, out argCount));
                }

                if (isImplicit)
                {
                    argCount += 1;
                }

                // Push instruction to call the function
                operations.Append(new ParametrizedOperation <int>(OperationType.Call, bracketPosition, argCount));

                // There should be a right bracket now
                if (!_iterator.Is(TokenType.BracketRight))
                {
                    throw new SyntaxException(_iterator.Position, "Expected ')'");
                }

                // Do not call _iterator.Next() here! This is done in the genericOperation method
                return(operations);
            };

            var operationConverters = new Dictionary <TokenType, Func <long, IOperationCollection> >();

            operationConverters.Add(TokenType.OperatorIncrement, o(OperationType.SuffixIncrement));
            operationConverters.Add(TokenType.OperatorDecrement, o(OperationType.SuffixDecrement));
            operationConverters.Add(TokenType.Period, (periodPosition) =>
            {
                _iterator.Next();
                long posFirstNamespace     = _iterator.Current.Position;
                List <string> propertyName = new List <string>();

                if (!_iterator.Is(TokenType.Name))
                {
                    throw new SyntaxException(_iterator.Position, "Expected name after '.' operator.");
                }
                propertyName.Add(_iterator.GetValue <string>());
                _iterator.CreateRevertPoint();
                _iterator.Next();

                while (_iterator.Is(TokenType.DoubleColon))
                {
                    _iterator.Next();
                    if (!_iterator.Is(TokenType.Name))
                    {
                        throw new SyntaxException(_iterator.Position, "Expected name after '::'.");
                    }
                    propertyName.Add(_iterator.GetValue <string>());
                    _iterator.Commit();
                    _iterator.CreateRevertPoint();
                    _iterator.Next();
                }

                // Check if the 'property access' is actually an implicit function call.
                if (_iterator.Is(TokenType.BracketLeft))
                {
                    // Discard the restore point
                    _iterator.Commit();

                    // Handle it as a function
                    var operations = new OperationCollection();
                    operations.Append(new ParametrizedOperation <string[]>(OperationType.LoadFunction, posFirstNamespace, propertyName.ToArray()));
                    operations.Append(new SimpleOperation(OperationType.Swap, -1)); // first argument and function are on the stack in the wrong order
                    operations.Append(functionCallHandler(_iterator.Current.Position, true));
                    return(operations);
                }
                else
                {
                    // Note that genericOperation() already calls _iterator.Next(), that's why
                    // the iterator must point to the _current_ instruction, NOT to the next one.
                    // We used revert points to store the state of the iterator.
                    _iterator.Revert();

                    // Since it is really a property now, we do not allow namespacing anymore
                    if (propertyName.Count != 1)
                    {
                        throw new SyntaxException(posFirstNamespace, "Namespaces are not allowed in property names");
                    }

                    return(new SingleOperation(new ParametrizedOperation <string>(OperationType.PropertyAccess, periodPosition, propertyName.First())));
                }
            });
            operationConverters.Add(TokenType.BracketLeft, (x) => functionCallHandler(x, false));
            operationConverters.Add(TokenType.SquareBracketLeft, (sqBrPosition) => // indexing
            {
                _iterator.Next();
                IOperationCollection operations = pushAssign(scope);
                operations.Append(new SimpleOperation(OperationType.Index, sqBrPosition));

                // There should be a right bracket now
                if (!_iterator.Is(TokenType.SquareBracketRight))
                {
                    throw new SyntaxException(_iterator.Position, "Expected ']'");
                }

                // Do not call _iterator.Next() here! This is done in the genericOperation method
                return(operations);
            });

            return(pushGenericUnaryLeftToRightOperation(scope, pushObject, operationConverters));
        }
Пример #18
0
        private IOperationCollection pushVariableAssignment(Scope scope)
        {
            // We need something of the form "type variableName"
            if (_iterator.Is(TokenType.Name))
            {
                // At this point it is not entirely clear whether we are dealing
                // with a variable assignment. Therefore we have to remember everything
                // we read from now on so that we can restore it.
                _iterator.CreateRevertPoint();

                // Read the variable type
                long   theTypePosition = _iterator.Position;
                string theTypePath;
                string theTypeContextPath;
                IType  theTypeInstance;
                try
                {
                    theTypePath        = string.Join("::", readNamespacePath(false).ToArray());
                    theTypeContextPath = Helper.PrependNamespace(theTypePath, _function.Signature.Namespace); // the current namespace might be implicit
                    if (_function.TypeTable.Has(theTypePath))
                    {
                        theTypeInstance = _function.TypeTable.Lookup(theTypePath);
                    }
                    else if (_function.TypeTable.Has(theTypeContextPath))
                    {
                        theTypeInstance = _function.TypeTable.Lookup(theTypeContextPath);
                    }
                    else
                    {
                        throw new SyntaxException(theTypePosition, "Unrecognized type: " + theTypePath);
                    }
                }
                catch (SyntaxException)
                {
                    // Something failed, so we are not dealing with a variable assignment.
                    // Proceed with the next layer.
                    _iterator.Revert();
                    return(pushAssign(scope));
                }

                // We read the name of the (base) type, now it might be
                // that case that it is followed by arbitrarily many "[]"
                // which indicate an array declaration

                // Read "[]" tokens which identify the type as array type
                int listDimension = 0;
                while (_iterator.Is(TokenType.SquareBracketLeft))
                {
                    listDimension++;
                    _iterator.Next();
                    if (!_iterator.Is(TokenType.SquareBracketRight))
                    {
                        listDimension = -1;
                        break;
                    }
                    _iterator.Next();
                }

                // If reading "[]" did not fail and the next token is a name,
                // we finally know that it *is* a variable assignment
                if (listDimension >= 0 && _iterator.Is(TokenType.Name))
                {
                    // Phew. Now remember to destroy the revert point.
                    _iterator.Commit();

                    // Apply the array dimension to the type
                    for (int i = 0; i < listDimension; i++)
                    {
                        theTypeInstance = new ArrayType(theTypeInstance);
                    }

                    string theVariableName = _iterator.GetValue <string>();
                    _iterator.Next();
                    switch (_iterator.Current.Type)
                    {
                    case TokenType.EndOfInstruction:
                        var ops1 = new OperationCollection();
                        ops1.Append(new SimpleOperation(OperationType.LoadUndefined, theTypePosition));
                        ops1.Append(new TwoParametrizedOperation <IType, string>(OperationType.CreateVariable, theTypePosition, theTypeInstance, theVariableName));
                        return(ops1);

                    case TokenType.OperatorAssign:
                        _iterator.Next();
                        var ops2 = new OperationCollection();
                        ops2.Append(pushAssign(scope));
                        ops2.Append(new TwoParametrizedOperation <IType, string>(OperationType.CreateVariable, theTypePosition, theTypeInstance, theVariableName));
                        return(ops2);

                    default:
                        throw new SyntaxException(_iterator.Position, "Unexpected token: " + _iterator.Current.Type);
                    }
                }
                else
                {
                    // Otherwise restore everything from the revert point
                    // and proceed with the next layer
                    _iterator.Revert();
                    return(pushAssign(scope));
                }
            }
            else
            {
                return(pushAssign(scope));
            }
        }