/// <summary> /// Parses a set of brackets containing arguments. /// </summary> /// <param name="scope">The scope for this token.</param> /// <param name="openBracketToken">The open bracket token.</param> /// <param name="sig">(optional) A signature for the function being called.</param> /// <returns>A new argument token.</returns> /// <remarks>This function assumes the opening bracket has already been read from the stream.</remarks> public static ArgsToken Parse(Scope scope, OperatorToken openBracketToken, FunctionSignature sig) { var code = scope.Code; var ret = new ArgsToken(scope, openBracketToken); var argIndex = 0; scope = scope.Clone(); scope.Hint |= ScopeHint.SuppressStatementStarts; ret._sig = sig; var args = sig != null?sig.Arguments.ToArray() : ArgumentDescriptor.EmptyArray; while (code.SkipWhiteSpace()) { code.Peek(); if (code.Text == ")") { ret.AddToken(new OperatorToken(scope, code.MovePeekedSpan(), ")")); ret._terminated = true; return(ret); } if (code.Text == ",") { ret.AddToken(new OperatorToken(scope, code.MovePeekedSpan(), ",")); argIndex++; continue; } var dataType = argIndex < args.Length ? args[argIndex].DataType : null; var exp = ExpressionToken.TryParse(scope, _endTokens, expectedDataType: dataType); if (exp != null) { ret.AddToken(exp); } else { break; } } return(ret); }
private static Token ProcessWord(ExpressionToken exp, Scope scope, string word, Span wordSpan) { // Global keyword that take effect anywhere. switch (word) { case "static": return(new KeywordToken(scope, wordSpan, word)); } var code = scope.Code; if (code.PeekExact('.')) { var dotSpan = code.MovePeekedSpan(); var word2 = code.PeekWordR(); if (!string.IsNullOrEmpty(word2)) { var word2Span = code.MovePeekedSpan(); var argsPresent = (scope.Hint & ScopeHint.SuppressFunctionCall) == 0 && code.PeekExact('('); var argsOpenBracketSpan = argsPresent ? code.MovePeekedSpan() : Span.Empty; foreach (var def in scope.DefinitionProvider.GetAny(wordSpan.Start, word)) { if (def.AllowsChild) { // When arguments are present, take only the definitions that accept arguments var childDefs = def.GetChildDefinitions(word2).Where(x => argsPresent ? x.ArgumentsRequired : true).ToArray(); if (childDefs.Any()) { ArgsToken argsToken = null; Definition childDef = null; if (argsPresent) { var openBracketToken = new OperatorToken(scope, argsOpenBracketSpan, "("); argsToken = ArgsToken.ParseAndChooseArguments(scope, openBracketToken, childDefs, out childDef); } else { childDef = childDefs[0]; } var word1Token = new IdentifierToken(scope, wordSpan, word, def); var dotToken = new DotToken(scope, dotSpan); var word2Token = new IdentifierToken(scope, word2Span, word2, childDef); var compToken = new CompositeToken(scope, childDef.DataType); compToken.AddToken(word1Token); compToken.AddToken(dotToken); compToken.AddToken(word2Token); if (argsToken != null) { compToken.AddToken(argsToken); } return(compToken); } } } } else { code.Position = dotSpan.Start; return(new UnknownToken(scope, wordSpan, word)); } } if ((scope.Hint & ScopeHint.SuppressFunctionCall) == 0 && code.PeekExact('(')) { var argsOpenBracketSpan = code.MovePeekedSpan(); foreach (var def in scope.DefinitionProvider.GetAny(wordSpan.Start, word)) { if (def.ArgumentsRequired) { var wordToken = new IdentifierToken(scope, wordSpan, word, def); var openBracketToken = new OperatorToken(scope, argsOpenBracketSpan, "("); var argsToken = ArgsToken.Parse(scope, openBracketToken, def.Signature); var compToken = new CompositeToken(scope, def.DataType); compToken.AddToken(wordToken); compToken.AddToken(argsToken); if (def.AllowsFunctionBody && (scope.Hint & ScopeHint.SuppressFunctionDefinition) == 0) { ParseFunctionAttributes(exp, scope, compToken); if (code.PeekExact('{')) { compToken.AddToken(BracesToken.Parse(scope, def, argsToken.Span.End + 1)); } } return(compToken); } } } foreach (var def in scope.DefinitionProvider.GetAny(wordSpan.Start, word)) { if (def.ArgumentsRequired || def.RequiresChild) { continue; } return(new IdentifierToken(scope, wordSpan, word, def)); } if (StatementToken.IsStatementBreakingWord(scope, word)) { // There could be a statement without a terminating ';' before this. // This can happen if it's a macro that already includes the ';'. return(null); } if (Constants.HighlightKeywords.Contains(word)) { return(new KeywordToken(scope, wordSpan, word)); } return(new UnknownToken(scope, wordSpan, word)); }
public static ArgsToken ParseAndChooseArguments(Scope scope, OperatorToken openBracketToken, Definition[] sigDefs, out Definition selectedDef) { #if DEBUG if (sigDefs == null) { throw new ArgumentNullException("sigDefs"); } if (sigDefs.Length == 0) { throw new ArgumentException("sigDefs must contain at least one signature definition."); } #endif if (sigDefs.Length == 1) { selectedDef = sigDefs[0]; return(Parse(scope, openBracketToken, sigDefs[0].ArgumentsSignature)); } var code = scope.Code; var ret = new ArgsToken(scope, openBracketToken); scope = scope.Clone(); scope.Hint |= ScopeHint.SuppressStatementStarts; var tokens = new List <Token>(); var dataTypes = new List <DataType>(); List <Token> bestTokens = null; var bestConfidence = 0.0f; Definition bestSigDef = null; var codeResetPos = code.Position; foreach (var sigDef in sigDefs) { var args = sigDef.Arguments.ToArray(); var argIndex = 0; var expectingDataType = true; tokens.Clear(); dataTypes.Clear(); code.Position = codeResetPos; while (code.SkipWhiteSpace()) { code.Peek(); if (code.Text == ")") { tokens.Add(new OperatorToken(scope, code.MovePeekedSpan(), ")")); ret._terminated = true; break; } else if (code.Text == ",") { tokens.Add(new OperatorToken(scope, code.MovePeekedSpan(), ",")); argIndex++; expectingDataType = true; continue; } var exp = ExpressionToken.TryParse(scope, _endTokens, expectedDataType: argIndex < args.Length ? args[argIndex].DataType : null); if (exp != null) { tokens.Add(exp); if (expectingDataType) { dataTypes.Add(exp.ValueDataType); } expectingDataType = false; } else { break; } } if (dataTypes.Count == args.Length) { var confidence = 1.0f; for (int i = 0, ii = args.Length; i < ii; i++) { confidence *= DataType.CalcArgumentCompatibility(args[i].DataType, dataTypes[i]); } if (confidence > bestConfidence) { bestConfidence = confidence; bestTokens = tokens; bestSigDef = sigDef; } } else if (bestTokens == null) { bestTokens = tokens; bestConfidence = 0.0f; bestSigDef = sigDef; } } ret.AddTokens(bestTokens); ret._sig = bestSigDef.ArgumentsSignature; ret._sigAlternatives = (from s in sigDefs where s.ArgumentsSignature != ret._sig select s.ArgumentsSignature).ToArray(); selectedDef = bestSigDef; return(ret); }