Exemplo n.º 1
0
        //let-statement ::= 'let' <var-name> ('[' <expression> ']')? '=' <expression> ';'
        private void ParseLetStatement()
        {
            Match(new Token(TokenType.Keyword, "let"));

            Token varName = NextToken();

            if (GetClosestSymbol(varName.Value) == null)
            {
                ThrowCompilationException("Undefined variable '" + varName.Value + "'");
            }
            if (!_methodSymTable.HasSymbol(varName.Value))
            {
                Symbol variable = _classSymTable.GetSymbol(varName.Value);
                if (variable.Kind == SymbolKind.Field &&
                    _currentSub.Kind != SubroutineKind.Constructor &&
                    _currentSub.Kind != SubroutineKind.Method)
                {
                    ThrowCompilationException("Instance fields may be used only from a method or a constructor");
                }
            }

            bool withArrayIndex = false;

            if (LookAheadToken.Value == "[")
            {
                VerifyArrayAccessAllowed(varName);
                withArrayIndex = true;
                Match(new Token(TokenType.Symbol, "["));
                ParseExpression();
                Match(new Token(TokenType.Symbol, "]"));
            }
            Match(new Token(TokenType.Symbol, "="));
            ParseExpression();
            _codeGenerator.Assignment(varName, withArrayIndex);
            Match(new Token(TokenType.Symbol, ";"));

            //TODO: Type checking, but this is really hard . . . (we need
            //to propagate the type of the LHS expression so that we can
            //verify that it's the same as the RHS, and if RHS is an array
            //access then we have no way of knowing what should come from the
            //array, unless we start tracking all array types and not just
            //use 'Array' for all arrays)
        }