Example #1
0
        /// <summary>
        /// Adds a statement to the unresolved list
        /// </summary>
        /// <param name="script"></param>
        /// <param name="statement"></param>
        /// <returns></returns>
        public bool AddUnresolvedStatement(LuatScript script, Statement statement)
        {
            LinkedListNode<Statement> node = statement.ListNode[script];
            if (node.List == script.UnresolvedStatements)
            {
                return false;
            }

            if (null != node.List)
            {
                if (node.List != script.ResolvedStatements)
                {
                    throw new Exception("Statement is part of an unknown list");
                }

                node.List.Remove(node);
            }

            script.UnresolvedStatements.AddFirst(node);
            return true;
        }
Example #2
0
		/// <summary>
		/// Matches a <c>ForStatement</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>ForStatement</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>For</c>.
		/// </remarks>
		protected virtual bool MatchForStatement(out Statement statement) {
			statement = null;
			int startOffset = this.LookAheadToken.StartOffset;
			if (!this.Match(LuatTokenId.For))
				return false;
			Identifier firstIdent = null;
			if (!this.MatchIdentifier(out firstIdent))
				return false;
			if (this.TokenIs(this.LookAheadToken, LuatTokenId.Assignment)) {
				// for a = b, c, d do ... end
				VariableExpression firstVar = new VariableExpression( firstIdent );
				ForStatement forStatement = new ForStatement();
				statement = forStatement;
				forStatement.Iterator = firstVar as VariableExpression;
				if (!this.Match(LuatTokenId.Assignment))
					return false;
				Expression start = null;
				if (!this.MatchExpression(out start))
					return false;
				forStatement.Start = start;
				if (!this.Match(LuatTokenId.Comma))
					return false;
				Expression end = null;
				if (!this.MatchExpression(out end))
					return false;
				forStatement.End = end;
				if (this.TokenIs(this.LookAheadToken, LuatTokenId.Comma)) {
					if (!this.Match(LuatTokenId.Comma))
						return false;
					Expression step = null;
					if (!this.MatchExpression(out step))
						return false;
					forStatement.Step = step;
				}
				if (!this.Match(LuatTokenId.Do))
					return false;
				BlockStatement body;
				if (!this.MatchBlock(out body))
					return false;
				forStatement.Body = body;
				if (!this.Match(LuatTokenId.End))
					return false;
				forStatement.StartOffset = startOffset; forStatement.EndOffset = this.Token.EndOffset;
			}
			else if (((this.TokenIs(this.LookAheadToken, LuatTokenId.Comma)) || (this.TokenIs(this.LookAheadToken, LuatTokenId.In)))) {
				// for a,b in c,d do ... end
				ForInStatement forInStatement = new ForInStatement();
				statement = forInStatement;
				forInStatement.Iterators.Add( firstIdent );
				if (this.TokenIs(this.LookAheadToken, LuatTokenId.Comma)) {
					if (!this.Match(LuatTokenId.Comma))
						return false;
					if (!this.MatchIdentifierList(forInStatement.Iterators))
						return false;
				}
				if (!this.Match(LuatTokenId.In))
					return false;
				if (!this.MatchExpressionList(forInStatement.Tables))
					return false;
				if (!this.Match(LuatTokenId.Do))
					return false;
				BlockStatement body;
				if (!this.MatchBlock(out body))
					return false;
				forInStatement.Body = body;
				if (!this.Match(LuatTokenId.End))
					return false;
				forInStatement.StartOffset = startOffset; forInStatement.EndOffset = this.Token.EndOffset;
			}
			else
				return false;
			return true;
		}
Example #3
0
		/// <summary>
		/// Matches a <c>LocalDeclaration</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>LocalDeclaration</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>Local</c>.
		/// </remarks>
		protected virtual bool MatchLocalDeclaration(out Statement statement) {
			statement = null;
			int start = this.LookAheadToken.StartOffset;
			if (!this.Match(LuatTokenId.Local))
				return false;
			if (!this.MatchLocalSuffix(out statement)) {
				return this.RaiseError( start, "Expected identifier or function declaration." );
			}
			else {
				statement.StartOffset = start;
				statement.EndOffset = this.Token.EndOffset;
			}
			return true;
		}
