/// <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; }
/// <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; }
/// <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; }