/// <summary> /// Parses a function definition. /// </summary> /// <remarks> /// Assumes the 'function' keyword has already been consumed. /// </remarks> internal static ExpressionBase Parse(PositionalTokenizer tokenizer, int line = 0, int column = 0) { var locationStart = new TextLocation(line, column); // location of 'function' keyword ExpressionBase.SkipWhitespace(tokenizer); line = tokenizer.Line; column = tokenizer.Column; var functionName = tokenizer.ReadIdentifier(); var functionNameVariable = new VariableDefinitionExpression(functionName.ToString(), line, column); var function = new UserFunctionDefinitionExpression(functionNameVariable); function.Location = new TextRange(locationStart.Line, locationStart.Column, 0, 0); if (functionName.IsEmpty) { return(ExpressionBase.ParseError(tokenizer, "Invalid function name")); } return(function.Parse(tokenizer)); }
protected new ExpressionBase Parse(PositionalTokenizer tokenizer) { ExpressionBase.SkipWhitespace(tokenizer); if (tokenizer.NextChar != '(') { return(ExpressionBase.ParseError(tokenizer, "Expected '(' after function name", Name)); } tokenizer.Advance(); ExpressionBase.SkipWhitespace(tokenizer); if (tokenizer.NextChar != ')') { do { var line = tokenizer.Line; var column = tokenizer.Column; var parameter = tokenizer.ReadIdentifier(); if (parameter.IsEmpty) { return(ExpressionBase.ParseError(tokenizer, "Invalid parameter name", line, column)); } var variableDefinition = new VariableDefinitionExpression(parameter.ToString(), line, column); Parameters.Add(variableDefinition); ExpressionBase.SkipWhitespace(tokenizer); if (tokenizer.NextChar == '=') { tokenizer.Advance(); ExpressionBase.SkipWhitespace(tokenizer); var value = ExpressionBase.Parse(tokenizer); if (value.Type == ExpressionType.ParseError) { return(ExpressionBase.ParseError(tokenizer, "Invalid default value for " + parameter.ToString(), value)); } var scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope()); scope.Context = new TriggerBuilderContext(); // prevent errors passing memory references as default parameters ExpressionBase evaluated; if (!value.ReplaceVariables(scope, out evaluated)) { return(ExpressionBase.ParseError(tokenizer, "Default value for " + parameter.ToString() + " is not constant", evaluated)); } DefaultParameters[parameter.ToString()] = evaluated; } else if (DefaultParameters.Count > 0) { return(ExpressionBase.ParseError(tokenizer, string.Format("Non-default parameter {0} appears after default parameters", parameter.ToString()), variableDefinition)); } if (tokenizer.NextChar == ')') { break; } if (tokenizer.NextChar != ',') { return(ExpressionBase.ParseError(tokenizer, "Expected ',' or ')' after parameter name, found: " + tokenizer.NextChar)); } tokenizer.Advance(); ExpressionBase.SkipWhitespace(tokenizer); } while (true); } tokenizer.Advance(); // closing parenthesis ExpressionBase.SkipWhitespace(tokenizer); ExpressionBase expression; if (tokenizer.Match("=>")) { return(ParseShorthandBody(tokenizer)); } if (tokenizer.NextChar != '{') { return(ExpressionBase.ParseError(tokenizer, "Expected '{' after function declaration", Name)); } tokenizer.Advance(); ExpressionBase.SkipWhitespace(tokenizer); bool seenReturn = false; while (tokenizer.NextChar != '}') { expression = ExpressionBase.Parse(tokenizer); if (expression.Type == ExpressionType.ParseError) { // the ExpressionTokenizer will capture the error, we should still return the incomplete FunctionDefinition if (tokenizer is ExpressionTokenizer) { break; } // not an ExpressionTokenizer, just return the error return(expression); } if (expression.Type == ExpressionType.Return) { seenReturn = true; } else if (seenReturn) { ExpressionBase.ParseError(tokenizer, "Expression after return statement", expression); } Expressions.Add(expression); ExpressionBase.SkipWhitespace(tokenizer); } Location = new TextRange(Location.Start, tokenizer.Location); tokenizer.Advance(); return(MakeReadOnly(this)); }
/// <summary> /// Parses a function definition. /// </summary> /// <remarks> /// Assumes the 'function' keyword has already been consumed. /// </remarks> internal static ExpressionBase Parse(PositionalTokenizer tokenizer, int line = 0, int column = 0) { var function = new FunctionDefinitionExpression(); function._keyword = new KeywordExpression("function", line, column); ExpressionBase.SkipWhitespace(tokenizer); line = tokenizer.Line; column = tokenizer.Column; var functionName = tokenizer.ReadIdentifier(); function.Name = new VariableDefinitionExpression(functionName.ToString(), line, column); if (functionName.IsEmpty) { ExpressionBase.ParseError(tokenizer, "Invalid function name"); return(function); } ExpressionBase.SkipWhitespace(tokenizer); if (tokenizer.NextChar != '(') { ExpressionBase.ParseError(tokenizer, "Expected '(' after function name", function.Name); return(function); } tokenizer.Advance(); ExpressionBase.SkipWhitespace(tokenizer); if (tokenizer.NextChar != ')') { do { line = tokenizer.Line; column = tokenizer.Column; var parameter = tokenizer.ReadIdentifier(); if (parameter.IsEmpty) { ExpressionBase.ParseError(tokenizer, "Invalid parameter name", line, column); return(function); } function.Parameters.Add(new VariableDefinitionExpression(parameter.ToString(), line, column)); ExpressionBase.SkipWhitespace(tokenizer); if (tokenizer.NextChar == ')') { break; } if (tokenizer.NextChar != ',') { ExpressionBase.ParseError(tokenizer, "Expected ',' or ')' after parameter name, found: " + tokenizer.NextChar); return(function); } tokenizer.Advance(); ExpressionBase.SkipWhitespace(tokenizer); } while (true); } tokenizer.Advance(); // closing parenthesis ExpressionBase.SkipWhitespace(tokenizer); ExpressionBase expression; if (tokenizer.Match("=>")) { ExpressionBase.SkipWhitespace(tokenizer); expression = ExpressionBase.Parse(tokenizer); if (expression.Type == ExpressionType.ParseError) { return(expression); } if (expression.Type == ExpressionType.Return) { return(new ParseErrorExpression("Return statement is implied by =>", ((ReturnExpression)expression).Keyword)); } var returnExpression = new ReturnExpression(expression); function.Expressions.Add(returnExpression); return(function); } if (tokenizer.NextChar != '{') { ExpressionBase.ParseError(tokenizer, "Expected '{' after function declaration", function.Name); return(function); } line = tokenizer.Line; column = tokenizer.Column; tokenizer.Advance(); ExpressionBase.SkipWhitespace(tokenizer); bool seenReturn = false; while (tokenizer.NextChar != '}') { expression = ExpressionBase.Parse(tokenizer); if (expression.Type == ExpressionType.ParseError) { return(expression); } if (expression.Type == ExpressionType.Return) { seenReturn = true; } else if (seenReturn) { ExpressionBase.ParseError(tokenizer, "Expression after return statement", expression); } function.Expressions.Add(expression); ExpressionBase.SkipWhitespace(tokenizer); } tokenizer.Advance(); return(function); }