Example #4
0
		/// <summary>
		/// Matches a <c>RepeatStatement</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>RepeatStatement</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>Repeat</c>.
		/// </remarks>
		protected virtual bool MatchRepeatStatement(out Statement statement) {
			statement = null;
			RepeatStatement repeatStatement = new RepeatStatement();
			repeatStatement.StartOffset = this.Token.StartOffset;
			statement = repeatStatement;
			if (!this.Match(LuatTokenId.Repeat))
				return false;
			BlockStatement Block;
			if (!this.MatchBlock(out Block))
				return false;
			repeatStatement.Block = Block;
			if (!this.Match(LuatTokenId.Until))
				return false;
			Expression conditional;
			if (!this.MatchExpression(out conditional))
				return false;
			repeatStatement.Conditional = conditional;
			repeatStatement.EndOffset = this.Token.EndOffset;
			return true;
		}
Example #5
0
		/// <summary>
		/// Matches a <c>IfStatement</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>IfStatement</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>If</c>.
		/// </remarks>
		protected virtual bool MatchIfStatement(out Statement statement) {
			IfStatement ifStatement = new IfStatement();
			statement = ifStatement;
			Expression       conditional;
			BlockStatement   block;
			ifStatement.StartOffset = this.LookAheadToken.StartOffset;
			if (!this.Match(LuatTokenId.If))
				return false;
			if (!this.MatchExpression(out conditional))
				return false;
			ifStatement.Conditional = conditional;
			if (!this.Match(LuatTokenId.Then))
				return false;
			if (!this.MatchBlock(out block))
				return false;
			ifStatement.Block       = block;
			while (this.TokenIs(this.LookAheadToken, LuatTokenId.Elseif)) {
				if (!this.Match(LuatTokenId.Elseif))
					return false;
				ConditionalBlock conditionalBlock = new ConditionalBlock();
				if (!this.MatchExpression(out conditional))
					return false;
				conditionalBlock.Conditional = conditional;
				if (!this.Match(LuatTokenId.Then))
					return false;
				if (!this.MatchBlock(out block))
					return false;
				conditionalBlock.Block = block;
				ifStatement.ElseIfs.Add( conditionalBlock );
			}
			if (this.TokenIs(this.LookAheadToken, LuatTokenId.Else)) {
				if (!this.Match(LuatTokenId.Else))
					return false;
				if (!this.MatchBlock(out block))
					return false;
				ifStatement.Else = block;
			}
			if (!this.Match(LuatTokenId.End))
				return false;
			ifStatement.EndOffset = this.Token.EndOffset;
			return true;
		}
Example #6
0
		/// <summary>
		/// Matches a <c>DoStatement</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>DoStatement</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>Do</c>.
		/// </remarks>
		protected virtual bool MatchDoStatement(out Statement statement) {
			statement = null;
			DoStatement doStatement = new DoStatement();
			doStatement.StartOffset = this.Token.StartOffset;
			statement = doStatement;
			if (!this.Match(LuatTokenId.Do))
				return false;
			BlockStatement body;
			if (!this.MatchBlock(out body))
				return false;
			doStatement.Body = body;
			if (!this.Match(LuatTokenId.End))
				return false;
			doStatement.EndOffset = this.Token.EndOffset;
			return true;
		}
Example #7
0
		/// <summary>
		/// Matches a <c>WhileStatement</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>WhileStatement</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>While</c>.
		/// </remarks>
		protected virtual bool MatchWhileStatement(out Statement statement) {
			statement = null;
			if (!this.Match(LuatTokenId.While))
				return false;
			WhileStatement whileStatement = new WhileStatement();
			whileStatement.StartOffset = this.Token.StartOffset;
			statement = whileStatement;
			Expression conditional;
			if (!this.MatchExpression(out conditional))
				return false;
			whileStatement.Conditional = conditional;
			if (!this.Match(LuatTokenId.Do))
				return false;
			BlockStatement Block;
			if (!this.MatchBlock(out Block))
				return false;
			whileStatement.Block = Block;
			if (!this.Match(LuatTokenId.End))
				return false;
			whileStatement.EndOffset = this.Token.EndOffset;
			return true;
		}
