/// <summary> /// Возвращает токены между ';' и 'завершить'. /// </summary> public static TokenList GetCaseBody(TokenList tokens, out int counter, int index) { int firstIndex = tokens.IndexOf(":") + 1; int lastIndex = tokens.IndexOf(KeywordType.Break); TokenList list = tokens.GetRange(firstIndex, lastIndex); if (list.Count == 0) { throw new EmptyBodyException("Конструкция 'случай' с пустым телом", lineIndex); } counter = index + lastIndex - 1; return(list); }
public void TokenList_Simple() { TokenList tokens = new TokenList(); Assert.AreEqual(0, tokens.Count); CssToken[] expect = new CssToken[] { new CssToken(CssTokenType.Asterisk, 10, 1), new CssToken(CssTokenType.Asterisk, 20, 1), new CssToken(CssTokenType.Asterisk, 30, 1), new CssToken(CssTokenType.Asterisk, 40, 1), new CssToken(CssTokenType.Asterisk, 50, 1), new CssToken(CssTokenType.Asterisk, 60, 1), }; // The token collection is supposed to automatically sort its contents, // so add the tokens in a weird order. tokens.Add(expect[3]); tokens.Add(expect[0]); tokens.Add(expect[1]); tokens.Add(expect[4]); tokens.Add(expect[2]); tokens.Insert(tokens.Count, expect[5]); Assert.AreEqual(expect.Length, tokens.Count); for (int i = 0; i < expect.Length; i++) { Assert.AreEqual(expect[i], tokens[i]); Assert.IsTrue(tokens.Contains(expect[i])); Assert.AreEqual(i, tokens.IndexOf(expect[i])); } // Test the binary search for the token collection Assert.AreEqual(0, tokens.FindInsertIndex(0, beforeExisting: true)); Assert.AreEqual(0, tokens.FindInsertIndex(10, beforeExisting: true)); Assert.AreEqual(1, tokens.FindInsertIndex(10, beforeExisting: false)); Assert.AreEqual(3, tokens.FindInsertIndex(35, beforeExisting: true)); Assert.AreEqual(3, tokens.FindInsertIndex(35, beforeExisting: false)); Assert.AreEqual(4, tokens.FindInsertIndex(50, beforeExisting: true)); Assert.AreEqual(5, tokens.FindInsertIndex(50, beforeExisting: false)); Assert.AreEqual(6, tokens.FindInsertIndex(61, beforeExisting: true)); Assert.AreEqual(6, tokens.FindInsertIndex(61, beforeExisting: false)); Assert.AreEqual(6, tokens.FindInsertIndex(100, beforeExisting: true)); Assert.AreEqual(6, tokens.FindInsertIndex(100, beforeExisting: false)); Assert.IsTrue(tokens.Remove(expect[2])); Assert.AreEqual(expect.Length - 1, tokens.Count); Assert.AreEqual(expect[3], tokens[2]); tokens.Clear(); Assert.AreEqual(0, tokens.Count); }
/// <summary> /// Парсит тела конструкций, в том числе и новой функции. /// </summary> public static void Parse(TokenList tokens, out int counter, bool isRoot = false) { counter = 0; while (counter < tokens.Count) { BaseGenerator generator = CodeManager.GetGenerator(parseMode); TokenList nextTokens = tokens.GetRange(counter); Token currentToken = tokens[counter]; Token nextToken = tokens.Get(counter + 1); if (currentToken.TypeIs(TokenType.NextLine)) { lineIndex++; counter++; continue; } if (currentToken.TypeIs(TokenType.Id)) { // <variableName> = <expression>; if (nextToken.TypeIs(TokenType.AssignOperator)) { string variableName = currentToken.value; TokenList expression = nextTokens.GetRange(nextTokens.IndexOf("=") + 1, nextTokens.IndexOf(";")); generator.AddVariableAssignment(variableName, expression, isRoot); counter += nextTokens.IndexOf(";") + 1; } // <id>(<expression>); else if (nextToken.TypeIs(TokenType.BeginParenthesis)) { Token name = currentToken; TokenList attributes = GetExpressionInParenthesis(nextTokens, errors: false); if (attributes.Count == 0 && !nextTokens.Get(2).TypeIs(TokenType.EndParenthesis)) { throw new ParseException($"После '(' при вызове функции без параметров ожидалось ')', а не '{nextToken}'", lineIndex); } generator.AddFunctionCall(name, attributes); counter += nextTokens.IndexOf(";") + 1; } else { throw new ParseException($"После '{currentToken}' ожидалось '=' либо '(', а не '{nextToken}'", lineIndex); } } else if (currentToken.TypeIs(TokenType.Keyword)) { // функция <functionName>(<parameters>) { <functionBody> } if (currentToken.TypeIs(KeywordType.Function)) { NewFunction newFunction = CodeManager.NewFunction; string name = nextToken.value; TokenList parameters = GetExpressionInParenthesis(nextTokens, errors: false); TokenList body = GetBody(nextTokens, out counter, counter); if (!nextToken.TypeIs(TokenType.Id)) { throw new ParseException($"После ключевого слова 'функция' ожидалось название объявляемой функции, а не '{nextToken}'", lineIndex); } if (!nextTokens.Get(2).TypeIs(TokenType.BeginParenthesis)) { throw new ParseException($"После названия функции ожидалось '(', а не '{nextToken}'", lineIndex); } if (parameters.Count == 0 && !nextTokens.Get(3).TypeIs(TokenType.EndParenthesis)) { throw new ParseException($"После '(' при объявлении функции без параметров ожидалось ')', а не '{nextToken}'", lineIndex); } parameters.DeleteAll(","); newFunction.AddFunctionHeader(name, parameters); parseMode = ParseMode.FunctionCreation; Parse(body, out _); newFunction.Create(); parseMode = ParseMode.Default; } // если (<expresion>) { <body> } else if (currentToken.TypeIs(KeywordType.If)) { TokenList expression = GetExpressionInParenthesis(nextTokens); TokenList body = GetBody(nextTokens, out counter, counter); if (!nextToken.TypeIs(TokenType.BeginParenthesis)) { throw new ParseException($"После ')' ожидалось '{{', а не {nextToken}", lineIndex); } generator.AddIfConstruction(expression); Parse(body, out _); generator.AddConstructionEnd(); } // иначе { <body> } else if (currentToken.TypeIs(KeywordType.Else)) { TokenList body = GetBody(nextTokens, out counter, counter); generator.AddElseConstruction(); Parse(body, out _); generator.AddConstructionEnd(); } // делать { <body> } пока (<expression>) else if (currentToken.TypeIs(KeywordType.Do)) { TokenList body = GetBody(nextTokens, out counter, counter); generator.AddDoConstruction(); Parse(body, out _); generator.AddConstructionEnd(); nextTokens = tokens.GetRange(counter); currentToken = tokens[counter]; if (currentToken.TypeIs(KeywordType.While)) { TokenList expression = GetExpressionInParenthesis(nextTokens); if (expression.Count == 0) { throw new ParseException($"Конструкция 'пока' без выражения", lineIndex); } generator.AddEndingWhileConstruction(expression); counter += nextTokens.IndexOf(";") + 1; } else { throw new ParseException($"После окончания конструкции 'делать' ожидалось ключевое слово 'пока'", lineIndex); } } // пока (<expression>) { <body> } else if (currentToken.TypeIs(KeywordType.While)) { TokenList expression = GetExpressionInParenthesis(nextTokens); TokenList body = GetBody(nextTokens, out counter, counter); generator.AddWhileConstruction(expression); Parse(body, out _); generator.AddConstructionEnd(); } // пробовать { <tryBody> } отловить [(<errorValue>)] { <catchBody> } else if (currentToken.TypeIs(KeywordType.Try)) { TokenList tryBody = GetBody(nextTokens, out counter, counter); generator.AddTryConstruction(); Parse(tryBody, out _); generator.AddConstructionEnd(); nextTokens = tokens.GetRange(counter); currentToken = tokens[counter]; if (currentToken.TypeIs(KeywordType.Catch)) { TokenList expression = GetExpressionInParenthesis(nextTokens, errors: false); TokenList catchBody = GetBody(nextTokens, out counter, counter); if (expression.Count == 1 && expression[0].TypeIs(TokenType.Id)) { generator.AddCatchConstruction(expression[0]); } else { generator.AddCatchConstruction(); } Parse(catchBody, out _); generator.AddConstructionEnd(); } } // определить (<value>) { <body> } else if (currentToken.TypeIs(KeywordType.Switch)) { TokenList expression = GetExpressionInParenthesis(nextTokens); TokenList body = GetBody(nextTokens, out counter, counter); if (expression.Count == 1 && expression[0].TypeIs(TokenType.Id)) { generator.AddSwitchConstruction(expression[0]); ParseSwitch(body); generator.AddConstructionEnd(); } } // использовать ... else if (currentToken.TypeIs(KeywordType.Use)) { // ссылки "<path>" if (nextToken.TypeIs(KeywordType.Links) && nextTokens.Get(2).TypeIs(TokenType.String) && Path.GetExtension(nextTokens[2].value) == GlobalParams.linksExtention) { CodeManager.UpdateNamesMap(nextTokens[2].value); } // <id> else if (nextToken.TypeIs(TokenType.Id)) { Compilator.AddUsing(nextToken.ToString()); Compilator.AddClassRef(nextToken.ToString()); } counter += nextTokens.IndexOf(";") + 1; } // импорт ... else if (currentToken.TypeIs(KeywordType.Import)) { if (nextToken.TypeIs(TokenType.String)) { string path = nextToken.value; if (File.Exists(path)) { string extention = Path.GetExtension(path); if (extention == GlobalParams.codeExtention) { // ...... } else { Compilator.AddRef(path); } } } counter += nextTokens.IndexOf(";") + 1; } else { throw new ParseException($"На первой позиции не ожидалось ключевое слово {currentToken}", lineIndex); } } else { throw new ParseException($"Не удалось распознать слово '{currentToken}'", lineIndex); } } }