diff --git a/docs/changelog/changes-v0.6.1.html b/docs/changelog/changes-v0.6.1.html new file mode 100644 index 0000000..a3dcae2 --- /dev/null +++ b/docs/changelog/changes-v0.6.1.html @@ -0,0 +1,10 @@ +

Changelog

+

Features

+ \ No newline at end of file diff --git a/src/DaedalusCompiler/Compilation/AssemblyBuilder.cs b/src/DaedalusCompiler/Compilation/AssemblyBuilder.cs index d0c4dc8..09f4f97 100644 --- a/src/DaedalusCompiler/Compilation/AssemblyBuilder.cs +++ b/src/DaedalusCompiler/Compilation/AssemblyBuilder.cs @@ -27,7 +27,7 @@ public AssemblyBuilderSnapshot(AssemblyBuilder assemblyBuilder) AssignmentType = assemblyBuilder.AssignmentType; FuncCallCtx = assemblyBuilder.FuncCallCtx == null ? null : new FuncCallContext(assemblyBuilder.FuncCallCtx); - ErrorContext = new ErrorContext(assemblyBuilder.ErrorContext);; + ErrorContext = new ErrorContext(assemblyBuilder.ErrorContext); } } @@ -56,10 +56,11 @@ public class AssemblyBuilder public DatSymbolType AssignmentType; private int _nextSymbolIndex; private bool _verbose; + public bool StrictSyntax; public readonly List Errors; - public AssemblyBuilder(bool verbose = true) + public AssemblyBuilder(bool verbose = true, bool strictSyntax=false) { ExecBlocks = new List(); Symbols = new List(); @@ -80,7 +81,8 @@ public AssemblyBuilder(bool verbose = true) AssignmentType = DatSymbolType.Undefined; _nextSymbolIndex = 0; _verbose = verbose; - + StrictSyntax = strictSyntax; + Errors = new List(); ErrorContext = new ErrorContext(this); } @@ -400,12 +402,13 @@ public void AssignmentEnd(string assignmentOperator) public void ExitOperator(string operatorText, bool twoArg=true) { - var instruction = AssemblyBuilderHelpers.GetInstructionForOperator(operatorText, twoArg); - _activeContext.SetEndInstruction(instruction); + if (!IsInsideConstDef) + { + var instruction = AssemblyBuilderHelpers.GetInstructionForOperator(operatorText, twoArg); + _activeContext.SetEndInstruction(instruction); + } } - - public void FuncCallStart(string funcName) { DatSymbol symbol = GetSymbolByName(funcName); diff --git a/src/DaedalusCompiler/Compilation/Compiler.cs b/src/DaedalusCompiler/Compilation/Compiler.cs index 22c3eee..0119525 100644 --- a/src/DaedalusCompiler/Compilation/Compiler.cs +++ b/src/DaedalusCompiler/Compilation/Compiler.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using Antlr4.Runtime.Tree; using DaedalusCompiler.Dat; @@ -17,13 +18,27 @@ public class Compiler private readonly string _outputDirPath; - public Compiler(string outputDirPath="output", bool verbose=true) + public Compiler(string outputDirPath="output", bool verbose=true, bool strictSyntax=false) { Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); - _assemblyBuilder = new AssemblyBuilder(verbose); + _assemblyBuilder = new AssemblyBuilder(verbose, strictSyntax); _ouBuilder = new OutputUnitsBuilder(verbose); _outputDirPath = outputDirPath; } + + public static string[] GetWarningCodesToSuppress(string line) + { + string ws = @"(?:[ \t])*"; + string newline = @"(?:\r\n?|\n)"; + RegexOptions options = RegexOptions.IgnoreCase | RegexOptions.Multiline; + string suppressWarningsPattern = $@"//{ws}suppress{ws}:((?:{ws}[a-zA-Z0-9]+)+){ws}{newline}?$"; + MatchCollection matches = Regex.Matches(line, suppressWarningsPattern, options); + foreach (Match match in matches) + { + return match.Groups[1].Value.Split(" ").Where(s => !s.Equals(String.Empty)).ToArray(); + } + return new string[]{}; + } public string GetBuiltinsPath() { @@ -66,6 +81,9 @@ public string GetBuiltinsPath() _assemblyBuilder.ErrorContext.FileContentLines = fileContent.Split(Environment.NewLine); _assemblyBuilder.ErrorContext.FilePath = paths[i]; _assemblyBuilder.ErrorContext.FileIndex = i; + _assemblyBuilder.ErrorContext.SuppressedWarningCodes = Compiler.GetWarningCodesToSuppress( + _assemblyBuilder.ErrorContext.FileContentLines[0] + ); ParseTreeWalker.Default.Walk(new DaedalusListener(_assemblyBuilder, i), parser.daedalusFile()); if (generateOutputUnits) { @@ -84,15 +102,39 @@ public string GetBuiltinsPath() } _assemblyBuilder.Finish(); - if (_assemblyBuilder.Errors.Any()) + + List errors = new List(); + foreach (CompilationMessage error in _assemblyBuilder.Errors) + { + if (error is CompilationError) + { + errors.Add(error); + } + else if (error is CompilationWarning compilationWarning) + { + if (compilationWarning.IsSuppressed == false) + { + errors.Add(compilationWarning); + } + } + } + + if (errors.Any()) { - _assemblyBuilder.Errors.Sort((x, y) => x.CompareTo(y)); + errors.Sort((x, y) => x.CompareTo(y)); + + bool stopCompilation = _assemblyBuilder.StrictSyntax; string lastErrorFilePath = ""; string lastErrorBlockName = null; var logger = new StdErrorLogger(); - foreach (CompilationMessage error in _assemblyBuilder.Errors) + foreach (CompilationMessage error in errors) { + if (error is CompilationError) + { + stopCompilation = true; + } + if (lastErrorFilePath != error.FilePath) { lastErrorFilePath = error.FilePath; @@ -115,7 +157,11 @@ public string GetBuiltinsPath() error.Print(logger); } - return false; + + if (stopCompilation) + { + return false; + } } if (compileToAssembly) diff --git a/src/DaedalusCompiler/Compilation/DaedalusListener.cs b/src/DaedalusCompiler/Compilation/DaedalusListener.cs index 5da0b4f..5020160 100644 --- a/src/DaedalusCompiler/Compilation/DaedalusListener.cs +++ b/src/DaedalusCompiler/Compilation/DaedalusListener.cs @@ -127,7 +127,9 @@ public override void EnterConstDef([NotNull] DaedalusParser.ConstDefContext cont } var location = GetLocation(context); - var assignmentExpression = constValueContext.constValueAssignment().expressionBlock().expression(); + DaedalusParser.ExpressionContext assignmentExpression = constValueContext.constValueAssignment().expressionBlock().expression(); + + _assemblyBuilder.ErrorContext.Context = assignmentExpression; var value = EvaluatorHelper.EvaluateConst(assignmentExpression, _assemblyBuilder, type); var symbol = SymbolBuilder.BuildConst(name, type, value, location); // TODO : Validate params @@ -141,6 +143,13 @@ public override void EnterConstDef([NotNull] DaedalusParser.ConstDefContext cont _assemblyBuilder.ErrorContext.Context = constArrayContext; var name = constArrayContext.nameNode().GetText(); + if (_assemblyBuilder.IsContextInsideExecBlock()) + { + BaseExecBlockContext baseExecBlock = _assemblyBuilder.ExecBlocks.Last(); + string execBlockName = baseExecBlock.GetSymbol().Name; + name = $"{execBlockName}.{name}"; + } + var location = GetLocation(context); int declaredSize = 0; @@ -245,6 +254,13 @@ public override void EnterVarDecl([NotNull] DaedalusParser.VarDeclContext contex if (varContext is DaedalusParser.VarArrayDeclContext varArrayContext) { var name = varArrayContext.nameNode().GetText(); + if (_assemblyBuilder.IsContextInsideExecBlock()) + { + BaseExecBlockContext baseExecBlock = _assemblyBuilder.ExecBlocks.Last(); + string execBlockName = baseExecBlock.GetSymbol().Name; + name = $"{execBlockName}.{name}"; + } + var location = GetLocation(context); var size = EvaluatorHelper.EvaluteArraySize(varArrayContext.arraySize(), _assemblyBuilder); @@ -380,6 +396,13 @@ public override void EnterInstanceDecl(DaedalusParser.InstanceDeclContext contex DatSymbol instanceSymbol = SymbolBuilder.BuildInstance(instanceName, referenceSymbolId, location); _assemblyBuilder.AddSymbol(instanceSymbol); symbols.Add(instanceSymbol); + + if (refSymbol.Type == DatSymbolType.Prototype) + { + _assemblyBuilder.ExecBlockStart(instanceSymbol, ExecBlockType.Instance); + _assemblyBuilder.AddInstruction(new Call(refSymbol)); + _assemblyBuilder.ExecBlockEnd(); + } } _assemblyBuilder.SharedBlockStart(symbols); @@ -564,6 +587,16 @@ public override void EnterIntegerLiteralValue(DaedalusParser.IntegerLiteralValue { if (!_assemblyBuilder.IsInsideConstDef) { + RuleContext grandparentContext = context.Parent.Parent; + if (grandparentContext is DaedalusParser.OneArgExpressionContext oneArgExpressionContext) + { + _assemblyBuilder.ErrorContext.Context = oneArgExpressionContext; + } + else + { + _assemblyBuilder.ErrorContext.Context = context; + } + bool isInsideFloatAssignment = _assemblyBuilder.IsInsideAssignment && _assemblyBuilder.AssignmentType == DatSymbolType.Float; bool isInsideFloatArgument = _assemblyBuilder.IsInsideArgList @@ -576,7 +609,8 @@ public override void EnterIntegerLiteralValue(DaedalusParser.IntegerLiteralValue } else { - _assemblyBuilder.AddInstruction(new PushInt(int.Parse(context.GetText()))); + int parsedInt = EvaluatorHelper.IntParse(context.GetText(), _assemblyBuilder); + _assemblyBuilder.AddInstruction(new PushInt(parsedInt)); } } } @@ -605,6 +639,17 @@ public override void EnterStringLiteralValue(DaedalusParser.StringLiteralValueCo /* * ENTER EXPRESSION */ + public override void EnterExpressionBlock(DaedalusParser.ExpressionBlockContext context) + { + _assemblyBuilder.ErrorContext.Context = context; + if (context.Parent is DaedalusParser.StatementContext) + { + _assemblyBuilder.Errors.Add( + new SingleExpressionWarning(_assemblyBuilder.ErrorContext, _assemblyBuilder.StrictSyntax) + ); + } + } + public override void EnterBracketExpression(DaedalusParser.BracketExpressionContext context) { _assemblyBuilder.ExpressionStart(); diff --git a/src/DaedalusCompiler/Compilation/DatBuilder.cs b/src/DaedalusCompiler/Compilation/DatBuilder.cs index abbbd36..563201f 100644 --- a/src/DaedalusCompiler/Compilation/DatBuilder.cs +++ b/src/DaedalusCompiler/Compilation/DatBuilder.cs @@ -135,12 +135,19 @@ public DatFile GetDatFile() { foreach (var symbol in sharedBlock.Symbols) { - symbol.FirstTokenAddress = _currentAddress; + if (symbol.FirstTokenAddress == -1) + { + symbol.FirstTokenAddress = _currentAddress; + } } } else { - execBlock.GetSymbol().FirstTokenAddress = _currentAddress; + DatSymbol symbol = execBlock.GetSymbol(); + if (symbol.FirstTokenAddress == -1) + { + symbol.FirstTokenAddress = _currentAddress; + } } tokens.AddRange(GetTokens(execBlock)); } diff --git a/src/DaedalusCompiler/Compilation/EvaluatorHelper.cs b/src/DaedalusCompiler/Compilation/EvaluatorHelper.cs index 6fb4f95..1ca6622 100644 --- a/src/DaedalusCompiler/Compilation/EvaluatorHelper.cs +++ b/src/DaedalusCompiler/Compilation/EvaluatorHelper.cs @@ -71,6 +71,19 @@ private static float GetFloat(string value) $"Unable to evaluate constant. Expression '{value}' contains unsupported operations."); } } + + public static int IntParse(string text, AssemblyBuilder assemblyBuilder) + { + try + { + return int.Parse(text); + } + catch (OverflowException) + { + assemblyBuilder.Errors.Add(new IntegerLiteralTooLargeError(assemblyBuilder.ErrorContext)); + return 0; + } + } private static int EvaluateConstIntExpression(DaedalusParser.ExpressionContext expression, AssemblyBuilder assemblyBuilder, string oper="") @@ -120,15 +133,7 @@ private static float GetFloat(string value) // value is simple literal if (valueChild is TerminalNodeImpl) { - try - { - return int.Parse(valueText); - } - catch (OverflowException) - { - // TODO should throw error for too small/ big int - throw new OverflowException(); - } + return IntParse(valueText, assemblyBuilder); } // value is reference to other constant diff --git a/src/DaedalusCompiler/Compilation/SemanticErrors.cs b/src/DaedalusCompiler/Compilation/SemanticErrors.cs index 85fb581..d6dce4b 100644 --- a/src/DaedalusCompiler/Compilation/SemanticErrors.cs +++ b/src/DaedalusCompiler/Compilation/SemanticErrors.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Runtime.InteropServices; using Antlr4.Runtime; using DaedalusCompiler.Dat; @@ -59,6 +58,7 @@ public class ErrorContext public string[] FileContentLines; public int FileIndex; public readonly AssemblyBuilder AssemblyBuilder; + public string[] SuppressedWarningCodes; public static readonly DatSymbol UndeclaredSymbol = new DatSymbol(); @@ -74,6 +74,7 @@ public ErrorContext(ErrorContext errorContext) FileContentLines = errorContext.FileContentLines; FileIndex = errorContext.FileIndex; AssemblyBuilder = errorContext.AssemblyBuilder; + SuppressedWarningCodes = errorContext.SuppressedWarningCodes; } } @@ -88,6 +89,16 @@ public abstract class CompilationMessage { public string ExecBlockName; public string ExecBlockType; + + public static string GetIdentifierRelativeName(string identifier) { + if (identifier.Contains(".")) + { + identifier = identifier.Split(".")[1]; + } + + return identifier; + } + protected abstract void PrintMessage(ErrorLogger logger); public void Print(ErrorLogger logger) @@ -185,8 +196,38 @@ protected CompilationError(ErrorContext errorContext) : base(errorContext) public abstract class CompilationWarning : CompilationMessage { - protected CompilationWarning(ErrorContext errorContext) : base(errorContext) + protected readonly string MessageType; + public bool IsSuppressed; + public const string Code = "UNKNOWN"; + + protected CompilationWarning(ErrorContext errorContext, bool strictSyntax) : base(errorContext) + { + IsSuppressed = false; + MessageType = strictSyntax ? "error" : "warning"; + + string[] suppressedLineWarningCodes = Compiler.GetWarningCodesToSuppress(_line); + string[] suppressedFileWarningCodes = errorContext.SuppressedWarningCodes; + string[] suppressedWarningCodes = suppressedLineWarningCodes.Concat(suppressedFileWarningCodes).ToArray(); + string code = GetType().GetField("Code").GetValue(null).ToString(); + + foreach (var warningCode in suppressedWarningCodes) + { + if (warningCode.Equals(code)) + { + IsSuppressed = true; + break; + } + } + } + } + + public class SingleExpressionWarning : CompilationWarning + { + public new const string Code = "W1"; + public SingleExpressionWarning(ErrorContext errorContext, bool strictSyntax) : base(errorContext, strictSyntax) { } + protected override void PrintMessage(ErrorLogger logger) { + logger.Log($"{FileName}:{_lineNo}:{_columnNo}: {MessageType} {Code}: usage of single-expression statement hack"); } } @@ -199,7 +240,6 @@ public class UndeclaredIdentifierError : CompilationError { _identifier = referenceContext.GetText(); } - protected override void PrintMessage(ErrorLogger logger) { logger.Log($"{FileName}:{_lineNo}:{_columnNo}: error: ‘{_identifier.Split(".").First()}’ undeclared"); @@ -263,7 +303,7 @@ public class InconsistentArraySizeError : CompilationError { public InconsistentArraySizeError(ErrorContext errorContext, string identifier, int declaredSize, int elementsCount) : base(errorContext) { - _identifier = identifier; + _identifier = GetIdentifierRelativeName(identifier); _declaredSize = declaredSize; _elementsCount = elementsCount; } @@ -281,7 +321,7 @@ public class InvalidArraySizeError : CompilationError { public InvalidArraySizeError(ErrorContext errorContext, string identifier, int declaredSize) : base(errorContext) { - _identifier = identifier; + _identifier = GetIdentifierRelativeName(identifier); _declaredSize = declaredSize; } @@ -291,4 +331,18 @@ protected override void PrintMessage(ErrorLogger logger) logger.Log($"{FileName}:{_lineNo}:{_columnNo}: error: array ‘{_identifier}’ has invalid size ‘{_declaredSize}’"); } } + + + public class IntegerLiteralTooLargeError : CompilationError { + + public IntegerLiteralTooLargeError(ErrorContext errorContext) : base(errorContext) + { + } + + + protected override void PrintMessage(ErrorLogger logger) + { + logger.Log($"{FileName}:{_lineNo}:{_columnNo}: error: integer literal is too large to be represented in an integer type"); + } + } } \ No newline at end of file diff --git a/src/DaedalusCompiler/Compilation/SymbolBuilder.cs b/src/DaedalusCompiler/Compilation/SymbolBuilder.cs index 85b1ec7..ae32a86 100644 --- a/src/DaedalusCompiler/Compilation/SymbolBuilder.cs +++ b/src/DaedalusCompiler/Compilation/SymbolBuilder.cs @@ -22,15 +22,21 @@ public static class SymbolBuilder } public static DatSymbol BuildParameter(string name, DatSymbolType type, DatSymbolLocation location = null, - int parentIndex = -1) + int parentIndex = -1, bool external=false) { - return BuildVariable(name, type, location, parentIndex); + DatSymbol symbol = BuildVariable(name, type, location, parentIndex); + if (type == DatSymbolType.Func && external == false) + { + symbol.ParametersCount = 1; + } + + return symbol; } public static DatSymbol BuildExternalParameter(string name, DatSymbolType type, DatSymbolLocation location = null, int parentIndex = -1) { - var symbol = BuildParameter(name, type, location, parentIndex); + var symbol = BuildParameter(name, type, location, parentIndex, true); symbol.ArrayLength = 0; symbol.Content = null; return symbol; @@ -114,6 +120,10 @@ public static DatSymbol BuildStringConst(object value, DatSymbolLocation locatio public static DatSymbol BuildFunc(string name, uint parametersCount, [NotNull] DatSymbolType returnType) { + if (returnType == DatSymbolType.Class) + { + returnType = DatSymbolType.Instance; + } DatSymbolFlag Flags = DatSymbolFlag.Const; if (returnType != DatSymbolType.Void) { diff --git a/src/DaedalusCompiler/Dat/DatSymbol.cs b/src/DaedalusCompiler/Dat/DatSymbol.cs index 9054f7b..66650b8 100644 --- a/src/DaedalusCompiler/Dat/DatSymbol.cs +++ b/src/DaedalusCompiler/Dat/DatSymbol.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Runtime.InteropServices; using System.Text; +using DaedalusCompiler.Compilation; namespace DaedalusCompiler.Dat { diff --git a/src/DaedalusCompiler/Program.cs b/src/DaedalusCompiler/Program.cs index a16cbf7..4485a1d 100644 --- a/src/DaedalusCompiler/Program.cs +++ b/src/DaedalusCompiler/Program.cs @@ -12,7 +12,7 @@ namespace DaedalusCompiler { class Program { - private const string version = "0.6.0"; + private const string version = "0.6.1"; private const string compiler_name = "daedalus-compiler"; static void ShowHelp() @@ -26,6 +26,7 @@ static void ShowHelp() "--load-dat loads Gothic DAT file and analyzes it, in that case file_path should be DAT file\n" + "--get-assembly compile code to readable assembly\n" + "--gen-ou generate output units files (ou.cls and ou.bin)\n" + + "--strict use more strict syntax version\n" + "--version displays version of compiler\n" + "--verbose" ); @@ -38,6 +39,7 @@ static void HandleOptionsParser(string[] args) var compileToAssembly = false; var generateOutputUnits = false; var verbose = false; + var strict = false; var getVersion = false; var p = new NDesk.Options.OptionSet () { @@ -46,6 +48,7 @@ static void HandleOptionsParser(string[] args) { "get-assembly", v => compileToAssembly = true }, { "gen-ou", v => generateOutputUnits = true }, { "verbose", v => verbose = true }, + { "strict", v => strict = true }, { "version|v", v => getVersion = true }, }; @@ -78,7 +81,7 @@ static void HandleOptionsParser(string[] args) } else { - CompileDaedalus(filePath, compileToAssembly, verbose, generateOutputUnits); + CompileDaedalus(filePath, compileToAssembly, verbose, generateOutputUnits, strict); } } } @@ -94,9 +97,9 @@ static void AnalyzeDATFile(string path) dat.Save(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), fileName)); } - static void CompileDaedalus(string path, bool compileToAssembly, bool verbose, bool generateOutputUnits) + static void CompileDaedalus(string path, bool compileToAssembly, bool verbose, bool generateOutputUnits, bool strictSyntax) { - var compiler = new Compiler("output", verbose); + var compiler = new Compiler("output", verbose, strictSyntax); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); bool compiledSuccessfully = compiler.CompileFromSrc(path, compileToAssembly, verbose, generateOutputUnits); diff --git a/src/Parser/Daedalus.g4 b/src/Parser/Daedalus.g4 index 5dad322..728e34d 100644 --- a/src/Parser/Daedalus.g4 +++ b/src/Parser/Daedalus.g4 @@ -64,7 +64,7 @@ varValueDecl: nameNode; parameterList: '(' (parameterDecl (',' parameterDecl)*? )? ')'; parameterDecl: Var typeReference nameNode ('[' arraySize ']')?; statementBlock: '{' ( ( (statement ';') | ( ifBlockStatement ( ';' )? ) ) )*? '}'; -statement: assignment | returnStatement | constDef | varDecl | funcCall | expression; +statement: assignment | returnStatement | constDef | varDecl | funcCall | expressionBlock; funcCall: nameNode '(' ( funcArgExpression ( ',' funcArgExpression )*? )? ')'; assignment: reference assignmentOperator expressionBlock; ifCondition: expressionBlock; diff --git a/src/Parser/Output/Daedalus.interp b/src/Parser/Output/Daedalus.interp index 9850a71..27dff21 100644 --- a/src/Parser/Output/Daedalus.interp +++ b/src/Parser/Output/Daedalus.interp @@ -170,4 +170,4 @@ logOrOperator atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 58, 443, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 3, 2, 3, 2, 7, 2, 105, 10, 2, 12, 2, 14, 2, 108, 11, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 116, 10, 3, 3, 3, 5, 3, 119, 10, 3, 3, 4, 3, 4, 3, 4, 5, 4, 124, 10, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 6, 5, 6, 138, 10, 6, 3, 6, 3, 6, 3, 6, 5, 6, 143, 10, 6, 7, 6, 145, 10, 6, 12, 6, 14, 6, 148, 11, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 156, 10, 7, 12, 7, 14, 7, 159, 11, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 7, 10, 181, 10, 10, 12, 10, 14, 10, 184, 11, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 5, 11, 194, 10, 11, 3, 11, 3, 11, 3, 11, 5, 11, 199, 10, 11, 7, 11, 201, 10, 11, 12, 11, 14, 11, 204, 11, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 7, 13, 217, 10, 13, 12, 13, 14, 13, 220, 11, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 18, 7, 18, 241, 10, 18, 12, 18, 14, 18, 244, 11, 18, 5, 18, 246, 10, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 5, 19, 257, 10, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 5, 20, 265, 10, 20, 5, 20, 267, 10, 20, 7, 20, 269, 10, 20, 12, 20, 14, 20, 272, 11, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 21, 3, 21, 3, 21, 5, 21, 282, 10, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 7, 22, 289, 10, 22, 12, 22, 14, 22, 292, 11, 22, 5, 22, 294, 10, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 25, 3, 26, 3, 26, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 7, 28, 318, 10, 28, 12, 28, 14, 28, 321, 11, 28, 3, 28, 5, 28, 324, 10, 28, 3, 29, 3, 29, 5, 29, 328, 10, 29, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 5, 32, 343, 10, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 7, 32, 381, 10, 32, 12, 32, 14, 32, 384, 11, 32, 3, 33, 3, 33, 5, 33, 388, 10, 33, 3, 34, 3, 34, 5, 34, 392, 10, 34, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 5, 35, 401, 10, 35, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 5, 36, 408, 10, 36, 3, 37, 3, 37, 3, 37, 5, 37, 413, 10, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 51, 10, 106, 157, 182, 218, 242, 270, 290, 319, 3, 62, 52, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 2, 10, 8, 2, 39, 39, 41, 42, 44, 44, 46, 46, 48, 48, 51, 51, 4, 2, 11, 11, 13, 16, 3, 2, 17, 18, 3, 2, 19, 20, 3, 2, 21, 24, 3, 2, 25, 26, 4, 2, 17, 18, 27, 28, 3, 2, 29, 31, 2, 446, 2, 106, 3, 2, 2, 2, 4, 115, 3, 2, 2, 2, 6, 123, 3, 2, 2, 2, 8, 127, 3, 2, 2, 2, 10, 133, 3, 2, 2, 2, 12, 149, 3, 2, 2, 2, 14, 162, 3, 2, 2, 2, 16, 169, 3, 2, 2, 2, 18, 176, 3, 2, 2, 2, 20, 189, 3, 2, 2, 2, 22, 205, 3, 2, 2, 2, 24, 211, 3, 2, 2, 2, 26, 223, 3, 2, 2, 2, 28, 226, 3, 2, 2, 2, 30, 229, 3, 2, 2, 2, 32, 234, 3, 2, 2, 2, 34, 236, 3, 2, 2, 2, 36, 249, 3, 2, 2, 2, 38, 258, 3, 2, 2, 2, 40, 281, 3, 2, 2, 2, 42, 283, 3, 2, 2, 2, 44, 297, 3, 2, 2, 2, 46, 301, 3, 2, 2, 2, 48, 303, 3, 2, 2, 2, 50, 306, 3, 2, 2, 2, 52, 311, 3, 2, 2, 2, 54, 315, 3, 2, 2, 2, 56, 325, 3, 2, 2, 2, 58, 329, 3, 2, 2, 2, 60, 331, 3, 2, 2, 2, 62, 342, 3, 2, 2, 2, 64, 387, 3, 2, 2, 2, 66, 391, 3, 2, 2, 2, 68, 400, 3, 2, 2, 2, 70, 402, 3, 2, 2, 2, 72, 409, 3, 2, 2, 2, 74, 414, 3, 2, 2, 2, 76, 416, 3, 2, 2, 2, 78, 418, 3, 2, 2, 2, 80, 420, 3, 2, 2, 2, 82, 422, 3, 2, 2, 2, 84, 424, 3, 2, 2, 2, 86, 426, 3, 2, 2, 2, 88, 428, 3, 2, 2, 2, 90, 430, 3, 2, 2, 2, 92, 432, 3, 2, 2, 2, 94, 434, 3, 2, 2, 2, 96, 436, 3, 2, 2, 2, 98, 438, 3, 2, 2, 2, 100, 440, 3, 2, 2, 2, 102, 105, 5, 4, 3, 2, 103, 105, 5, 6, 4, 2, 104, 102, 3, 2, 2, 2, 104, 103, 3, 2, 2, 2, 105, 108, 3, 2, 2, 2, 106, 107, 3, 2, 2, 2, 106, 104, 3, 2, 2, 2, 107, 109, 3, 2, 2, 2, 108, 106, 3, 2, 2, 2, 109, 110, 7, 2, 2, 3, 110, 3, 3, 2, 2, 2, 111, 116, 5, 8, 5, 2, 112, 116, 5, 12, 7, 2, 113, 116, 5, 14, 8, 2, 114, 116, 5, 16, 9, 2, 115, 111, 3, 2, 2, 2, 115, 112, 3, 2, 2, 2, 115, 113, 3, 2, 2, 2, 115, 114, 3, 2, 2, 2, 116, 118, 3, 2, 2, 2, 117, 119, 7, 3, 2, 2, 118, 117, 3, 2, 2, 2, 118, 119, 3, 2, 2, 2, 119, 5, 3, 2, 2, 2, 120, 124, 5, 10, 6, 2, 121, 124, 5, 20, 11, 2, 122, 124, 5, 18, 10, 2, 123, 120, 3, 2, 2, 2, 123, 121, 3, 2, 2, 2, 123, 122, 3, 2, 2, 2, 124, 125, 3, 2, 2, 2, 125, 126, 7, 3, 2, 2, 126, 7, 3, 2, 2, 2, 127, 128, 7, 41, 2, 2, 128, 129, 5, 74, 38, 2, 129, 130, 5, 76, 39, 2, 130, 131, 5, 34, 18, 2, 131, 132, 5, 38, 20, 2, 132, 9, 3, 2, 2, 2, 133, 134, 7, 36, 2, 2, 134, 137, 5, 74, 38, 2, 135, 138, 5, 26, 14, 2, 136, 138, 5, 22, 12, 2, 137, 135, 3, 2, 2, 2, 137, 136, 3, 2, 2, 2, 138, 146, 3, 2, 2, 2, 139, 142, 7, 4, 2, 2, 140, 143, 5, 26, 14, 2, 141, 143, 5, 22, 12, 2, 142, 140, 3, 2, 2, 2, 142, 141, 3, 2, 2, 2, 143, 145, 3, 2, 2, 2, 144, 139, 3, 2, 2, 2, 145, 148, 3, 2, 2, 2, 146, 144, 3, 2, 2, 2, 146, 147, 3, 2, 2, 2, 147, 11, 3, 2, 2, 2, 148, 146, 3, 2, 2, 2, 149, 150, 7, 43, 2, 2, 150, 151, 5, 76, 39, 2, 151, 157, 7, 5, 2, 2, 152, 153, 5, 20, 11, 2, 153, 154, 7, 3, 2, 2, 154, 156, 3, 2, 2, 2, 155, 152, 3, 2, 2, 2, 156, 159, 3, 2, 2, 2, 157, 158, 3, 2, 2, 2, 157, 155, 3, 2, 2, 2, 158, 160, 3, 2, 2, 2, 159, 157, 3, 2, 2, 2, 160, 161, 7, 6, 2, 2, 161, 13, 3, 2, 2, 2, 162, 163, 7, 47, 2, 2, 163, 164, 5, 76, 39, 2, 164, 165, 7, 7, 2, 2, 165, 166, 5, 78, 40, 2, 166, 167, 7, 8, 2, 2, 167, 168, 5, 38, 20, 2, 168, 15, 3, 2, 2, 2, 169, 170, 7, 48, 2, 2, 170, 171, 5, 76, 39, 2, 171, 172, 7, 7, 2, 2, 172, 173, 5, 78, 40, 2, 173, 174, 7, 8, 2, 2, 174, 175, 5, 38, 20, 2, 175, 17, 3, 2, 2, 2, 176, 177, 7, 48, 2, 2, 177, 182, 5, 76, 39, 2, 178, 179, 7, 4, 2, 2, 179, 181, 5, 76, 39, 2, 180, 178, 3, 2, 2, 2, 181, 184, 3, 2, 2, 2, 182, 183, 3, 2, 2, 2, 182, 180, 3, 2, 2, 2, 183, 185, 3, 2, 2, 2, 184, 182, 3, 2, 2, 2, 185, 186, 7, 7, 2, 2, 186, 187, 5, 78, 40, 2, 187, 188, 7, 8, 2, 2, 188, 19, 3, 2, 2, 2, 189, 190, 7, 37, 2, 2, 190, 193, 5, 74, 38, 2, 191, 194, 5, 32, 17, 2, 192, 194, 5, 30, 16, 2, 193, 191, 3, 2, 2, 2, 193, 192, 3, 2, 2, 2, 194, 202, 3, 2, 2, 2, 195, 198, 7, 4, 2, 2, 196, 199, 5, 32, 17, 2, 197, 199, 5, 30, 16, 2, 198, 196, 3, 2, 2, 2, 198, 197, 3, 2, 2, 2, 199, 201, 3, 2, 2, 2, 200, 195, 3, 2, 2, 2, 201, 204, 3, 2, 2, 2, 202, 200, 3, 2, 2, 2, 202, 203, 3, 2, 2, 2, 203, 21, 3, 2, 2, 2, 204, 202, 3, 2, 2, 2, 205, 206, 5, 76, 39, 2, 206, 207, 7, 9, 2, 2, 207, 208, 5, 66, 34, 2, 208, 209, 7, 10, 2, 2, 209, 210, 5, 24, 13, 2, 210, 23, 3, 2, 2, 2, 211, 212, 7, 11, 2, 2, 212, 213, 7, 5, 2, 2, 213, 218, 5, 60, 31, 2, 214, 215, 7, 4, 2, 2, 215, 217, 5, 60, 31, 2, 216, 214, 3, 2, 2, 2, 217, 220, 3, 2, 2, 2, 218, 219, 3, 2, 2, 2, 218, 216, 3, 2, 2, 2, 219, 221, 3, 2, 2, 2, 220, 218, 3, 2, 2, 2, 221, 222, 7, 6, 2, 2, 222, 25, 3, 2, 2, 2, 223, 224, 5, 76, 39, 2, 224, 225, 5, 28, 15, 2, 225, 27, 3, 2, 2, 2, 226, 227, 7, 11, 2, 2, 227, 228, 5, 60, 31, 2, 228, 29, 3, 2, 2, 2, 229, 230, 5, 76, 39, 2, 230, 231, 7, 9, 2, 2, 231, 232, 5, 66, 34, 2, 232, 233, 7, 10, 2, 2, 233, 31, 3, 2, 2, 2, 234, 235, 5, 76, 39, 2, 235, 33, 3, 2, 2, 2, 236, 245, 7, 7, 2, 2, 237, 242, 5, 36, 19, 2, 238, 239, 7, 4, 2, 2, 239, 241, 5, 36, 19, 2, 240, 238, 3, 2, 2, 2, 241, 244, 3, 2, 2, 2, 242, 243, 3, 2, 2, 2, 242, 240, 3, 2, 2, 2, 243, 246, 3, 2, 2, 2, 244, 242, 3, 2, 2, 2, 245, 237, 3, 2, 2, 2, 245, 246, 3, 2, 2, 2, 246, 247, 3, 2, 2, 2, 247, 248, 7, 8, 2, 2, 248, 35, 3, 2, 2, 2, 249, 250, 7, 37, 2, 2, 250, 251, 5, 74, 38, 2, 251, 256, 5, 76, 39, 2, 252, 253, 7, 9, 2, 2, 253, 254, 5, 66, 34, 2, 254, 255, 7, 10, 2, 2, 255, 257, 3, 2, 2, 2, 256, 252, 3, 2, 2, 2, 256, 257, 3, 2, 2, 2, 257, 37, 3, 2, 2, 2, 258, 270, 7, 5, 2, 2, 259, 260, 5, 40, 21, 2, 260, 261, 7, 3, 2, 2, 261, 267, 3, 2, 2, 2, 262, 264, 5, 54, 28, 2, 263, 265, 7, 3, 2, 2, 264, 263, 3, 2, 2, 2, 264, 265, 3, 2, 2, 2, 265, 267, 3, 2, 2, 2, 266, 259, 3, 2, 2, 2, 266, 262, 3, 2, 2, 2, 267, 269, 3, 2, 2, 2, 268, 266, 3, 2, 2, 2, 269, 272, 3, 2, 2, 2, 270, 271, 3, 2, 2, 2, 270, 268, 3, 2, 2, 2, 271, 273, 3, 2, 2, 2, 272, 270, 3, 2, 2, 2, 273, 274, 7, 6, 2, 2, 274, 39, 3, 2, 2, 2, 275, 282, 5, 44, 23, 2, 276, 282, 5, 56, 29, 2, 277, 282, 5, 10, 6, 2, 278, 282, 5, 20, 11, 2, 279, 282, 5, 42, 22, 2, 280, 282, 5, 62, 32, 2, 281, 275, 3, 2, 2, 2, 281, 276, 3, 2, 2, 2, 281, 277, 3, 2, 2, 2, 281, 278, 3, 2, 2, 2, 281, 279, 3, 2, 2, 2, 281, 280, 3, 2, 2, 2, 282, 41, 3, 2, 2, 2, 283, 284, 5, 76, 39, 2, 284, 293, 7, 7, 2, 2, 285, 290, 5, 58, 30, 2, 286, 287, 7, 4, 2, 2, 287, 289, 5, 58, 30, 2, 288, 286, 3, 2, 2, 2, 289, 292, 3, 2, 2, 2, 290, 291, 3, 2, 2, 2, 290, 288, 3, 2, 2, 2, 291, 294, 3, 2, 2, 2, 292, 290, 3, 2, 2, 2, 293, 285, 3, 2, 2, 2, 293, 294, 3, 2, 2, 2, 294, 295, 3, 2, 2, 2, 295, 296, 7, 8, 2, 2, 296, 43, 3, 2, 2, 2, 297, 298, 5, 72, 37, 2, 298, 299, 5, 80, 41, 2, 299, 300, 5, 60, 31, 2, 300, 45, 3, 2, 2, 2, 301, 302, 5, 60, 31, 2, 302, 47, 3, 2, 2, 2, 303, 304, 7, 40, 2, 2, 304, 305, 5, 38, 20, 2, 305, 49, 3, 2, 2, 2, 306, 307, 7, 40, 2, 2, 307, 308, 7, 38, 2, 2, 308, 309, 5, 46, 24, 2, 309, 310, 5, 38, 20, 2, 310, 51, 3, 2, 2, 2, 311, 312, 7, 38, 2, 2, 312, 313, 5, 46, 24, 2, 313, 314, 5, 38, 20, 2, 314, 53, 3, 2, 2, 2, 315, 319, 5, 52, 27, 2, 316, 318, 5, 50, 26, 2, 317, 316, 3, 2, 2, 2, 318, 321, 3, 2, 2, 2, 319, 320, 3, 2, 2, 2, 319, 317, 3, 2, 2, 2, 320, 323, 3, 2, 2, 2, 321, 319, 3, 2, 2, 2, 322, 324, 5, 48, 25, 2, 323, 322, 3, 2, 2, 2, 323, 324, 3, 2, 2, 2, 324, 55, 3, 2, 2, 2, 325, 327, 7, 45, 2, 2, 326, 328, 5, 60, 31, 2, 327, 326, 3, 2, 2, 2, 327, 328, 3, 2, 2, 2, 328, 57, 3, 2, 2, 2, 329, 330, 5, 60, 31, 2, 330, 59, 3, 2, 2, 2, 331, 332, 5, 62, 32, 2, 332, 61, 3, 2, 2, 2, 333, 334, 8, 32, 1, 2, 334, 335, 7, 7, 2, 2, 335, 336, 5, 62, 32, 2, 336, 337, 7, 8, 2, 2, 337, 343, 3, 2, 2, 2, 338, 339, 5, 90, 46, 2, 339, 340, 5, 62, 32, 13, 340, 343, 3, 2, 2, 2, 341, 343, 5, 68, 35, 2, 342, 333, 3, 2, 2, 2, 342, 338, 3, 2, 2, 2, 342, 341, 3, 2, 2, 2, 343, 382, 3, 2, 2, 2, 344, 345, 12, 12, 2, 2, 345, 346, 5, 92, 47, 2, 346, 347, 5, 62, 32, 13, 347, 381, 3, 2, 2, 2, 348, 349, 12, 11, 2, 2, 349, 350, 5, 82, 42, 2, 350, 351, 5, 62, 32, 12, 351, 381, 3, 2, 2, 2, 352, 353, 12, 10, 2, 2, 353, 354, 5, 84, 43, 2, 354, 355, 5, 62, 32, 11, 355, 381, 3, 2, 2, 2, 356, 357, 12, 9, 2, 2, 357, 358, 5, 86, 44, 2, 358, 359, 5, 62, 32, 10, 359, 381, 3, 2, 2, 2, 360, 361, 12, 8, 2, 2, 361, 362, 5, 88, 45, 2, 362, 363, 5, 62, 32, 9, 363, 381, 3, 2, 2, 2, 364, 365, 12, 7, 2, 2, 365, 366, 5, 94, 48, 2, 366, 367, 5, 62, 32, 8, 367, 381, 3, 2, 2, 2, 368, 369, 12, 6, 2, 2, 369, 370, 5, 96, 49, 2, 370, 371, 5, 62, 32, 7, 371, 381, 3, 2, 2, 2, 372, 373, 12, 5, 2, 2, 373, 374, 5, 98, 50, 2, 374, 375, 5, 62, 32, 6, 375, 381, 3, 2, 2, 2, 376, 377, 12, 4, 2, 2, 377, 378, 5, 100, 51, 2, 378, 379, 5, 62, 32, 5, 379, 381, 3, 2, 2, 2, 380, 344, 3, 2, 2, 2, 380, 348, 3, 2, 2, 2, 380, 352, 3, 2, 2, 2, 380, 356, 3, 2, 2, 2, 380, 360, 3, 2, 2, 2, 380, 364, 3, 2, 2, 2, 380, 368, 3, 2, 2, 2, 380, 372, 3, 2, 2, 2, 380, 376, 3, 2, 2, 2, 381, 384, 3, 2, 2, 2, 382, 380, 3, 2, 2, 2, 382, 383, 3, 2, 2, 2, 383, 63, 3, 2, 2, 2, 384, 382, 3, 2, 2, 2, 385, 388, 7, 52, 2, 2, 386, 388, 5, 70, 36, 2, 387, 385, 3, 2, 2, 2, 387, 386, 3, 2, 2, 2, 388, 65, 3, 2, 2, 2, 389, 392, 7, 52, 2, 2, 390, 392, 5, 70, 36, 2, 391, 389, 3, 2, 2, 2, 391, 390, 3, 2, 2, 2, 392, 67, 3, 2, 2, 2, 393, 401, 7, 52, 2, 2, 394, 401, 7, 53, 2, 2, 395, 401, 7, 54, 2, 2, 396, 401, 7, 49, 2, 2, 397, 401, 7, 50, 2, 2, 398, 401, 5, 42, 22, 2, 399, 401, 5, 72, 37, 2, 400, 393, 3, 2, 2, 2, 400, 394, 3, 2, 2, 2, 400, 395, 3, 2, 2, 2, 400, 396, 3, 2, 2, 2, 400, 397, 3, 2, 2, 2, 400, 398, 3, 2, 2, 2, 400, 399, 3, 2, 2, 2, 401, 69, 3, 2, 2, 2, 402, 407, 7, 51, 2, 2, 403, 404, 7, 9, 2, 2, 404, 405, 5, 64, 33, 2, 405, 406, 7, 10, 2, 2, 406, 408, 3, 2, 2, 2, 407, 403, 3, 2, 2, 2, 407, 408, 3, 2, 2, 2, 408, 71, 3, 2, 2, 2, 409, 412, 5, 70, 36, 2, 410, 411, 7, 12, 2, 2, 411, 413, 5, 70, 36, 2, 412, 410, 3, 2, 2, 2, 412, 413, 3, 2, 2, 2, 413, 73, 3, 2, 2, 2, 414, 415, 9, 2, 2, 2, 415, 75, 3, 2, 2, 2, 416, 417, 7, 51, 2, 2, 417, 77, 3, 2, 2, 2, 418, 419, 7, 51, 2, 2, 419, 79, 3, 2, 2, 2, 420, 421, 9, 3, 2, 2, 421, 81, 3, 2, 2, 2, 422, 423, 9, 4, 2, 2, 423, 83, 3, 2, 2, 2, 424, 425, 9, 5, 2, 2, 425, 85, 3, 2, 2, 2, 426, 427, 9, 6, 2, 2, 427, 87, 3, 2, 2, 2, 428, 429, 9, 7, 2, 2, 429, 89, 3, 2, 2, 2, 430, 431, 9, 8, 2, 2, 431, 91, 3, 2, 2, 2, 432, 433, 9, 9, 2, 2, 433, 93, 3, 2, 2, 2, 434, 435, 7, 32, 2, 2, 435, 95, 3, 2, 2, 2, 436, 437, 7, 33, 2, 2, 437, 97, 3, 2, 2, 2, 438, 439, 7, 34, 2, 2, 439, 99, 3, 2, 2, 2, 440, 441, 7, 35, 2, 2, 441, 101, 3, 2, 2, 2, 36, 104, 106, 115, 118, 123, 137, 142, 146, 157, 182, 193, 198, 202, 218, 242, 245, 256, 264, 266, 270, 281, 290, 293, 319, 323, 327, 342, 380, 382, 387, 391, 400, 407, 412] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 58, 443, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 3, 2, 3, 2, 7, 2, 105, 10, 2, 12, 2, 14, 2, 108, 11, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 116, 10, 3, 3, 3, 5, 3, 119, 10, 3, 3, 4, 3, 4, 3, 4, 5, 4, 124, 10, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 6, 5, 6, 138, 10, 6, 3, 6, 3, 6, 3, 6, 5, 6, 143, 10, 6, 7, 6, 145, 10, 6, 12, 6, 14, 6, 148, 11, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 156, 10, 7, 12, 7, 14, 7, 159, 11, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 7, 10, 181, 10, 10, 12, 10, 14, 10, 184, 11, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 5, 11, 194, 10, 11, 3, 11, 3, 11, 3, 11, 5, 11, 199, 10, 11, 7, 11, 201, 10, 11, 12, 11, 14, 11, 204, 11, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 7, 13, 217, 10, 13, 12, 13, 14, 13, 220, 11, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 18, 7, 18, 241, 10, 18, 12, 18, 14, 18, 244, 11, 18, 5, 18, 246, 10, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 5, 19, 257, 10, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 5, 20, 265, 10, 20, 5, 20, 267, 10, 20, 7, 20, 269, 10, 20, 12, 20, 14, 20, 272, 11, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 21, 3, 21, 3, 21, 5, 21, 282, 10, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 7, 22, 289, 10, 22, 12, 22, 14, 22, 292, 11, 22, 5, 22, 294, 10, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 25, 3, 26, 3, 26, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 7, 28, 318, 10, 28, 12, 28, 14, 28, 321, 11, 28, 3, 28, 5, 28, 324, 10, 28, 3, 29, 3, 29, 5, 29, 328, 10, 29, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 5, 32, 343, 10, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 7, 32, 381, 10, 32, 12, 32, 14, 32, 384, 11, 32, 3, 33, 3, 33, 5, 33, 388, 10, 33, 3, 34, 3, 34, 5, 34, 392, 10, 34, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 5, 35, 401, 10, 35, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 5, 36, 408, 10, 36, 3, 37, 3, 37, 3, 37, 5, 37, 413, 10, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 51, 10, 106, 157, 182, 218, 242, 270, 290, 319, 3, 62, 52, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 2, 10, 8, 2, 39, 39, 41, 42, 44, 44, 46, 46, 48, 48, 51, 51, 4, 2, 11, 11, 13, 16, 3, 2, 17, 18, 3, 2, 19, 20, 3, 2, 21, 24, 3, 2, 25, 26, 4, 2, 17, 18, 27, 28, 3, 2, 29, 31, 2, 446, 2, 106, 3, 2, 2, 2, 4, 115, 3, 2, 2, 2, 6, 123, 3, 2, 2, 2, 8, 127, 3, 2, 2, 2, 10, 133, 3, 2, 2, 2, 12, 149, 3, 2, 2, 2, 14, 162, 3, 2, 2, 2, 16, 169, 3, 2, 2, 2, 18, 176, 3, 2, 2, 2, 20, 189, 3, 2, 2, 2, 22, 205, 3, 2, 2, 2, 24, 211, 3, 2, 2, 2, 26, 223, 3, 2, 2, 2, 28, 226, 3, 2, 2, 2, 30, 229, 3, 2, 2, 2, 32, 234, 3, 2, 2, 2, 34, 236, 3, 2, 2, 2, 36, 249, 3, 2, 2, 2, 38, 258, 3, 2, 2, 2, 40, 281, 3, 2, 2, 2, 42, 283, 3, 2, 2, 2, 44, 297, 3, 2, 2, 2, 46, 301, 3, 2, 2, 2, 48, 303, 3, 2, 2, 2, 50, 306, 3, 2, 2, 2, 52, 311, 3, 2, 2, 2, 54, 315, 3, 2, 2, 2, 56, 325, 3, 2, 2, 2, 58, 329, 3, 2, 2, 2, 60, 331, 3, 2, 2, 2, 62, 342, 3, 2, 2, 2, 64, 387, 3, 2, 2, 2, 66, 391, 3, 2, 2, 2, 68, 400, 3, 2, 2, 2, 70, 402, 3, 2, 2, 2, 72, 409, 3, 2, 2, 2, 74, 414, 3, 2, 2, 2, 76, 416, 3, 2, 2, 2, 78, 418, 3, 2, 2, 2, 80, 420, 3, 2, 2, 2, 82, 422, 3, 2, 2, 2, 84, 424, 3, 2, 2, 2, 86, 426, 3, 2, 2, 2, 88, 428, 3, 2, 2, 2, 90, 430, 3, 2, 2, 2, 92, 432, 3, 2, 2, 2, 94, 434, 3, 2, 2, 2, 96, 436, 3, 2, 2, 2, 98, 438, 3, 2, 2, 2, 100, 440, 3, 2, 2, 2, 102, 105, 5, 4, 3, 2, 103, 105, 5, 6, 4, 2, 104, 102, 3, 2, 2, 2, 104, 103, 3, 2, 2, 2, 105, 108, 3, 2, 2, 2, 106, 107, 3, 2, 2, 2, 106, 104, 3, 2, 2, 2, 107, 109, 3, 2, 2, 2, 108, 106, 3, 2, 2, 2, 109, 110, 7, 2, 2, 3, 110, 3, 3, 2, 2, 2, 111, 116, 5, 8, 5, 2, 112, 116, 5, 12, 7, 2, 113, 116, 5, 14, 8, 2, 114, 116, 5, 16, 9, 2, 115, 111, 3, 2, 2, 2, 115, 112, 3, 2, 2, 2, 115, 113, 3, 2, 2, 2, 115, 114, 3, 2, 2, 2, 116, 118, 3, 2, 2, 2, 117, 119, 7, 3, 2, 2, 118, 117, 3, 2, 2, 2, 118, 119, 3, 2, 2, 2, 119, 5, 3, 2, 2, 2, 120, 124, 5, 10, 6, 2, 121, 124, 5, 20, 11, 2, 122, 124, 5, 18, 10, 2, 123, 120, 3, 2, 2, 2, 123, 121, 3, 2, 2, 2, 123, 122, 3, 2, 2, 2, 124, 125, 3, 2, 2, 2, 125, 126, 7, 3, 2, 2, 126, 7, 3, 2, 2, 2, 127, 128, 7, 41, 2, 2, 128, 129, 5, 74, 38, 2, 129, 130, 5, 76, 39, 2, 130, 131, 5, 34, 18, 2, 131, 132, 5, 38, 20, 2, 132, 9, 3, 2, 2, 2, 133, 134, 7, 36, 2, 2, 134, 137, 5, 74, 38, 2, 135, 138, 5, 26, 14, 2, 136, 138, 5, 22, 12, 2, 137, 135, 3, 2, 2, 2, 137, 136, 3, 2, 2, 2, 138, 146, 3, 2, 2, 2, 139, 142, 7, 4, 2, 2, 140, 143, 5, 26, 14, 2, 141, 143, 5, 22, 12, 2, 142, 140, 3, 2, 2, 2, 142, 141, 3, 2, 2, 2, 143, 145, 3, 2, 2, 2, 144, 139, 3, 2, 2, 2, 145, 148, 3, 2, 2, 2, 146, 144, 3, 2, 2, 2, 146, 147, 3, 2, 2, 2, 147, 11, 3, 2, 2, 2, 148, 146, 3, 2, 2, 2, 149, 150, 7, 43, 2, 2, 150, 151, 5, 76, 39, 2, 151, 157, 7, 5, 2, 2, 152, 153, 5, 20, 11, 2, 153, 154, 7, 3, 2, 2, 154, 156, 3, 2, 2, 2, 155, 152, 3, 2, 2, 2, 156, 159, 3, 2, 2, 2, 157, 158, 3, 2, 2, 2, 157, 155, 3, 2, 2, 2, 158, 160, 3, 2, 2, 2, 159, 157, 3, 2, 2, 2, 160, 161, 7, 6, 2, 2, 161, 13, 3, 2, 2, 2, 162, 163, 7, 47, 2, 2, 163, 164, 5, 76, 39, 2, 164, 165, 7, 7, 2, 2, 165, 166, 5, 78, 40, 2, 166, 167, 7, 8, 2, 2, 167, 168, 5, 38, 20, 2, 168, 15, 3, 2, 2, 2, 169, 170, 7, 48, 2, 2, 170, 171, 5, 76, 39, 2, 171, 172, 7, 7, 2, 2, 172, 173, 5, 78, 40, 2, 173, 174, 7, 8, 2, 2, 174, 175, 5, 38, 20, 2, 175, 17, 3, 2, 2, 2, 176, 177, 7, 48, 2, 2, 177, 182, 5, 76, 39, 2, 178, 179, 7, 4, 2, 2, 179, 181, 5, 76, 39, 2, 180, 178, 3, 2, 2, 2, 181, 184, 3, 2, 2, 2, 182, 183, 3, 2, 2, 2, 182, 180, 3, 2, 2, 2, 183, 185, 3, 2, 2, 2, 184, 182, 3, 2, 2, 2, 185, 186, 7, 7, 2, 2, 186, 187, 5, 78, 40, 2, 187, 188, 7, 8, 2, 2, 188, 19, 3, 2, 2, 2, 189, 190, 7, 37, 2, 2, 190, 193, 5, 74, 38, 2, 191, 194, 5, 32, 17, 2, 192, 194, 5, 30, 16, 2, 193, 191, 3, 2, 2, 2, 193, 192, 3, 2, 2, 2, 194, 202, 3, 2, 2, 2, 195, 198, 7, 4, 2, 2, 196, 199, 5, 32, 17, 2, 197, 199, 5, 30, 16, 2, 198, 196, 3, 2, 2, 2, 198, 197, 3, 2, 2, 2, 199, 201, 3, 2, 2, 2, 200, 195, 3, 2, 2, 2, 201, 204, 3, 2, 2, 2, 202, 200, 3, 2, 2, 2, 202, 203, 3, 2, 2, 2, 203, 21, 3, 2, 2, 2, 204, 202, 3, 2, 2, 2, 205, 206, 5, 76, 39, 2, 206, 207, 7, 9, 2, 2, 207, 208, 5, 66, 34, 2, 208, 209, 7, 10, 2, 2, 209, 210, 5, 24, 13, 2, 210, 23, 3, 2, 2, 2, 211, 212, 7, 11, 2, 2, 212, 213, 7, 5, 2, 2, 213, 218, 5, 60, 31, 2, 214, 215, 7, 4, 2, 2, 215, 217, 5, 60, 31, 2, 216, 214, 3, 2, 2, 2, 217, 220, 3, 2, 2, 2, 218, 219, 3, 2, 2, 2, 218, 216, 3, 2, 2, 2, 219, 221, 3, 2, 2, 2, 220, 218, 3, 2, 2, 2, 221, 222, 7, 6, 2, 2, 222, 25, 3, 2, 2, 2, 223, 224, 5, 76, 39, 2, 224, 225, 5, 28, 15, 2, 225, 27, 3, 2, 2, 2, 226, 227, 7, 11, 2, 2, 227, 228, 5, 60, 31, 2, 228, 29, 3, 2, 2, 2, 229, 230, 5, 76, 39, 2, 230, 231, 7, 9, 2, 2, 231, 232, 5, 66, 34, 2, 232, 233, 7, 10, 2, 2, 233, 31, 3, 2, 2, 2, 234, 235, 5, 76, 39, 2, 235, 33, 3, 2, 2, 2, 236, 245, 7, 7, 2, 2, 237, 242, 5, 36, 19, 2, 238, 239, 7, 4, 2, 2, 239, 241, 5, 36, 19, 2, 240, 238, 3, 2, 2, 2, 241, 244, 3, 2, 2, 2, 242, 243, 3, 2, 2, 2, 242, 240, 3, 2, 2, 2, 243, 246, 3, 2, 2, 2, 244, 242, 3, 2, 2, 2, 245, 237, 3, 2, 2, 2, 245, 246, 3, 2, 2, 2, 246, 247, 3, 2, 2, 2, 247, 248, 7, 8, 2, 2, 248, 35, 3, 2, 2, 2, 249, 250, 7, 37, 2, 2, 250, 251, 5, 74, 38, 2, 251, 256, 5, 76, 39, 2, 252, 253, 7, 9, 2, 2, 253, 254, 5, 66, 34, 2, 254, 255, 7, 10, 2, 2, 255, 257, 3, 2, 2, 2, 256, 252, 3, 2, 2, 2, 256, 257, 3, 2, 2, 2, 257, 37, 3, 2, 2, 2, 258, 270, 7, 5, 2, 2, 259, 260, 5, 40, 21, 2, 260, 261, 7, 3, 2, 2, 261, 267, 3, 2, 2, 2, 262, 264, 5, 54, 28, 2, 263, 265, 7, 3, 2, 2, 264, 263, 3, 2, 2, 2, 264, 265, 3, 2, 2, 2, 265, 267, 3, 2, 2, 2, 266, 259, 3, 2, 2, 2, 266, 262, 3, 2, 2, 2, 267, 269, 3, 2, 2, 2, 268, 266, 3, 2, 2, 2, 269, 272, 3, 2, 2, 2, 270, 271, 3, 2, 2, 2, 270, 268, 3, 2, 2, 2, 271, 273, 3, 2, 2, 2, 272, 270, 3, 2, 2, 2, 273, 274, 7, 6, 2, 2, 274, 39, 3, 2, 2, 2, 275, 282, 5, 44, 23, 2, 276, 282, 5, 56, 29, 2, 277, 282, 5, 10, 6, 2, 278, 282, 5, 20, 11, 2, 279, 282, 5, 42, 22, 2, 280, 282, 5, 60, 31, 2, 281, 275, 3, 2, 2, 2, 281, 276, 3, 2, 2, 2, 281, 277, 3, 2, 2, 2, 281, 278, 3, 2, 2, 2, 281, 279, 3, 2, 2, 2, 281, 280, 3, 2, 2, 2, 282, 41, 3, 2, 2, 2, 283, 284, 5, 76, 39, 2, 284, 293, 7, 7, 2, 2, 285, 290, 5, 58, 30, 2, 286, 287, 7, 4, 2, 2, 287, 289, 5, 58, 30, 2, 288, 286, 3, 2, 2, 2, 289, 292, 3, 2, 2, 2, 290, 291, 3, 2, 2, 2, 290, 288, 3, 2, 2, 2, 291, 294, 3, 2, 2, 2, 292, 290, 3, 2, 2, 2, 293, 285, 3, 2, 2, 2, 293, 294, 3, 2, 2, 2, 294, 295, 3, 2, 2, 2, 295, 296, 7, 8, 2, 2, 296, 43, 3, 2, 2, 2, 297, 298, 5, 72, 37, 2, 298, 299, 5, 80, 41, 2, 299, 300, 5, 60, 31, 2, 300, 45, 3, 2, 2, 2, 301, 302, 5, 60, 31, 2, 302, 47, 3, 2, 2, 2, 303, 304, 7, 40, 2, 2, 304, 305, 5, 38, 20, 2, 305, 49, 3, 2, 2, 2, 306, 307, 7, 40, 2, 2, 307, 308, 7, 38, 2, 2, 308, 309, 5, 46, 24, 2, 309, 310, 5, 38, 20, 2, 310, 51, 3, 2, 2, 2, 311, 312, 7, 38, 2, 2, 312, 313, 5, 46, 24, 2, 313, 314, 5, 38, 20, 2, 314, 53, 3, 2, 2, 2, 315, 319, 5, 52, 27, 2, 316, 318, 5, 50, 26, 2, 317, 316, 3, 2, 2, 2, 318, 321, 3, 2, 2, 2, 319, 320, 3, 2, 2, 2, 319, 317, 3, 2, 2, 2, 320, 323, 3, 2, 2, 2, 321, 319, 3, 2, 2, 2, 322, 324, 5, 48, 25, 2, 323, 322, 3, 2, 2, 2, 323, 324, 3, 2, 2, 2, 324, 55, 3, 2, 2, 2, 325, 327, 7, 45, 2, 2, 326, 328, 5, 60, 31, 2, 327, 326, 3, 2, 2, 2, 327, 328, 3, 2, 2, 2, 328, 57, 3, 2, 2, 2, 329, 330, 5, 60, 31, 2, 330, 59, 3, 2, 2, 2, 331, 332, 5, 62, 32, 2, 332, 61, 3, 2, 2, 2, 333, 334, 8, 32, 1, 2, 334, 335, 7, 7, 2, 2, 335, 336, 5, 62, 32, 2, 336, 337, 7, 8, 2, 2, 337, 343, 3, 2, 2, 2, 338, 339, 5, 90, 46, 2, 339, 340, 5, 62, 32, 13, 340, 343, 3, 2, 2, 2, 341, 343, 5, 68, 35, 2, 342, 333, 3, 2, 2, 2, 342, 338, 3, 2, 2, 2, 342, 341, 3, 2, 2, 2, 343, 382, 3, 2, 2, 2, 344, 345, 12, 12, 2, 2, 345, 346, 5, 92, 47, 2, 346, 347, 5, 62, 32, 13, 347, 381, 3, 2, 2, 2, 348, 349, 12, 11, 2, 2, 349, 350, 5, 82, 42, 2, 350, 351, 5, 62, 32, 12, 351, 381, 3, 2, 2, 2, 352, 353, 12, 10, 2, 2, 353, 354, 5, 84, 43, 2, 354, 355, 5, 62, 32, 11, 355, 381, 3, 2, 2, 2, 356, 357, 12, 9, 2, 2, 357, 358, 5, 86, 44, 2, 358, 359, 5, 62, 32, 10, 359, 381, 3, 2, 2, 2, 360, 361, 12, 8, 2, 2, 361, 362, 5, 88, 45, 2, 362, 363, 5, 62, 32, 9, 363, 381, 3, 2, 2, 2, 364, 365, 12, 7, 2, 2, 365, 366, 5, 94, 48, 2, 366, 367, 5, 62, 32, 8, 367, 381, 3, 2, 2, 2, 368, 369, 12, 6, 2, 2, 369, 370, 5, 96, 49, 2, 370, 371, 5, 62, 32, 7, 371, 381, 3, 2, 2, 2, 372, 373, 12, 5, 2, 2, 373, 374, 5, 98, 50, 2, 374, 375, 5, 62, 32, 6, 375, 381, 3, 2, 2, 2, 376, 377, 12, 4, 2, 2, 377, 378, 5, 100, 51, 2, 378, 379, 5, 62, 32, 5, 379, 381, 3, 2, 2, 2, 380, 344, 3, 2, 2, 2, 380, 348, 3, 2, 2, 2, 380, 352, 3, 2, 2, 2, 380, 356, 3, 2, 2, 2, 380, 360, 3, 2, 2, 2, 380, 364, 3, 2, 2, 2, 380, 368, 3, 2, 2, 2, 380, 372, 3, 2, 2, 2, 380, 376, 3, 2, 2, 2, 381, 384, 3, 2, 2, 2, 382, 380, 3, 2, 2, 2, 382, 383, 3, 2, 2, 2, 383, 63, 3, 2, 2, 2, 384, 382, 3, 2, 2, 2, 385, 388, 7, 52, 2, 2, 386, 388, 5, 70, 36, 2, 387, 385, 3, 2, 2, 2, 387, 386, 3, 2, 2, 2, 388, 65, 3, 2, 2, 2, 389, 392, 7, 52, 2, 2, 390, 392, 5, 70, 36, 2, 391, 389, 3, 2, 2, 2, 391, 390, 3, 2, 2, 2, 392, 67, 3, 2, 2, 2, 393, 401, 7, 52, 2, 2, 394, 401, 7, 53, 2, 2, 395, 401, 7, 54, 2, 2, 396, 401, 7, 49, 2, 2, 397, 401, 7, 50, 2, 2, 398, 401, 5, 42, 22, 2, 399, 401, 5, 72, 37, 2, 400, 393, 3, 2, 2, 2, 400, 394, 3, 2, 2, 2, 400, 395, 3, 2, 2, 2, 400, 396, 3, 2, 2, 2, 400, 397, 3, 2, 2, 2, 400, 398, 3, 2, 2, 2, 400, 399, 3, 2, 2, 2, 401, 69, 3, 2, 2, 2, 402, 407, 7, 51, 2, 2, 403, 404, 7, 9, 2, 2, 404, 405, 5, 64, 33, 2, 405, 406, 7, 10, 2, 2, 406, 408, 3, 2, 2, 2, 407, 403, 3, 2, 2, 2, 407, 408, 3, 2, 2, 2, 408, 71, 3, 2, 2, 2, 409, 412, 5, 70, 36, 2, 410, 411, 7, 12, 2, 2, 411, 413, 5, 70, 36, 2, 412, 410, 3, 2, 2, 2, 412, 413, 3, 2, 2, 2, 413, 73, 3, 2, 2, 2, 414, 415, 9, 2, 2, 2, 415, 75, 3, 2, 2, 2, 416, 417, 7, 51, 2, 2, 417, 77, 3, 2, 2, 2, 418, 419, 7, 51, 2, 2, 419, 79, 3, 2, 2, 2, 420, 421, 9, 3, 2, 2, 421, 81, 3, 2, 2, 2, 422, 423, 9, 4, 2, 2, 423, 83, 3, 2, 2, 2, 424, 425, 9, 5, 2, 2, 425, 85, 3, 2, 2, 2, 426, 427, 9, 6, 2, 2, 427, 87, 3, 2, 2, 2, 428, 429, 9, 7, 2, 2, 429, 89, 3, 2, 2, 2, 430, 431, 9, 8, 2, 2, 431, 91, 3, 2, 2, 2, 432, 433, 9, 9, 2, 2, 433, 93, 3, 2, 2, 2, 434, 435, 7, 32, 2, 2, 435, 95, 3, 2, 2, 2, 436, 437, 7, 33, 2, 2, 437, 97, 3, 2, 2, 2, 438, 439, 7, 34, 2, 2, 439, 99, 3, 2, 2, 2, 440, 441, 7, 35, 2, 2, 441, 101, 3, 2, 2, 2, 36, 104, 106, 115, 118, 123, 137, 142, 146, 157, 182, 193, 198, 202, 218, 242, 245, 256, 264, 266, 270, 281, 290, 293, 319, 323, 327, 342, 380, 382, 387, 391, 400, 407, 412] \ No newline at end of file diff --git a/src/Parser/Output/DaedalusParser.cs b/src/Parser/Output/DaedalusParser.cs index 1bab19d..bfabe49 100644 --- a/src/Parser/Output/DaedalusParser.cs +++ b/src/Parser/Output/DaedalusParser.cs @@ -1375,8 +1375,8 @@ public partial class StatementContext : ParserRuleContext { public FuncCallContext funcCall() { return GetRuleContext(0); } - public ExpressionContext expression() { - return GetRuleContext(0); + public ExpressionBlockContext expressionBlock() { + return GetRuleContext(0); } public StatementContext(ParserRuleContext parent, int invokingState) : base(parent, invokingState) @@ -1434,7 +1434,7 @@ public StatementContext(ParserRuleContext parent, int invokingState) case 6: EnterOuterAlt(_localctx, 6); { - State = 278; expression(0); + State = 278; expressionBlock(); } break; } @@ -3625,21 +3625,21 @@ public LogOrOperatorContext(ParserRuleContext parent, int invokingState) '\x113', '\x11A', '\x5', ',', '\x17', '\x2', '\x114', '\x11A', '\x5', '\x38', '\x1D', '\x2', '\x115', '\x11A', '\x5', '\n', '\x6', '\x2', '\x116', '\x11A', '\x5', '\x14', '\v', '\x2', '\x117', '\x11A', '\x5', '*', '\x16', - '\x2', '\x118', '\x11A', '\x5', '>', ' ', '\x2', '\x119', '\x113', '\x3', - '\x2', '\x2', '\x2', '\x119', '\x114', '\x3', '\x2', '\x2', '\x2', '\x119', - '\x115', '\x3', '\x2', '\x2', '\x2', '\x119', '\x116', '\x3', '\x2', '\x2', - '\x2', '\x119', '\x117', '\x3', '\x2', '\x2', '\x2', '\x119', '\x118', - '\x3', '\x2', '\x2', '\x2', '\x11A', ')', '\x3', '\x2', '\x2', '\x2', - '\x11B', '\x11C', '\x5', 'L', '\'', '\x2', '\x11C', '\x125', '\a', '\a', - '\x2', '\x2', '\x11D', '\x122', '\x5', ':', '\x1E', '\x2', '\x11E', '\x11F', - '\a', '\x4', '\x2', '\x2', '\x11F', '\x121', '\x5', ':', '\x1E', '\x2', - '\x120', '\x11E', '\x3', '\x2', '\x2', '\x2', '\x121', '\x124', '\x3', - '\x2', '\x2', '\x2', '\x122', '\x123', '\x3', '\x2', '\x2', '\x2', '\x122', - '\x120', '\x3', '\x2', '\x2', '\x2', '\x123', '\x126', '\x3', '\x2', '\x2', - '\x2', '\x124', '\x122', '\x3', '\x2', '\x2', '\x2', '\x125', '\x11D', - '\x3', '\x2', '\x2', '\x2', '\x125', '\x126', '\x3', '\x2', '\x2', '\x2', - '\x126', '\x127', '\x3', '\x2', '\x2', '\x2', '\x127', '\x128', '\a', - '\b', '\x2', '\x2', '\x128', '+', '\x3', '\x2', '\x2', '\x2', '\x129', + '\x2', '\x118', '\x11A', '\x5', '<', '\x1F', '\x2', '\x119', '\x113', + '\x3', '\x2', '\x2', '\x2', '\x119', '\x114', '\x3', '\x2', '\x2', '\x2', + '\x119', '\x115', '\x3', '\x2', '\x2', '\x2', '\x119', '\x116', '\x3', + '\x2', '\x2', '\x2', '\x119', '\x117', '\x3', '\x2', '\x2', '\x2', '\x119', + '\x118', '\x3', '\x2', '\x2', '\x2', '\x11A', ')', '\x3', '\x2', '\x2', + '\x2', '\x11B', '\x11C', '\x5', 'L', '\'', '\x2', '\x11C', '\x125', '\a', + '\a', '\x2', '\x2', '\x11D', '\x122', '\x5', ':', '\x1E', '\x2', '\x11E', + '\x11F', '\a', '\x4', '\x2', '\x2', '\x11F', '\x121', '\x5', ':', '\x1E', + '\x2', '\x120', '\x11E', '\x3', '\x2', '\x2', '\x2', '\x121', '\x124', + '\x3', '\x2', '\x2', '\x2', '\x122', '\x123', '\x3', '\x2', '\x2', '\x2', + '\x122', '\x120', '\x3', '\x2', '\x2', '\x2', '\x123', '\x126', '\x3', + '\x2', '\x2', '\x2', '\x124', '\x122', '\x3', '\x2', '\x2', '\x2', '\x125', + '\x11D', '\x3', '\x2', '\x2', '\x2', '\x125', '\x126', '\x3', '\x2', '\x2', + '\x2', '\x126', '\x127', '\x3', '\x2', '\x2', '\x2', '\x127', '\x128', + '\a', '\b', '\x2', '\x2', '\x128', '+', '\x3', '\x2', '\x2', '\x2', '\x129', '\x12A', '\x5', 'H', '%', '\x2', '\x12A', '\x12B', '\x5', 'P', ')', '\x2', '\x12B', '\x12C', '\x5', '<', '\x1F', '\x2', '\x12C', '-', '\x3', '\x2', '\x2', '\x2', '\x12D', '\x12E', '\x5', '<', '\x1F', '\x2', '\x12E', '/', diff --git a/test/DaedalusCompiler.Tests/OutputComparisonTests.cs b/test/DaedalusCompiler.Tests/OutputComparisonTests.cs index 7955f0a..88fa30d 100644 --- a/test/DaedalusCompiler.Tests/OutputComparisonTests.cs +++ b/test/DaedalusCompiler.Tests/OutputComparisonTests.cs @@ -14,167 +14,110 @@ namespace DaedalusCompiler.Tests { - public static class Constants - { - public const string SrcPathsLabel = "SRC_PATHS"; - public const string DatPathsLabel = "DAT_PATHS"; - public const string OuPathsLabel = "OU_PATHS"; - public const string ScriptsUrlLabel = "SCRIPTS_URL"; - public const string ScriptsPasswordLabel = "SCRIPTS_PASSWORD"; - - public const string ScriptsFileName = "Scripts.zip"; - public const string ProjectName = "DaedalusCompiler.Tests"; - } - - - public class Config - { - public List SRC_PATHS; - public List DAT_PATHS; - public List OU_PATHS; - public string SCRIPTS_URL; - public string SCRIPTS_PASSWORD; - - public List GetPaths(string envVarName) - { - switch (envVarName) - { - case Constants.SrcPathsLabel: - return SRC_PATHS; - case Constants.DatPathsLabel: - return DAT_PATHS; - case Constants.OuPathsLabel: - return OU_PATHS; - default: - return null; - } - } - } - public class DatComparisonTests { + private const string ProjectName = "DaedalusCompiler.Tests"; private readonly ITestOutputHelper _output; + private readonly string _downloadTo; + private string _scriptsPath; + + private List _srcPaths = new List() + { + "Scripts/Content/*.src", + "Scripts/System/*.src" + }; + private string _datPath = "Scripts/_compiled/*.dat"; + private string _ouPath = "Scripts/Content/Cutscene/ou.*"; + private string _outputPath = "output"; - private string _projectPath; private Dictionary _srcPathToDatPath; - private Config _config; private static readonly HashSet NameExceptions = new HashSet() { "FACE_N_TOUGH_LEE_ÄHNLICH" }; - public DatComparisonTests(ITestOutputHelper output) { - _output = output; + // string projectPath = Path.Combine(Environment.CurrentDirectory.Split(ProjectName).First(), ProjectName); + string baseDirectory = AppDomain.CurrentDomain.BaseDirectory; + DirectoryInfo baseDirectoryInfo = new DirectoryInfo(baseDirectory); + string solutionPath = baseDirectoryInfo.Parent?.Parent?.Parent?.Parent?.Parent?.ToString(); + string projectPath = Path.Combine(solutionPath, "test", "DaedalusCompiler.Tests"); - LoadJsonConfig(); - DownloadScripts(); - ExtractScripts(); - InitializeSrcPathToDatPath(); + _downloadTo = "{PROJECT_PATH}/TestFiles/".Replace("{PROJECT_PATH}", projectPath); + _output = output; } - private void LoadJsonConfig() + private void PrepareScripts(string name, string url, string zipPassword) { - _projectPath = Path.Combine(Environment.CurrentDirectory.Split(Constants.ProjectName).First(), Constants.ProjectName); - string configPath = Path.Combine(_projectPath, "config.json"); - if (File.Exists(configPath)) - { - using (StreamReader reader = new StreamReader(configPath)) - { - string content = reader.ReadToEnd(); - _config = JsonConvert.DeserializeObject(content); - } - } - } + _scriptsPath = Path.Combine(_downloadTo, name); - private void DownloadScripts() - { - string scriptsUrl = _config?.SCRIPTS_URL ?? Environment.GetEnvironmentVariable(Constants.ScriptsUrlLabel); - if (scriptsUrl == null) - { - return; - } - - string scriptsFilePath = Path.Combine(_projectPath, Constants.ScriptsFileName); + string scriptsFileName = Path.ChangeExtension(name, "zip"); + string scriptsFilePath = Path.Combine(_downloadTo, scriptsFileName); + + (new FileInfo(scriptsFilePath)).Directory?.Create(); File.Delete(scriptsFilePath); - - using (WebClient client = new WebClient()) - { - client.DownloadFile(scriptsUrl, scriptsFilePath); - _output.WriteLine($"Downloaded {Constants.ScriptsFileName}."); - } - } - private void ExtractScripts() - { - string scriptsFilePath = Path.Combine(_projectPath, Constants.ScriptsFileName); - if (!File.Exists(scriptsFilePath)) + using (WebClient client = new WebClient()) { - return; + client.DownloadFile(url, scriptsFilePath); + _output.WriteLine($"Downloaded {scriptsFileName}."); } - string scriptsPassword = _config?.SCRIPTS_PASSWORD ?? Environment.GetEnvironmentVariable(Constants.ScriptsPasswordLabel); - Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); using (ZipFile archive = new ZipFile(scriptsFilePath)) { - archive.Password = scriptsPassword ; - archive.ExtractAll(_projectPath, ExtractExistingFileAction.OverwriteSilently); - _output.WriteLine($"Extracted {Constants.ScriptsFileName} into {_projectPath}."); + archive.Password = zipPassword ; + archive.ExtractAll(_scriptsPath, ExtractExistingFileAction.OverwriteSilently); + _output.WriteLine($"Extracted {scriptsFileName} into {_scriptsPath}."); } } - private void InitializeSrcPathToDatPath() + private void CompileScripts(string compileTime="", string compileUsername="") { _srcPathToDatPath = new Dictionary(); - - List srcPaths = GetPaths(Constants.SrcPathsLabel); - List datPaths = GetPaths(Constants.DatPathsLabel); - + List srcPaths = WildcardExpansion(_srcPaths); + List datPaths = WildcardExpansion(_datPath); Dictionary filenameToSrcPath = GetFilenameWithoutExtensionToPathMapping(srcPaths); Dictionary filenameToDatPath = GetFilenameWithoutExtensionToPathMapping(datPaths); - foreach (string filename in filenameToSrcPath.Keys) { string srcPath = filenameToSrcPath[filename]; string datPath = filenameToDatPath[filename]; _srcPathToDatPath[srcPath] = datPath; } - } - - private List GetPaths(string envVarName) - { - List wildcardPaths = _config?.GetPaths(envVarName) ?? GetListFromEnvironmentVariable(envVarName); - if (wildcardPaths == null) + string outputDirPath = Path.Combine(_scriptsPath, _outputPath); + foreach(KeyValuePair entry in _srcPathToDatPath) { - throw new Exception($"Couldn't load {envVarName}! Please set up proper environment variable or config.json file!"); + string srcPath = entry.Key; + string datPath = entry.Value; + string datFileName = Path.GetFileName(datPath).ToLower(); + bool generateOutputUnits = (datFileName == "gothic.dat"); + + Compiler compiler = new Compiler(outputDirPath); + if (generateOutputUnits) + { + compiler.SetCompilationDateTimeText(compileTime); + compiler.SetCompilationUserName(compileUsername); + } + compiler.CompileFromSrc(srcPath, compileToAssembly:false, verbose:false, generateOutputUnits: generateOutputUnits); } - - wildcardPaths = wildcardPaths.Select(x => x.Replace("{PROJECT_PATH}", _projectPath)).ToList(); - return WildcardExpansion(wildcardPaths); - } - - private List GetListFromEnvironmentVariable(string variableName) + + private List WildcardExpansion(string wildcardPath) { - string variableContent = Environment.GetEnvironmentVariable(variableName); - _output.WriteLine($"{variableName} = {Environment.GetEnvironmentVariable(variableName)}"); - return variableContent - ?.Split(";") - .Where(x => !string.IsNullOrEmpty(x)) - .ToList(); + return WildcardExpansion(new List() {wildcardPath}); } - - private static List WildcardExpansion(List wildcardPaths) + + private List WildcardExpansion(List wildcardPaths) { List paths = new List(); foreach (var wildcardPath in wildcardPaths) { - string dirPath = Path.GetDirectoryName(wildcardPath); + string dirPath = Path.Combine(_scriptsPath, Path.GetDirectoryName(wildcardPath)); string filenamePattern = Path.GetFileName(wildcardPath); EnumerationOptions options = new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive }; paths.AddRange(Directory.GetFiles(dirPath, filenamePattern, options).ToList()); @@ -182,8 +125,7 @@ private static List WildcardExpansion(List wildcardPaths) return paths; } - - + private static Dictionary GetFilenameWithoutExtensionToPathMapping(List paths) { return paths.ToDictionary(x => Path.GetFileNameWithoutExtension(x).ToLower(), x => x); @@ -194,16 +136,41 @@ private static List WildcardExpansion(List wildcardPaths) { return paths.ToDictionary(x => Path.GetFileName(x).ToLower(), x => x); } + + private void CompareDats() + { + string outputDirPath = Path.Combine(_scriptsPath, _outputPath); + foreach (KeyValuePair entry in _srcPathToDatPath) + { + string datPath = entry.Value; + string datFileName = Path.GetFileName(datPath).ToLower(); + string outputDatPath = Path.Combine(outputDirPath, datFileName); + + DatFile expectedDatFile = new DatFile(datPath); + DatFile datFile = new DatFile(outputDatPath); + + Assert.Equal(expectedDatFile.Version, datFile.Version); + CompareSymbols(expectedDatFile.Symbols.ToList(), datFile.Symbols.ToList()); + CompareTokens(expectedDatFile.Tokens.ToList(), datFile.Tokens.ToList()); + } + } - private void CompareDats(string expectedDatPath, string datPath) + private void CompareOuFiles() { - DatFile expectedDatFile = new DatFile(expectedDatPath); - DatFile datFile = new DatFile(datPath); + string outputDirPath = Path.Combine(_scriptsPath, _outputPath); - Assert.Equal(expectedDatFile.Version, datFile.Version); - CompareSymbols(expectedDatFile.Symbols.ToList(), datFile.Symbols.ToList()); - CompareTokens(expectedDatFile.Tokens.ToList(), datFile.Tokens.ToList()); + string ouCslFileName = "ou.csl"; + string ouBinFileName = "ou.bin"; + + string outputOuCslPath = Path.Combine(outputDirPath, ouCslFileName); + string outputOuBinPath = Path.Combine(outputDirPath, ouBinFileName); + + List ouPaths = WildcardExpansion(_ouPath); + Dictionary filenameToOuPath = GetFilenameToPathMapping(ouPaths); + + CompareFilesByteByByte(filenameToOuPath[ouCslFileName], outputOuCslPath); + CompareFilesByteByByte(filenameToOuPath[ouBinFileName], outputOuBinPath); } private void CompareSymbols(List expectedSymbols, List symbols) @@ -212,7 +179,8 @@ private void CompareSymbols(List expectedSymbols, List sym { DatSymbolType.Int, DatSymbolType.Float, - DatSymbolType.String + DatSymbolType.String, + DatSymbolType.Func }; int lastParentIndex = DatSymbol.NULL_INDEX; @@ -286,44 +254,33 @@ private void CompareFilesByteByByte(string expectedOuPath, string ouPath) } } + [Fact] - public void TestIfCompiledScriptsMatchOriginalDatAndOuFiles() + public void TestIfCompiledScriptsMatchOriginalDatAndOuFilesG2NotR() { - string baseDirectory = AppDomain.CurrentDomain.BaseDirectory; - DirectoryInfo baseDirectoryInfo = new DirectoryInfo(baseDirectory); - string solutionPath = baseDirectoryInfo.Parent?.Parent?.Parent?.Parent?.Parent?.ToString(); - - string outputDirPath = Path.Combine(solutionPath, "test", "DaedalusCompiler.Tests", "output"); - - foreach(KeyValuePair entry in _srcPathToDatPath) - { - string srcPath = entry.Key; - string datPath = entry.Value; - string datFileName = Path.GetFileName(datPath).ToLower(); - string outputDatPath = Path.Combine(outputDirPath, datFileName); - bool generateOutputUnits = (datFileName == "gothic.dat"); - - Compiler compiler = new Compiler(outputDirPath); - if (generateOutputUnits) - { - compiler.SetCompilationDateTimeText("13.11.2018 15:30:55"); - compiler.SetCompilationUserName("kisio"); - } - compiler.CompileFromSrc(srcPath, compileToAssembly:false, verbose:false, generateOutputUnits: generateOutputUnits); - CompareDats(datPath, outputDatPath); - } + PrepareScripts( + "G2NotR", + "https://drive.google.com/uc?authuser=0&id=1TZFfADoOPrmdNHbrbxMAad7Mk63HKloT&export=download", + "dziejekhorinis" + ); - string ouCslFileName = "ou.csl"; - string ouBinFileName = "ou.bin"; - - string outputOuCslPath = Path.Combine(outputDirPath, ouCslFileName); - string outputOuBinPath = Path.Combine(outputDirPath, ouBinFileName); - - List ouPaths = GetPaths(Constants.OuPathsLabel); - Dictionary filenameToOuPath = GetFilenameToPathMapping(ouPaths); + CompileScripts("13.11.2018 15:30:55", "kisio"); + + CompareDats(); + CompareOuFiles(); + } + + [Fact] + public void TestIfCompiledScriptsMatchOriginalDatAndOuFilesIkarusAndLeGo() + { + PrepareScripts( + "IkarusAndLego", + "https://drive.google.com/uc?authuser=0&id=1OkTUUHYt7tXTg_ewmyFQaqYMFv_6gOxW&export=download", + "dziejekhorinis" + ); - CompareFilesByteByByte(filenameToOuPath[ouCslFileName], outputOuCslPath); - CompareFilesByteByByte(filenameToOuPath[ouBinFileName], outputOuBinPath); + CompileScripts(); + CompareDats(); } } } \ No newline at end of file diff --git a/test/DaedalusCompiler.Tests/ParsingSourceToAbstractAssemblyTests.cs b/test/DaedalusCompiler.Tests/ParsingSourceToAbstractAssemblyTests.cs index f7daa71..6664960 100644 --- a/test/DaedalusCompiler.Tests/ParsingSourceToAbstractAssemblyTests.cs +++ b/test/DaedalusCompiler.Tests/ParsingSourceToAbstractAssemblyTests.cs @@ -47,12 +47,42 @@ private List GetExecBlockInstructions(string execBlockName) ParseData(); } - - BaseExecBlockContext block = _assemblyBuilder.ExecBlocks.Find(execBlock => - execBlock.GetSymbol().Name.ToUpper() == execBlockName.ToUpper()); + List instructions = new List(); + + bool alreadyFound = false; + foreach (BaseExecBlockContext execBlock in _assemblyBuilder.ExecBlocks) + { + DatSymbol testedSymbol = execBlock.GetSymbol(); + if (execBlock is SharedExecBlockContext sharedExecBlockContext) + { + foreach (DatSymbol symbol in sharedExecBlockContext.Symbols) + { + if (symbol.Name.ToUpper() == execBlockName.ToUpper()) + { + testedSymbol = symbol; + break; + } + } + } + + if (testedSymbol.Name.ToUpper() == execBlockName.ToUpper()) + { + instructions.AddRange(execBlock.Body); + _assemblyBuilder.ActiveExecBlock = execBlock; + alreadyFound = true; + } + else if (alreadyFound) + { + break; + } + } + + if (alreadyFound == false ) + { + throw new KeyNotFoundException(); + } - _assemblyBuilder.ActiveExecBlock = block; - return block.Body; + return instructions; } private void ParseData() @@ -66,6 +96,10 @@ private void ParseData() _assemblyBuilder.IsCurrentlyParsingExternals = false; } + _assemblyBuilder.ErrorContext.FileContentLines = _code.Split(Environment.NewLine); + _assemblyBuilder.ErrorContext.SuppressedWarningCodes = Compiler.GetWarningCodesToSuppress( + _assemblyBuilder.ErrorContext.FileContentLines[0] + ); Utils.WalkSourceCode(_code, _assemblyBuilder); _assemblyBuilder.Finish(); } @@ -1901,7 +1935,7 @@ public void TestIntArrElementWithLocalConstIntIndexExpression() func void testFunc() { const int INDEX_ZERO = 0; const int INDEX_ONE = 1; - const int INDEX_TWO = 2; + const int INDEX_TWO = 1 + 1; x = 1; tab[INDEX_ZERO] = 2; tab[INDEX_ONE] = 3; @@ -3089,6 +3123,7 @@ class C_NPC { prototype varprototype(C_NPC) {}; instance varinstance(C_NPC) {}; instance varinstance2(varprototype) {}; + instance varinstance3(varprototype); func int retint() {}; @@ -3163,6 +3198,31 @@ class C_NPC { }; AssertInstructionsMatch(); + _instructions = GetExecBlockInstructions("varinstance"); + _expectedInstructions = new List + { + new Ret() + }; + AssertInstructionsMatch(); + + _instructions = GetExecBlockInstructions("varinstance2"); + _expectedInstructions = new List + { + new Call(Ref("varprototype")), + + new Ret() + }; + AssertInstructionsMatch(); + + _instructions = GetExecBlockInstructions("varinstance3"); + _expectedInstructions = new List + { + new Call(Ref("varprototype")), + + new Ret() + }; + AssertInstructionsMatch(); + _expectedSymbols = new List { Ref("C_NPC"), @@ -3179,6 +3239,7 @@ class C_NPC { Ref("varprototype"), Ref("varinstance"), Ref("varinstance2"), + Ref("varinstance3"), Ref("retint"), Ref("testFunc"), }; @@ -5828,5 +5889,181 @@ class Person { }; AssertSymbolsMatch(); } + + [Fact] + public void TestSingleExpressionReturnHack() + { + _code = @" + func void testFunc() { + var int x; + x = 5; + x; + return; + }; + "; + + _instructions = GetExecBlockInstructions("testFunc"); + _expectedInstructions = new List + { + // x = 5; + new PushInt(5), + new PushVar(Ref("testFunc.x")), + new Assign(), + + // x; + new PushVar(Ref("testFunc.x")), + + // return; + new Ret(), + + new Ret() + }; + AssertInstructionsMatch(); + + _expectedSymbols = new List + { + Ref("testFunc"), + Ref("testFunc.x"), + }; + AssertSymbolsMatch(); + } + + + [Fact] + public void TestInlineInstanceDeclarations() + { + _code = @" + class C_NPC { var int data [200]; }; + instance Mage, Archer, Barbarian(C_NPC); + + prototype Orc(C_NPC) {}; + instance Warrior, Elite, Shaman(Orc); + "; + + + _instructions = GetExecBlockInstructions("Mage"); + _expectedInstructions = new List + { + new Ret(), + }; + AssertInstructionsMatch(); + + + _instructions = GetExecBlockInstructions("Archer"); + _expectedInstructions = new List + { + new Ret(), + }; + AssertInstructionsMatch(); + + + _instructions = GetExecBlockInstructions("Barbarian"); + _expectedInstructions = new List + { + new Ret(), + }; + AssertInstructionsMatch(); + + + _instructions = GetExecBlockInstructions("Orc"); + _expectedInstructions = new List + { + new Ret(), + }; + AssertInstructionsMatch(); + + + _instructions = GetExecBlockInstructions("Warrior"); + _expectedInstructions = new List + { + new Call(Ref("Orc")), + }; + AssertInstructionsMatch(); + + + _instructions = GetExecBlockInstructions("Elite"); + _expectedInstructions = new List + { + new Call(Ref("Orc")), + }; + AssertInstructionsMatch(); + + + _instructions = GetExecBlockInstructions("Shaman"); + _expectedInstructions = new List + { + new Call(Ref("Orc")), + new Ret(), + }; + AssertInstructionsMatch(); + + + _expectedSymbols = new List + { + Ref("C_NPC"), + Ref("C_NPC.data"), + + Ref("Mage"), + Ref("Archer"), + Ref("Barbarian"), + + Ref("Orc"), + + Ref("Warrior"), + Ref("Elite"), + Ref("Shaman") + }; + AssertSymbolsMatch(); + } + + + [Fact] + public void TestIntArrayLocalVariableReturn() + { + _code = @" + func int testFunc() { + var int a[2048]; + return a; + }; + + func int secondFunc() { + const int b[3] = {1, 2, 3}; + return b; + }; + "; + + + _instructions = GetExecBlockInstructions("testFunc"); + _expectedInstructions = new List + { + new PushVar(Ref("testFunc.a")), + new Ret(), + + new Ret(), + }; + AssertInstructionsMatch(); + + + _instructions = GetExecBlockInstructions("secondFunc"); + _expectedInstructions = new List + { + new PushVar(Ref("secondFunc.b")), + new Ret(), + + new Ret(), + }; + AssertInstructionsMatch(); + + + _expectedSymbols = new List + { + Ref("testFunc"), + Ref("testFunc.a"), + + Ref("secondFunc"), + Ref("secondFunc.b") + }; + AssertSymbolsMatch(); + } } } diff --git a/test/DaedalusCompiler.Tests/SemanticErrorsTests.cs b/test/DaedalusCompiler.Tests/SemanticErrorsTests.cs index b736ebe..2a6e589 100644 --- a/test/DaedalusCompiler.Tests/SemanticErrorsTests.cs +++ b/test/DaedalusCompiler.Tests/SemanticErrorsTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using DaedalusCompiler.Compilation; @@ -40,6 +41,9 @@ private void ParseData() _expectedCompilationOutput = string.Join(Environment.NewLine, compilationOutputLines); _assemblyBuilder.ErrorContext.FileContentLines = _code.Split(Environment.NewLine); + _assemblyBuilder.ErrorContext.SuppressedWarningCodes = Compiler.GetWarningCodesToSuppress( + _assemblyBuilder.ErrorContext.FileContentLines[0] + ); if (_externalCode != string.Empty) { _assemblyBuilder.IsCurrentlyParsingExternals = true; @@ -55,13 +59,30 @@ private void AssertCompilationOutputMatch() { ParseData(); var logger = new StringBufforErrorLogger(); + logger.Log(""); - if (_assemblyBuilder.Errors.Any()) + List errors = new List(); + foreach (CompilationMessage error in _assemblyBuilder.Errors) { - _assemblyBuilder.Errors.Sort((x, y) => x.CompareTo(y)); + if (error is CompilationError) + { + errors.Add(error); + } + else if (error is CompilationWarning compilationWarning) + { + if (compilationWarning.IsSuppressed == false) + { + errors.Add(compilationWarning); + } + } + } + + if (errors.Any()) + { + errors.Sort((x, y) => x.CompareTo(y)); string lastErrorBlockName = null; - foreach (CompilationMessage error in _assemblyBuilder.Errors) + foreach (CompilationMessage error in errors) { if (lastErrorBlockName != error.ExecBlockName) { @@ -290,8 +311,123 @@ public void TestInvalidConstArraySizeElements() [Fact] public void TestIntValueOutOfMinAndMaxRange() { - // TODO + _code = @" + const int MAX_INT = 2147483647; + const int MIN_INT = -2147483648; + const int TOO_BIG_INT_POSITIVE = 2147483648; + const int TOO_BIG_INT_NEGATIVE = -2147483649; + + func void testFunc() { + var int max_int; + max_int = 2147483647; + var int min_int; + min_int = -2147483647; // not -2147483648, because minus and number value are in separate assembly instructions + var int too_big_int_positive; + too_big_int_positive = 2147483648; + var int too_big_int_negative; + too_big_int_negative = -2147483648; + }; + "; + + _expectedCompilationOutput = @" + test.d:3:33: error: integer literal is too large to be represented in an integer type + const int TOO_BIG_INT_POSITIVE = 2147483648; + ^ + test.d:4:33: error: integer literal is too large to be represented in an integer type + const int TOO_BIG_INT_NEGATIVE = -2147483649; + ^ + test.d: In function ‘testFunc’: + test.d:12:27: error: integer literal is too large to be represented in an integer type + too_big_int_positive = 2147483648; + ^ + test.d:14:27: error: integer literal is too large to be represented in an integer type + too_big_int_negative = -2147483648; + ^ + "; + + AssertCompilationOutputMatch(); } + [Fact] + public void TestSingleExpressionHack() + { + _code = @" + func void testFunc() { + var int x; + x = 5; + x; + return; + }; + "; + + _expectedCompilationOutput = @" + test.d: In function ‘testFunc’: + test.d:4:4: warning W1: usage of single-expression statement hack + x; + ^ + "; + + AssertCompilationOutputMatch(); + } + + [Fact] + public void TestSingleExpressionHackStrictMode() + { + _assemblyBuilder.StrictSyntax = true; + + _code = @" + func void testFunc() { + var int x; + x = 5; + x; + return; + }; + "; + + _expectedCompilationOutput = @" + test.d: In function ‘testFunc’: + test.d:4:4: error W1: usage of single-expression statement hack + x; + ^ + "; + + AssertCompilationOutputMatch(); + } + + [Fact] + public void TestSingleExpressionHackWarningLineSuppress() + { + _code = @" + func void testFunc() { + var int x; + x = 5; + x; //suppress: W1 + return; + }; + "; + + _expectedCompilationOutput = @""; + + AssertCompilationOutputMatch(); + } + + [Fact] + public void TestSingleExpressionHackWarningFileSuppress() + { + _code = @" + //suppress: W1 + + func void testFunc() { + var int x; + x = 5; + x; + return; + }; + "; + + _expectedCompilationOutput = @""; + + AssertCompilationOutputMatch(); + } } } \ No newline at end of file diff --git a/test/DaedalusCompiler.Tests/config.json b/test/DaedalusCompiler.Tests/config.json deleted file mode 100644 index d4bee8b..0000000 --- a/test/DaedalusCompiler.Tests/config.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "SRC_PATHS": [ - "{PROJECT_PATH}/Scripts/Content/*.src", - "{PROJECT_PATH}/Scripts/System/*.src" - ], - "DAT_PATHS": [ - "{PROJECT_PATH}/Scripts/_compiled/*.dat" - ], - "OU_PATHS": [ - "{PROJECT_PATH}/Scripts/Content/Cutscene/ou.*" - ], - "SCRIPTS_URL": "https://drive.google.com/uc?authuser=0&id=1TZFfADoOPrmdNHbrbxMAad7Mk63HKloT&export=download", - "SCRIPTS_PASSWORD": "dziejekhorinis" -} - diff --git a/test/DaedalusCompiler.Tests/config.json.template b/test/DaedalusCompiler.Tests/config.json.template deleted file mode 100644 index dd791cb..0000000 --- a/test/DaedalusCompiler.Tests/config.json.template +++ /dev/null @@ -1,14 +0,0 @@ -{ - "SRC_PATHS": [ - "{PROJECT_PATH}/Scripts/Content/*.src", - "{PROJECT_PATH}/Scripts/System/*.src" - ], - "DAT_PATHS": [ - "{PROJECT_PATH}/Scripts/_compiled/*.dat" - ], - OU_PATHS": [ - "{PROJECT_PATH}/Scripts/Content/Cutscene/ou.*" - ], - "SCRIPTS_URL": "", - "SCRIPTS_PASSWORD": "" -} \ No newline at end of file