Example #8
0
		/// <summary>
		/// Matches a <c>LastStatementInner</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>LastStatementInner</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>Return</c>, <c>Break</c>.
		/// </remarks>
		protected virtual bool MatchLastStatementInner(out Statement statement) {
			statement = null;
			if (this.TokenIs(this.LookAheadToken, LuatTokenId.Return)) {
				if (!this.MatchReturnStatement(out statement))
					return false;
			}
			else if (this.TokenIs(this.LookAheadToken, LuatTokenId.Break)) {
				if (!this.MatchBreakStatement(out statement))
					return false;
			}
			else
				return false;
			return true;
		}
Example #9
0
		/// <summary>
		/// Matches a <c>AssignmentOrFunctionCall</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>AssignmentOrFunctionCall</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>OpenParenthesis</c>, <c>OpenCurlyBrace</c>, <c>Identifier</c>, <c>TripleDot</c>, <c>Nil</c>, <c>False</c>, <c>True</c>, <c>Number</c>, <c>Subtraction</c>, <c>Not</c>, <c>Hash</c>, <c>String</c>.
		/// </remarks>
		protected virtual bool MatchAssignmentOrFunctionCall(out Statement statement) {
			Expression expression = null;
			statement             = null;
			int start = this.LookAheadToken.StartOffset;
			if (!this.MatchExpressionNoFunction(out expression))
				return false;
			if ( IsFunctionCall( expression ) )
				{
				statement = new ExpressionStatement( expression );
				return true;
			}
			
			AssignmentStatement assignment = new AssignmentStatement();
			statement = assignment;
			
			assignment.Variables.Add( expression );
			while (this.TokenIs(this.LookAheadToken, LuatTokenId.Comma)) {
				if (!this.Match(LuatTokenId.Comma))
					return false;
				if (!this.MatchExpressionNoFunction(out expression))
					return false;
				assignment.Variables.Add( expression );
			}
			if (!this.Match(LuatTokenId.Assignment))
				return false;
			if (!this.MatchExpressionList(assignment.Values))
				return false;
			foreach( Expression variable in assignment.Variables )
				{
				// Mark the LHS expression as being assigned.
				// This alters the way certain variables are resolved.
				variable.IsLHSOfAssignment = true;
				
				if( false == IsVariable( variable ) )
					{
					// First expression was not a variable or a function call.
					// Invalid statement
					string message = "The left-hand side of an assignment must be a variable";
					compilationUnit.SyntaxErrors.Add(new SyntaxError( variable.TextRange, message ) );
				}
			}
			
			assignment.StartOffset = start;
			assignment.EndOffset   = this.Token.EndOffset;
			return true;
		}
Example #10
0
		/// <summary>
		/// Matches a <c>StatementInner</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>StatementInner</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>Do</c>, <c>While</c>, <c>Repeat</c>, <c>If</c>, <c>For</c>, <c>Local</c>, <c>Function</c>, <c>OpenParenthesis</c>, <c>OpenCurlyBrace</c>, <c>Identifier</c>, <c>TripleDot</c>, <c>Nil</c>, <c>False</c>, <c>True</c>, <c>Number</c>, <c>Subtraction</c>, <c>Not</c>, <c>Hash</c>, <c>String</c>.
		/// </remarks>
		protected virtual bool MatchStatementInner(out Statement statement) {
			statement = null;
			if (this.IsInMultiMatchSet(2, this.LookAheadToken)) {
				if (!this.MatchAssignmentOrFunctionCall(out statement))
					return false;
			}
			else if (this.TokenIs(this.LookAheadToken, LuatTokenId.Do)) {
				if (!this.MatchDoStatement(out statement))
					return false;
			}
			else if (this.TokenIs(this.LookAheadToken, LuatTokenId.While)) {
				if (!this.MatchWhileStatement(out statement))
					return false;
			}
			else if (this.TokenIs(this.LookAheadToken, LuatTokenId.Repeat)) {
				if (!this.MatchRepeatStatement(out statement))
					return false;
			}
			else if (this.TokenIs(this.LookAheadToken, LuatTokenId.If)) {
				if (!this.MatchIfStatement(out statement))
					return false;
			}
			else if (this.TokenIs(this.LookAheadToken, LuatTokenId.For)) {
				if (!this.MatchForStatement(out statement))
					return false;
			}
			else if (this.TokenIs(this.LookAheadToken, LuatTokenId.Function)) {
				if (!this.MatchFunctionDeclaration(out statement))
					return false;
			}
			else if (this.TokenIs(this.LookAheadToken, LuatTokenId.Local)) {
				if (!this.MatchLocalDeclaration(out statement))
					return false;
			}
			else
				return false;
			return true;
		}
Example #11
0
		/// <summary>
		/// Matches a <c>BreakStatement</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>BreakStatement</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>Break</c>.
		/// </remarks>
		protected virtual bool MatchBreakStatement(out Statement statement) {
			statement = null;
			if (!this.Match(LuatTokenId.Break))
				return false;
			statement = new BreakStatement( this.Token.TextRange );
			return true;
		}
Example #12
0
		/// <summary>
		/// Matches a <c>ReturnStatement</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>ReturnStatement</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>Return</c>.
		/// </remarks>
		protected virtual bool MatchReturnStatement(out Statement statement) {
			statement = null;
			int start = this.LookAheadToken.StartOffset;
			if (!this.Match(LuatTokenId.Return))
				return false;
			ReturnStatement returnStatement = new ReturnStatement();
			returnStatement.IsMultiline     = this.LexicalParser.LookAheadTokenIsOnDifferentLine;
			if (this.IsInMultiMatchSet(3, this.LookAheadToken)) {
				if (!this.MatchExpressionList(returnStatement.Values))
					return false;
			}
			returnStatement.StartOffset = start; returnStatement.EndOffset = this.Token.EndOffset;
		if ( returnStatement.Values.Count == 0 ) { returnStatement.IsMultiline = false; }
		statement = returnStatement;
			return true;
		}
Example #13
0
		/// <summary>
		/// Matches a <c>FunctionDeclaration</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>FunctionDeclaration</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>Function</c>.
		/// </remarks>
		protected virtual bool MatchFunctionDeclaration(out Statement statement) {
			statement = null;
			int start = this.LookAheadToken.StartOffset;
			string description = this.GetDescription();
			bool expectsSelf;
			if (!this.Match(LuatTokenId.Function))
				return false;
			Expression name;
			if (!this.MatchFunctionName(out name, out expectsSelf))
				return false;
			Function function;
			if (!this.MatchFunctionBody(out function))
				return false;
			AssignmentStatement assignment = new AssignmentStatement();
			assignment.Variables.Add( name );
			assignment.Values.Add( function );
			
			// Use the preceding comment as the function description
			function.Description = (null != description)
				? description.Trim( '\n', '\r' )
				: null;
			
			function.ExpectsSelf = expectsSelf;
			
			// Mark the LHS expression as being assigned.
			// This alters the way certain variables are resolved.
			name.IsLHSOfAssignment = true;
			
			assignment.StartOffset = start; assignment.EndOffset = this.Token.EndOffset;
			statement = assignment;
			return true;
		}
Example #14
0
		/// <summary>
		/// Matches a <c>LocalSuffix</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>LocalSuffix</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>Function</c>, <c>Identifier</c>.
		/// </remarks>
		protected virtual bool MatchLocalSuffix(out Statement statement) {
			statement = null;
			AssignmentStatement assignment = new AssignmentStatement();
			assignment.IsLocal = true;
			Identifier type = null;
			if (this.TokenIs(this.LookAheadToken, LuatTokenId.Identifier)) {
				if (!this.MatchVariableList(assignment.Variables))
					return false;
				if (this.TokenIs(this.LookAheadToken, LuatTokenId.Colon)) {
					if (!this.Match(LuatTokenId.Colon))
						return false;
					if (!this.MatchIdentifier(out type))
						return false;
				}
				if (this.TokenIs(this.LookAheadToken, LuatTokenId.Assignment)) {
					if (!this.Match(LuatTokenId.Assignment))
						return false;
					if (!this.MatchExpressionList(assignment.Values))
						return false;
				}
			}
			else if (this.TokenIs(this.LookAheadToken, LuatTokenId.Function)) {
				if (!this.Match(LuatTokenId.Function))
					return false;
				Expression variableNode;
				if (!this.MatchVariable(out variableNode))
					return false;
				Function function;
				if (!this.MatchFunctionBody(out function))
					return false;
				VariableExpression variableExpression = variableNode as VariableExpression;
				assignment.Variables.Add( variableNode );
				assignment.Values.Add( function );
			}
			else
				return false;
			foreach ( VariableExpression v in assignment.Variables )
				{
				v.IsLHSOfAssignment = true;
				v.IsLocal           = true;
				v.Type              = type == null ? null : type.Text;
			}
			
			statement = assignment;
			return true;
		}