From 6ae3a3f42605efad43a483c8bc2bf46b5376d144 Mon Sep 17 00:00:00 2001 From: Yael Dekel Date: Thu, 26 Dec 2019 20:27:57 +0200 Subject: [PATCH] Expression estimator/transformer (#4548) * Expression transform * Add API and unit tests * Change ExprType to ExprTypeKind * Fix tests for Linux * Fix unit tests * change file header * Fix test failure on Linux * Sample and documentation * change sample --- docs/api-reference/expression-estimator.md | 181 ++ .../Dynamic/Transforms/Expression.cs | 104 + .../Expression/BuiltinFunctions.cs | 1095 ++++++++++ .../Expression/CharCursor.cs | 111 + .../Expression/CodeGen.cs | 1434 +++++++++++++ .../Expression/Error.cs | 46 + .../Expression/Exec.cs | 35 + .../Expression/FunctionProvider.cs | 44 + .../Expression/IlGeneratorExtensions.cs | 405 ++++ .../Expression/KeyWordTable.cs | 109 + .../Expression/LambdaBinder.cs | 1858 +++++++++++++++++ .../Expression/LambdaParser.cs | 795 +++++++ .../Expression/LexCharUtils.cs | 250 +++ .../Expression/Lexer.cs | 844 ++++++++ .../Expression/MethodGenerator.cs | 185 ++ .../Expression/Node.cs | 1206 +++++++++++ .../Expression/Printer.cs | 571 +++++ .../Expression/TokKind.cs | 212 ++ .../Expression/TokenCursor.cs | 196 ++ .../Expression/Tokens.cs | 292 +++ .../ExpressionCatalog.cs | 23 + .../ExpressionTransformer.cs | 992 +++++++++ .../Microsoft.ML.Transforms.csproj | 4 + .../Common/ExprParser/ExprBindExOutput.txt | 714 +++++++ .../Common/ExprParser/ExprBindOutput.txt | 1473 +++++++++++++ .../Common/ExprParser/ExprCodeGenOutput.txt | 682 ++++++ .../Common/ExprParser/ExprEvalOutput.txt | 197 ++ .../Common/ExprParser/ExprParseOutput.txt | 255 +++ .../Common/SavePipe/SavePipeExpr-All-Data.txt | 720 +++++++ .../SavePipe/SavePipeExpr-All-Schema.txt | 80 + .../Common/SavePipe/SavePipeExpr-CursLog.txt | 1 + .../Common/SavePipe/SavePipeExpr-Data.txt | 720 +++++++ .../SavePipe/SavePipeExpr-Extra-Data.txt | 716 +++++++ .../SavePipe/SavePipeExpr-Extra-Schema.txt | 47 + .../Common/SavePipe/SavePipeExpr-Schema.txt | 134 ++ .../SavePipe/SavePipeExprTextDef-Data.txt | 109 + .../SavePipe/SavePipeExprTextDef-Schema.txt | 15 + .../SavePipe/SavePipeExprTextDef-b-Schema.txt | 6 + .../SavePipe/SavePipeExprTextFull-Data.txt | 109 + .../SavePipe/SavePipeExprTextFull-Schema.txt | 15 + .../SavePipeExprTextFull-b-Schema.txt | 15 + .../Common/SavePipe/SavePipeExprVec1-Data.txt | 110 + .../SavePipe/SavePipeExprVec1-Schema.txt | 29 + .../SavePipe/SavePipeExprVec1-b-Schema.txt | 26 + .../Common/SavePipe/SavePipeExprVec2-Data.txt | 112 + .../SavePipe/SavePipeExprVec2-Schema.txt | 35 + .../SavePipe/SavePipeExprVec2-b-Schema.txt | 35 + .../SavePipe/SavePipeExprVec2-c-Schema.txt | 35 + .../SavePipe/SavePipeExprVec2-d-Schema.txt | 35 + .../DataPipe/TestDataPipe.cs | 122 ++ .../ExpressionLanguageTests.cs | 683 ++++++ .../TestData/ExprBindExInput.txt | 613 ++++++ .../TestData/ExprBindInput.txt | 1560 ++++++++++++++ .../TestData/ExprCodeGenInput.txt | 719 +++++++ .../TestData/ExprEvalInput.txt | 485 +++++ .../TestData/ExprParseInput.txt | 240 +++ .../Microsoft.ML.Tests.csproj | 8 + .../ExpressionTransformerTests.cs | 61 + 58 files changed, 21908 insertions(+) create mode 100644 docs/api-reference/expression-estimator.md create mode 100644 docs/samples/Microsoft.ML.Samples/Dynamic/Transforms/Expression.cs create mode 100644 src/Microsoft.ML.Transforms/Expression/BuiltinFunctions.cs create mode 100644 src/Microsoft.ML.Transforms/Expression/CharCursor.cs create mode 100644 src/Microsoft.ML.Transforms/Expression/CodeGen.cs create mode 100644 src/Microsoft.ML.Transforms/Expression/Error.cs create mode 100644 src/Microsoft.ML.Transforms/Expression/Exec.cs create mode 100644 src/Microsoft.ML.Transforms/Expression/FunctionProvider.cs create mode 100644 src/Microsoft.ML.Transforms/Expression/IlGeneratorExtensions.cs create mode 100644 src/Microsoft.ML.Transforms/Expression/KeyWordTable.cs create mode 100644 src/Microsoft.ML.Transforms/Expression/LambdaBinder.cs create mode 100644 src/Microsoft.ML.Transforms/Expression/LambdaParser.cs create mode 100644 src/Microsoft.ML.Transforms/Expression/LexCharUtils.cs create mode 100644 src/Microsoft.ML.Transforms/Expression/Lexer.cs create mode 100644 src/Microsoft.ML.Transforms/Expression/MethodGenerator.cs create mode 100644 src/Microsoft.ML.Transforms/Expression/Node.cs create mode 100644 src/Microsoft.ML.Transforms/Expression/Printer.cs create mode 100644 src/Microsoft.ML.Transforms/Expression/TokKind.cs create mode 100644 src/Microsoft.ML.Transforms/Expression/TokenCursor.cs create mode 100644 src/Microsoft.ML.Transforms/Expression/Tokens.cs create mode 100644 src/Microsoft.ML.Transforms/ExpressionCatalog.cs create mode 100644 src/Microsoft.ML.Transforms/ExpressionTransformer.cs create mode 100644 test/BaselineOutput/Common/ExprParser/ExprBindExOutput.txt create mode 100644 test/BaselineOutput/Common/ExprParser/ExprBindOutput.txt create mode 100644 test/BaselineOutput/Common/ExprParser/ExprCodeGenOutput.txt create mode 100644 test/BaselineOutput/Common/ExprParser/ExprEvalOutput.txt create mode 100644 test/BaselineOutput/Common/ExprParser/ExprParseOutput.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExpr-All-Data.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExpr-All-Schema.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExpr-CursLog.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExpr-Data.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExpr-Extra-Data.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExpr-Extra-Schema.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExpr-Schema.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExprTextDef-Data.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExprTextDef-Schema.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExprTextDef-b-Schema.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExprTextFull-Data.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExprTextFull-Schema.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExprTextFull-b-Schema.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExprVec1-Data.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExprVec1-Schema.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExprVec1-b-Schema.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-Data.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-Schema.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-b-Schema.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-c-Schema.txt create mode 100644 test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-d-Schema.txt create mode 100644 test/Microsoft.ML.Tests/ExpressionLanguageTests/ExpressionLanguageTests.cs create mode 100644 test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprBindExInput.txt create mode 100644 test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprBindInput.txt create mode 100644 test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprCodeGenInput.txt create mode 100644 test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprEvalInput.txt create mode 100644 test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprParseInput.txt create mode 100644 test/Microsoft.ML.Tests/Transformers/ExpressionTransformerTests.cs diff --git a/docs/api-reference/expression-estimator.md b/docs/api-reference/expression-estimator.md new file mode 100644 index 0000000000..34b79b1349 --- /dev/null +++ b/docs/api-reference/expression-estimator.md @@ -0,0 +1,181 @@ +### The Expression Language + +The language for the expression estimator should be comfortable to a broad range of users. It shares many similarities with some popular languages. +It is case sensitive, supports multiple types and has a rich set of operators and functions. It is pure functional, in the sense that there are no +mutable values or mutating operations in the language. It does not have, nor need, any exception mechanism, instead producing NA values when a normal +value is not appropriate. It is statically typed, but all types are inferred by the compiler. + +## Syntax + +Syntax for the lambda consists of a parameter list followed by either colon (:) or arrow (=>) followed by an expression. +The parameter list can be either a single identifier or a comma-separated list of one or more identifiers surrounded by parentheses. + +_lambda:_ + +- _parameter-list **:** expression_ +- _parameter-list **=>** expression_ + +_parameter-list:_ + +- _identifier_ +- **(** _parameter-names_ **)** + +_parameter-names:_ + +- _identifier_ +- _identifier **,** parameter-names_ + +The expression can use parameters, literals, operators, with-expressions, and functions. + +## Literals + +- The boolean literals are true and false. +- Integer literals may be decimal or hexadecimal (e.g., 0x1234ABCD). They can be suffixed with u or U, indicating unsigned, +as well as l or L, indicating long (Int64). The use of u or U is rare and only affects promotion of certain 32 bit hexadecimal values, +determining whether the constant is considered a negative Int32 value or a positive Int64 value. +- Floating point literals use the standard syntax, including exponential notation (123.45e-37). They can be suffixed with +f or F, indicating single precision, or d or D, indicating double precision. Unlike in C#, the default precision of a +floating point literal is single precision. To specify double precision, append d or D. +- Text literals are enclosed in double-quotation marks and support the standard escape mechanisms. + +## Operators + +The operators of the expression language are listed in the following table, in precendence order. Unless otherwise noted, +binary operators are left associative and propagate NA values (if either operand value is NA, the result is NA). Generally, +overflow of integer values produces NA, while overflow of floating point values produces infinity. + +| **Operator** | **Meaning** | **Arity**| **Comments** | +| --- | --- | ---| --- | +| ​? : | ​conditional | ​Ternary | The expression ​condition ? value1 : value2 resolves to value1 if condition is true and to value2 if condition is false. The condition must be boolean, while value1 and value2 must be of compatible type. | +| ​?? | ​coalesce | ​Binary | The expression ​x ?? y resolves to x if x is not NA, and resolves to y otherwise. The operands must be both Singles, or both Doubles. This operator is right associative. | +| \| \| or | ​logical or | ​Binary | ​The operands and result are boolean. If one operand is true, the result is true, otherwise it is false. | +| ​&& and | ​logical and | ​Binary | ​The operands and result are boolean. If one operand is false, the result is false, otherwise, it is true. | +| ​==, =
!=, <>
<, <=
>, >= | equals
not equals
less than or equal to
greater than or equal to | ​Multiple |- The comparison operators are multi-arity, meaning they can be applied to two or more operands. For example, a == b == c results in true if a, b, and c have the same value. The not equal operator requires that all of the operands be distinct, so 1 != 2 != 1 is false. To test whether x is non-negative but less than 10, use 0 <= x < 10. There is no need to write 0 <= x && x < 10, and doing so will not perform as well. Operators listed on the same line can be combined in a single expression, so a > b >= c is legal, but a < b >= c is not.
- Equals and not equals apply to any operand type, while the ordered operators require numeric operands. | +| ​+ - | ​addition and subtraction | ​Binary | Numeric addition and subtraction with NA propagation. | +| ​\* / % | ​multiplication, division, and modulus | ​Binary | ​​Numeric multiplication, division, and modulus with NA propagation. | +| ​- ! not | numeric negation and logical not​ | ​Unary | ​These are unary prefix operators, negation (-) requiring a numeric operand, and not (!) requiring a boolean operand. | +| ​^ | ​power | ​Binary | ​This is right associative exponentiation. It requires numeric operands. For integer operands, 0^0 produce 1.| +| ​( ) | ​parenthetical grouping | ​Unary | Standard meaning. | + +## The With Expression + +The syntax for the with-expression is: + +_with-expression:_ + +- **with** **(** assignment-list **;** expression **)** + +_assignment-list:_ + +- assignment +- assignment **,** assignment-list + +_assignment:_ + +- identifier **=** expression + +The with-expression introduces one or more named values. For example, the following expression converts a celcius temperature to fahrenheit, then produces a message based on whether the fahrenheit is too low or high. +``` +c => with(f = c * 9 / 5 + 32 ; f < 60 ? "Too Cold!" : f > 90 ? "Too Hot!" : "Just Right!") +``` +The expression for one assignment may reference the identifiers introduced by previous assignments, as in this example that returns -1, 0, or 1 instead of the messages: +``` +c : with(f = c * 9 / 5 + 32, cold = f < 60, hot = f > 90 ; -float(cold) + float(hot)) +``` +As demonstrated above, the with-expression is useful when an expression value is needed multiple times in a larger expression. It is also useful when dealing with complicated or significant constants: +``` + ticks => with( + ticksPerSecond = 10000000L, + ticksPerHour = ticksPerSecond \* 3600, + ticksPerDay = ticksPerHour \* 24, + day = ticks / ticksPerDay, + dayEpoch = 1 ; + (day + dayEpoch) % 7) +``` +This computes the day of the week from the number of ticks (as an Int64) since the standard .Net DateTime epoch (01/01/0001 +in the idealized Gregorian calendar). Assignments are used for number of ticks in a second, number of ticks in an hour, +number of ticks in a year, and the day of the week for the epoch. For this example, we want to map Sunday to zero, so, +since the epoch is a Monday, we set dayEpoch to 1. If the epoch were changed or we wanted to map a different day of the week to zero, +we'd simply change dayEpoch. Note that ticksPerSecond is defined as 10000000L, to make it an Int64 value (8 byte integer). +Without the L suffix, ticksPerDay will overflow Int32's range. + +## Functions + +The expression transform supports many useful functions. + +General unary functions that can accept an operand of any type are listed in the following table. + +| **​Name** | ​ **Meaning** | ​ **Comments** | +| --- | --- | --- | +| ​isna | ​test for na | Returns a boolean value indicating whether the operand is an NA value. | +| ​na | the na value | ​Returns the NA value of the same type as the operand (either float or double). Note that this does not evaluate the operand, it only uses the operand to determine the type of NA to return, and that determination happens at compile time. | +| ​default | ​the default value | ​​Returns the default value of the same type as the operand. For example, to map NA values to default values, use x ?? default(x). Note that this does not evaluate the operand, it only uses the operand to determine the type of default value to return, and that determination happens at compile time. For numeric types, the default is zero. For boolean, the default is false. For text, the default is empty. | + +The unary conversion functions are listed in the following table. An NA operand produces an NA, or throws if the type does not support it. +A conversion that doesn't succeed, or overflow also result in NA or an exception. The most common case of this is when converting from text, +which uses the standard conversion parsing. When converting from a floating point value (float or double) to an integer value +(Int32 or Int64), the conversion does a truncate operation (round toward zero). + +| **​Name** | ​ **Meaning** | ​ **Comments** | +| --- | --- | --- | +| ​bool | ​convert to BL | The operand must be text or boolean. | +| ​int | convert to I4 | ​The input may be of any type. | +| ​long | ​convert to I8 | The input may be of any type. | +| ​single, float | ​convert to R4 | ​The input may be of any type. | +| ​double | ​convert to R8 | ​​The input may be of any type. | +| ​text | ​convert to TX | ​​​The input may be of any type. This produces a default text representation. | + +The unary functions that require a numeric operand are listed in the following table. The result type is the same as the operand type. An NA operand value produces NA. + +| **​Name** | ​ **Meaning** | ​ **Comments** | +| --- | --- | --- | +| ​abs | ​absolute value | ​Produces the absolute value of the operand. | +| ​sign | sign (-1, 0, 1) | ​Produces -1, 0, or 1 depending on whether the operand is negative, zero, or positive. | + +The binary functions that require numeric operands are listed in the following table. When the operand types aren't the same, +the operands are promoted to an appropriate type. The result type is the same as the promoted operand type. An NA operand value produces NA. + +| **​Name** | ​ **Meaning** | ​ **Comments** | +| --- | --- | --- | +| ​min | ​minimum | ​Produces the minimum of the operands. | +| ​max | maximum | ​Produces the maximum of the operands. | + +The unary functions that require a floating point operand are listed in the following table. The result type is the same as the operand type. Overflow produces infinity. Invalid input values produce NA. + +| **​Name** | ​ **Meaning** | ​ **Comments** | +| --- | --- | --- | +| ​sqrt | ​square root | ​Negative operands produce NA. | +| trunc, ​truncate | ​truncate to an integer | ​Rounds toward zero to the nearest integer value. | +| ​floor | ​floor | ​Rounds toward negative infinity to the nearest integer value. | +| ​ceil, ceiling | ​ceiling | ​Rounds toward positive infinity to the nearest integer value. | +| ​round | ​unbiased rounding | ​Rounds to the nearest integer value. When the operand is half way between two integer values, this produces the even integer. | +| ​exp | ​exponential | ​Raises e to the operand. | +| ln, ​log | ​logarithm | ​Produces the natural (base e) logarithm. There is also a two operand version of log for using a different base. | +| ​deg, degrees | ​radians to degrees | ​Maps from radians to degrees. | +| ​rad, radians | ​degrees to radians | ​Maps from degrees to radians. | +| ​sin, sind | ​sine | ​Takes the sine of an angle. The sin function assumes the operand is in radians, while the sind function assumes that the operand is in degrees. | +| ​cos, cosd | ​cosine | ​​Takes the cosine of an angle. The cos function assumes the operand is in radians, while the cosd function assumes that the operand is in degrees. | +| ​tan, tand | ​tangent | ​​Takes the tangent of an angle. The tan function assumes the operand is in radians, while the tand function assumes that the operand is in degrees. | +| ​sinh | ​hyperbolic sine | ​Takes the hyperbolic sine of its operand. | +| ​cosh | ​hyperbolic cosine | ​​Takes the hyperbolic cosine of its operand. | +| ​tanh | ​hyperbolic tangent | ​​Takes the hyperbolic tangent of its operand. | +| ​asin | ​inverse sine | ​Takes the inverse sine of its operand. | +| ​acos | ​inverse cosine | ​​Takes the inverse cosine of its operand. | +| ​atan | ​inverse tangent | ​​Takes the inverse tangent of its operand. | + +The binary functions that require floating point operands are listed in the following table. When the operand types aren't the same, the operands are promoted to an appropriate type. The result type is the same as the promoted operand type. An NA operand value produces NA. + +| **​Name** | ​ **Meaning** | ​ **Comments** | +| --- | --- | --- | +| ​log | ​logarithm with given base | ​The second operand is the base. The first is the value to take the logarithm of. | +| ​atan2, atanyx | determine angle | Determines the angle between -pi and pi from the given y and x values. Note that y is the first operand. | + +The text functions are listed in the following table. + +| **​Name** | ​ **Meaning** | ​ **Comments** | +| --- | --- | --- | +| ​len(x) | length of text | The operand must be text. The result is an I4 indicating the length of the operand. If the operand is NA, the result is NA. | +| ​lower(x), upper(x) | lower or upper case | Maps the text to lower or upper case. | +| left(x, k), ​right(x, k) | ​substring | ​The first operand must be text and the second operand must be Int32. If the second operand is negative it is treated as an offset from the end of the text. This adjusted index is then clamped to 0 to len(x). The result is the characters to the left or right of the resulting position. | +| ​mid(x, a, b) | ​substring | ​The first operand must be text and the other two operands must be Int32. The indices are transformed in the same way as for the left and right functions: negative values are treated as offsets from the end of the text; these adjusted indices are clamped to 0 to len(x). The second clamped index is also clamped below to the first clamped index. The result is the characters between these two clamped indices. | +| ​concat(x1, x2, ..., xn) | ​concatenation | ​This accepts an arbitrary number of operands (including zero). All operands must be text. The result is the concatenation of all the operands, in order. | \ No newline at end of file diff --git a/docs/samples/Microsoft.ML.Samples/Dynamic/Transforms/Expression.cs b/docs/samples/Microsoft.ML.Samples/Dynamic/Transforms/Expression.cs new file mode 100644 index 0000000000..193a65e86e --- /dev/null +++ b/docs/samples/Microsoft.ML.Samples/Dynamic/Transforms/Expression.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using Microsoft.ML; +using Microsoft.ML.Data; + +namespace Samples.Dynamic.Transforms +{ + public static class Expression + { + public static void Example() + { + // Create a new ML context, for ML.NET operations. It can be used for + // exception tracking and logging, as well as the source of randomness. + var mlContext = new MLContext(); + + // Create a small dataset as an IEnumerable. + var samples = new List() + { + new InputData(0.5f, new[] { 1f, 0.2f }, 3, "hi", true, new[] { "zero", "one" }), + new InputData(-2.7f, new[] { 3.5f, -0.1f }, 2, "bye", false, new[] { "a", "b" }), + new InputData(1.3f, new[] { 1.9f, 3.3f }, 39, "hi", false, new[] { "0", "1" }), + new InputData(3, new[] { 3f, 3f }, 4, "hello", true, new[] { "c", "d" }), + new InputData(0, new[] { 1f, 1f }, 1, "hi", true, new[] { "zero", "one" }), + new InputData(30.4f, new[] { 10f, 4f }, 9, "bye", true, new[] { "e", "f" }), + new InputData(5.6f, new[] { 1.1f, 2.2f }, 0, "hey", false, new[] { "g", "h" }), + }; + + // Convert training data to IDataView. + var dataview = mlContext.Data.LoadFromEnumerable(samples); + + // A pipeline that applies various expressions to the input columns. + var pipeline = mlContext.Transforms.Expression("Expr1", "(x,y)=>log(y)+x", + nameof(InputData.FloatColumn), nameof(InputData.FloatVectorColumn)) + .Append(mlContext.Transforms.Expression("Expr2", "(b,s,i)=>b ? len(s) : i", + nameof(InputData.BooleanColumn), nameof(InputData.StringVectorColumn), nameof(InputData.IntColumn))) + .Append(mlContext.Transforms.Expression("Expr3", "(s,f1,f2,i)=>len(concat(s,\"a\"))+f1+f2+i", + nameof(InputData.StringColumn), nameof(InputData.FloatVectorColumn), nameof(InputData.FloatColumn), nameof(InputData.IntColumn))) + .Append(mlContext.Transforms.Expression("Expr4", "(x,y)=>cos(x+pi())*y", + nameof(InputData.FloatColumn), nameof(InputData.IntColumn))); + + // The transformed data. + var transformedData = pipeline.Fit(dataview).Transform(dataview); + + // Now let's take a look at what this concatenation did. + // We can extract the newly created column as an IEnumerable of + // TransformedData. + var featuresColumn = mlContext.Data.CreateEnumerable( + transformedData, reuseRowObject: false); + + // And we can write out a few rows + Console.WriteLine($"Features column obtained post-transformation."); + foreach (var featureRow in featuresColumn) + { + Console.Write(string.Join(" ", featureRow.Expr1)); + Console.Write(" "); + Console.Write(string.Join(" ", featureRow.Expr2)); + Console.Write(" "); + Console.Write(string.Join(" ", featureRow.Expr3)); + Console.Write(" "); + Console.WriteLine(featureRow.Expr4); + } + + // Expected output: + // Features column obtained post-transformation. + // 0.5 - 1.109438 4 3 7.5 6.7 - 2.63274768567112 + // - 1.447237 NaN 2 2 6.8 3.2 1.80814432479224 + // 1.941854 2.493922 39 39 45.2 46.6 - 10.4324561082543 + // 4.098612 4.098612 1 1 16 16 3.95996998640178 + // 0 0 4 3 5 5 - 1 + // 32.70258 31.78629 1 1 53.4 47.4 - 4.74149076052604 + // 5.69531 6.388457 0 0 10.7 11.8 0 + } + + private class InputData + { + public float FloatColumn; + [VectorType(3)] + public float[] FloatVectorColumn; + public int IntColumn; + public string StringColumn; + public bool BooleanColumn; + [VectorType(2)] + public string[] StringVectorColumn; + + public InputData(float f, float[] fv, int i, string s, bool b, string[] sv) + { + FloatColumn = f; + FloatVectorColumn = fv; + IntColumn = i; + StringColumn = s; + BooleanColumn = b; + StringVectorColumn = sv; + } + } + + private sealed class TransformedData + { + public float[] Expr1 { get; set; } + public int[] Expr2 { get; set; } + public float[] Expr3 { get; set; } + public double Expr4 { get; set; } + } + } +} diff --git a/src/Microsoft.ML.Transforms/Expression/BuiltinFunctions.cs b/src/Microsoft.ML.Transforms/Expression/BuiltinFunctions.cs new file mode 100644 index 0000000000..02935718b3 --- /dev/null +++ b/src/Microsoft.ML.Transforms/Expression/BuiltinFunctions.cs @@ -0,0 +1,1095 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma warning disable 420 // volatile with Interlocked.CompareExchange + +using System; +using System.Globalization; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using Microsoft.ML.Data; +using Microsoft.ML.Data.Conversion; +using Microsoft.ML.Internal.Utilities; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.Transforms +{ + using BL = System.Boolean; + using I4 = System.Int32; + using I8 = System.Int64; + using R4 = Single; + using R8 = Double; + using TX = ReadOnlyMemory; + + internal static class FunctionProviderUtils + { + /// + /// Returns whether the given object is non-null and an NA value for one of the standard types. + /// + public static bool IsNA(object v) + { + if (v == null) + return false; + Type type = v.GetType(); + if (type == typeof(R4)) + return R4.IsNaN((R4)v); + if (type == typeof(R8)) + return R8.IsNaN((R8)v); + Contracts.Assert(type == typeof(BL) || type == typeof(I4) || type == typeof(I8) || type == typeof(TX), + "Unexpected constant value type!"); + return false; + } + + /// + /// Returns the standard NA value for the given standard type. + /// + public static object GetNA(Type type) + { + if (type == typeof(R4)) + return R4.NaN; + if (type == typeof(R8)) + return R8.NaN; + Contracts.Assert(false, "Unexpected constant value type!"); + return null; + } + + /// + /// Helper method to bundle one or more MethodInfos into an array. + /// + public static MethodInfo[] Ret(params MethodInfo[] funcs) + { + Contracts.AssertValue(funcs); + return funcs; + } + + /// + /// Returns the MethodInfo for the given delegate. + /// + public static MethodInfo Fn(Func fn) + { + Contracts.AssertValue(fn); + Contracts.Assert(fn.Target == null); + return fn.GetMethodInfo(); + } + + /// + /// Returns the MethodInfo for the given delegate. + /// + public static MethodInfo Fn(Func fn) + { + Contracts.AssertValue(fn); + Contracts.Assert(fn.Target == null); + return fn.GetMethodInfo(); + } + + /// + /// Returns the MethodInfo for the given delegate. + /// + public static MethodInfo Fn(Func fn) + { + Contracts.AssertValue(fn); + Contracts.Assert(fn.Target == null); + return fn.GetMethodInfo(); + } + + /// + /// Returns the MethodInfo for the given delegate. + /// + public static MethodInfo Fn(Func fn) + { + Contracts.AssertValue(fn); + Contracts.Assert(fn.Target == null); + return fn.GetMethodInfo(); + } + } + + /// + /// The standard builtin functions for ExprTransform. + /// + internal sealed class BuiltinFunctions : IFunctionProvider + { + private static volatile BuiltinFunctions _instance; + public static BuiltinFunctions Instance + { + get + { + if (_instance == null) + Interlocked.CompareExchange(ref _instance, new BuiltinFunctions(), null); + return _instance; + } + } + + public string NameSpace { get { return "global"; } } + + /// + /// Returns the MethodInfo for + /// + private static MethodInfo Id() + { + Action fn = Id; + Contracts.Assert(fn.Target == null); + return fn.GetMethodInfo(); + } + + // This is an "identity" function. + private static void Id(T src) { } + + public MethodInfo[] Lookup(string name) + { + switch (name) + { + case "pi": + return FunctionProviderUtils.Ret(FunctionProviderUtils.Fn(Pi)); + + case "na": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(NA), + FunctionProviderUtils.Fn(NA)); + case "default": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Default), + FunctionProviderUtils.Fn(Default), + FunctionProviderUtils.Fn(Default), + FunctionProviderUtils.Fn(Default), + FunctionProviderUtils.Fn(Default), + FunctionProviderUtils.Fn(Default)); + + case "abs": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Math.Abs), + FunctionProviderUtils.Fn(Math.Abs), + FunctionProviderUtils.Fn(Math.Abs), + FunctionProviderUtils.Fn(Math.Abs)); + case "sign": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Sign), + FunctionProviderUtils.Fn(Sign), + FunctionProviderUtils.Fn(Sign), + FunctionProviderUtils.Fn(Sign)); + case "exp": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Exp), + FunctionProviderUtils.Fn(Math.Exp)); + case "ln": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Log), + FunctionProviderUtils.Fn(Math.Log)); + case "log": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Log), + FunctionProviderUtils.Fn(Math.Log), + FunctionProviderUtils.Fn(Log), + FunctionProviderUtils.Fn(Math.Log)); + + case "deg": + case "degrees": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Deg), + FunctionProviderUtils.Fn(Deg)); + case "rad": + case "radians": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Rad), + FunctionProviderUtils.Fn(Rad)); + + case "sin": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Sin), + FunctionProviderUtils.Fn(Sin)); + case "sind": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(SinD), + FunctionProviderUtils.Fn(SinD)); + case "cos": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Cos), + FunctionProviderUtils.Fn(Cos)); + case "cosd": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(CosD), + FunctionProviderUtils.Fn(CosD)); + case "tan": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Tan), + FunctionProviderUtils.Fn(Math.Tan)); + case "tand": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(TanD), + FunctionProviderUtils.Fn(TanD)); + + case "asin": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Asin), + FunctionProviderUtils.Fn(Math.Asin)); + case "acos": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Acos), + FunctionProviderUtils.Fn(Math.Acos)); + case "atan": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Atan), + FunctionProviderUtils.Fn(Math.Atan)); + case "atan2": + case "atanyx": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Atan2), + FunctionProviderUtils.Fn(Atan2)); + + case "sinh": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Sinh), + FunctionProviderUtils.Fn(Math.Sinh)); + case "cosh": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Cosh), + FunctionProviderUtils.Fn(Math.Cosh)); + case "tanh": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Tanh), + FunctionProviderUtils.Fn(Math.Tanh)); + + case "sqrt": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Sqrt), + FunctionProviderUtils.Fn(Math.Sqrt)); + + case "trunc": + case "truncate": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Truncate), + FunctionProviderUtils.Fn(Math.Truncate)); + case "floor": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Floor), + FunctionProviderUtils.Fn(Math.Floor)); + case "ceil": + case "ceiling": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Ceiling), + FunctionProviderUtils.Fn(Math.Ceiling)); + case "round": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Round), + FunctionProviderUtils.Fn(Math.Round)); + + case "min": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Math.Min), + FunctionProviderUtils.Fn(Math.Min), + FunctionProviderUtils.Fn(Math.Min), + FunctionProviderUtils.Fn(Math.Min)); + case "max": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Math.Max), + FunctionProviderUtils.Fn(Math.Max), + FunctionProviderUtils.Fn(Math.Max), + FunctionProviderUtils.Fn(Math.Max)); + + case "len": + return FunctionProviderUtils.Ret(FunctionProviderUtils.Fn(Len)); + case "lower": + return FunctionProviderUtils.Ret(FunctionProviderUtils.Fn(Lower)); + case "upper": + return FunctionProviderUtils.Ret(FunctionProviderUtils.Fn(Upper)); + case "right": + return FunctionProviderUtils.Ret(FunctionProviderUtils.Fn(Right)); + case "left": + return FunctionProviderUtils.Ret(FunctionProviderUtils.Fn(Left)); + case "mid": + return FunctionProviderUtils.Ret(FunctionProviderUtils.Fn(Mid)); + + case "concat": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Empty), + Id(), + FunctionProviderUtils.Fn(Concat), + FunctionProviderUtils.Fn(Concat), + FunctionProviderUtils.Fn(Concat)); + + case "isna": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(IsNA), + FunctionProviderUtils.Fn(IsNA)); + + case "bool": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(ToBL), + Id()); + case "int": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Convert.ToInt32), + FunctionProviderUtils.Fn(Convert.ToInt32), + FunctionProviderUtils.Fn(Convert.ToInt32), + FunctionProviderUtils.Fn(Convert.ToInt32), + FunctionProviderUtils.Fn(ToI4), + Id()); + case "long": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Convert.ToInt64), + FunctionProviderUtils.Fn(Convert.ToInt64), + FunctionProviderUtils.Fn(Convert.ToInt64), + FunctionProviderUtils.Fn(Convert.ToInt64), + FunctionProviderUtils.Fn(ToI8), + Id()); + case "float": + case "single": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Convert.ToSingle), + FunctionProviderUtils.Fn(Convert.ToSingle), + FunctionProviderUtils.Fn(ToR4), + FunctionProviderUtils.Fn(ToR4), + FunctionProviderUtils.Fn(Convert.ToSingle), + FunctionProviderUtils.Fn(ToR4)); + case "double": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Convert.ToDouble), + FunctionProviderUtils.Fn(Convert.ToDouble), + FunctionProviderUtils.Fn(ToR8), + FunctionProviderUtils.Fn(ToR8), + FunctionProviderUtils.Fn(Convert.ToDouble), + FunctionProviderUtils.Fn(ToR8)); + case "text": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(ToTX), + FunctionProviderUtils.Fn(ToTX), + FunctionProviderUtils.Fn(ToTX), + FunctionProviderUtils.Fn(ToTX), + FunctionProviderUtils.Fn(ToTX), + Id()); + } + + return null; + } + + public object ResolveToConstant(string name, MethodInfo fn, object[] values) + { + Contracts.CheckNonEmpty(name, nameof(name)); + Contracts.CheckValue(fn, nameof(fn)); + Contracts.CheckParam(Utils.Size(values) > 0, nameof(values), "Expected values to have positive length"); + Contracts.CheckParam(!values.All(x => x != null), nameof(values), "Expected values to contain at least one null"); + + switch (name) + { + case "na": + { + Contracts.Assert(values.Length == 1); + + Type type = fn.ReturnType; + if (type == typeof(R4)) + return R4.NaN; + if (type == typeof(R8)) + return R8.NaN; + return null; + } + case "default": + { + Contracts.Assert(values.Length == 1); + + Type type = fn.ReturnType; + if (type == typeof(I4)) + return default(I4); + if (type == typeof(I8)) + return default(I8); + if (type == typeof(R4)) + return default(R4); + if (type == typeof(R8)) + return default(R8); + if (type == typeof(BL)) + return default(BL); + if (type == typeof(TX)) + return default(TX); + Contracts.Assert(false, "Unexpected return type!"); + return null; + } + } + + // By default, constant NA arguments produce an NA result. Note that this is not true for isna, + // but those functions will get here only if values contains a single null, not an NA. + for (int i = 0; i < values.Length; i++) + { + if (FunctionProviderUtils.IsNA(values[i])) + { + Contracts.Assert(values.Length > 1); + return FunctionProviderUtils.GetNA(fn.ReturnType); + } + } + + return null; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R8 Pi() + { + return Math.PI; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 NA(R4 a) + { + return R4.NaN; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R8 NA(R8 a) + { + return R8.NaN; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static I4 Default(I4 a) + { + return default(I4); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static I8 Default(I8 a) + { + return default(I8); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Default(R4 a) + { + return default(R4); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R8 Default(R8 a) + { + return default(R8); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BL Default(BL a) + { + return default(BL); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TX Default(TX a) + { + return default(TX); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Sign(R4 a) + { + // Preserves NaN. Unfortunately, it also preserves negative zero, + // but perhaps that is a good thing? + return a > 0 ? +1 : a < 0 ? -1 : a; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R8 Sign(R8 a) + { + // Preserves NaN. Unfortunately, it also preserves negative zero, + // but perhaps that is a good thing? + return a > 0 ? +1 : a < 0 ? -1 : a; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static I4 Sign(I4 a) + { + return a > 0 ? +1 : a < 0 ? -1 : a; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static I8 Sign(I8 a) + { + return a > 0 ? +1 : a < 0 ? -1 : a; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Pow(R4 a, R4 b) + { + return (R4)Math.Pow(a, b); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Exp(R4 a) + { + return (R4)Math.Exp(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Log(R4 a) + { + return (R4)Math.Log(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Log(R4 a, R4 b) + { + return (R4)Math.Log(a, b); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Deg(R4 a) + { + return (R4)(a * (180 / Math.PI)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R8 Deg(R8 a) + { + return a * (180 / Math.PI); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Rad(R4 a) + { + return (R4)(a * (Math.PI / 180)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R8 Rad(R8 a) + { + return a * (Math.PI / 180); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Sin(R4 a) + { + return (R4)Math.Sin(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R8 Sin(R8 a) + { + return MathUtils.Sin(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 SinD(R4 a) + { + return (R4)Math.Sin(a * (Math.PI / 180)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R8 SinD(R8 a) + { + return MathUtils.Sin(a * (Math.PI / 180)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Cos(R4 a) + { + return (R4)Math.Cos(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R8 Cos(R8 a) + { + return MathUtils.Cos(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 CosD(R4 a) + { + return (R4)Math.Cos(a * (Math.PI / 180)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R8 CosD(R8 a) + { + return MathUtils.Cos(a * (Math.PI / 180)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Tan(R4 a) + { + return (R4)Math.Tan(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 TanD(R4 a) + { + return (R4)Math.Tan(a * (Math.PI / 180)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R8 TanD(R8 a) + { + return Math.Tan(a * (Math.PI / 180)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Asin(R4 a) + { + return (R4)Math.Asin(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Acos(R4 a) + { + return (R4)Math.Acos(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Atan(R4 a) + { + return (R4)Math.Atan(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Atan2(R4 a, R4 b) + { + // According to the documentation of Math.Atan2: if x and y are either System.Double.PositiveInfinity + // or System.Double.NegativeInfinity, the method returns System.Double.NaN, but this seems to not be the case. + if (R4.IsInfinity(a) && R4.IsInfinity(b)) + return R4.NaN; + return (R4)Math.Atan2(a, b); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R8 Atan2(R8 a, R8 b) + { + // According to the documentation of Math.Atan2: if x and y are either System.Double.PositiveInfinity + // or System.Double.NegativeInfinity, the method returns System.Double.NaN, but this seems to not be the case. + if (R8.IsInfinity(a) && R8.IsInfinity(b)) + return R8.NaN; + return Math.Atan2(a, b); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Sinh(R4 a) + { + return (R4)Math.Sinh(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Cosh(R4 a) + { + return (R4)Math.Cosh(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Tanh(R4 a) + { + return (R4)Math.Tanh(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Sqrt(R4 a) + { + return (R4)Math.Sqrt(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Truncate(R4 a) + { + return (R4)Math.Truncate(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Floor(R4 a) + { + return (R4)Math.Floor(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Ceiling(R4 a) + { + return (R4)Math.Ceiling(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 Round(R4 a) + { + return (R4)Math.Round(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TX Lower(TX a) + { + if (a.IsEmpty) + return a; + var sb = new StringBuilder(); + ReadOnlyMemoryUtils.AddLowerCaseToStringBuilder(a.Span, sb); + return sb.ToString().AsMemory(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TX Upper(TX a) + { + if (a.IsEmpty) + return a; + var dst = new char[a.Length]; + a.Span.ToUpperInvariant(dst); + return new TX(dst); + } + + // Special case some common Concat sizes, for better efficiency. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TX Empty() + { + return TX.Empty; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TX Concat(TX a, TX b) + { + if (a.IsEmpty) + return b; + if (b.IsEmpty) + return a; + var dst = new char[a.Length + b.Length]; + a.Span.CopyTo(dst); + b.Span.CopyTo(new Span(dst, a.Length, b.Length)); + return new TX(dst); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TX Concat(TX a, TX b, TX c) + { + var dst = new char[a.Length + b.Length + c.Length]; + a.Span.CopyTo(dst); + b.Span.CopyTo(new Span(dst, a.Length, b.Length)); + c.Span.CopyTo(new Span(dst, a.Length + b.Length, c.Length)); + return new TX(dst); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TX Concat(TX[] a) + { + Contracts.AssertValue(a); + + int len = 0; + for (int i = 0; i < a.Length; i++) + len += a[i].Length; + if (len == 0) + return TX.Empty; + + var sb = new StringBuilder(len); + for (int i = 0; i < a.Length; i++) + sb.AppendSpan(a[i].Span); + return sb.ToString().AsMemory(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static I4 Len(TX a) + { + return a.Length; + } + + /// + /// Given an index meant to index into a given sequence normalize it according to + /// these rules: negative indices get added to them, and + /// then the index is clamped the range 0 to inclusive, + /// and that result is returned. (For those familiar with Python, this is the same + /// as the logic for slice normalization.) + /// + /// The index to normalize + /// The length of the sequence + /// The normalized version of the index, a non-positive value no greater + /// than . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int NormalizeIndex(int i, int len) + { + Contracts.Assert(0 <= len); + if (i < 0) + { + if ((i += len) < 0) + return 0; + } + else if (i > len) + return len; + return i; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TX Right(TX a, I4 min) + { + if (a.IsEmpty) + return a; + return a.Slice(NormalizeIndex(min, a.Length)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TX Left(TX a, I4 lim) + { + if (a.IsEmpty) + return a; + return a.Slice(0, NormalizeIndex(lim, a.Length)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TX Mid(TX a, I4 min, I4 lim) + { + if (a.IsEmpty) + return a; + int im = NormalizeIndex(min, a.Length); + int il = NormalizeIndex(lim, a.Length); + if (im >= il) + return TX.Empty; + return a.Slice(im, il - im); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BL IsNA(R4 a) + { + return R4.IsNaN(a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BL IsNA(R8 a) + { + return R8.IsNaN(a); + } + + public static BL ToBL(TX a) + { + BL res = default(BL); + Conversions.Instance.Convert(in a, ref res); + return res; + } + + public static I4 ToI4(TX a) + { + I4 res = default(I4); + Conversions.Instance.Convert(in a, ref res); + return res; + } + + public static I8 ToI8(TX a) + { + I8 res = default(I8); + Conversions.Instance.Convert(in a, ref res); + return res; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 ToR4(R4 a) + { + // Note that the cast is intentional and NOT a no-op. It forces the JIT + // to narrow to R4 when it might be tempted to keep intermediate + // computations in larger precision. + return (R4)a; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R4 ToR4(R8 a) + { + return (R4)a; + } + + public static R4 ToR4(TX a) + { + R4 res = default(R4); + Conversions.Instance.Convert(in a, ref res); + return res; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R8 ToR8(R4 a) + { + return (R8)a; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static R8 ToR8(R8 a) + { + // Note that the cast is intentional and NOT a no-op. It forces the JIT + // to narrow to R4 when it might be tempted to keep intermediate + // computations in larger precision. + return a; + } + + public static R8 ToR8(TX a) + { + R8 res = default(R8); + Conversions.Instance.Convert(in a, ref res); + return res; + } + + public static TX ToTX(I4 src) => src.ToString().AsMemory(); + public static TX ToTX(I8 src) => src.ToString().AsMemory(); + public static TX ToTX(R4 src) => src.ToString("R", CultureInfo.InvariantCulture).AsMemory(); + public static TX ToTX(R8 src) => src.ToString("G17", CultureInfo.InvariantCulture).AsMemory(); + public static TX ToTX(BL src) + { + if (!src) + return "0".AsMemory(); + else + return "1".AsMemory(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BL Equals(TX first, TX second) + { + return first.Span.SequenceEqual(second.Span); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BL NotEquals(TX first, TX second) + { + return !Equals(first, second); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte Not(bool b) + { + return !b ? (byte)1 : default; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BL False() + { + return false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BL True() + { + return true; + } + + /// + /// Raise a to the b power. Special cases: + /// * 1^NA => 1 + /// * NA^0 => 1 + /// + public static I4 Pow(I4 a, I4 b) + { + if (a == 1) + return 1; + switch (b) + { + case 0: + return 1; + case 1: + return a; + case 2: + return a * a; + } + if (a == -1) + return (b & 1) == 0 ? 1 : -1; + if (b < 0) + throw Contracts.Except("Cannot raise an integer to a negative power"); + + // Since the abs of the base is at least two, the exponent must be less than 31. + if (b >= 31) + throw Contracts.Except("Cannot raise an integer to a power greater than 30"); + + if (a == 0) + { + if (b == 0) + return 1; + return 0; + } + + bool neg = false; + if (a < 0) + { + a = -a; + neg = (b & 1) != 0; + } + Contracts.Assert(a >= 2); + + // Since the exponent is at least three, the base must be <= 1290. + Contracts.Assert(b >= 3); + if (a > 1290) + throw Contracts.Except($"Base must be at most 1290 when raising to the power of {b}"); + + // REVIEW: Should we use a checked context and exception catching like I8 does? + ulong u = (ulong)(uint)a; + ulong result = 1; + for (; ; ) + { + if ((b & 1) != 0 && (result *= u) > I4.MaxValue) + throw Contracts.Except("Overflow"); + b >>= 1; + if (b == 0) + break; + if ((u *= u) > I4.MaxValue) + throw Contracts.Except("Overflow"); + } + Contracts.Assert(result <= I4.MaxValue); + + var res = (I4)result; + if (neg) + res = -res; + return res; + } + + /// + /// Raise a to the b power. Special cases: + /// * 1^NA => 1 + /// * NA^0 => 1 + /// + public static I8 Pow(I8 a, I8 b) + { + if (a == 1) + return 1; + switch (b) + { + case 0: + return 1; + case 1: + return a; + case 2: + return a * a; + } + if (a == -1) + return (b & 1) == 0 ? 1 : -1; + if (b < 0) + throw Contracts.Except("Cannot raise an integer to a negative power"); + + // Since the abs of the base is at least two, the exponent must be less than 63. + if (b >= 63) + throw Contracts.Except("Cannot raise an integer to a power greater than 62"); + + if (a == 0) + { + if (b == 0) + return 1; + return 0; + } + + bool neg = false; + if (a < 0) + { + a = -a; + neg = (b & 1) != 0; + } + Contracts.Assert(a >= 2); + + // Since the exponent is at least three, the base must be < 2^21. + Contracts.Assert(b >= 3); + if (a >= (1L << 21)) + throw Contracts.Except($"Base must be less than 2^21 when raising to the power of {b}"); + + long res = 1; + long x = a; + // REVIEW: Is the catch too slow in the overflow case? + try + { + checked + { + for (; ; ) + { + if ((b & 1) != 0) + res *= x; + b >>= 1; + if (b == 0) + break; + x *= x; + } + } + } + catch (OverflowException) + { + throw Contracts.Except("Overflow"); + } + Contracts.Assert(res > 0); + + if (neg) + res = -res; + return res; + } + } +} diff --git a/src/Microsoft.ML.Transforms/Expression/CharCursor.cs b/src/Microsoft.ML.Transforms/Expression/CharCursor.cs new file mode 100644 index 0000000000..79a696b643 --- /dev/null +++ b/src/Microsoft.ML.Transforms/Expression/CharCursor.cs @@ -0,0 +1,111 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.Transforms +{ + internal sealed class CharCursor + { + private readonly char[] _buffer; + + // The base index for the beginning of the buffer. + private int _ichBase; + + // Position within the buffer. + private int _ichNext; + private int _ichLim; + private bool _fNoMore; + + public bool Eof { get; private set; } + + public int IchCur => _ichBase + _ichNext - 1; + + public char ChCur { get; private set; } + + public CharCursor(string text) + : this(Contracts.CheckRef(text, nameof(text)).ToCharArray(), text.Length) + { + } + + public CharCursor(string text, int ichMin, int ichLim) + : this(text.ToCharArray(ichMin, ichLim - ichMin), ichLim - ichMin) + { + } + + private CharCursor(char[] buffer, int ichLimInit) + { + Contracts.AssertValue(buffer); + Contracts.Assert(0 <= ichLimInit && ichLimInit <= buffer.Length); + + _buffer = buffer; + _ichBase = 0; + _ichNext = 0; + _ichLim = ichLimInit; + _fNoMore = false; + Eof = false; + ChNext(); + } + + // Fetch the next character into _chCur and return it. + public char ChNext() + { + if (Eof) + return ChCur; + + if (_ichNext < _ichLim || EnsureMore()) + { + Contracts.Assert(_ichNext < _ichLim); + return ChCur = _buffer[_ichNext++]; + } + + Contracts.Assert(_fNoMore); + Eof = true; + _ichNext++; // This is so the final IchCur is reported correctly. + return ChCur = '\x00'; + } + + public char ChPeek(int dich) + { + // If someone is peeking at ich, they should have peeked everything up to ich. + Contracts.Assert(0 < dich && dich <= _ichLim - _ichNext + 1); + + int ich = dich + _ichNext - 1; + if (ich < _ichLim) + return _buffer[ich]; + if (EnsureMore()) + { + ich = dich + _ichNext - 1; + Contracts.Assert(ich < _ichLim); + return _buffer[ich]; + } + + Contracts.Assert(_fNoMore); + return '\x00'; + } + + private bool EnsureMore() + { + if (_fNoMore) + return false; + + if (_ichNext > 0) + { + int ichDst = 0; + int ichSrc = _ichNext; + while (ichSrc < _ichLim) + _buffer[ichDst++] = _buffer[ichSrc++]; + _ichBase += _ichNext; + _ichNext = 0; + _ichLim = ichDst; + } + + int ichLim = _ichLim; + + Contracts.Assert(ichLim == _ichLim); + _fNoMore = true; + return false; + } + } +} diff --git a/src/Microsoft.ML.Transforms/Expression/CodeGen.cs b/src/Microsoft.ML.Transforms/Expression/CodeGen.cs new file mode 100644 index 0000000000..f5ebef5488 --- /dev/null +++ b/src/Microsoft.ML.Transforms/Expression/CodeGen.cs @@ -0,0 +1,1434 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using Microsoft.ML.Internal.Utilities; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.Transforms +{ + using BL = System.Boolean; + using I4 = System.Int32; + using I8 = System.Int64; + using R4 = Single; + using R8 = Double; + using TX = ReadOnlyMemory; + + internal sealed partial class LambdaCompiler : IDisposable + { + public const int MaxParams = 16; + + private LambdaNode _top; + private Type _delType; + private MethodGenerator _meth; + + public static Delegate Compile(out List errors, LambdaNode node) + { + Contracts.CheckValue(node, nameof(node)); + + using (var cmp = new LambdaCompiler(node)) + return cmp.Do(out errors); + } + + private LambdaCompiler(LambdaNode node) + { + Contracts.AssertValue(node); + Contracts.Assert(1 <= node.Vars.Length & node.Vars.Length <= MaxParams); + Contracts.Assert(MaxParams <= 16); + Contracts.AssertValue(node.ResultType); + + _top = node; + + Type typeFn; + switch (node.Vars.Length) + { + case 1: + { typeFn = typeof(Func<,>); break; } + case 2: + { typeFn = typeof(Func<,,>); break; } + case 3: + { typeFn = typeof(Func<,,,>); break; } + case 4: + { typeFn = typeof(Func<,,,,>); break; } + case 5: + { typeFn = typeof(Func<,,,,,>); break; } + default: + throw Contracts.Except("Internal error in LambdaCompiler: Maximum number of inputs exceeded."); + } + + var types = new Type[node.Vars.Length + 1]; + foreach (var v in node.Vars) + { + Contracts.Assert(0 <= v.Index & v.Index < node.Vars.Length); + Contracts.Assert(types[v.Index] == null); + types[v.Index] = v.Type.RawType; + } + types[node.Vars.Length] = node.ResultType.RawType; + _delType = typeFn.MakeGenericType(types); + + Array.Copy(types, 0, types, 1, types.Length - 1); + types[0] = typeof(object); + + _meth = new MethodGenerator("lambda", typeof(Exec), node.ResultType.RawType, types); + } + + private Delegate Do(out List errors) + { + var visitor = new Visitor(_meth); + _top.Expr.Accept(visitor); + + errors = visitor.GetErrors(); + if (errors != null) + return null; + + _meth.Il.Ret(); + return _meth.CreateDelegate(_delType); + } + + public void Dispose() + { + _meth.Dispose(); + } + } + + internal sealed partial class LambdaCompiler + { + private sealed class Visitor : ExprVisitor + { + private MethodGenerator _meth; + private ILGenerator _gen; + private List _errors; + private readonly MethodInfo _methGetFalseBL; + private readonly MethodInfo _methGetTrueBL; + + private sealed class CachedWithLocal + { + public readonly WithLocalNode Node; + /// + /// The IL local containing the computed value. + /// + public readonly LocalBuilder Value; + /// + /// The boolean local indicating whether the value has been computed yet. + /// If the value is pre-computed, this is null. + /// + public readonly LocalBuilder Flag; + + public CachedWithLocal(WithLocalNode node, LocalBuilder value, LocalBuilder flag) + { + Contracts.AssertValue(node); + Contracts.AssertValue(value); + Contracts.AssertValueOrNull(flag); + Node = node; + Value = value; + Flag = flag; + } + } + + // The active cached "with" locals. For "with" local values that are aggressively computed, the + // corresponding flag local is null. For lazy computed values, the flag indicates whether + // the value has been computed and stored yet. Lazy computed values avoid potentially + // expensive computation that might not be needed, but result in code bloat since each + // use tests the flag, and if false, computes and stores the value. + private List _cacheWith; + + public Visitor(MethodGenerator meth) + { + _meth = meth; + _gen = meth.Il; + + Func f = BuiltinFunctions.False; + Contracts.Assert(f.Target == null); + _methGetFalseBL = f.GetMethodInfo(); + + Func t = BuiltinFunctions.True; + Contracts.Assert(t.Target == null); + _methGetTrueBL = t.GetMethodInfo(); + + _cacheWith = new List(); + } + + public List GetErrors() + { + return _errors; + } + + private void DoConvert(ExprNode node) + { + Contracts.AssertValue(node); + if (!node.NeedsConversion) + { + // When dealing with floating point, always emit the conversion so + // the result is stable. + if (node.IsR4) + _gen.Conv_R4(); + else if (node.IsR8) + _gen.Conv_R8(); + return; + } + + switch (node.SrcKind) + { + default: + Contracts.Assert(false, "Unexpected src kind in DoConvert"); + PostError(node, "Internal error in implicit conversion"); + break; + + case ExprTypeKind.R4: + // R4 will only implicitly convert to R8. + if (node.IsR8) + { + _gen.Conv_R8(); + return; + } + break; + case ExprTypeKind.I4: + // I4 can convert to I8, R4, or R8. + switch (node.ExprType) + { + case ExprTypeKind.I8: + _gen.Conv_I8(); + return; + case ExprTypeKind.R4: + _gen.Conv_R4(); + return; + case ExprTypeKind.R8: + _gen.Conv_R8(); + return; + } + break; + case ExprTypeKind.I8: + // I8 will only implicitly convert to R8. + if (node.IsR8) + { + _gen.Conv_R8(); + return; + } + break; + } + + Contracts.Assert(false, "Unexpected dst kind in DoConvert"); + PostError(node, "Internal error(2) in implicit conversion"); + } + + private void PostError(Node node) + { + Utils.Add(ref _errors, new Error(node.Token, "Code generation error")); + } + + private void PostError(Node node, string msg) + { + Utils.Add(ref _errors, new Error(node.Token, msg)); + } + + private void PostError(Node node, string msg, params object[] args) + { + Utils.Add(ref _errors, new Error(node.Token, msg, args)); + } + + private bool TryUseValue(ExprNode node) + { + var value = node.ExprValue; + if (value == null) + return false; + + switch (node.ExprType) + { + case ExprTypeKind.BL: + Contracts.Assert(value is BL); + GenBL((BL)value); + break; + case ExprTypeKind.I4: + Contracts.Assert(value is I4); + _gen.Ldc_I4((I4)value); + break; + case ExprTypeKind.I8: + Contracts.Assert(value is I8); + _gen.Ldc_I8((I8)value); + break; + case ExprTypeKind.R4: + Contracts.Assert(value is R4); + _gen.Ldc_R4((R4)value); + break; + case ExprTypeKind.R8: + Contracts.Assert(value is R8); + _gen.Ldc_R8((R8)value); + break; + case ExprTypeKind.TX: + { + Contracts.Assert(value is TX); + TX text = (TX)value; + _gen.Ldstr(text.ToString()); + CallFnc(Exec.ToTX); + } + break; + + case ExprTypeKind.Error: + PostError(node); + break; + + default: + PostError(node, "Bad ExprType"); + break; + } + + return true; + } + + public override void Visit(BoolLitNode node) + { + Contracts.Assert(node.IsBool); + Contracts.Assert(node.ExprValue is BL); + GenBL((BL)node.ExprValue); + } + + public override void Visit(StrLitNode node) + { + Contracts.Assert(node.IsTX); + Contracts.Assert(node.ExprValue is TX); + TX text = (TX)node.ExprValue; + + _gen.Ldstr(text.ToString()); + CallFnc(Exec.ToTX); + } + + public override void Visit(NumLitNode node) + { + Contracts.Assert(node.IsNumber); + var value = node.ExprValue; + Contracts.Assert(value != null); + switch (node.ExprType) + { + case ExprTypeKind.I4: + Contracts.Assert(value is I4); + _gen.Ldc_I4((I4)value); + break; + case ExprTypeKind.I8: + Contracts.Assert(value is I8); + _gen.Ldc_I8((I8)value); + break; + case ExprTypeKind.R4: + Contracts.Assert(value is R4); + _gen.Ldc_R4((R4)value); + break; + case ExprTypeKind.R8: + Contracts.Assert(value is R8); + _gen.Ldc_R8((R8)value); + break; + default: + Contracts.Assert(false, "Bad NumLitNode"); + PostError(node, "Internal error in numeric literal"); + break; + } + } + + public override void Visit(IdentNode node) + { + if (TryUseValue(node)) + return; + + Node referent = node.Referent; + if (node.Referent == null) + { + PostError(node, "Unbound name!"); + return; + } + + switch (referent.Kind) + { + default: + PostError(node, "Unbound name!"); + return; + + case NodeKind.Param: + _gen.Ldarg(referent.AsParam.Index + 1); + break; + + case NodeKind.WithLocal: + var loc = referent.AsWithLocal; + Contracts.Assert(loc.Value.ExprValue == null); + Contracts.Assert(loc.GenCount >= 0); + + if (loc.UseCount <= 1) + { + Contracts.Assert(loc.UseCount == 1); + Contracts.Assert(loc.Index == -1); + loc.GenCount++; + loc.Value.Accept(this); + } + else + { + Contracts.Assert(0 <= loc.Index & loc.Index < _cacheWith.Count); + var cache = _cacheWith[loc.Index]; + Contracts.Assert(cache.Value != null); + if (cache.Flag != null) + { + // This is a lazy computed value. If we've already computed the value, skip the code + // that generates it. If this is the first place that generates it, we don't need to + // test the bool - we know it hasn't been computed yet (since we never jump backwards). + bool needTest = loc.GenCount > 0; + Label labHave = default(Label); + if (needTest) + { + labHave = _gen.DefineLabel(); + _gen + .Ldloc(cache.Flag) + .Brtrue(labHave); + } + + // Generate the code for the value. + loc.GenCount++; + loc.Value.Accept(this); + + // Store the value and set the flag indicating that we have it. + _gen + .Stloc(cache.Value) + .Ldc_I4(1) + .Stloc(cache.Flag); + if (needTest) + _gen.MarkLabel(labHave); + } + + // Load the value. + _gen.Ldloc(cache.Value); + } + break; + } + DoConvert(node); + } + + public override bool PreVisit(UnaryOpNode node) + { + if (TryUseValue(node)) + return false; + return true; + } + + public override void PostVisit(UnaryOpNode node) + { + Contracts.AssertValue(node); + + switch (node.Op) + { + default: + Contracts.Assert(false, "Bad unary op"); + PostError(node, "Internal error in unary operator"); + break; + + case UnaryOp.Minus: + Contracts.Assert(node.IsNumber); + Contracts.Assert(node.Arg.ExprType == node.SrcKind); + switch (node.SrcKind) + { + case ExprTypeKind.I4: + _gen.Neg(); + break; + case ExprTypeKind.I8: + _gen.Neg(); + break; + case ExprTypeKind.R4: + case ExprTypeKind.R8: + _gen.Neg(); + break; + + default: + Contracts.Assert(false, "Bad operand type in unary minus"); + PostError(node, "Internal error in unary minus"); + break; + } + break; + + case UnaryOp.Not: + CallFnc(BuiltinFunctions.Not); + break; + } + + DoConvert(node); + } + + public override bool PreVisit(BinaryOpNode node) + { + Contracts.AssertValue(node); + + if (TryUseValue(node)) + return false; + + if (node.ReduceToLeft) + { + node.Left.Accept(this); + DoConvert(node); + return false; + } + + if (node.ReduceToRight) + { + node.Right.Accept(this); + DoConvert(node); + return false; + } + + switch (node.Op) + { + default: + Contracts.Assert(false, "Bad binary op"); + PostError(node, "Internal error in binary operator"); + break; + + case BinaryOp.Coalesce: + GenCoalesce(node); + break; + + case BinaryOp.Or: + case BinaryOp.And: + GenBoolBinOp(node); + break; + + case BinaryOp.Add: + case BinaryOp.Sub: + case BinaryOp.Mul: + case BinaryOp.Div: + case BinaryOp.Mod: + case BinaryOp.Power: + GenNumBinOp(node); + break; + + case BinaryOp.Error: + PostError(node); + break; + } + + DoConvert(node); + return false; + } + + private void GenBoolBinOp(BinaryOpNode node) + { + Contracts.AssertValue(node); + Contracts.Assert(node.Op == BinaryOp.Or || node.Op == BinaryOp.And); + Contracts.Assert(node.SrcKind == ExprTypeKind.BL); + Contracts.Assert(node.Left.IsBool); + Contracts.Assert(node.Right.IsBool); + + // This does naive code gen for short-circuiting binary bool operators. + // Ideally, this would cooperate with comparisons to produce better code gen. + // However, this is merely an optimization issue, not correctness, so possibly + // not worth the additional complexity. + + Label labEnd = _gen.DefineLabel(); + + node.Left.Accept(this); + _gen.Dup(); + + if (node.Op == BinaryOp.Or) + _gen.Brtrue(labEnd); + else + _gen.Brfalse(labEnd); + + _gen.Pop(); + node.Right.Accept(this); + + _gen.Br(labEnd); + _gen.MarkLabel(labEnd); + } + + private void GenNumBinOp(BinaryOpNode node) + { + Contracts.AssertValue(node); + + // Note that checking for special known values like NA and identity values + // is done in the binder and handled in PreVisit(BinaryOpNode). + node.Left.Accept(this); + node.Right.Accept(this); + + if (node.SrcKind == ExprTypeKind.I4) + { + Contracts.Assert(node.Left.IsI4); + Contracts.Assert(node.Right.IsI4); + switch (node.Op) + { + default: + Contracts.Assert(false, "Bad numeric bin op"); + PostError(node, "Internal error in numeric binary operator"); + break; + + case BinaryOp.Add: + _gen.Add(); + break; + case BinaryOp.Sub: + _gen.Sub(); + break; + case BinaryOp.Mul: + _gen.Mul_Ovf(); + break; + case BinaryOp.Div: + _gen.Div(); + break; + case BinaryOp.Mod: + _gen.Rem(); + break; + case BinaryOp.Power: + CallBin(BuiltinFunctions.Pow); + break; + } + } + else if (node.SrcKind == ExprTypeKind.I8) + { + Contracts.Assert(node.Left.IsI8); + Contracts.Assert(node.Right.IsI8); + switch (node.Op) + { + default: + Contracts.Assert(false, "Bad numeric bin op"); + PostError(node, "Internal error in numeric binary operator"); + break; + + case BinaryOp.Add: + _gen.Add(); + break; + case BinaryOp.Sub: + _gen.Sub(); + break; + case BinaryOp.Mul: + _gen.Mul(); + break; + case BinaryOp.Div: + _gen.Div(); + break; + case BinaryOp.Mod: + _gen.Rem(); + break; + case BinaryOp.Power: + CallBin(BuiltinFunctions.Pow); + break; + } + } + else if (node.SrcKind == ExprTypeKind.R4) + { + Contracts.Assert(node.Left.IsR4); + Contracts.Assert(node.Right.IsR4); + switch (node.Op) + { + default: + Contracts.Assert(false, "Bad numeric bin op"); + PostError(node, "Internal error in numeric binary operator"); + break; + + case BinaryOp.Add: + _gen.Add(); + break; + case BinaryOp.Sub: + _gen.Sub(); + break; + case BinaryOp.Mul: + _gen.Mul(); + break; + case BinaryOp.Div: + _gen.Div(); + break; + case BinaryOp.Mod: + _gen.Rem(); + break; + case BinaryOp.Power: + CallBin(BuiltinFunctions.Pow); + break; + } + } + else + { + Contracts.Assert(node.SrcKind == ExprTypeKind.R8); + Contracts.Assert(node.Left.IsR8); + Contracts.Assert(node.Right.IsR8); + switch (node.Op) + { + default: + Contracts.Assert(false, "Bad numeric bin op"); + PostError(node, "Internal error in numeric binary operator"); + break; + + case BinaryOp.Add: + _gen.Add(); + break; + case BinaryOp.Sub: + _gen.Sub(); + break; + case BinaryOp.Mul: + _gen.Mul(); + break; + case BinaryOp.Div: + _gen.Div(); + break; + case BinaryOp.Mod: + _gen.Rem(); + break; + case BinaryOp.Power: + CallBin(Math.Pow); + break; + } + } + } + + private void GenBL(BL value) + { + MethodInfo meth; + if (!value) + meth = _methGetFalseBL; + else + meth = _methGetTrueBL; + _gen.Call(meth); + } + + private void CallFnc(Func fn) + { + _gen.Call(fn.GetMethodInfo()); + } + + private void CallFnc(Func fn) + { + _gen.Call(fn.GetMethodInfo()); + } + + private void CallBin(Func fn) + { + _gen.Call(fn.GetMethodInfo()); + } + + private void GenCoalesce(BinaryOpNode node) + { + Contracts.AssertValue(node); + Contracts.Assert(node.Op == BinaryOp.Coalesce); + + // If left is a constant, then the binder should have dealt with it! + Contracts.Assert(node.Left.ExprValue == null); + + Label labEnd = _gen.DefineLabel(); + + // Branch to end if the left operand is NOT NA. + node.Left.Accept(this); + GenBrNa(node.Left, labEnd); + + _gen.Pop(); + node.Right.Accept(this); + _gen.MarkLabel(labEnd); + } + + public override void PostVisit(BinaryOpNode node) + { + Contracts.Assert(false); + } + + public override bool PreVisit(ConditionalNode node) + { + Contracts.AssertValue(node); + + if (TryUseValue(node)) + return false; + + var cond = (BL?)node.Cond.ExprValue; + if (cond != null) + { + if (cond.Value) + node.Left.Accept(this); + else + node.Right.Accept(this); + goto LDone; + } + + Label labEnd = _gen.DefineLabel(); + Label labFalse = _gen.DefineLabel(); + + node.Cond.Accept(this); + _gen.Brfalse(labFalse); + + // Left is the "true" branch. + node.Left.Accept(this); + _gen.Br(labEnd) + .MarkLabel(labFalse); + + node.Right.Accept(this); + _gen.Br(labEnd); + _gen.MarkLabel(labEnd); + + LDone: + DoConvert(node); + return false; + } + + public override void PostVisit(ConditionalNode node) + { + Contracts.Assert(false); + } + + public override bool PreVisit(CompareNode node) + { + Contracts.AssertValue(node); + Contracts.Assert(node.Operands.Items.Length >= 2); + + if (TryUseValue(node)) + return false; + + ExprTypeKind kind = node.ArgTypeKind; + Node[] items = node.Operands.Items; + if (kind == ExprTypeKind.TX && items.Length == 2) + { + // Two value text comparison is handled by methods. + items[0].Accept(this); + items[1].Accept(this); + switch (node.Op) + { + default: + Contracts.Assert(false, "Bad bool compare op"); + break; + + case CompareOp.Equal: + CallFnc(BuiltinFunctions.Equals); + break; + case CompareOp.NotEqual: + CallFnc(BuiltinFunctions.NotEquals); + break; + } + + DoConvert(node); + return false; + } + + Label labEnd = _gen.DefineLabel(); + if (items.Length == 2) + { + // Common case of two operands. Note that the binder should have handled the case when + // one or both is a constant NA. + + ExprNode arg; + GenRaw(arg = items[0].AsExpr); + Contracts.Assert(arg.ExprType == kind); + GenRaw(arg = items[1].AsExpr); + Contracts.Assert(arg.ExprType == kind); + + TokKind tid = node.Operands.Delimiters[0].Kind; + Contracts.Assert(tid == node.TidLax || tid == node.TidStrict); + var isStrict = tid == node.TidStrict; + switch (kind) + { + case ExprTypeKind.BL: + GenCmpBool(node.Op, isStrict); + break; + case ExprTypeKind.I4: + case ExprTypeKind.I8: + GenCmpInt(node.Op, isStrict); + break; + case ExprTypeKind.R4: + case ExprTypeKind.R8: + GenCmpFloat(node.Op, isStrict); + break; + + default: + PostError(node, "Compare codegen for this comparison is NYI"); + return false; + } + } + else + { + // For more than two items, we use branching instructions instead of ceq, clt, cgt, etc. + Contracts.Assert(items.Length > 2); + + // Get the comparison generation function and the (raw) local type. + Action fnc; + Type typeLoc; + switch (kind) + { + case ExprTypeKind.BL: + fnc = GenCmpBool; + typeLoc = typeof(byte); + break; + case ExprTypeKind.TX: + fnc = GenCmpText; + typeLoc = typeof(TX); + break; + case ExprTypeKind.I4: + fnc = GenCmpInt; + typeLoc = typeof(int); + break; + case ExprTypeKind.I8: + fnc = GenCmpInt; + typeLoc = typeof(long); + break; + case ExprTypeKind.R4: + fnc = GenCmpFloat; + typeLoc = typeof(R4); + break; + case ExprTypeKind.R8: + fnc = GenCmpFloat; + typeLoc = typeof(R8); + break; + + default: + PostError(node, "Compare codegen for this comparison is NYI"); + return false; + } + + Label labFalse = _gen.DefineLabel(); + if (node.Op != CompareOp.NotEqual) + { + // Note: this loop doesn't work for != so it is handled separately below. + ExprNode arg = items[0].AsExpr; + Contracts.Assert(arg.ExprType == kind); + + GenRaw(arg = items[0].AsExpr); + Contracts.Assert(arg.ExprType == kind); + + for (int i = 1; ; i++) + { + TokKind tid = node.Operands.Delimiters[i - 1].Kind; + Contracts.Assert(tid == node.TidLax || tid == node.TidStrict); + var isStrict = tid == node.TidStrict; + + arg = items[i].AsExpr; + Contracts.Assert(arg.ExprType == kind); + GenRaw(arg); + + if (i == items.Length - 1) + { + // Last one. + fnc(node.Op, isStrict, labFalse); + break; + } + + // We'll need this value again, so stash it in a local. + _gen.Dup(); + using (var local = _meth.AcquireTemporary(typeLoc)) + { + _gen.Stloc(local.Local); + fnc(node.Op, isStrict, labFalse); + _gen.Ldloc(local.Local); + } + } + } + else + { + // NotEqual is special - it means that the values are all distinct, so comparing adjacent + // items is not enough. + Contracts.Assert(node.Op == CompareOp.NotEqual & items.Length > 2); + + // We need a local for each item. + var locals = new MethodGenerator.Temporary[items.Length]; + for (int i = 0; i < locals.Length; i++) + locals[i] = _meth.AcquireTemporary(typeLoc); + try + { + ExprNode arg = items[0].AsExpr; + Contracts.Assert(arg.ExprType == kind); + + GenRaw(arg); + _gen.Stloc(locals[0].Local); + + for (int i = 1; i < items.Length; i++) + { + // Need to evaluate the expression and store it in the local. + arg = items[i].AsExpr; + Contracts.Assert(arg.ExprType == kind); + GenRaw(arg); + _gen.Stloc(locals[i].Local); + + for (int j = 0; j < i; j++) + { + _gen.Ldloc(locals[j].Local) + .Ldloc(locals[i].Local); + fnc(node.Op, true, labFalse); + } + } + } + finally + { + for (int i = locals.Length; --i >= 0;) + locals[i].Dispose(); + } + } + + _gen.Call(_methGetTrueBL) + .Br(labEnd); + + _gen.MarkLabel(labFalse); + _gen.Call(_methGetFalseBL) + .Br(labEnd); + } + + _gen.MarkLabel(labEnd); + + DoConvert(node); + return false; + } + + /// + /// Get the raw bits from an expression node. If the node is constant, this avoids the + /// silly "convert to dv type" followed by "extract raw bits". Returns whether the expression + /// is a constant NA, with null meaning "don't know". + /// + private void GenRaw(ExprNode node) + { + Contracts.AssertValue(node); + + var val = node.ExprValue; + if (val != null) + { + switch (node.ExprType) + { + case ExprTypeKind.BL: + { + var x = (BL)val; + _gen.Ldc_I4(x ? 1 : 0); + return; + } + case ExprTypeKind.I4: + { + var x = (I4)val; + _gen.Ldc_I4(x); + return; + } + case ExprTypeKind.I8: + { + var x = (I8)val; + _gen.Ldc_I8(x); + return; + } + case ExprTypeKind.R4: + { + var x = (R4)val; + _gen.Ldc_R4(x); + return; + } + case ExprTypeKind.R8: + { + var x = (R8)val; + _gen.Ldc_R8(x); + return; + } + case ExprTypeKind.TX: + { + var x = (TX)val; + _gen.Ldstr(x.ToString()); + CallFnc(Exec.ToTX); + return; + } + } + } + + node.Accept(this); + } + + /// + /// Generate code to branch to labNa if the top stack element is NA. + /// Note that this leaves the element on the stack (duplicates before comparing). + /// If rev is true, this branches when NOT NA. + /// + private void GenBrNa(ExprNode node, Label labNa, bool dup = true) + { + GenBrNaCore(node, node.ExprType, labNa, dup); + } + + /// + /// Generate code to branch to labNa if the top stack element is NA. + /// If dup is true, this leaves the element on the stack (duplicates before comparing). + /// If rev is true, this branches when NOT NA. + /// + private void GenBrNaCore(ExprNode node, ExprTypeKind kind, Label labNa, bool dup) + { + if (dup) + _gen.Dup(); + + switch (kind) + { + case ExprTypeKind.R4: + case ExprTypeKind.R8: + // Any value that is not equal to itself is an NA. + _gen.Dup(); + _gen.Beq(labNa); + break; + case ExprTypeKind.Error: + case ExprTypeKind.None: + Contracts.Assert(false, "Bad expr kind in GenBrNa"); + PostError(node, "Internal error in GenBrNa"); + break; + } + } + + /// + /// Generate a bool from comparing the raw bits. The values are guaranteed to not be NA. + /// + private void GenCmpBool(CompareOp op, bool isStrict) + { + switch (op) + { + default: + Contracts.Assert(false, "Bad bool compare op"); + break; + + case CompareOp.Equal: + _gen.Ceq(); + break; + case CompareOp.NotEqual: + _gen.Xor(); + break; + } + } + + /// + /// Generate a bool from comparing the raw bits. The values are guaranteed to not be NA. + /// + private void GenCmpInt(CompareOp op, bool isStrict) + { + switch (op) + { + default: + Contracts.Assert(false, "Bad compare op"); + break; + + case CompareOp.Equal: + _gen.Ceq(); + break; + case CompareOp.NotEqual: + _gen.Ceq().Ldc_I4(0).Ceq(); + break; + case CompareOp.DecrChain: + if (isStrict) + _gen.Cgt(); + else + _gen.Clt().Ldc_I4(0).Ceq(); + break; + case CompareOp.IncrChain: + if (isStrict) + _gen.Clt(); + else + _gen.Cgt().Ldc_I4(0).Ceq(); + break; + } + } + + /// + /// Generate a bool from comparing the raw bits. The values are guaranteed to not be NA. + /// + private void GenCmpFloat(CompareOp op, bool isStrict) + { + switch (op) + { + default: + Contracts.Assert(false, "Bad compare op"); + break; + + case CompareOp.Equal: + _gen.Ceq(); + break; + case CompareOp.NotEqual: + _gen.Ceq().Ldc_I4(0).Ceq(); + break; + case CompareOp.DecrChain: + if (isStrict) + _gen.Cgt(); + else + _gen.Clt_Un().Ldc_I4(0).Ceq(); + break; + case CompareOp.IncrChain: + if (isStrict) + _gen.Clt(); + else + _gen.Cgt_Un().Ldc_I4(0).Ceq(); + break; + } + } + + private void GenCmpBool(CompareOp op, bool isStrict, Label labFalse) + { + switch (op) + { + default: + Contracts.Assert(false, "Bad bool compare op"); + break; + + case CompareOp.Equal: + _gen.Bne_Un(labFalse); + break; + case CompareOp.NotEqual: + _gen.Beq(labFalse); + break; + } + } + + private void GenCmpText(CompareOp op, bool isStrict, Label labFalse) + { + // Note that NA values don't come through here, so we don't need NA propagating equality comparison. + switch (op) + { + default: + Contracts.Assert(false, "Bad bool compare op"); + break; + + case CompareOp.Equal: + CallFnc(BuiltinFunctions.Equals); + _gen.Brfalse(labFalse); + break; + case CompareOp.NotEqual: + CallFnc(BuiltinFunctions.Equals); + _gen.Brtrue(labFalse); + break; + } + } + + private void GenCmpInt(CompareOp op, bool isStrict, Label labFalse) + { + switch (op) + { + default: + Contracts.Assert(false, "Bad compare op"); + break; + + case CompareOp.Equal: + _gen.Bne_Un(labFalse); + break; + case CompareOp.NotEqual: + _gen.Beq(labFalse); + break; + case CompareOp.DecrChain: + if (isStrict) + _gen.Ble(labFalse); + else + _gen.Blt(labFalse); + break; + case CompareOp.IncrChain: + if (isStrict) + _gen.Bge(labFalse); + else + _gen.Bgt(labFalse); + break; + } + } + + private void GenCmpFloat(CompareOp op, bool isStrict, Label labFalse) + { + switch (op) + { + default: + Contracts.Assert(false, "Bad compare op"); + break; + + case CompareOp.Equal: + _gen.Bne_Un(labFalse); + break; + case CompareOp.NotEqual: + _gen.Beq(labFalse); + break; + case CompareOp.DecrChain: + if (isStrict) + _gen.Ble_Un(labFalse); + else + _gen.Blt_Un(labFalse); + break; + case CompareOp.IncrChain: + if (isStrict) + _gen.Bge_Un(labFalse); + else + _gen.Bgt_Un(labFalse); + break; + } + } + + public override void PostVisit(CompareNode node) + { + Contracts.Assert(false); + } + + public override bool PreVisit(CallNode node) + { + Contracts.AssertValue(node); + + if (TryUseValue(node)) + return false; + + if (node.Method == null) + { + Contracts.Assert(false, "Bad function"); + PostError(node, "Internal error: unknown function: '{0}'", node.Head.Value); + return false; + } + + var meth = node.Method; + var ps = meth.GetParameters(); + Type type; + if (Utils.Size(ps) > 0 && (type = ps[ps.Length - 1].ParameterType).IsArray) + { + // Variable case, so can't be identity. + Contracts.Assert(node.Method.ReturnType != typeof(void)); + + // Get the item type of the array. + type = type.GetElementType(); + + var args = node.Args.Items; + int head = ps.Length - 1; + int tail = node.Args.Items.Length - head; + Contracts.Assert(tail >= 0); + + // Generate the "head" args. + for (int i = 0; i < head; i++) + args[i].Accept(this); + + // Bundle the "tail" args into an array. + _gen.Ldc_I4(tail) + .Newarr(type); + for (int i = 0; i < tail; i++) + { + _gen.Dup() + .Ldc_I4(i); + args[head + i].Accept(this); + _gen.Stelem(type); + } + + // Make the call. + _gen.Call(node.Method); + } + else + { + Contracts.Assert(Utils.Size(ps) == node.Args.Items.Length); + node.Args.Accept(this); + + // An identity function is marked with a void return type. + if (node.Method.ReturnType != typeof(void)) + _gen.Call(node.Method); + else + Contracts.Assert(node.Args.Items.Length == 1); + } + + DoConvert(node); + return false; + } + + public override void PostVisit(CallNode node) + { + Contracts.Assert(false); + } + + public override void PostVisit(ListNode node) + { + Contracts.AssertValue(node); + } + + public override bool PreVisit(WithNode node) + { + Contracts.AssertValue(node); + + var local = node.Local; + Contracts.Assert(local.Index == -1); + Contracts.Assert(local.UseCount >= 0); + + if (local.Value.ExprValue != null || local.UseCount <= 1) + { + // In this case, simply inline the code generation, no need + // to cache the value in an IL local. + node.Body.Accept(this); + Contracts.Assert(local.Index == -1); + } + else + { + // REVIEW: What's a reasonable value? This allows binary uses of 7 locals. + // This should cover most cases, but allows a rather large bloat factor. + const int maxTotalUse = 128; + + // This case uses a cache value. When lazy, it also keeps a bool flag indicating + // whether the value has been computed and stored in the cache yet. + int index = _cacheWith.Count; + + // Lazy can bloat code gen exponentially. This test decides whether to be lazy for this + // particular local, based on its use count and nesting. This assumes the worst case, + // that each lazy value is used by the next lazy value the full UseCount number of times. + // REVIEW: We should try to do better at some point.... Strictness analysis would + // solve this, but is non-trivial to implement. + bool lazy = true; + long totalUse = local.UseCount; + if (totalUse > maxTotalUse) + lazy = false; + else + { + for (int i = index; --i >= 0;) + { + var item = _cacheWith[i]; + Contracts.Assert(item.Node.UseCount >= 2); + if (item.Flag == null) + continue; + totalUse *= item.Node.UseCount; + if (totalUse > maxTotalUse) + { + lazy = false; + break; + } + } + } + + // This risks code gen + // bloat but avoids unnecessary computation. Perhaps we should determine whether the + // value is always needed. However, this can be quite complicated, requiring flow + // analysis through all expression kinds. + + // REVIEW: Should we always make the code generation lazy? This risks code gen + // bloat but avoids unnecessary computation. Perhaps we should determine whether the + // value is always needed. However, this can be quite complicated, requiring flow + // analysis through all expression kinds. + using (var value = _meth.AcquireTemporary(ExprNode.ToSysType(local.Value.ExprType))) + using (var flag = lazy ? _meth.AcquireTemporary(typeof(bool)) : default(MethodGenerator.Temporary)) + { + LocalBuilder flagBldr = flag.Local; + Contracts.Assert((flagBldr != null) == lazy); + + if (lazy) + { + _gen + .Ldc_I4(0) + .Stloc(flagBldr); + } + else + { + local.Value.Accept(this); + _gen.Stloc(value.Local); + } + + // Activate the cache item. + var cache = new CachedWithLocal(local, value.Local, flag.Local); + _cacheWith.Add(cache); + Contracts.Assert(_cacheWith.Count == index + 1); + + // Generate the code for the body. + local.Index = index; + node.Body.Accept(this); + Contracts.Assert(local.Index == index); + local.Index = -1; + + // Remove the cache locals. + Contracts.Assert(_cacheWith.Count == index + 1); + Contracts.Assert(_cacheWith[index] == cache); + _cacheWith.RemoveAt(index); + } + } + +#if DEBUG + System.Diagnostics.Debug.WriteLine("Generated code '{0}' times for '{1}'", local.GenCount, local); +#endif + return false; + } + + public override void PostVisit(WithNode node) + { + Contracts.Assert(false); + } + + public override bool PreVisit(WithLocalNode node) + { + Contracts.Assert(false); + return false; + } + + public override void PostVisit(WithLocalNode node) + { + Contracts.Assert(false); + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.ML.Transforms/Expression/Error.cs b/src/Microsoft.ML.Transforms/Expression/Error.cs new file mode 100644 index 0000000000..e6dc80fea5 --- /dev/null +++ b/src/Microsoft.ML.Transforms/Expression/Error.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.ML.Internal.Utilities; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.Transforms +{ + internal sealed class Error + { + public readonly Token Token; + public readonly string Message; + // Args may be null. + public readonly object[] Args; + + public Error(Token tok, string msg) + { + Contracts.AssertValue(tok); + Contracts.AssertNonEmpty(msg); + Token = tok; + Message = msg; + Args = null; + } + + public Error(Token tok, string msg, params object[] args) + { + Contracts.AssertValue(tok); + Contracts.AssertNonEmpty(msg); + Contracts.AssertValue(args); + Token = tok; + Message = msg; + Args = args; + } + + public string GetMessage() + { + var msg = Message; + if (Utils.Size(Args) > 0) + msg = string.Format(msg, Args); + if (Token != null) + msg = string.Format("at '{0}': {1}", Token, msg); + return msg; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.ML.Transforms/Expression/Exec.cs b/src/Microsoft.ML.Transforms/Expression/Exec.cs new file mode 100644 index 0000000000..cba51e5e18 --- /dev/null +++ b/src/Microsoft.ML.Transforms/Expression/Exec.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.Transforms +{ + using TX = ReadOnlyMemory; + + /// + /// This class contains static helper methods needed for execution. + /// + internal sealed class Exec + { + /// + /// Currently this class is not intended to be instantiated. However the methods generated + /// by ExprTransform need to be associated with some public type. This one serves that + /// purpose as well as containing static helpers. + /// + private Exec() + { + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TX ToTX(string str) + { + // We shouldn't allow a null in here. + Contracts.AssertValue(str); + return str.AsMemory(); + } + } +} diff --git a/src/Microsoft.ML.Transforms/Expression/FunctionProvider.cs b/src/Microsoft.ML.Transforms/Expression/FunctionProvider.cs new file mode 100644 index 0000000000..aa898f63ef --- /dev/null +++ b/src/Microsoft.ML.Transforms/Expression/FunctionProvider.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Reflection; + +namespace Microsoft.ML.Transforms +{ + public delegate void SignatureFunctionProvider(); + + /// + /// This interface enables extending the ExprTransform language with additional functions. + /// + public interface IFunctionProvider + { + /// + /// The namespace for this provider. This should be a legal identifier in the expression language. + /// Multiple providers may contribute to the same namespace. + /// + string NameSpace { get; } + + /// + /// Returns an array of overloads for the given function name. This may return null instead of an + /// empty array. The returned MethodInfos should be public static methods that can be freely invoked + /// by IL in a different assembly. They should also be "pure" functions - with the output only + /// depending on the inputs and NOT on any global state. + /// + MethodInfo[] Lookup(string name); + + /// + /// If the function's value can be determined by the given subset of its arguments, this should + /// return the resulting value. Note that this should only be called if values is non-empty and + /// contains at least one null. If all the arguments are non-null, then the MethodInfo will be + /// invoked to produce the value. + /// + /// The name of the function. + /// The MethodInfo provided by Lookup. When there are multiple overloads of + /// a function with a given name, this can be used to determine which overload is being used. + /// The values of the input arguments, with null for the non-constant arguments. This should + /// only be called if there is at least one null. + /// The constant value, when it can be determined; null otherwise. + object ResolveToConstant(string name, MethodInfo meth, object[] values); + } +} diff --git a/src/Microsoft.ML.Transforms/Expression/IlGeneratorExtensions.cs b/src/Microsoft.ML.Transforms/Expression/IlGeneratorExtensions.cs new file mode 100644 index 0000000000..d765e7f9fb --- /dev/null +++ b/src/Microsoft.ML.Transforms/Expression/IlGeneratorExtensions.cs @@ -0,0 +1,405 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Reflection; +using System.Reflection.Emit; +using Microsoft.ML.Runtime; + +#pragma warning disable MSML_GeneralName // The names are derived from .NET OpCode names. These do not adhere to .NET naming standards. +namespace Microsoft.ML.Transforms +{ + /// + /// Helper extension methods for using ILGenerator. + /// Rather than typing out something like: + /// il.Emit(OpCodes.Ldarg_0); + /// il.Emit(OpCodes.Ldarg_1); + /// il.Emit(OpCodes.Ldc_I4, i); + /// il.Emit(OpCodes.Ldelem_Ref); + /// il.Emit(OpCodes.Stfld, literalFields[i]); + /// You can do: + /// il + /// .Ldarg(0) + /// .Ldarg(1) + /// .Ldc_I4(i) + /// .Ldelem_Ref() + /// .Stfld(literalFields[i]); + /// It also provides some type safety over the Emit methods by ensuring + /// that you don't pass any args when using Add or that you only + /// pass a Label when using Br. + /// + internal static class ILGeneratorExtensions + { + public static ILGenerator Add(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Add); + return il; + } + + public static ILGenerator Beq(this ILGenerator il, Label label) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Beq, label); + return il; + } + + public static ILGenerator Bge(this ILGenerator il, Label label) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Bge, label); + return il; + } + + public static ILGenerator Bge_Un(this ILGenerator il, Label label) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Bge_Un, label); + return il; + } + + public static ILGenerator Bgt(this ILGenerator il, Label label) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Bgt, label); + return il; + } + + public static ILGenerator Bgt_Un(this ILGenerator il, Label label) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Bgt_Un, label); + return il; + } + + public static ILGenerator Ble(this ILGenerator il, Label label) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Ble, label); + return il; + } + + public static ILGenerator Ble_Un(this ILGenerator il, Label label) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Ble_Un, label); + return il; + } + + public static ILGenerator Blt(this ILGenerator il, Label label) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Blt, label); + return il; + } + + public static ILGenerator Blt_Un(this ILGenerator il, Label label) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Blt_Un, label); + return il; + } + + public static ILGenerator Bne_Un(this ILGenerator il, Label label) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Bne_Un, label); + return il; + } + + public static ILGenerator Br(this ILGenerator il, Label label) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Br, label); + return il; + } + + public static ILGenerator Brfalse(this ILGenerator il, Label label) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Brfalse, label); + return il; + } + + public static ILGenerator Brtrue(this ILGenerator il, Label label) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Brtrue, label); + return il; + } + + public static ILGenerator Call(this ILGenerator il, MethodInfo info) + { + Contracts.AssertValue(il); + Contracts.AssertValue(info); + Contracts.Assert(!info.IsVirtual); + il.Emit(OpCodes.Call, info); + return il; + } + + public static ILGenerator Ceq(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Ceq); + return il; + } + + public static ILGenerator Cgt(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Cgt); + return il; + } + + public static ILGenerator Cgt_Un(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Cgt_Un); + return il; + } + + public static ILGenerator Clt(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Clt); + return il; + } + + public static ILGenerator Clt_Un(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Clt_Un); + return il; + } + + public static ILGenerator Conv_I8(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Conv_I8); + return il; + } + + public static ILGenerator Conv_R4(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Conv_R4); + return il; + } + + public static ILGenerator Conv_R8(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Conv_R8); + return il; + } + + public static ILGenerator Div(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Div); + return il; + } + + public static ILGenerator Dup(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Dup); + return il; + } + + public static ILGenerator Ldarg(this ILGenerator il, int arg) + { + Contracts.AssertValue(il); + Contracts.Assert(0 <= arg && arg <= short.MaxValue); + + switch (arg) + { + case 0: + il.Emit(OpCodes.Ldarg_0); + break; + case 1: + il.Emit(OpCodes.Ldarg_1); + break; + case 2: + il.Emit(OpCodes.Ldarg_2); + break; + case 3: + il.Emit(OpCodes.Ldarg_3); + break; + default: + if (arg <= byte.MaxValue) + il.Emit(OpCodes.Ldarg_S, (byte)arg); + else + il.Emit(OpCodes.Ldarg, (short)arg); + break; + } + return il; + } + + public static ILGenerator Ldc_I4(this ILGenerator il, int arg) + { + Contracts.AssertValue(il); + + switch (arg) + { + case -1: + il.Emit(OpCodes.Ldc_I4_M1); + break; + case 0: + il.Emit(OpCodes.Ldc_I4_0); + break; + case 1: + il.Emit(OpCodes.Ldc_I4_1); + break; + case 2: + il.Emit(OpCodes.Ldc_I4_2); + break; + case 3: + il.Emit(OpCodes.Ldc_I4_3); + break; + case 4: + il.Emit(OpCodes.Ldc_I4_4); + break; + case 5: + il.Emit(OpCodes.Ldc_I4_5); + break; + case 6: + il.Emit(OpCodes.Ldc_I4_6); + break; + case 7: + il.Emit(OpCodes.Ldc_I4_7); + break; + case 8: + il.Emit(OpCodes.Ldc_I4_8); + break; + default: + // REVIEW: Docs say use ILGenerator.Emit(OpCode, byte) even though the value is signed + if (sbyte.MinValue <= arg && arg <= sbyte.MaxValue) + il.Emit(OpCodes.Ldc_I4_S, (byte)arg); + else + il.Emit(OpCodes.Ldc_I4, arg); + break; + } + return il; + } + + public static ILGenerator Ldc_I8(this ILGenerator il, long arg) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Ldc_I8, arg); + return il; + } + + public static ILGenerator Ldc_R4(this ILGenerator il, float arg) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Ldc_R4, arg); + return il; + } + + public static ILGenerator Ldc_R8(this ILGenerator il, double arg) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Ldc_R8, arg); + return il; + } + + public static ILGenerator Ldloc(this ILGenerator il, LocalBuilder builder) + { + Contracts.AssertValue(il); + Contracts.AssertValue(builder); + il.Emit(OpCodes.Ldloc, builder); + return il; + } + + public static ILGenerator Ldstr(this ILGenerator il, string str) + { + Contracts.AssertValue(il); + Contracts.AssertValue(str); + il.Emit(OpCodes.Ldstr, str); + return il; + } + + public static ILGenerator Mul(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Mul); + return il; + } + + public static ILGenerator Mul_Ovf(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Mul_Ovf); + return il; + } + + public static ILGenerator Neg(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Neg); + return il; + } + + public static ILGenerator Newarr(this ILGenerator il, Type type) + { + Contracts.AssertValue(il); + Contracts.AssertValue(type); + il.Emit(OpCodes.Newarr, type); + return il; + } + + public static ILGenerator Pop(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Pop); + return il; + } + + public static ILGenerator Rem(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Rem); + return il; + } + + public static ILGenerator Ret(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Ret); + return il; + } + + public static ILGenerator Stelem(this ILGenerator il, Type type) + { + Contracts.AssertValue(il); + Contracts.AssertValue(type); + il.Emit(OpCodes.Stelem, type); + return il; + } + + public static ILGenerator Stloc(this ILGenerator il, LocalBuilder builder) + { + Contracts.AssertValue(il); + Contracts.AssertValue(builder); + il.Emit(OpCodes.Stloc, builder); + return il; + } + + public static ILGenerator Sub(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Sub); + return il; + } + + public static ILGenerator Xor(this ILGenerator il) + { + Contracts.AssertValue(il); + il.Emit(OpCodes.Xor); + return il; + } + } +} +#pragma warning restore MSML_GeneralName \ No newline at end of file diff --git a/src/Microsoft.ML.Transforms/Expression/KeyWordTable.cs b/src/Microsoft.ML.Transforms/Expression/KeyWordTable.cs new file mode 100644 index 0000000000..822dbcd50d --- /dev/null +++ b/src/Microsoft.ML.Transforms/Expression/KeyWordTable.cs @@ -0,0 +1,109 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Microsoft.ML.Internal.Utilities; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.Transforms +{ + /// + /// Maps from normalized string to keyword token kind. A lexer must be provided with one of these. + /// + internal partial class KeyWordTable + { + public struct KeyWordKind + { + public readonly TokKind Kind; + public readonly bool IsContextKeyWord; + + public KeyWordKind(TokKind kind, bool isContextKeyWord) + { + Kind = kind; + IsContextKeyWord = isContextKeyWord; + } + } + + private readonly NormStr.Pool _pool; + private Dictionary _mpnstrtidWord; + private Dictionary _mpnstrtidPunc; + + public KeyWordTable(NormStr.Pool pool) + { + Contracts.AssertValue(pool); + + _pool = pool; + _mpnstrtidWord = new Dictionary(); + _mpnstrtidPunc = new Dictionary(); + } + + public void AddKeyWord(string str, TokKind tid) + { + Contracts.AssertNonEmpty(str); + _mpnstrtidWord.Add(_pool.Add(str), new KeyWordKind(tid, false)); + } + + public bool TryAddPunctuator(string str, TokKind tid) + { + Contracts.AssertNonEmpty(str); + + // Note: this assumes that once a prefix is found, that all shorter + // prefixes are mapped to something (TokKind.None to indicate that + // it is only a prefix and not itself a token). + + TokKind tidCur; + NormStr nstr = _pool.Add(str); + if (_mpnstrtidPunc.TryGetValue(_pool.Add(str), out tidCur)) + { + if (tidCur == tid) + return true; + if (tidCur != TokKind.None) + return false; + } + else + { + // Map all prefixes (that aren't already mapped) to TokKind.None. + for (int cch = str.Length; --cch > 0;) + { + NormStr nstrTmp = _pool.Add(str.Substring(0, cch)); + TokKind tidTmp; + if (_mpnstrtidPunc.TryGetValue(_pool.Add(nstrTmp.Value), out tidTmp)) + break; + _mpnstrtidPunc.Add(nstrTmp, TokKind.None); + } + } + _mpnstrtidPunc[nstr] = tid; + return true; + } + + public void AddPunctuator(string str, TokKind tid) + { + Contracts.AssertNonEmpty(str); + if (!TryAddPunctuator(str, tid)) + Contracts.Assert(false, "duplicate punctuator!"); + } + + public bool IsKeyWord(NormStr nstr, out KeyWordKind kind) + { + Contracts.Assert(!nstr.Value.IsEmpty); + return _mpnstrtidWord.TryGetValue(nstr, out kind); + } + + public bool IsPunctuator(NormStr nstr, out TokKind tid) + { + Contracts.Assert(!nstr.Value.IsEmpty); + return _mpnstrtidPunc.TryGetValue(nstr, out tid); + } + + public IEnumerable> Punctuators + { + get { return _mpnstrtidPunc; } + } + + public IEnumerable> KeyWords + { + get { return _mpnstrtidWord; } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.ML.Transforms/Expression/LambdaBinder.cs b/src/Microsoft.ML.Transforms/Expression/LambdaBinder.cs new file mode 100644 index 0000000000..8a756fec08 --- /dev/null +++ b/src/Microsoft.ML.Transforms/Expression/LambdaBinder.cs @@ -0,0 +1,1858 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Microsoft.ML.Data; +using Microsoft.ML.Internal.Utilities; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.Transforms +{ + using BL = System.Boolean; + using I4 = System.Int32; + using I8 = System.Int64; + using R4 = Single; + using R8 = Double; + using TX = ReadOnlyMemory; + + internal sealed partial class LambdaBinder : NodeVisitor + { + private readonly IHost _host; + // The stack of active with nodes. + private List _rgwith; + + private List _errors; + private LambdaNode _lambda; + + private readonly IFunctionProvider[] _providers; + private readonly Action _printError; + + private LambdaBinder(IHostEnvironment env, Action printError) + { + _host = env.Register("LambdaBinder"); + _printError = printError; + _rgwith = new List(); + _providers = env.ComponentCatalog.GetAllDerivedClasses(typeof(IFunctionProvider), typeof(SignatureFunctionProvider)) + .Select(info => info.CreateInstance(_host)) + .Prepend(BuiltinFunctions.Instance) + .ToArray(); + } + + /// + /// Run Lambda binder on LambdaNode and populate Expr values. + /// The errors contain list of user errors that occurred during binding. + /// The printError delegate is only used for reporting issues with function provider implementations, which are programmer errors. + /// In particular, it is NOT used to report user errors in the lambda expression. + /// + public static void Run(IHostEnvironment env, ref List errors, LambdaNode node, Action printError) + { + Contracts.AssertValue(env); + env.AssertValueOrNull(errors); + env.AssertValue(node); + env.AssertValue(printError); + + var binder = new LambdaBinder(env, printError); + binder._errors = errors; + node.Accept(binder); + env.Assert(binder._rgwith.Count == 0); + + var expr = node.Expr; + switch (expr.ExprType) + { + case ExprTypeKind.BL: + node.ResultType = BooleanDataViewType.Instance; + break; + case ExprTypeKind.I4: + node.ResultType = NumberDataViewType.Int32; + break; + case ExprTypeKind.I8: + node.ResultType = NumberDataViewType.Int64; + break; + case ExprTypeKind.R4: + node.ResultType = NumberDataViewType.Single; + break; + case ExprTypeKind.R8: + node.ResultType = NumberDataViewType.Double; + break; + case ExprTypeKind.TX: + node.ResultType = TextDataViewType.Instance; + break; + default: + if (!binder.HasErrors) + binder.PostError(expr, "Invalid result type"); + break; + } + + errors = binder._errors; + } + + private bool HasErrors + { + get { return Utils.Size(_errors) > 0; } + } + + private void PostError(Node node, string msg) + { + Utils.Add(ref _errors, new Error(node.Token, msg)); + } + + private void PostError(Node node, string msg, params object[] args) + { + Utils.Add(ref _errors, new Error(node.Token, string.Format(msg, args))); + } + + public override void Visit(BoolLitNode node) + { + _host.AssertValue(node); + _host.Assert(node.IsBool); + _host.AssertValue(node.ExprValue); + } + + public override void Visit(StrLitNode node) + { + _host.AssertValue(node); + _host.Assert(node.IsTX); + _host.AssertValue(node.ExprValue); + } + + public override void Visit(NumLitNode node) + { + _host.AssertValue(node); + _host.Assert(node.IsNumber || node.IsError); + _host.Assert((node.ExprValue == null) == node.IsError); + + if (node.IsError) + PostError(node, "Overflow"); + } + + public override void Visit(NameNode node) + { + } + + public override void Visit(IdentNode node) + { + _host.AssertValue(node); + + // If the IdentNode didn't actually have an IdentToken, just bag out. + if (node.IsMissing) + { + _host.Assert(HasErrors); + node.SetType(ExprTypeKind.Error); + return; + } + + // Look for "with" locals. + string name = node.Value; + for (int i = _rgwith.Count; --i >= 0;) + { + var with = _rgwith[i]; + if (name == with.Local.Name) + { + node.Referent = with.Local; + node.SetValue(with.Local.Value); + // REVIEW: Note that some uses might get pruned, but this gives us + // an upper bound on the time of places in the code where this value is needed. + with.Local.UseCount++; + return; + } + } + + // Look for parameters. + ParamNode param; + if (_lambda != null && (param = _lambda.FindParam(node.Value)) != null) + { + node.Referent = param; + node.SetType(param.ExprType); + return; + } + + PostError(node, "Unresolved identifier '{0}'", node.Value); + node.SetType(ExprTypeKind.Error); + } + + public override void Visit(ParamNode node) + { + _host.AssertValue(node); + _host.Assert(node.ExprType != 0); + } + + public override bool PreVisit(LambdaNode node) + { + _host.AssertValue(node); + _host.Assert(_lambda == null, "Can't support nested lambdas"); + + _lambda = node; + + node.Expr.Accept(this); + + _host.Assert(_lambda == node); + _lambda = null; + + return false; + } + + public override void PostVisit(LambdaNode node) + { + _host.Assert(false); + } + + private string GetStr(ExprTypeKind kind) + { + switch (kind) + { + case ExprTypeKind.BL: + return "boolean"; + case ExprTypeKind.R4: + case ExprTypeKind.R8: + return "numeric"; + case ExprTypeKind.I4: + case ExprTypeKind.I8: + return "integer"; + case ExprTypeKind.TX: + return "text"; + } + + return null; + } + + private void BadNum(ExprNode arg) + { + if (!arg.IsError) + PostError(arg, "Invalid numeric operand"); + _host.Assert(HasErrors); + } + + private void BadNum(ExprNode node, ExprNode arg) + { + BadNum(arg); + _host.Assert(HasErrors); + node.SetType(ExprTypeKind.Error); + } + + private void BadText(ExprNode arg) + { + if (!arg.IsError) + PostError(arg, "Invalid text operand"); + _host.Assert(HasErrors); + } + + private void BadArg(ExprNode arg, ExprTypeKind kind) + { + if (!arg.IsError) + { + var str = GetStr(kind); + if (str != null) + PostError(arg, "Invalid {0} operand", str); + else + PostError(arg, "Invalid operand"); + } + _host.Assert(HasErrors); + } + + public override void PostVisit(UnaryOpNode node) + { + _host.AssertValue(node); + var arg = node.Arg; + switch (node.Op) + { + case UnaryOp.Minus: + switch (arg.ExprType) + { + default: + BadNum(node, arg); + break; + case ExprTypeKind.I4: + node.SetValue(-(I4?)arg.ExprValue); + break; + case ExprTypeKind.I8: + node.SetValue(-(I8?)arg.ExprValue); + break; + case ExprTypeKind.R4: + node.SetValue(-(R4?)arg.ExprValue); + break; + case ExprTypeKind.R8: + node.SetValue(-(R8?)arg.ExprValue); + break; + } + break; + + case UnaryOp.Not: + BL? bl = GetBoolOp(node.Arg); + if (bl != null) + node.SetValue(!bl.Value); + else + node.SetValue(bl); + break; + + default: + _host.Assert(false); + PostError(node, "Unknown unary operator"); + node.SetType(ExprTypeKind.Error); + break; + } + } + + private BL? GetBoolOp(ExprNode arg) + { + _host.AssertValue(arg); + if (arg.IsBool) + return (BL?)arg.ExprValue; + BadArg(arg, ExprTypeKind.BL); + return null; + } + + public override void PostVisit(BinaryOpNode node) + { + _host.AssertValue(node); + + // REVIEW: We should really use the standard function overload resolution + // mechanism that CallNode binding uses. That would ensure that our type promotion + // and resolution mechanisms are consistent. + switch (node.Op) + { + case BinaryOp.Coalesce: + if (!node.Left.IsRx) + { + BadArg(node, node.Left.ExprType); + node.SetType(ExprTypeKind.Error); + } + else // Default to numeric. + ApplyNumericBinOp(node); + break; + + case BinaryOp.Or: + case BinaryOp.And: + ApplyBoolBinOp(node); + break; + + case BinaryOp.Add: + case BinaryOp.Sub: + case BinaryOp.Mul: + case BinaryOp.Div: + case BinaryOp.Mod: + case BinaryOp.Power: + ApplyNumericBinOp(node); + break; + + case BinaryOp.Error: + _host.Assert(HasErrors); + node.SetType(ExprTypeKind.Error); + break; + + default: + _host.Assert(false); + PostError(node, "Unknown binary operator"); + node.SetType(ExprTypeKind.Error); + break; + } + } + + private void ApplyBoolBinOp(BinaryOpNode node) + { + _host.AssertValue(node); + _host.Assert(node.Op == BinaryOp.And || node.Op == BinaryOp.Or || node.Op == BinaryOp.Coalesce); + + node.SetType(ExprTypeKind.BL); + + BL? v1 = GetBoolOp(node.Left); + BL? v2 = GetBoolOp(node.Right); + switch (node.Op) + { + case BinaryOp.Or: + if (v1 != null && v2 != null) + node.SetValue(v1.Value | v2.Value); + else if (v1 != null && v1.Value || v2 != null && v2.Value) + node.SetValue(true); + else if (v1 != null && !v1.Value) + node.ReduceToRight = true; + else if (v2 != null && !v2.Value) + node.ReduceToLeft = true; + break; + + case BinaryOp.And: + if (v1 != null && v2 != null) + node.SetValue(v1.Value & v2.Value); + else if (v1 != null && !v1.Value || v2 != null && !v2.Value) + node.SetValue(false); + else if (v1 != null && v1.Value) + node.ReduceToRight = true; + else if (v2 != null && v2.Value) + node.ReduceToLeft = true; + break; + + case BinaryOp.Coalesce: + if (v1 != null) + node.SetValue(v1); + break; + } + + _host.Assert(node.IsBool); + } + + /// + /// Reconcile the types of the two ExprNodes. Favor numeric types in cases + /// where the types can't be reconciled. This does not guarantee that + /// the resulting kind is numeric, eg, if both a and b are of type Text, it + /// simply sets kind to Text. + /// + private void ReconcileNumericTypes(ExprNode a, ExprNode b, out ExprTypeKind kind) + { + _host.AssertValue(a); + _host.AssertValue(b); + + // REVIEW: Consider converting I4 + R4 to R8, unless the I4 + // is a constant known to not lose precision when converted to R4. + if (!CanPromote(false, a.ExprType, b.ExprType, out kind)) + { + // If either is numeric, use that numeric type. + if (a.IsNumber) + kind = a.ExprType; + else if (b.IsNumber) + kind = b.ExprType; + else // Default to Float (for error reporting). + kind = ExprTypeKind.Float; + _host.Assert(MapKindToIndex(kind) >= 0); + } + } + + private void ApplyNumericBinOp(BinaryOpNode node) + { + _host.AssertValue(node); + + var left = node.Left; + var right = node.Right; + ExprTypeKind kind; + ReconcileNumericTypes(left, right, out kind); + + // REVIEW: Should we prohibit constant evaluations that produce NA? + switch (kind) + { + default: + // Default to Float (for error reporting). + goto case ExprTypeKind.Float; + + case ExprTypeKind.I4: + { + node.SetType(ExprTypeKind.I4); + I4? v1; + I4? v2; + // Boiler plate below here... + bool f1 = left.TryGet(out v1); + bool f2 = right.TryGet(out v2); + if (!f1) + BadNum(left); + else if (!f2) + BadNum(right); + else + ReduceBinOp(node, v1, v2); + } + break; + case ExprTypeKind.I8: + { + node.SetType(ExprTypeKind.I8); + I8? v1; + I8? v2; + // Boiler plate below here... + bool f1 = left.TryGet(out v1); + bool f2 = right.TryGet(out v2); + if (!f1) + BadNum(left); + else if (!f2) + BadNum(right); + else + ReduceBinOp(node, v1, v2); + } + break; + case ExprTypeKind.R4: + { + node.SetType(ExprTypeKind.R4); + R4? v1; + R4? v2; + // Boiler plate below here... + bool f1 = left.TryGet(out v1); + bool f2 = right.TryGet(out v2); + if (!f1) + BadNum(left); + else if (!f2) + BadNum(right); + else + ReduceBinOp(node, v1, v2); + } + break; + case ExprTypeKind.R8: + { + node.SetType(ExprTypeKind.R8); + R8? v1; + R8? v2; + // Boiler plate below here... + bool f1 = left.TryGet(out v1); + bool f2 = right.TryGet(out v2); + if (!f1) + BadNum(left); + else if (!f2) + BadNum(right); + else + ReduceBinOp(node, v1, v2); + } + break; + } + } + + #region ReduceBinOp + + // The I4 and I8 methods are identical, as are the R4 and R8 methods. + private void ReduceBinOp(BinaryOpNode node, I4? a, I4? b) + { + if (a != null && b != null) + node.SetValue(BinOp(node, a.Value, b.Value)); + else if (a != null) + { + // Special reductions when only the left value is known. + var v = a.Value; + switch (node.Op) + { + case BinaryOp.Add: + if (v == 0) + node.ReduceToRight = true; + break; + case BinaryOp.Mul: + if (v == 1) + node.ReduceToRight = true; + break; + } + } + else if (b != null) + { + // Special reductions when only the right value is known. + var v = b.Value; + switch (node.Op) + { + case BinaryOp.Add: + if (v == 0) + node.ReduceToLeft = true; + break; + case BinaryOp.Mul: + if (v == 1) + node.ReduceToLeft = true; + break; + } + } + } + + private void ReduceBinOp(BinaryOpNode node, I8? a, I8? b) + { + if (a != null && b != null) + node.SetValue(BinOp(node, a.Value, b.Value)); + else if (a != null) + { + // Special reductions when only the left value is known. + var v = a.Value; + switch (node.Op) + { + case BinaryOp.Add: + if (v == 0) + node.ReduceToRight = true; + break; + case BinaryOp.Mul: + if (v == 1) + node.ReduceToRight = true; + break; + } + } + else if (b != null) + { + // Special reductions when only the right value is known. + var v = b.Value; + switch (node.Op) + { + case BinaryOp.Add: + if (v == 0) + node.ReduceToLeft = true; + break; + case BinaryOp.Mul: + if (v == 1) + node.ReduceToLeft = true; + break; + } + } + } + + private void ReduceBinOp(BinaryOpNode node, R4? a, R4? b) + { + if (a != null && b != null) + node.SetValue(BinOp(node, a.Value, b.Value)); + else if (a != null) + { + // Special reductions when only the left value is known. + var v = a.Value; + switch (node.Op) + { + case BinaryOp.Coalesce: + if (!R4.IsNaN(v)) + node.SetValue(v); + else + node.ReduceToRight = true; + break; + case BinaryOp.Add: + if (R4.IsNaN(v)) + node.SetValue(v); + else if (v == 0) + node.ReduceToRight = true; + break; + case BinaryOp.Mul: + if (R4.IsNaN(v)) + node.SetValue(v); + else if (v == 1) + node.ReduceToRight = true; + break; + case BinaryOp.Sub: + case BinaryOp.Div: + case BinaryOp.Mod: + if (R4.IsNaN(v)) + node.SetValue(v); + break; + } + } + else if (b != null) + { + // Special reductions when only the right value is known. + var v = b.Value; + switch (node.Op) + { + case BinaryOp.Coalesce: + if (R4.IsNaN(v)) + node.ReduceToLeft = true; + break; + case BinaryOp.Add: + if (R4.IsNaN(v)) + node.SetValue(v); + else if (v == 0) + node.ReduceToLeft = true; + break; + case BinaryOp.Mul: + if (R4.IsNaN(v)) + node.SetValue(v); + else if (v == 1) + node.ReduceToLeft = true; + break; + case BinaryOp.Sub: + case BinaryOp.Div: + case BinaryOp.Mod: + if (R4.IsNaN(v)) + node.SetValue(v); + break; + } + } + } + + private void ReduceBinOp(BinaryOpNode node, R8? a, R8? b) + { + if (a != null && b != null) + node.SetValue(BinOp(node, a.Value, b.Value)); + else if (a != null) + { + // Special reductions when only the left value is known. + var v = a.Value; + switch (node.Op) + { + case BinaryOp.Coalesce: + if (!R8.IsNaN(v)) + node.SetValue(v); + else + node.ReduceToRight = true; + break; + case BinaryOp.Add: + if (R8.IsNaN(v)) + node.SetValue(v); + else if (v == 0) + node.ReduceToRight = true; + break; + case BinaryOp.Mul: + if (R8.IsNaN(v)) + node.SetValue(v); + else if (v == 1) + node.ReduceToRight = true; + break; + case BinaryOp.Sub: + case BinaryOp.Div: + case BinaryOp.Mod: + if (R8.IsNaN(v)) + node.SetValue(v); + break; + } + } + else if (b != null) + { + // Special reductions when only the right value is known. + var v = b.Value; + switch (node.Op) + { + case BinaryOp.Coalesce: + if (R8.IsNaN(v)) + node.ReduceToLeft = true; + break; + case BinaryOp.Add: + if (R8.IsNaN(v)) + node.SetValue(v); + else if (v == 0) + node.ReduceToLeft = true; + break; + case BinaryOp.Mul: + if (R8.IsNaN(v)) + node.SetValue(v); + else if (v == 1) + node.ReduceToLeft = true; + break; + case BinaryOp.Sub: + case BinaryOp.Div: + case BinaryOp.Mod: + if (R8.IsNaN(v)) + node.SetValue(v); + break; + } + } + } + + #endregion ReduceBinOp + + #region BinOp + + private I4 BinOp(BinaryOpNode node, I4 v1, I4 v2) + { + switch (node.Op) + { + case BinaryOp.Add: + return v1 + v2; + case BinaryOp.Sub: + return v1 - v2; + case BinaryOp.Mul: + return v1 * v2; + case BinaryOp.Div: + return v1 / v2; + case BinaryOp.Mod: + return v1 % v2; + case BinaryOp.Power: + return BuiltinFunctions.Pow(v1, v2); + default: + _host.Assert(false); + throw Contracts.Except(); + } + } + + private I8 BinOp(BinaryOpNode node, I8 v1, I8 v2) + { + switch (node.Op) + { + case BinaryOp.Add: + return v1 + v2; + case BinaryOp.Sub: + return v1 - v2; + case BinaryOp.Mul: + return v1 * v2; + case BinaryOp.Div: + return v1 / v2; + case BinaryOp.Mod: + return v1 % v2; + case BinaryOp.Power: + return BuiltinFunctions.Pow(v1, v2); + default: + _host.Assert(false); + throw Contracts.Except(); + } + } + + private R4 BinOp(BinaryOpNode node, R4 v1, R4 v2) + { + switch (node.Op) + { + case BinaryOp.Coalesce: + return !R4.IsNaN(v1) ? v1 : v2; + case BinaryOp.Add: + return v1 + v2; + case BinaryOp.Sub: + return v1 - v2; + case BinaryOp.Mul: + return v1 * v2; + case BinaryOp.Div: + return v1 / v2; + case BinaryOp.Mod: + return v1 % v2; + case BinaryOp.Power: + return BuiltinFunctions.Pow(v1, v2); + default: + _host.Assert(false); + return R4.NaN; + } + } + + private R8 BinOp(BinaryOpNode node, R8 v1, R8 v2) + { + switch (node.Op) + { + case BinaryOp.Coalesce: + return !R8.IsNaN(v1) ? v1 : v2; + case BinaryOp.Add: + return v1 + v2; + case BinaryOp.Sub: + return v1 - v2; + case BinaryOp.Mul: + return v1 * v2; + case BinaryOp.Div: + return v1 / v2; + case BinaryOp.Mod: + return v1 % v2; + case BinaryOp.Power: + return Math.Pow(v1, v2); + default: + _host.Assert(false); + return R8.NaN; + } + } + #endregion BinOp + + public override void PostVisit(ConditionalNode node) + { + _host.AssertValue(node); + + BL? cond = GetBoolOp(node.Cond); + + var left = node.Left; + var right = node.Right; + ExprTypeKind kind; + if (!CanPromote(false, left.ExprType, right.ExprType, out kind)) + { + // If either is numeric, use that numeric type. Otherwise, use the first + // that isn't error or none. + if (left.IsNumber) + kind = left.ExprType; + else if (right.IsNumber) + kind = right.ExprType; + else if (!left.IsError && !left.IsNone) + kind = left.ExprType; + else if (!right.IsError && !right.IsNone) + kind = right.ExprType; + else + kind = ExprTypeKind.None; + } + + switch (kind) + { + default: + PostError(node, "Invalid conditional expression"); + node.SetType(ExprTypeKind.Error); + break; + + case ExprTypeKind.BL: + { + node.SetType(ExprTypeKind.BL); + BL? v1 = GetBoolOp(node.Left); + BL? v2 = GetBoolOp(node.Right); + if (cond != null) + { + if (cond.Value) + node.SetValue(v1); + else + node.SetValue(v2); + } + } + break; + case ExprTypeKind.I4: + { + node.SetType(ExprTypeKind.I4); + I4? v1; + I4? v2; + bool f1 = left.TryGet(out v1); + bool f2 = right.TryGet(out v2); + if (!f1) + BadNum(left); + if (!f2) + BadNum(right); + if (cond != null) + { + if (cond.Value) + node.SetValue(v1); + else + node.SetValue(v2); + } + } + break; + case ExprTypeKind.I8: + { + node.SetType(ExprTypeKind.I8); + I8? v1; + I8? v2; + bool f1 = left.TryGet(out v1); + bool f2 = right.TryGet(out v2); + if (!f1) + BadNum(left); + if (!f2) + BadNum(right); + if (cond != null) + { + if (cond.Value) + node.SetValue(v1); + else + node.SetValue(v2); + } + } + break; + case ExprTypeKind.R4: + { + node.SetType(ExprTypeKind.R4); + R4? v1; + R4? v2; + bool f1 = left.TryGet(out v1); + bool f2 = right.TryGet(out v2); + if (!f1) + BadNum(left); + if (!f2) + BadNum(right); + if (cond != null) + { + if (cond.Value) + node.SetValue(v1); + else + node.SetValue(v2); + } + } + break; + case ExprTypeKind.R8: + { + node.SetType(ExprTypeKind.R8); + R8? v1; + R8? v2; + bool f1 = left.TryGet(out v1); + bool f2 = right.TryGet(out v2); + if (!f1) + BadNum(left); + if (!f2) + BadNum(right); + if (cond != null) + { + if (cond.Value) + node.SetValue(v1); + else + node.SetValue(v2); + } + } + break; + case ExprTypeKind.TX: + { + node.SetType(ExprTypeKind.TX); + TX? v1; + TX? v2; + bool f1 = left.TryGet(out v1); + bool f2 = right.TryGet(out v2); + if (!f1) + BadText(left); + if (!f2) + BadText(right); + if (cond != null) + { + if (cond.Value) + node.SetValue(v1); + else + node.SetValue(v2); + } + } + break; + } + } + + public override void PostVisit(CompareNode node) + { + _host.AssertValue(node); + + TokKind tidLax = node.TidLax; + TokKind tidStrict = node.TidStrict; + ExprTypeKind kind = ExprTypeKind.None; + + // First validate the types. + ExprNode arg; + bool hasErrors = false; + var items = node.Operands.Items; + for (int i = 0; i < items.Length; i++) + { + arg = items[i].AsExpr; + if (!ValidateType(arg, ref kind)) + { + BadArg(arg, kind); + hasErrors = true; + } + } + + // Set the arg type and the type of this node. + node.ArgTypeKind = kind; + node.SetType(ExprTypeKind.BL); + + if (hasErrors) + { + _host.Assert(HasErrors); + return; + } + + // Find the number of initial constant inputs in "lim" and convert the args to "kind". + int lim = items.Length; + int count = lim; + for (int i = 0; i < count; i++) + { + arg = items[i].AsExpr; + arg.Convert(kind); + if (i < lim && arg.ExprValue == null) + lim = i; + } + + // Now try to compute the value. + int ifn = (int)kind; + if (ifn >= _fnEqual.Length || ifn < 0) + { + _host.Assert(false); + PostError(node, "Internal error in CompareNode"); + return; + } + + Cmp cmpLax; + Cmp cmpStrict; + switch (node.Op) + { + case CompareOp.DecrChain: + cmpLax = _fnGreaterEqual[ifn]; + cmpStrict = _fnGreater[ifn]; + break; + case CompareOp.IncrChain: + cmpLax = _fnLessEqual[ifn]; + cmpStrict = _fnLess[ifn]; + break; + case CompareOp.Equal: + cmpLax = _fnEqual[ifn]; + cmpStrict = cmpLax; + break; + case CompareOp.NotEqual: + cmpLax = _fnNotEqual[ifn]; + cmpStrict = cmpLax; + break; + default: + _host.Assert(false); + return; + } + + _host.Assert((cmpLax == null) == (cmpStrict == null)); + if (cmpLax == null) + { + PostError(node, "Bad operands for comparison"); + return; + } + + // If one of the first two operands is NA, the result is NA, even if the other operand + // is not a constant. + object value; + if (lim < 2 && (value = items[1 - lim].AsExpr.ExprValue) != null && !cmpLax(value, value).HasValue) + { + node.SetValue(default(BL?)); + return; + } + + // See if we can reduce to a constant BL value. + if (lim >= 2) + { + if (node.Op != CompareOp.NotEqual) + { + // Note: this loop doesn't work for != when there are more than two operands, + // so != is handled separately below. + bool isStrict = false; + arg = items[0].AsExpr; + _host.Assert(arg.ExprType == kind); + var valuePrev = arg.ExprValue; + _host.Assert(valuePrev != null); + for (int i = 1; i < lim; i++) + { + TokKind tid = node.Operands.Delimiters[i - 1].Kind; + _host.Assert(tid == tidLax || tid == tidStrict); + + if (tid == tidStrict) + isStrict = true; + + arg = items[i].AsExpr; + _host.Assert(arg.ExprType == kind); + + value = arg.ExprValue; + _host.Assert(value != null); + BL? res = isStrict ? cmpStrict(valuePrev, value) : cmpLax(valuePrev, value); + if (res == null || !res.Value) + { + node.SetValue(false); + return; + } + valuePrev = value; + isStrict = false; + } + } + else + { + // NotEqual is special - it means that the values are all distinct, so comparing adjacent + // items is not enough. + for (int i = 1; i < lim; i++) + { + arg = items[i].AsExpr; + _host.Assert(arg.ExprType == kind); + + value = arg.ExprValue; + _host.Assert(value != null); + for (int j = 0; j < i; j++) + { + var arg2 = items[j].AsExpr; + _host.Assert(arg2.ExprType == kind); + + var value2 = arg2.ExprValue; + _host.Assert(value2 != null); + BL? res = cmpStrict(value2, value); + if (res == null || !res.Value) + { + node.SetValue(res); + return; + } + } + } + } + + if (lim == count) + node.SetValue(true); + } + } + + private sealed class Candidate + { + public readonly IFunctionProvider Provider; + public readonly MethodInfo Method; + public readonly ExprTypeKind[] Kinds; + public readonly ExprTypeKind ReturnKind; + public readonly bool IsVariable; + + public bool MatchesArity(int arity) + { + if (!IsVariable) + return arity == Kinds.Length; + Contracts.Assert(Kinds.Length > 0); + return arity >= Kinds.Length - 1; + } + + public int Arity + { + get { return Kinds.Length; } + } + + public bool IsIdentity + { + get { return Method.ReturnType == typeof(void); } + } + + public static bool TryGetCandidate(CallNode node, IFunctionProvider provider, MethodInfo meth, Action printError, out Candidate cand) + { + cand = default(Candidate); + if (meth == null) + return false; + + // An "identity" function has one parameter and returns void. + var ps = meth.GetParameters(); + bool isIdent = ps.Length == 1 && meth.ReturnType == typeof(void); + + if (!meth.IsStatic || !meth.IsPublic && !isIdent) + { + // This is an error in the extension functions, not in the user code. + printError(string.Format( + "Error in ExprTransform: Function '{0}' in namespace '{1}' must be static and public", + node.Head.Value, provider.NameSpace)); + return false; + } + + // Verify the parameter types. + bool isVar = false; + var kinds = new ExprTypeKind[ps.Length]; + for (int i = 0; i < ps.Length; i++) + { + var type = ps[i].ParameterType; + if (i == ps.Length - 1 && !isIdent && type.IsArray) + { + // Last parameter is variable. + isVar = true; + type = type.GetElementType(); + } + var extCur = ExprNode.ToExprTypeKind(type); + if (extCur <= ExprTypeKind.Error || extCur >= ExprTypeKind._Lim) + { + printError(string.Format( + "Error in ExprTransform: Function '{0}' in namespace '{1}' has invalid parameter type '{2}'", + node.Head.Value, provider.NameSpace, type)); + return false; + } + kinds[i] = extCur; + } + + // Verify the return type. + ExprTypeKind kindRet; + if (isIdent) + { + Contracts.Assert(kinds.Length == 1); + kindRet = kinds[0]; + } + else + { + var extRet = ExprNode.ToExprTypeKind(meth.ReturnType); + kindRet = extRet; + if (kindRet <= ExprTypeKind.Error || kindRet >= ExprTypeKind._Lim) + { + printError(string.Format( + "Error in ExprTransform: Function '{0}' in namespace '{1}' has invalid return type '{2}'", + node.Head.Value, provider.NameSpace, meth.ReturnType)); + return false; + } + } + + cand = new Candidate(provider, meth, kinds, kindRet, isVar); + return true; + } + + private Candidate(IFunctionProvider provider, MethodInfo meth, ExprTypeKind[] kinds, ExprTypeKind kindRet, bool isVar) + { + Contracts.AssertValue(provider); + Contracts.AssertValue(meth); + Contracts.AssertValue(kinds); + Provider = provider; + Method = meth; + Kinds = kinds; + ReturnKind = kindRet; + IsVariable = isVar; + } + + /// + /// Returns whether this candidate is applicable to the given argument types. + /// + public bool IsApplicable(ExprTypeKind[] kinds, out int bad) + { + Contracts.Assert(kinds.Length == Kinds.Length || IsVariable && kinds.Length >= Kinds.Length - 1); + + bad = 0; + int head = IsVariable ? Kinds.Length - 1 : Kinds.Length; + + for (int i = 0; i < head; i++) + { + if (!CanConvert(kinds[i], Kinds[i])) + bad++; + } + + if (IsVariable) + { + // Handle the tail. + var kind = Kinds[Kinds.Length - 1]; + for (int i = head; i < kinds.Length; i++) + { + if (!CanConvert(kinds[i], kind)) + bad++; + } + } + + return bad == 0; + } + + /// + /// Returns -1 if 'this' is better than 'other', 0 if they are the same, +1 otherwise. + /// Non-variable is always better than variable. When both are variable, longer prefix is + /// better than shorter prefix. + /// + public int CompareSignatures(Candidate other) + { + Contracts.AssertValue(other); + + if (IsVariable) + { + if (!other.IsVariable) + return +1; + if (Kinds.Length != other.Kinds.Length) + return Kinds.Length > other.Kinds.Length ? -1 : +1; + } + else if (other.IsVariable) + return -1; + + int cmp = 0; + for (int k = 0; k < Kinds.Length; k++) + { + var t1 = Kinds[k]; + var t2 = other.Kinds[k]; + if (t1 == t2) + continue; + if (!CanConvert(t1, t2)) + return +1; + cmp = -1; + } + return cmp; + } + } + + public override void PostVisit(CallNode node) + { + _host.AssertValue(node); + + // Get the argument types and number of arguments. + var kinds = node.Args.Items.Select(item => item.AsExpr.ExprType).ToArray(); + var arity = kinds.Length; + + // Find the candidates. + bool hasGoodArity = false; + var candidates = new List(); + foreach (var prov in _providers) + { + if (node.NameSpace != null && prov.NameSpace != node.NameSpace.Value) + continue; + + var meths = prov.Lookup(node.Head.Value); + if (Utils.Size(meths) == 0) + continue; + + foreach (var meth in meths) + { + Candidate cand; + if (!Candidate.TryGetCandidate(node, prov, meth, _printError, out cand)) + continue; + + bool good = cand.MatchesArity(arity); + if (hasGoodArity) + { + // We've seen one or more with good arity, so ignore wrong arity. + if (!good) + continue; + } + else if (good) + { + // This is the first one with good arity. + candidates.Clear(); + hasGoodArity = true; + } + + candidates.Add(cand); + } + } + + if (candidates.Count == 0) + { + // Unknown function. + PostError(node.Head, "Unknown function"); + node.SetType(ExprTypeKind.Error); + return; + } + + if (!hasGoodArity) + { + // No overloads have the target arity. Generate an appropriate error. + // REVIEW: Will this be good enough with variable arity functions? + var arities = candidates.Select(c => c.Arity).Distinct().OrderBy(x => x).ToArray(); + if (arities.Length == 1) + { + if (arities[0] == 1) + PostError(node, "Expected one argument to function '{1}'", arities[0], node.Head.Value); + else + PostError(node, "Expected {0} arguments to function '{1}'", arities[0], node.Head.Value); + } + else if (arities.Length == 2) + PostError(node, "Expected {0} or {1} arguments to function '{2}'", arities[0], arities[1], node.Head.Value); + else + PostError(node, "No overload of function '{0}' takes {1} arguments", node.Head.Value, arity); + + // Set the type of the node. If there is only one possible type, use that, otherwise, use Error. + var kindsRet = candidates.Select(c => c.ReturnKind).Distinct().ToArray(); + if (kindsRet.Length == 1) + node.SetType(kindsRet[0]); + else + node.SetType(ExprTypeKind.Error); + return; + } + + // Count applicable candidates and move them to the front. + int count = 0; + int minBad = int.MaxValue; + int icandMinBad = -1; + for (int i = 0; i < candidates.Count; i++) + { + var cand = candidates[i]; + int bad; + if (cand.IsApplicable(kinds, out bad)) + candidates[count++] = cand; + else if (bad < minBad) + { + minBad = bad; + icandMinBad = i; + } + } + if (0 < count && count < candidates.Count) + candidates.RemoveRange(count, candidates.Count - count); + _host.Assert(candidates.Count > 0); + _host.Assert(count == 0 || count == candidates.Count); + + // When there are multiple, GetBestOverload picks the one to use and emits an + // error message if there isn't a unique best answer. + Candidate best; + if (count > 1) + best = GetBestOverload(node, candidates); + else if (count == 1) + best = candidates[0]; + else + { + _host.Assert(0 <= icandMinBad & icandMinBad < candidates.Count); + best = candidates[icandMinBad]; + PostError(node, "The best overload of '{0}' has some invalid arguments", node.Head.Value); + } + + // First convert the arguments to the proper types and get any constant values. + var args = new object[node.Args.Items.Length]; + bool all = true; + // For variable, limit the index into best.Kinds to ivMax. + int ivMax = best.Kinds.Length - 1; + for (int i = 0; i < node.Args.Items.Length; i++) + { + args[i] = Convert(node.Args.Items[i].AsExpr, best.Kinds[Math.Min(i, ivMax)]); + all &= args[i] != null; + } + + object res; + if (best.IsIdentity) + { + _host.Assert(!best.IsVariable); + _host.Assert(best.Arity == 1); + res = args[0]; + } + else if (!all) + { + res = best.Provider.ResolveToConstant(node.Head.Value, best.Method, args); + if (res != null && res.GetType() != best.Method.ReturnType) + { + _printError(string.Format( + "Error in ExprTransform: Function '{0}' in namespace '{1}' produced wrong constant value type '{2}' vs '{3}'", + node.Head.Value, best.Provider.NameSpace, res.GetType(), best.Method.ReturnType)); + res = null; + } + } + else + { + if (best.IsVariable) + { + int head = best.Kinds.Length - 1; + int tail = args.Length - head; + _host.Assert(tail >= 0); + var type = best.Method.GetParameters()[ivMax].ParameterType; + _host.Assert(type.IsArray); + type = type.GetElementType(); + Array rest = Array.CreateInstance(type, tail); + for (int i = 0; i < tail; i++) + rest.SetValue(args[head + i], i); + Array.Resize(ref args, head + 1); + args[head] = rest; + } + + res = best.Method.Invoke(null, args); + _host.Assert(res != null); + _host.Assert(res.GetType() == best.Method.ReturnType); + } + + node.SetType(best.ReturnKind, res); + node.SetMethod(best.Method); + } + + /// + /// Returns whether the given source type can be converted to the given destination type, + /// for the purposes of function invocation. Returns true if src is null and dst is any + /// valid type. + /// + private static bool CanConvert(ExprTypeKind src, ExprTypeKind dst) + { + // src can be Error, but dst should not be. + Contracts.Assert(ExprTypeKind.Error <= src & src < ExprTypeKind._Lim); + Contracts.Assert(ExprTypeKind.Error < dst & dst < ExprTypeKind._Lim); + + if (src == ExprTypeKind.Error) + return true; + + if (src == dst) + return true; + if (src == ExprTypeKind.I4) + return dst == ExprTypeKind.I8 || dst == ExprTypeKind.R4 || dst == ExprTypeKind.R8; + if (src == ExprTypeKind.I8) + return dst == ExprTypeKind.R8; + if (src == ExprTypeKind.R4) + return dst == ExprTypeKind.R8; + return false; + } + + /// + /// Convert the given ExprNode to the given type and get its value, when constant. + /// + private object Convert(ExprNode expr, ExprTypeKind kind) + { + switch (kind) + { + case ExprTypeKind.BL: + { + BL? val; + if (!expr.TryGet(out val)) + BadArg(expr, ExprTypeKind.BL); + return val; + } + case ExprTypeKind.I4: + { + I4? val; + if (!expr.TryGet(out val)) + BadArg(expr, ExprTypeKind.I4); + return val; + } + case ExprTypeKind.I8: + { + I8? val; + if (!expr.TryGet(out val)) + BadArg(expr, ExprTypeKind.I8); + return val; + } + case ExprTypeKind.R4: + { + R4? val; + if (!expr.TryGet(out val)) + BadArg(expr, ExprTypeKind.R4); + return val; + } + case ExprTypeKind.R8: + { + R8? val; + if (!expr.TryGet(out val)) + BadArg(expr, ExprTypeKind.R8); + return val; + } + case ExprTypeKind.TX: + { + TX? val; + if (!expr.TryGet(out val)) + BadArg(expr, ExprTypeKind.TX); + return val; + } + default: + _host.Assert(false, "Unexpected type in Convert"); + PostError(expr, "Internal error in Convert"); + return null; + } + } + + /// + /// Multiple applicable candidates; pick the best one. We use a simplification of + /// C#'s rules, only considering the types TX, BL, I4, I8, R4, R8. Basically, parameter + /// type X is better than parameter type Y if X can be converted to Y. The conversions are: + /// I4 => I8, I4 => R4, I4 => R8, I8 => R8, R4 => R8. + /// + private Candidate GetBestOverload(CallNode node, List candidates) + { + _host.Assert(Utils.Size(candidates) >= 2); + + var dup1 = default(Candidate); + var dup2 = default(Candidate); + for (int i = 0; i < candidates.Count; i++) + { + var c1 = candidates[i]; + int dup = -1; + for (int j = 0; ; j++) + { + if (j == i) + continue; + + if (j >= candidates.Count) + { + if (dup < 0) + return c1; + if (dup1 == null) + { + dup1 = c1; + dup2 = candidates[dup]; + } + break; + } + + int cmp = c1.CompareSignatures(candidates[j]); + + // Break if c1 isn't better. + if (cmp > 0) + break; + if (cmp == 0) + dup = j; + } + } + + _host.Assert((dup1 != null) == (dup2 != null)); + if (dup1 != null) + { + if (dup1.Provider.NameSpace.CompareTo(dup2.Provider.NameSpace) > 0) + Utils.Swap(ref dup1, ref dup2); + PostError(node, "Duplicate candidate functions in namespaces '{0}' and '{1}'", + dup1.Provider.NameSpace, dup2.Provider.NameSpace); + } + else + PostError(node, "Ambiguous invocation of function '{0}'", node.Head.Value); + + return dup1 ?? candidates[0]; + } + + public override void PostVisit(ListNode node) + { + _host.AssertValue(node); + } + + public override bool PreVisit(WithNode node) + { + _host.AssertValue(node); + + // First bind the value expressions. + node.Local.Accept(this); + + // Push the with. + int iwith = _rgwith.Count; + _rgwith.Add(node); + + // Bind the body. + node.Body.Accept(this); + + // Pop the var context. + _host.Assert(_rgwith.Count == iwith + 1); + _host.Assert(_rgwith[iwith] == node); + _rgwith.RemoveAt(iwith); + _host.Assert(_rgwith.Count == iwith); + + node.SetValue(node.Body); + + return false; + } + + public override void PostVisit(WithNode node) + { + _host.Assert(false); + } + + public override void PostVisit(WithLocalNode node) + { + _host.AssertValue(node); + } + + // This aggregates the type of expr into itemKind. It returns false + // if an error condition is encountered. This takes into account + // possible conversions. + private bool ValidateType(ExprNode expr, ref ExprTypeKind itemKind) + { + _host.AssertValue(expr); + _host.Assert(expr.ExprType != 0); + + ExprTypeKind kind = expr.ExprType; + switch (kind) + { + case ExprTypeKind.Error: + _host.Assert(HasErrors); + return false; + case ExprTypeKind.None: + return false; + } + + if (kind == itemKind) + return true; + + switch (itemKind) + { + case ExprTypeKind.Error: + // This is the first non-error item type we've seen. + _host.Assert(HasErrors); + itemKind = kind; + return true; + case ExprTypeKind.None: + // This is the first non-error item type we've seen. + itemKind = kind; + return true; + } + + ExprTypeKind kindNew; + if (!CanPromote(true, kind, itemKind, out kindNew)) + return false; + + itemKind = kindNew; + return true; + } + + internal static bool CanPromote(bool precise, ExprTypeKind k1, ExprTypeKind k2, out ExprTypeKind res) + { + if (k1 == k2) + { + res = k1; + if (res != ExprTypeKind.Error && res != ExprTypeKind.None) + return true; + res = ExprTypeKind.Error; + return false; + } + + // Encode numeric types in a two-bit value. + int i1 = MapKindToIndex(k1); + int i2 = MapKindToIndex(k2); + if (i1 < 0 || i2 < 0) + { + res = ExprTypeKind.Error; + return false; + } + + Contracts.Assert(0 <= i1 & i1 < 4); + Contracts.Assert(0 <= i2 & i2 < 4); + Contracts.Assert(i1 != i2); + + // Combine the two two-bit values. + int index = i1 | (i2 << 2); + Contracts.Assert(0 <= index & index < 16); + switch (index) + { + // Only integer types -> I8 + case 0x1: + case 0x4: + res = ExprTypeKind.I8; + return true; + + // R4 and I4 -> R8 for precise and R4 otherwise. + case 0x2: + case 0x8: + res = precise ? ExprTypeKind.R8 : ExprTypeKind.R4; + return true; + + // At least one RX type and at least one 8-byte type -> R8 + case 0x3: + case 0x6: + case 0x7: + case 0x9: + case 0xB: + case 0xC: + case 0xD: + case 0xE: + res = ExprTypeKind.R8; + return true; + + default: + Contracts.Assert(false); + res = ExprTypeKind.Error; + return false; + } + } + + /// + /// Maps numeric type kinds to an index 0,1,2,3. All others map to -1. + /// + private static int MapKindToIndex(ExprTypeKind kind) + { + switch (kind) + { + case ExprTypeKind.I4: + return 0; + case ExprTypeKind.I8: + return 1; + case ExprTypeKind.R4: + return 2; + case ExprTypeKind.R8: + return 3; + } + return -1; + } + } + + internal sealed partial class LambdaBinder : NodeVisitor + { + // This partial contains stuff needed for equality and ordered comparison. + private static T Cast(object a) + { + Contracts.Assert(a is T); + return (T)a; + } + + private delegate BL? Cmp(object a, object b); + + // Indexed by ExprTypeKind. + private static readonly Cmp[] _fnEqual = new Cmp[(int)ExprTypeKind._Lim] + { + // None, Error + null, null, + + (a,b) => Cast(a) == Cast(b), + (a,b) => Cast(a) == Cast(b), + (a,b) => Cast(a) == Cast(b), + (a,b) => { var x = Cast(a); var y = Cast(b); if (x == y) return true; if (!R4.IsNaN(x) && !R4.IsNaN(y)) return false; return null; }, + (a,b) => { var x = Cast(a); var y = Cast(b); if (x == y) return true; if (!R8.IsNaN(x) && !R8.IsNaN(y)) return false; return null; }, + (a,b) => Cast(a).Span.SequenceEqual(Cast(b).Span), + }; + + // Indexed by ExprTypeKind. + private static readonly Cmp[] _fnNotEqual = new Cmp[(int)ExprTypeKind._Lim] + { + // None, Error + null, null, + + (a,b) => Cast(a) != Cast(b), + (a,b) => Cast(a) != Cast(b), + (a,b) => Cast(a) != Cast(b), + (a,b) => { var x = Cast(a); var y = Cast(b); if (x == y) return false; if (!R4.IsNaN(x) && !R4.IsNaN(y)) return true; return null; }, + (a,b) => { var x = Cast(a); var y = Cast(b); if (x == y) return false; if (!R8.IsNaN(x) && !R8.IsNaN(y)) return true; return null; }, + (a,b) => !Cast(a).Span.SequenceEqual(Cast(b).Span), + }; + + // Indexed by ExprTypeKind. + private static readonly Cmp[] _fnLess = new Cmp[(int)ExprTypeKind._Lim] + { + // None, Error + null, null, + + null, + (a,b) => Cast(a) < Cast(b), + (a,b) => Cast(a) < Cast(b), + (a,b) => { var x = Cast(a); var y = Cast(b); if (x < y) return true; if (x >= y) return false; return null; }, + (a,b) => { var x = Cast(a); var y = Cast(b); if (x < y) return true; if (x >= y) return false; return null; }, + null, + }; + + // Indexed by ExprTypeKind. + private static readonly Cmp[] _fnLessEqual = new Cmp[(int)ExprTypeKind._Lim] + { + // None, Error + null, null, + + null, + (a,b) => Cast(a) <= Cast(b), + (a,b) => Cast(a) <= Cast(b), + (a,b) => { var x = Cast(a); var y = Cast(b); if (x <= y) return true; if (x > y) return false; return null; }, + (a,b) => { var x = Cast(a); var y = Cast(b); if (x <= y) return true; if (x > y) return false; return null; }, + null, + }; + + // Indexed by ExprTypeKind. + private static readonly Cmp[] _fnGreater = new Cmp[(int)ExprTypeKind._Lim] + { + // None, Error + null, null, + + null, + (a,b) => Cast(a) > Cast(b), + (a,b) => Cast(a) > Cast(b), + (a,b) => { var x = Cast(a); var y = Cast(b); if (x > y) return true; if (x <= y) return false; return null; }, + (a,b) => { var x = Cast(a); var y = Cast(b); if (x > y) return true; if (x <= y) return false; return null; }, + null, + }; + + // Indexed by ExprTypeKind. + private static readonly Cmp[] _fnGreaterEqual = new Cmp[(int)ExprTypeKind._Lim] + { + // None, Error + null, null, + + null, + (a,b) => Cast(a) >= Cast(b), + (a,b) => Cast(a) >= Cast(b), + (a,b) => { var x = Cast(a); var y = Cast(b); if (x >= y) return true; if (x < y) return false; return null; }, + (a,b) => { var x = Cast(a); var y = Cast(b); if (x >= y) return true; if (x < y) return false; return null; }, + null, + }; + } +} \ No newline at end of file diff --git a/src/Microsoft.ML.Transforms/Expression/LambdaParser.cs b/src/Microsoft.ML.Transforms/Expression/LambdaParser.cs new file mode 100644 index 0000000000..c003265bc6 --- /dev/null +++ b/src/Microsoft.ML.Transforms/Expression/LambdaParser.cs @@ -0,0 +1,795 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using Microsoft.ML.Data; +using Microsoft.ML.Internal.Utilities; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.Transforms +{ + internal sealed class LambdaParser + { + public struct SourcePos + { + public readonly int IchMin; + public readonly int IchLim; + public readonly int LineMin; + public readonly int ColumnMin; + public readonly int LineLim; + public readonly int ColumnLim; + + public SourcePos(List lineMap, TextSpan span, int lineMin = 1) + { + Contracts.AssertValue(lineMap); + Contracts.Assert(span.Min <= span.Lim); + + IchMin = span.Min; + IchLim = span.Lim; + + if (Utils.Size(lineMap) == 0) + { + LineMin = lineMin; + ColumnMin = IchMin + 1; + LineLim = lineMin; + ColumnLim = IchLim + 1; + return; + } + + int index = FindIndex(lineMap, IchMin, 0); + LineMin = index + lineMin; + int ichBase = index == 0 ? 0 : lineMap[index - 1]; + ColumnMin = IchMin - ichBase + 1; + + if (index == lineMap.Count || IchLim < lineMap[index]) + { + // Same line. + LineLim = LineMin; + ColumnLim = IchLim - ichBase + 1; + } + else + { + index = FindIndex(lineMap, IchLim, index); + Contracts.Assert(index > 0); + ichBase = lineMap[index - 1]; + LineLim = index + lineMin; + ColumnLim = IchLim - ichBase + 1; + } + } + + private static int FindIndex(List map, int value, int ivMin) + { + Contracts.Assert(ivMin <= map.Count); + int ivLim = map.Count; + while (ivMin < ivLim) + { + int iv = (ivMin + ivLim) / 2; + if (value >= map[iv]) + ivMin = iv + 1; + else + ivLim = iv; + } + Contracts.Assert(0 <= ivMin & ivMin <= map.Count); + Contracts.Assert(ivMin == map.Count || value < map[ivMin]); + Contracts.Assert(ivMin == 0 || value >= map[ivMin - 1]); + return ivMin; + } + } + + // This is re-usable state (if we choose to re-use). + private readonly NormStr.Pool _pool; + private readonly KeyWordTable _kwt; + private readonly Lexer _lex; + + // Created lazily. If we choose to share static state in the future, this + // should be volatile and set using Interlocked.CompareExchange. + private Dictionary _mapTidStr; + + // This is the parsing state. + private int[] _perm; // The parameter permutation. + private DataViewType[] _types; + private TokenCursor _curs; + private List _errors; + private List _lineMap; + + private LambdaParser() + { + _pool = new NormStr.Pool(); + _kwt = new KeyWordTable(_pool); + InitKeyWordTable(); + _lex = new Lexer(_pool, _kwt); + } + + private void InitKeyWordTable() + { + Action p = _kwt.AddPunctuator; + + p("^", TokKind.Car); + + p("*", TokKind.Mul); + p("/", TokKind.Div); + p("%", TokKind.Per); + p("+", TokKind.Add); + p("-", TokKind.Sub); + + p("&&", TokKind.AmpAmp); + p("||", TokKind.BarBar); + + p("!", TokKind.Bng); + p("!=", TokKind.BngEqu); + + p("=", TokKind.Equ); + p("==", TokKind.EquEqu); + p("=>", TokKind.EquGrt); + p("<", TokKind.Lss); + p("<=", TokKind.LssEqu); + p("<>", TokKind.LssGrt); + p(">", TokKind.Grt); + p(">=", TokKind.GrtEqu); + + p(".", TokKind.Dot); + p(",", TokKind.Comma); + p(":", TokKind.Colon); + p(";", TokKind.Semi); + p("?", TokKind.Que); + p("??", TokKind.QueQue); + + p("(", TokKind.OpenParen); + p(")", TokKind.CloseParen); + + Action w = _kwt.AddKeyWord; + + w("false", TokKind.False); + w("true", TokKind.True); + w("not", TokKind.Not); + w("and", TokKind.And); + w("or", TokKind.Or); + w("with", TokKind.With); + } + + public static LambdaNode Parse(out List errors, out List lineMap, CharCursor chars, int[] perm, params DataViewType[] types) + { + Contracts.AssertValue(chars); + Contracts.AssertNonEmpty(types); + Contracts.Assert(types.Length <= LambdaCompiler.MaxParams); + Contracts.Assert(Utils.Size(perm) == types.Length); + + LambdaParser psr = new LambdaParser(); + return psr.ParseCore(out errors, out lineMap, chars, perm, types); + } + + private LambdaNode ParseCore(out List errors, out List lineMap, CharCursor chars, int[] perm, DataViewType[] types) + { + Contracts.AssertValue(chars); + Contracts.AssertNonEmpty(types); + Contracts.Assert(Utils.Size(perm) == types.Length); + + _errors = null; + _lineMap = new List(); + _curs = new TokenCursor(_lex.LexSource(chars)); + _types = types; + _perm = perm; + + // Skip over initial comments, new lines, lexing errors, etc. + SkipJunk(); + + LambdaNode node = ParseLambda(TokCur); + if (TidCur != TokKind.Eof) + PostError(TokCur, "Expected end of input"); + + errors = _errors; + lineMap = _lineMap; + + _errors = null; + _lineMap = null; + _curs = null; + + return node; + } + + private void AddError(Error err) + { + Contracts.Assert(_errors == null || _errors.Count > 0); + + if (Utils.Size(_errors) > 0 && _errors[_errors.Count - 1].Token == err.Token) + { + // There's already an error report on this token, so don't issue another. + return; + } + + if (_errors == null) + _errors = new List(); + _errors.Add(err); + } + + private void PostError(Token tok, string msg) + { + var err = new Error(tok, msg); + AddError(err); + } + + private void PostError(Token tok, string msg, params object[] args) + { + var err = new Error(tok, msg, args); + AddError(err); + } + + private void PostTidError(Token tok, TokKind tidWanted) + { + Contracts.Assert(tidWanted != tok.Kind); + Contracts.Assert(tidWanted != tok.KindContext); + PostError(tok, "Expected: '{0}', Found: '{1}'", Stringize(tidWanted), Stringize(tok)); + } + + private string Stringize(Token tok) + { + Contracts.AssertValue(tok); + switch (tok.Kind) + { + case TokKind.Ident: + return tok.As().Value; + default: + return Stringize(tok.Kind); + } + } + + private string Stringize(TokKind tid) + { + if (_mapTidStr == null) + { + // Build the inverse key word table, mapping token kinds to strings. + _mapTidStr = new Dictionary(); + foreach (var kvp in _kwt.KeyWords) + { + if (!kvp.Value.IsContextKeyWord) + _mapTidStr[kvp.Value.Kind] = kvp.Key.Value.ToString(); + } + foreach (var kvp in _kwt.Punctuators) + _mapTidStr[kvp.Value] = kvp.Key.Value.ToString(); + } + + string str; + if (_mapTidStr.TryGetValue(tid, out str)) + return str; + + return string.Format("<{0}>", tid); + } + + private TokKind TidCur + { + get { return _curs.TidCur; } + } + + private TokKind CtxCur + { + get { return _curs.CtxCur; } + } + + private Token TokCur + { + get { return _curs.TokCur; } + } + + private Token TokPeek(int cv = 1) + { + Contracts.Assert(cv > 0); + + for (int ctok = 0; ;) + { + var tok = _curs.TokPeek(++ctok); + switch (tok.Kind) + { + case TokKind.NewLine: + case TokKind.Comment: + case TokKind.Error: + case TokKind.ErrorInline: + break; + + default: + if (--cv <= 0) + return tok; + break; + } + } + } + + private TokKind TidPeek(int cv = 1) + { + return TokPeek(cv).Kind; + } + + private TokKind TidNext() + { + _curs.TidNext(); + SkipJunk(); + return _curs.TidCur; + } + + private void SkipJunk() + { + for (; ; ) + { + switch (_curs.TidCur) + { + case TokKind.NewLine: + _lineMap.Add(_curs.TokCur.Span.Lim); + break; + case TokKind.Comment: + break; + + case TokKind.Error: + case TokKind.ErrorInline: + PostError(_curs.TokCur, _curs.TokCur.As().ToString()); + break; + + default: + return; + } + _curs.TidNext(); + } + } + + private Token TokMove() + { + Token tok = TokCur; + TidNext(); + return tok; + } + + // Eats a token of the given kind. If the token is not the right kind, + // leaves the current token and reports and returns an error. + private bool EatTid(TokKind tid) + { + if (TidCur == tid || CtxCur == tid) + { + TidNext(); + return true; + } + PostTidError(TokCur, tid); + return false; + } + + // Returns the current token if it's of the given kind and moves to the next token. + // If the token is not the right kind, reports an error, leaves the token, and returns null. + private Token TokEat(TokKind tid) + { + if (TidCur == tid) + return TokMove(); + + PostTidError(TokCur, tid); + return null; + } + + private LambdaNode ParseLambda(Token tokFirst) + { + var items = new List(); + if (TidCur == TokKind.Ident) + { + // Single parameter. + items.Add(ParseParam(0)); + } + else + { + EatTid(TokKind.OpenParen); + for (; ; ) + { + items.Add(ParseParam(items.Count)); + if (TidCur != TokKind.Comma) + break; + TidNext(); + } + EatTid(TokKind.CloseParen); + } + if (items.Count != _types.Length) + PostError(tokFirst, "Wrong number of parameters, expected: {0}", _types.Length); + + // Allow either : or => since the latter is problematic on the command line. + Token tok = TidCur == TokKind.Colon ? TokMove() : TokEat(TokKind.EquGrt); + ExprNode expr = ParseExpr(); + + return new LambdaNode(tok ?? tokFirst, items.ToArray(), expr); + } + + private ParamNode ParseParam(int index) + { + Contracts.Assert(0 <= index); + Token tok = TokCur; + string name; + + if (tok.Kind == TokKind.Ident) + { + name = tok.As().Value; + TidNext(); + } + else + { + PostTidError(TokCur, TokKind.Ident); + name = ""; + } + + DataViewType type; + if (index < _types.Length) + { + type = _types[index]; + for (int i = 0; ; i++) + { + Contracts.Assert(i < _perm.Length); + Contracts.Assert(0 <= _perm[i] && _perm[i] < _perm.Length); + if (_perm[i] == index) + { + index = i; + break; + } + } + } + else + { + PostError(tok, "Too many parameters, expected {0}", _types.Length); + type = null; + } + + var res = new ParamNode(tok, name, index, type); + + if (res.ExprType == ExprTypeKind.None) + PostError(tok, "Unsupported type"); + + return res; + } + + private ExprNode ParseExpr() + { + return ParseExpr(Precedence.None); + } + + // Parses the next (maximal) expression with precedence >= precMin. + private ExprNode ParseExpr(Precedence precMin) + { + // ParseOperand may accept PrefixUnary and higher, so ParseExpr should never be called + // with precMin > Precedence.PrefixUnary - it will not correctly handle those cases. + Contracts.Assert(Precedence.None <= precMin); + Contracts.Assert(precMin <= Precedence.PrefixUnary); + + // Get the left operand. + ExprNode node = ParsePrimary(); + + // Process operators and right operands as long as the precedence bound is satisfied. + for (; ; ) + { + Contracts.AssertValue(node); + switch (TidCur) + { + case TokKind.Car: + Contracts.Assert(precMin <= Precedence.Power); + // Note that the right operand can include unary operators. + node = new BinaryOpNode(TokMove(), BinaryOp.Power, node, ParseExpr(Precedence.PrefixUnary)); + break; + + case TokKind.Mul: + if (precMin > Precedence.Mul) + return node; + node = new BinaryOpNode(TokMove(), BinaryOp.Mul, node, ParseExpr(Precedence.Mul + 1)); + break; + case TokKind.Div: + if (precMin > Precedence.Mul) + return node; + node = new BinaryOpNode(TokMove(), BinaryOp.Div, node, ParseExpr(Precedence.Mul + 1)); + break; + case TokKind.Per: + if (precMin > Precedence.Mul) + return node; + node = new BinaryOpNode(TokMove(), BinaryOp.Mod, node, ParseExpr(Precedence.Mul + 1)); + break; + + case TokKind.Sub: + if (precMin > Precedence.Add) + return node; + node = new BinaryOpNode(TokMove(), BinaryOp.Sub, node, ParseExpr(Precedence.Add + 1)); + break; + case TokKind.Add: + if (precMin > Precedence.Add) + return node; + node = new BinaryOpNode(TokMove(), BinaryOp.Add, node, ParseExpr(Precedence.Add + 1)); + break; + + case TokKind.AmpAmp: + case TokKind.And: + if (precMin > Precedence.And) + return node; + node = new BinaryOpNode(TokMove(), BinaryOp.And, node, ParseExpr(Precedence.And + 1)); + break; + case TokKind.BarBar: + case TokKind.Or: + if (precMin > Precedence.Or) + return node; + node = new BinaryOpNode(TokMove(), BinaryOp.Or, node, ParseExpr(Precedence.Or + 1)); + break; + + case TokKind.QueQue: + if (precMin > Precedence.Coalesce) + return node; + // Note that the associativity is different than other binary operators (right instead of left), + // so the recursive call accepts Precedence.Coal. + node = new BinaryOpNode(TokMove(), BinaryOp.Coalesce, node, ParseExpr(Precedence.Coalesce)); + break; + + case TokKind.Que: + if (precMin > Precedence.Conditional) + return node; + node = new ConditionalNode(TokMove(), node, ParseExpr(), TokEat(TokKind.Colon), ParseExpr()); + break; + + // Comparison operators + // expr = ... = expr + // expr <> ... <> expr + case TokKind.Equ: + case TokKind.EquEqu: + if (precMin > Precedence.Compare) + return node; + node = ParseCompareExpr(node, CompareOp.Equal, TokKind.Equ, TokKind.EquEqu); + break; + + case TokKind.LssGrt: + case TokKind.BngEqu: + if (precMin > Precedence.Compare) + return node; + node = ParseCompareExpr(node, CompareOp.NotEqual, TokKind.LssGrt, TokKind.BngEqu); + break; + + // expr < expr + // expr <= expr + case TokKind.Lss: + case TokKind.LssEqu: + if (precMin > Precedence.Compare) + return node; + node = ParseCompareExpr(node, CompareOp.IncrChain, TokKind.LssEqu, TokKind.Lss); + break; + + // expr > expr + // expr >= expr + case TokKind.Grt: + case TokKind.GrtEqu: + if (precMin > Precedence.Compare) + return node; + node = ParseCompareExpr(node, CompareOp.DecrChain, TokKind.GrtEqu, TokKind.Grt); + break; + + case TokKind.True: + case TokKind.False: + case TokKind.IntLit: + case TokKind.FltLit: + case TokKind.DblLit: + case TokKind.CharLit: + case TokKind.StrLit: + PostError(TokCur, "Operator expected"); + node = new BinaryOpNode(TokCur, BinaryOp.Error, node, ParseExpr(Precedence.Error)); + break; + + default: + return node; + } + } + } + + private ExprNode ParsePrimary() + { + switch (TidCur) + { + // (Expr) + case TokKind.OpenParen: + return ParseParenExpr(); + + // -Expr + case TokKind.Sub: + return new UnaryOpNode(TokMove(), UnaryOp.Minus, ParseExpr(Precedence.PrefixUnary)); + + // not Expr + case TokKind.Not: + case TokKind.Bng: + return new UnaryOpNode(TokMove(), UnaryOp.Not, ParseExpr(Precedence.PrefixUnary)); + + // Literals + case TokKind.IntLit: + case TokKind.FltLit: + case TokKind.DblLit: + return new NumLitNode(TokMove().As()); + case TokKind.True: + case TokKind.False: + return new BoolLitNode(TokMove()); + case TokKind.StrLit: + return new StrLitNode(TokMove().As()); + + // Name + case TokKind.Ident: + if (TidPeek() == TokKind.OpenParen) + return ParseInvocation(); + if (TidPeek() == TokKind.Dot && TidPeek(2) == TokKind.Ident && TidPeek(3) == TokKind.OpenParen) + return ParseInvocationWithNameSpace(); + return ParseIdent(); + + case TokKind.CharLit: + var result = ParseIdent(); + TokMove(); + return result; + + case TokKind.With: + return ParseWith(); + + default: + // Error + return ParseIdent(); + } + } + + private CompareNode ParseCompareExpr(ExprNode node, CompareOp op, TokKind tidLax, TokKind tidStrict) + { + Contracts.AssertValue(node); + Contracts.Assert(TidCur == tidLax || TidCur == tidStrict); + + Token tok = TokCur; + List list = new List(); + List ops = new List(); + list.Add(node); + for (; ; ) + { + if (TidCur != tidLax && TidCur != tidStrict) + break; + ops.Add(TokMove()); + list.Add(ParseExpr(Precedence.Compare + 1)); + } + Contracts.Assert(list.Count >= 2); + + // The grammar disallows mixed direction expressions like: + // a < b > c <= 4 + // After posting an error, we continue parsing to produce: ((a < b) > c) <= 4. + // Note that this will also produce a type checking error. + Contracts.Assert(TidCur != tidLax); + Contracts.Assert(TidCur != tidStrict); + switch (TidCur) + { + case TokKind.LssGrt: + case TokKind.BngEqu: + case TokKind.Equ: + case TokKind.EquEqu: + case TokKind.Lss: + case TokKind.LssEqu: + case TokKind.Grt: + case TokKind.GrtEqu: + PostError(TokCur, "Mixed direction not allowed"); + break; + } + + return new CompareNode(tok, op, new ListNode(tok, list.ToArray(), ops.ToArray())); + } + + private IdentNode ParseIdent() + { + if (TidCur == TokKind.Ident) + return new IdentNode(TokMove().As()); + PostTidError(TokCur, TokKind.Ident); + return new IdentNode(TokCur, "", true); + } + + private CallNode ParseInvocation() + { + Contracts.Assert(TidCur == TokKind.Ident); + Contracts.Assert(TidPeek() == TokKind.OpenParen); + + NameNode head = new NameNode(TokMove().As()); + Contracts.Assert(TidCur == TokKind.OpenParen); + + Token tok = TokMove(); + return new CallNode(tok, head, ParseList(tok, TokKind.CloseParen), TokEat(TokKind.CloseParen)); + } + + private CallNode ParseInvocationWithNameSpace() + { + Contracts.Assert(TidCur == TokKind.Ident); + Contracts.Assert(TidPeek() == TokKind.Dot); + Contracts.Assert(TidPeek(2) == TokKind.Ident); + Contracts.Assert(TidPeek(3) == TokKind.OpenParen); + + NameNode ns = new NameNode(TokMove().As()); + Contracts.Assert(TidCur == TokKind.Dot); + Token tokDot = TokMove(); + NameNode head = new NameNode(TokMove().As()); + Contracts.Assert(TidCur == TokKind.OpenParen); + Token tokParen = TokMove(); + + return new CallNode(tokParen, ns, tokDot, head, ParseList(tokParen, TokKind.CloseParen), TokEat(TokKind.CloseParen)); + } + + private ExprNode ParseParenExpr() + { + Contracts.Assert(TidCur == TokKind.OpenParen); + + TidNext(); + ExprNode node = ParseExpr(Precedence.None); + EatTid(TokKind.CloseParen); + return node; + } + + private ListNode ParseList(Token tok, TokKind tidEmpty) + { + if (TidCur == tidEmpty) + return new ListNode(tok, new Node[0], null); + + List commas = null; + List list = new List(); + for (; ; ) + { + list.Add(ParseExpr()); + if (TidCur != TokKind.Comma) + break; + Utils.Add(ref commas, TokMove()); + } + return new ListNode(tok, list.ToArray(), Utils.ToArray(commas)); + } + + // Note that the grammar allows multiple assignments per with expression. This is simply syntactic sugar + // for chained with expressions. + private WithNode ParseWith(Token tokWith = null) + { + Token tok; + Token tokOpen; + if (tokWith == null) + { + // We're at the beginning of the "with" syntax. + Contracts.Assert(TidCur == TokKind.With); + tokWith = TokMove(); + tok = tokWith; + tokOpen = TokCur; + EatTid(TokKind.OpenParen); + } + else + { + // We're at a comma between with assignments. + Contracts.Assert(TidCur == TokKind.Comma); + tok = TokMove(); + tokOpen = tok; + } + + var local = ParseWithLocal(); + + ExprNode body; + if (TidCur == TokKind.Comma) + { + // Recurse to get the nested scenario. + body = ParseWith(tokWith); + } + else + { + EatTid(TokKind.Semi); + body = ParseExpr(); + EatTid(TokKind.CloseParen); + } + + return new WithNode(tok, local, body); + } + + private WithLocalNode ParseWithLocal() + { + Token tok = TokCur; + string name; + + if (tok.Kind == TokKind.Ident) + { + name = tok.As().Value; + TidNext(); + } + else + { + PostTidError(TokCur, TokKind.Ident); + name = ""; + } + + if (TidCur == TokKind.Equ) + tok = TokCur; + EatTid(TokKind.Equ); + + var value = ParseExpr(); + return new WithLocalNode(tok, name, value); + } + } +} diff --git a/src/Microsoft.ML.Transforms/Expression/LexCharUtils.cs b/src/Microsoft.ML.Transforms/Expression/LexCharUtils.cs new file mode 100644 index 0000000000..079e860234 --- /dev/null +++ b/src/Microsoft.ML.Transforms/Expression/LexCharUtils.cs @@ -0,0 +1,250 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Globalization; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.Transforms +{ + /// + /// Indicates which lex routine should be called when this character is the first + /// character of a token. Each character is associated with exactly one of these values. + /// Some associations may at first be surprising. For example, dot (.) uses NumLit and + /// slash (/) uses Comment. + /// + internal enum LexStartKind : ushort + { + None, + Punc, + Ident, + NumLit, + StrLit, + Verbatim, + Comment, + PreProc, + Space, + LineTerm, + } + + /// + /// Encapsulates information needed to map characters to tokens. + /// + internal static class LexCharUtils + { + /// + /// Bit masks of the UnicodeCategory enum. A couple extra values are defined + /// for convenience for the C# lexical grammar. + /// + [Flags] + private enum UniCatFlags : uint + { + ConnectorPunctuation = 1 << UnicodeCategory.ConnectorPunctuation, // Pc + DecimalDigitNumber = 1 << UnicodeCategory.DecimalDigitNumber, // Nd + Format = 1 << UnicodeCategory.Format, // Cf + LetterNumber = 1 << UnicodeCategory.LetterNumber, // Nl + LowercaseLetter = 1 << UnicodeCategory.LowercaseLetter, // Ll + ModifierLetter = 1 << UnicodeCategory.ModifierLetter, // Lm + NonSpacingMark = 1 << UnicodeCategory.NonSpacingMark, // Mn + OtherLetter = 1 << UnicodeCategory.OtherLetter, // Lo + SpaceSeparator = 1 << UnicodeCategory.SpaceSeparator, // Zs + SpacingCombiningMark = 1 << UnicodeCategory.SpacingCombiningMark, // Mc + TitlecaseLetter = 1 << UnicodeCategory.TitlecaseLetter, // Lt + UppercaseLetter = 1 << UnicodeCategory.UppercaseLetter, // Lu + + // Useful combinations. + IdentStartChar = UppercaseLetter | LowercaseLetter | TitlecaseLetter | + ModifierLetter | OtherLetter | LetterNumber, + IdentPartChar = IdentStartChar | NonSpacingMark | SpacingCombiningMark | + DecimalDigitNumber | ConnectorPunctuation | Format, + } + + /// + /// Indicates the different roles a character may have (as non-leading character). This is used for + /// subsequent (not first) characters in a token. For example, digits all have the Ident flag set. + /// + [Flags] + private enum LexCharKind : ushort + { + None = 0x0000, + Punc = 0x0001, + Ident = 0x0002, + Digit = 0x0004, + HexDigit = 0x0008, + Space = 0x0010, + LineTerm = 0x0020, + }; + + /// + /// Information for each character. We have a table of these for all characters less than 0x80. + /// + private struct LexCharInfo + { + public readonly LexStartKind StartKind; + public readonly LexCharKind CharKind; + + public LexCharInfo(LexStartKind sk, LexCharKind ck) + { + StartKind = sk; + CharKind = ck; + } + + public bool Is(LexCharKind kind) + { + return (CharKind & kind) != 0; + } + } + + // The mapping from character to CharInfo for characters less than 128. + private static LexCharInfo[] _rgchi; + + static LexCharUtils() + { + // Init the array of CharInfo's. + _rgchi = new LexCharInfo[128]; + + // a - f are Ident and HexDigit + var info = new LexCharInfo(LexStartKind.Ident, LexCharKind.Ident | LexCharKind.HexDigit); + for (char ch = 'a'; ch <= 'f'; ch++) + _rgchi[ch] = info; + for (char ch = 'A'; ch <= 'F'; ch++) + _rgchi[ch] = info; + + // g - z are just Ident. + info = new LexCharInfo(LexStartKind.Ident, LexCharKind.Ident); + for (char ch = 'g'; ch <= 'z'; ch++) + _rgchi[ch] = info; + for (char ch = 'G'; ch <= 'Z'; ch++) + _rgchi[ch] = info; + _rgchi['_'] = info; + + // Digits are Digit | HexDigit | Ident. + info = new LexCharInfo(LexStartKind.NumLit, LexCharKind.Digit | LexCharKind.HexDigit | LexCharKind.Ident); + for (char ch = '0'; ch <= '9'; ch++) + _rgchi[ch] = info; + // Dot can start a numeric literal. + _rgchi['.'] = new LexCharInfo(LexStartKind.NumLit, LexCharKind.Punc); + + // Space characters. + info = new LexCharInfo(LexStartKind.Space, LexCharKind.Space); + foreach (char ch in " \x09\x0B\x0C") + _rgchi[ch] = info; + + // Line terminators. + info = new LexCharInfo(LexStartKind.LineTerm, LexCharKind.LineTerm); + _rgchi['\xA'] = info; + _rgchi['\xD'] = info; + + // Special lead characters: literals, verbatim, comment, pre-processor. + info = new LexCharInfo(LexStartKind.StrLit, LexCharKind.None); + _rgchi['"'] = info; + _rgchi['\''] = info; + _rgchi['@'] = new LexCharInfo(LexStartKind.Verbatim, LexCharKind.None); + _rgchi['/'] = new LexCharInfo(LexStartKind.Comment, LexCharKind.Punc); + _rgchi['#'] = new LexCharInfo(LexStartKind.PreProc, LexCharKind.None); + + // Punctuators. Some that you might think belong here (like . and /) are handled + // by other LexStartKinds. + info = new LexCharInfo(LexStartKind.Punc, LexCharKind.Punc); + foreach (char ch in "!%&()*+,-:;<=>?[]^{|}~") + _rgchi[ch] = info; + } + + private static UniCatFlags GetCatFlags(char ch) + { + return (UniCatFlags)(1u << (int)CharUnicodeInfo.GetUnicodeCategory(ch)); + } + + /// + /// Returns the lexical character type of the given character. + /// + public static LexStartKind StartKind(char ch) + { + if (ch < _rgchi.Length) + return _rgchi[ch].StartKind; + + UniCatFlags ucf = GetCatFlags(ch); + if ((ucf & UniCatFlags.IdentStartChar) != 0) + return LexStartKind.Ident; + if ((ucf & UniCatFlags.SpaceSeparator) != 0) + return LexStartKind.Space; + return LexStartKind.None; + } + + public static bool IsPunc(char ch) + { + return ch < _rgchi.Length && _rgchi[ch].Is(LexCharKind.Punc); + } + public static bool IsDigit(char ch) + { + return ch < _rgchi.Length && _rgchi[ch].Is(LexCharKind.Digit); + } + public static bool IsHexDigit(char ch) + { + return ch < _rgchi.Length && _rgchi[ch].Is(LexCharKind.HexDigit); + } + public static bool IsIdentStart(char ch) + { + if (ch < _rgchi.Length) + return _rgchi[ch].Is(LexCharKind.Ident) && !_rgchi[ch].Is(LexCharKind.Digit); + return (GetCatFlags(ch) & UniCatFlags.IdentPartChar) != 0; + } + public static bool IsIdent(char ch) + { + if (ch < _rgchi.Length) + return _rgchi[ch].Is(LexCharKind.Ident); + return (GetCatFlags(ch) & UniCatFlags.IdentPartChar) != 0; + } + public static bool IsFormat(char ch) + { + return ch >= _rgchi.Length && CharUnicodeInfo.GetUnicodeCategory(ch) == UnicodeCategory.Format; + } + public static bool IsSpace(char ch) + { + if (ch < _rgchi.Length) + return _rgchi[ch].Is(LexCharKind.Space); + return CharUnicodeInfo.GetUnicodeCategory(ch) == UnicodeCategory.SpaceSeparator; + } + public static bool IsLineTerm(char ch) + { + if (ch < _rgchi.Length) + return _rgchi[ch].Is(LexCharKind.LineTerm); + return ch == '\u0085' || ch == '\u2028' || ch == '\u2029'; + } + + public static int GetDecVal(char ch) + { + Contracts.Assert('0' <= ch && ch <= '9'); + return ch - '0'; + } + + public static int GetHexVal(char ch) + { + Contracts.Assert(IsHexDigit(ch)); + if (ch >= 'a') + { + Contracts.Assert(ch <= 'f'); + return ch - ('a' - 10); + } + if (ch >= 'A') + { + Contracts.Assert(ch <= 'F'); + return ch - ('A' - 10); + } + Contracts.Assert('0' <= ch && ch <= '9'); + return ch - '0'; + } + + /// + /// Convert the given uint to a unicode escape. + /// Note that the uint contains raw hex - not a surrogate pair. + /// + public static string GetUniEscape(uint u) + { + if (u < 0x00010000) + return string.Format(@"\u{0:X4}", u); + return string.Format(@"\U{0:X8}", u); + } + } +} diff --git a/src/Microsoft.ML.Transforms/Expression/Lexer.cs b/src/Microsoft.ML.Transforms/Expression/Lexer.cs new file mode 100644 index 0000000000..4ff07e70f6 --- /dev/null +++ b/src/Microsoft.ML.Transforms/Expression/Lexer.cs @@ -0,0 +1,844 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using Microsoft.ML.Internal.Utilities; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.Transforms +{ + /// + /// The lexer. This is effectively a template. Call LexSource to get an Enumerable of tokens. + /// + [BestFriend] + internal partial class Lexer + { + private readonly NormStr.Pool _pool; + private readonly KeyWordTable _kwt; + + /// + /// The constructor. Caller must provide the name pool and key word table. + /// + public Lexer(NormStr.Pool pool, KeyWordTable kwt) + { + Contracts.AssertValue(pool); + Contracts.AssertValue(kwt); + _pool = pool; + _kwt = kwt; + } + + public IEnumerable LexSource(CharCursor cursor) + { + Contracts.AssertValue(cursor); + + LexerImpl impl = new LexerImpl(this, cursor); + Token tok; + while ((tok = impl.GetNextToken()) != null) + yield return tok; + yield return impl.GetEof(); + } + + private partial class LexerImpl + { + private readonly Lexer _lex; + private readonly CharCursor _cursor; + + private StringBuilder _sb; // Used while building a token. + private int _ichMinTok; // The start of the current token. + private Queue _queue; // For multiple returns. +#pragma warning disable 414 + // This will be used by any pre-processor, so keep it around. + private bool _fLineStart; +#pragma warning restore 414 + + public LexerImpl(Lexer lex, CharCursor cursor) + { + _lex = lex; + _cursor = cursor; + _sb = new StringBuilder(); + _queue = new Queue(4); + _fLineStart = true; + } + + /// + /// Whether we've hit the end of input yet. If this returns true, ChCur will be zero. + /// + private bool Eof { get { return _cursor.Eof; } } + + /// + /// The current character. Zero if we've hit the end of input. + /// + private char ChCur + { + get { return _cursor.ChCur; } + } + + /// + /// Advance to the next character and return it. + /// + private char ChNext() + { + return _cursor.ChNext(); + } + + private char ChPeek(int ich) + { + return _cursor.ChPeek(ich); + } + + /// + /// Marks the beginning of the current token. + /// + private void StartTok() + { + _ichMinTok = _cursor.IchCur; + } + + /// + /// Called to embed an error token in the stream. + /// + private void ReportError(ErrId eid) + { + ReportError(_ichMinTok, _cursor.IchCur, eid, null); + } + + private void ReportError(ErrId eid, params object[] args) + { + ReportError(_ichMinTok, _cursor.IchCur, eid, args); + } + + private void ReportError(int ichMin, int ichLim, ErrId eid, params object[] args) + { + // REVIEW: Fix this so the error is marked as nested if appropriate! + ErrorToken err = new ErrorToken(GetTextSpan(ichMin, ichLim), eid, args); + _queue.Enqueue(err); + } + + private TextSpan GetSpan() + { + var span = new TextSpan(_ichMinTok, _cursor.IchCur); + StartTok(); + return span; + } + + private TextSpan GetTextSpan(int ichMin, int ichLim) + { + return new TextSpan(ichMin, ichLim); + } + + /// + /// Form and return the next token. Returns null to signal end of input. + /// + public Token GetNextToken() + { + // New line tokens and errors can be "nested" inside comments or string literals + // so this code isn't as simple as lexing a single token and returning it. + // Note that we return the outer token before nested ones. + + while (_queue.Count == 0) + { + if (Eof) + return null; + Token tokNew = FetchToken(); + if (tokNew != null) + return tokNew; + } + + // Only new lines and errors should be enqueued. + Token tok = _queue.Dequeue(); + Contracts.Assert(tok.Kind == TokKind.NewLine || tok.Kind == TokKind.Error); + return tok; + } + + /// + /// Call once GetNextToken returns null if you need an Eof token. + /// + public EofToken GetEof() + { + Contracts.Assert(Eof); + return new EofToken(GetTextSpan(_cursor.IchCur, _cursor.IchCur)); + } + + private Token FetchToken() + { + Contracts.Assert(!Eof); + StartTok(); + + LexStartKind kind = LexCharUtils.StartKind(ChCur); + if (kind != LexStartKind.Space && kind != LexStartKind.PreProc) + _fLineStart = false; + + switch (kind) + { + case LexStartKind.Punc: + return LexPunc(); + case LexStartKind.NumLit: + return LexNumLit(); + case LexStartKind.StrLit: + return LexStrLit(); + case LexStartKind.Verbatim: + if (ChPeek(1) == '"') + return LexStrLit(); + if (LexCharUtils.StartKind(ChPeek(1)) == LexStartKind.Ident) + return LexIdent(); + ChNext(); + ReportError(ErrId.VerbatimLiteralExpected); + return null; + case LexStartKind.Ident: + return LexIdent(); + case LexStartKind.Comment: + return LexComment(); + case LexStartKind.Space: + return LexSpace(); + case LexStartKind.LineTerm: + LexLineTerm(); + return null; + case LexStartKind.PreProc: + return LexPreProc(); + default: + return LexError(); + } + } + + /// + /// Called to lex a punctuator (operator). Asserts the current character lex type + /// is LexCharType.Punc. + /// + private Token LexPunc() + { + int cchPunc = 0; + TokKind tidPunc = TokKind.None; + + _sb.Length = 0; + _sb.Append(ChCur); + for (; ; ) + { + TokKind tidCur; + NormStr nstr = _lex._pool.Add(_sb); + if (!_lex._kwt.IsPunctuator(nstr, out tidCur)) + break; + + if (tidCur != TokKind.None) + { + // This is a real punctuator, not just a prefix. + tidPunc = tidCur; + cchPunc = _sb.Length; + } + + char ch = ChPeek(_sb.Length); + if (!LexCharUtils.IsPunc(ch)) + break; + _sb.Append(ch); + } + if (cchPunc == 0) + return LexError(); + while (--cchPunc >= 0) + ChNext(); + return KeyToken.Create(GetSpan(), tidPunc); + } + + /// + /// Called to lex a numeric literal or a Dot token. Asserts the current + /// character lex type is LexCharType.NumLit. + /// + private Token LexNumLit() + { + Contracts.Assert(LexCharUtils.StartKind(ChCur) == LexStartKind.NumLit); + Contracts.Assert(LexCharUtils.IsDigit(ChCur) || ChCur == '.'); + + // A dot not followed by a digit is just a Dot. This is a very common case (hence first). + if (ChCur == '.' && !LexCharUtils.IsDigit(ChPeek(1))) + return LexPunc(); + + // Check for a hex literal. Note that 0x followed by a non-hex-digit is really a 0 followed + // by an identifier. + if (ChCur == '0' && (ChPeek(1) == 'x' || ChPeek(1) == 'X') && LexCharUtils.IsHexDigit(ChPeek(2))) + { + // Advance to first hex digit. + ChNext(); + ChNext(); + return LexHexInt(); + } + + // Decimal literal (possible floating point). + Contracts.Assert(LexCharUtils.IsDigit(ChCur) || ChCur == '.' && LexCharUtils.IsDigit(ChPeek(1))); + bool fExp = false; + bool fDot = ChCur == '.'; + _sb.Length = 0; + _sb.Append(ChCur); + + for (; ; ) + { + if (ChNext() == '.') + { + if (fDot || !LexCharUtils.IsDigit(ChPeek(1))) + break; + fDot = true; + } + else if (!LexCharUtils.IsDigit(ChCur)) + break; + _sb.Append(ChCur); + } + + // Check for an exponent. + if (ChCur == 'e' || ChCur == 'E') + { + char chTmp = ChPeek(1); + if (LexCharUtils.IsDigit(chTmp) || (chTmp == '+' || chTmp == '-') && LexCharUtils.IsDigit(ChPeek(2))) + { + fExp = true; + _sb.Append(ChCur); + _sb.Append(ChNext()); + while (LexCharUtils.IsDigit(chTmp = ChNext())) + _sb.Append(chTmp); + } + } + + bool fReal = fDot | fExp; + char chSuf = LexRealSuffix(fReal); + if (fReal || chSuf != '\0') + return LexRealNum(chSuf); + + // Integer type. + return LexDecInt(LexIntSuffix()); + } + + /// + /// Lex a hex literal optionally followed by an integer suffix. Asserts the current + /// character is a hex digit. + /// + private Token LexHexInt() + { + Contracts.Assert(LexCharUtils.IsHexDigit(ChCur)); + + ulong u = 0; + bool fOverflow = false; + + do + { + if ((u & 0xF000000000000000) != 0 && !fOverflow) + { + ReportError(ErrId.IntOverflow); + fOverflow = true; + } + u = (u << 4) + (ulong)LexCharUtils.GetHexVal(ChCur); + } while (LexCharUtils.IsHexDigit(ChNext())); + + if (fOverflow) + u = ulong.MaxValue; + + return new IntLitToken(GetSpan(), u, LexIntSuffix() | IntLitKind.Hex); + } + + /// + /// Lex a decimal integer literal. The digits must be in _sb. + /// + private Token LexDecInt(IntLitKind ilk) + { + // Digits are in _sb. + Contracts.Assert(_sb.Length > 0); + ulong u = 0; + + try + { + for (int ich = 0; ich < _sb.Length; ich++) + u = checked(u * 10 + (ulong)LexCharUtils.GetDecVal(_sb[ich])); + } + catch (System.OverflowException) + { + ReportError(ErrId.IntOverflow); + u = ulong.MaxValue; + } + return new IntLitToken(GetSpan(), u, ilk); + } + + /// + /// Lex a real literal (float, double or decimal). The characters should be in _sb. + /// + private Token LexRealNum(char chSuf) + { + // Digits are in _sb. + Contracts.Assert(_sb.Length > 0); + + TextSpan span = GetSpan(); + switch (chSuf) + { + default: + Contracts.Assert(chSuf == '\0' || chSuf == 'D'); + try + { + double dbl = double.Parse(_sb.ToString(), NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent); + return new DblLitToken(span, dbl, chSuf != 0); + } + catch (OverflowException) + { + ReportError(ErrId.FloatOverflow, "double"); + return new DblLitToken(span, double.PositiveInfinity, chSuf != 0); + } + case 'F': + try + { + double dbl = double.Parse(_sb.ToString(), NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent); + return new FltLitToken(span, (float)dbl); + } + catch (OverflowException) + { + ReportError(ErrId.FloatOverflow, "float"); + return new FltLitToken(span, float.PositiveInfinity); + } + } + } + + /// + /// Lex an optional integer suffix (U and/or L). + /// + private IntLitKind LexIntSuffix() + { + IntLitKind ilk = IntLitKind.None; + + for (; ; ) + { + if (ChCur == 'U' || ChCur == 'u') + { + if ((ilk & IntLitKind.Uns) != 0) + break; + ilk |= IntLitKind.Uns; + } + else if (ChCur == 'L' || ChCur == 'l') + { + if ((ilk & IntLitKind.Lng) != 0) + break; + ilk |= IntLitKind.Lng; + } + else + break; + ChNext(); + } + return ilk; + } + + /// + /// Lex an optional real suffix (F, D, M). + /// + private char LexRealSuffix(bool fKnown) + { + char ch; + + switch (ChCur) + { + default: + return '\0'; + case 'd': + case 'D': + ch = 'D'; + break; + case 'f': + case 'F': + ch = 'F'; + break; + case 'l': + case 'L': + if (!fKnown) + return '\0'; + ch = 'L'; + break; + } + ChNext(); + return ch; + } + + /// + /// Lex a string or character literal. + /// + private Token LexStrLit() + { + char chQuote; + + _sb.Length = 0; + if (ChCur == '@') + { + chQuote = '"'; + ChNext(); + Contracts.Assert(ChCur == '"'); + ChNext(); + for (; ; ) + { + char ch = ChCur; + if (ch == '"') + { + ChNext(); + if (ChCur != '"') + break; + ChNext(); + } + else if (LexCharUtils.IsLineTerm(ch)) + ch = LexLineTerm(_sb); + else if (Eof) + { + ReportError(ErrId.UnterminatedString); + break; + } + else + ChNext(); + _sb.Append(ch); + } + } + else + { + Contracts.Assert(ChCur == '"' || ChCur == '\''); + chQuote = ChCur; + + ChNext(); + for (; ; ) + { + char ch = ChCur; + if (ch == chQuote || Eof || LexCharUtils.IsLineTerm(ch)) + break; + if (ch == '\\') + { + uint u; + if (!FLexEscChar(false, out u)) + continue; + if (u < 0x10000) + ch = (char)u; + else + { + char chT; + if (!ConvertToSurrogatePair(u, out chT, out ch)) + continue; + _sb.Append(chT); + } + } + else + ChNext(); + _sb.Append(ch); + } + + if (ChCur != chQuote) + ReportError(ErrId.NewlineInConst); + else + ChNext(); + } + + if (chQuote == '"') + return new StrLitToken(GetSpan(), _sb.ToString()); + + if (_sb.Length != 1) + ReportError(_sb.Length == 0 ? ErrId.CharConstEmpty : ErrId.CharConstTooLong); + return new CharLitToken(GetSpan(), _sb.Length > 0 ? _sb[0] : '\0'); + } + + /// + /// Lex a character escape. Returns true if successful (ch is valid). + /// + private bool FLexEscChar(bool fUniOnly, out uint u) + { + Contracts.Assert(ChCur == '\\'); + + int ichErr = _cursor.IchCur; + bool fUni; + int cchHex; + + switch (ChNext()) + { + case 'u': + fUni = true; + cchHex = 4; + goto LHex; + case 'U': + fUni = true; + cchHex = 8; + goto LHex; + default: + if (!fUniOnly) + { + switch (ChCur) + { + default: + goto LBad; + case 'x': + case 'X': + fUni = false; + cchHex = 4; + goto LHex; + case '\'': + u = 0x0027; + break; + case '"': + u = 0x0022; + break; + case '\\': + u = 0x005C; + break; + case '0': + u = 0x0000; + break; + case 'a': + u = 0x0007; + break; + case 'b': + u = 0x0008; + break; + case 'f': + u = 0x000C; + break; + case 'n': + u = 0x000A; + break; + case 'r': + u = 0x000D; + break; + case 't': + u = 0x0009; + break; + case 'v': + u = 0x000B; + break; + } + ChNext(); + return true; + } + LBad: + ReportError(ichErr, _cursor.IchCur, ErrId.BadEscape); + u = 0; + return false; + } + + LHex: + bool fRet = true; + ChNext(); + + u = 0; + for (int ich = 0; ich < cchHex; ich++) + { + if (!LexCharUtils.IsHexDigit(ChCur)) + { + fRet = (ich > 0); + if (fUni || !fRet) + ReportError(ichErr, _cursor.IchCur, ErrId.BadEscape); + break; + } + u = (u << 4) + (uint)LexCharUtils.GetHexVal(ChCur); + ChNext(); + } + return fRet; + } + + /// + /// Convert the pair of characters to a surrogate pair. + /// + private bool ConvertToSurrogatePair(uint u, out char ch1, out char ch2) + { + Contracts.Assert(u > 0x0000FFFF); + if (u > 0x0010FFFF) + { + ReportError(ErrId.BadEscape); + ch1 = ch2 = '\0'; + return false; + } + ch1 = (char)((u - 0x10000) / 0x400 + 0xD800); + ch2 = (char)((u - 0x10000) % 0x400 + 0xDC00); + return true; + } + + /// + /// Lex an identifier. + /// + private Token LexIdent() + { + bool fVerbatim = false; + if (ChCur == '@') + { + fVerbatim = true; + ChNext(); + } + + NormStr nstr = LexIdentCore(ref fVerbatim); + if (nstr == null) + { + // Error already reported. + return null; + } + + if (!fVerbatim) + { + KeyWordTable.KeyWordKind kind; + if (_lex._kwt.IsKeyWord(nstr, out kind)) + return KeyToken.CreateKeyWord(GetSpan(), nstr.Value.ToString(), kind.Kind, kind.IsContextKeyWord); + } + return new IdentToken(GetSpan(), nstr.Value.ToString()); + } + + private NormStr LexIdentCore(ref bool fVerbatim) + { + Contracts.Assert(LexCharUtils.IsIdentStart(ChCur)); + + _sb.Length = 0; + for (; ; ) + { + char ch; + if (ChCur == '\\') + { + uint u; + int ichErr = _cursor.IchCur; + + if (!FLexEscChar(true, out u)) + break; + if (u > 0xFFFF || !LexCharUtils.IsIdent(ch = (char)u)) + { + ReportError(ichErr, _cursor.IchCur, ErrId.BadChar, LexCharUtils.GetUniEscape(u)); + break; + } + fVerbatim = true; + } + else + { + if (!LexCharUtils.IsIdent(ChCur)) + break; + ch = ChCur; + ChNext(); + } + Contracts.Assert(LexCharUtils.IsIdent(ch)); + if (!LexCharUtils.IsFormat(ch)) + _sb.Append(ch); + } + + if (_sb.Length == 0) + return null; + + return _lex._pool.Add(_sb); + } + + /// + /// Lex a comment. + /// + private Token LexComment() + { + Contracts.Assert(ChCur == '/'); + int ichErr = _cursor.IchCur; + + switch (ChPeek(1)) + { + default: + return LexPunc(); + case '/': + // Single line comment. + ChNext(); + _sb.Length = 0; + _sb.Append("//"); + for (; ; ) + { + if (LexCharUtils.IsLineTerm(ChNext()) || Eof) + return new CommentToken(GetSpan(), _sb.ToString(), 0); + _sb.Append(ChCur); + } + case '*': + /* block comment */ + ChNext(); + _sb.Length = 0; + _sb.Append("/*"); + ChNext(); + int lines = 0; + for (; ; ) + { + if (Eof) + { + ReportError(ichErr, _cursor.IchCur, ErrId.UnterminatedComment); + break; + } + char ch = ChCur; + if (LexCharUtils.IsLineTerm(ch)) + { + ch = LexLineTerm(_sb); + lines++; + } + else + ChNext(); + _sb.Append(ch); + if (ch == '*' && ChCur == '/') + { + _sb.Append('/'); + ChNext(); + break; + } + } + // We support comment keywords. + KeyWordTable.KeyWordKind kind; + NormStr nstr = _lex._pool.Add(_sb); + if (_lex._kwt.IsKeyWord(nstr, out kind)) + return KeyToken.CreateKeyWord(GetSpan(), nstr.ToString(), kind.Kind, kind.IsContextKeyWord); + return new CommentToken(GetSpan(), _sb.ToString(), lines); + } + } + + /// + /// Lex a sequence of spacing characters. + /// Always returns null. + /// + private Token LexSpace() + { + Contracts.Assert(LexCharUtils.StartKind(ChCur) == LexStartKind.Space); + while (LexCharUtils.IsSpace(ChNext())) + ; + return null; + } + + /// + /// Lex a line termination character. Transforms CRLF into a single LF. + /// Updates the line mapping. When this "drops" a character and sb is not + /// null, it adds the character to sb. It does NOT add the returned character + /// to the sb. + /// + private char LexLineTerm(StringBuilder sb = null) + { + Contracts.Assert(LexCharUtils.StartKind(ChCur) == LexStartKind.LineTerm); + int ichMin = _cursor.IchCur; + if (ChCur == '\xD' && ChPeek(1) == '\xA') + { + if (sb != null) + sb.Append(ChCur); + ChNext(); + } + char ch = ChCur; + ChNext(); + + if (_ichMinTok == ichMin) + { + // Not nested. + _queue.Enqueue(new NewLineToken(GetSpan(), false)); + } + else + { + // Is nested. + _queue.Enqueue(new NewLineToken(GetTextSpan(ichMin, _cursor.IchCur), true)); + } + _fLineStart = true; + return ch; + } + + private Token LexPreProc() + { + // We don't currently support pre-processing. + return LexError(); + } + + /// + /// Skip over an error character. Always returns null. + /// REVIEW: Should we skip over multiple? + /// + private Token LexError() + { + _sb.Length = 0; + do + { + _sb.AppendFormat("{0}({1})", ChCur, LexCharUtils.GetUniEscape(ChCur)); + } while (LexCharUtils.StartKind(ChNext()) == LexStartKind.None && !Eof); + return new ErrorToken(GetSpan(), ErrId.BadChar, _sb.ToString()); + } + } + } +} diff --git a/src/Microsoft.ML.Transforms/Expression/MethodGenerator.cs b/src/Microsoft.ML.Transforms/Expression/MethodGenerator.cs new file mode 100644 index 0000000000..b2ebd1a21d --- /dev/null +++ b/src/Microsoft.ML.Transforms/Expression/MethodGenerator.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Reflection.Emit; +using Microsoft.ML.Internal.Utilities; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.Transforms +{ + /// + /// MethodGenerator is used to build a method by specifying the IL. + /// + internal sealed class MethodGenerator : IDisposable + { + private DynamicMethod _method; + + public ILGenerator Il { get; private set; } + + public MethodGenerator(string name, Type thisType, Type returnType, params Type[] parameterTypes) + { + Contracts.CheckNonEmpty(name, nameof(name)); + Contracts.CheckValue(thisType, nameof(thisType)); + Contracts.AssertValueOrNull(returnType); + Contracts.AssertValueOrNull(parameterTypes); + + _method = new DynamicMethod(name, returnType, parameterTypes, thisType); + Il = _method.GetILGenerator(); + } + + /// + /// Create and return a delegate of the given "delegateType" and currying the + /// given "thisObj". Note that "thisObj" may be null and "delegateType" should + /// match the types indicated when the MethodGenerator was created. + /// + public Delegate CreateDelegate(Type delegateType) + { + Contracts.CheckValue(delegateType, nameof(delegateType)); + + var del = _method.CreateDelegate(delegateType, null); + Dispose(); + return del; + } + + /// + /// This is idempotent (calling multiple times has the same affect as calling once). + /// + public void Dispose() + { + _method = null; + Il = null; + _locals = null; + } + + /// + /// Represents a temporary local. A MethodGenerator maintains a cache of temporary locals. + /// Clients can 'check-out' temporaries from the cache, use them, then release (Dispose) when + /// they are no longer needed so other clients can reuse the temporary to cut down on the number + /// of locals created. Note that Temporary is a struct, but should NOT be copied around. It is + /// critical that a stray copy of a Temporary is not disposed! + /// + /// We have two 'types' of temporaries: 'Regular' and 'Ref'. 'Ref' temporaries are special in that + /// they should be used when you need to use ldloca. Grouping this way should help the JIT optimize + /// local usage. + /// + public struct Temporary : IDisposable + { + private Action _dispose; + private bool _isRef; + + // Should only be created by MethodGenerator. Too bad C# can't enforce this without + // reversing the class nesting. + internal Temporary(Action dispose, LocalBuilder localBuilder, bool isRef) + { + Contracts.AssertValue(dispose); + Contracts.AssertValue(localBuilder); + + _dispose = dispose; + Local = localBuilder; + _isRef = isRef; + } + + public LocalBuilder Local { get; private set; } + + public void Dispose() + { + if (Local == null) + return; + + Contracts.AssertValue(_dispose); + _dispose(Local, _isRef); + Local = null; + _dispose = null; + } + } + + private struct LocalKey : IEquatable + { + public readonly Type Type; + public readonly bool IsRef; + + public LocalKey(Type type, bool isRef) + { + Contracts.AssertValue(type); + Type = type; + IsRef = isRef; + } + + public static bool operator ==(LocalKey key0, LocalKey key1) + { + return key0.Equals(key1); + } + + public static bool operator !=(LocalKey key0, LocalKey key1) + { + return !key0.Equals(key1); + } + + public override int GetHashCode() + { + return Hashing.CombineHash(Type.GetHashCode(), Hashing.HashInt(IsRef.GetHashCode())); + } + + public override bool Equals(object obj) + { + if (obj == null || !(obj is LocalKey)) + return false; + return Equals((LocalKey)obj); + } + + public bool Equals(LocalKey other) + { + return IsRef == other.IsRef && Type == other.Type; + } + } + + private Dictionary> _locals; + private Action _tempDisposer; + + public Temporary AcquireTemporary(Type type, bool isRef = false) + { + Contracts.CheckValue(type, nameof(type)); + Contracts.Check(Il != null, "Cannot access IL for a method that has already been created"); + + if (_tempDisposer == null) + _tempDisposer = ReleaseLocal; + + LocalKey key = new LocalKey(type, isRef); + List locals; + if (_locals != null && _locals.TryGetValue(key, out locals) && locals.Count > 0) + { + var temp = locals[locals.Count - 1]; + locals.RemoveAt(locals.Count - 1); + return new Temporary(_tempDisposer, temp, key.IsRef); + } + return new Temporary(_tempDisposer, Il.DeclareLocal(key.Type), key.IsRef); + } + + /// + /// Called by the Temporary struct's Dispose method, through the _tempDisposer delegate. + /// + private void ReleaseLocal(LocalBuilder localBuilder, bool isRef) + { + Contracts.AssertValue(localBuilder); + + LocalKey key = new LocalKey(localBuilder.LocalType, isRef); + + List locals; + if (_locals == null) + _locals = new Dictionary>(); + else if (_locals.TryGetValue(key, out locals)) + { + Contracts.Assert(!locals.Contains(localBuilder)); + locals.Add(localBuilder); + return; + } + + locals = new List(4); + _locals.Add(key, locals); + locals.Add(localBuilder); + } + } +} diff --git a/src/Microsoft.ML.Transforms/Expression/Node.cs b/src/Microsoft.ML.Transforms/Expression/Node.cs new file mode 100644 index 0000000000..69342e20c7 --- /dev/null +++ b/src/Microsoft.ML.Transforms/Expression/Node.cs @@ -0,0 +1,1206 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.IO; +using System.Reflection; +using Microsoft.ML.Data; +using Microsoft.ML.Internal.Utilities; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.Transforms +{ + using BL = System.Boolean; + using I4 = System.Int32; + using I8 = System.Int64; + using R4 = Single; + using R8 = Double; + using TX = ReadOnlyMemory; + + // Operator precedence. + internal enum Precedence : byte + { + None, + Conditional, + Coalesce, + Or, + And, + Compare, + Concat, + Add, + Mul, + Error, + PrefixUnary, + Power, + Postfix, + Primary, + Atomic, + } + + // Types of comparison chains. + internal enum CompareOp + { + Equal, + NotEqual, + IncrChain, + DecrChain + } + + // Binary operators. + internal enum BinaryOp + { + Coalesce, + Or, + And, + Add, + Sub, + Mul, + Div, + Mod, + Power, + Error + } + + // Unary operators. + internal enum UnaryOp + { + Not, + Minus, + } + + internal enum NodeKind + { + Lambda, + Param, + + Conditional, + BinaryOp, + UnaryOp, + Compare, + + Call, + List, + With, + WithLocal, + + Name, + Ident, + BoolLit, + NumLit, + StrLit, + } + + // Note: there are some arrays in LambdaBinder that are indexed by these enum values. + internal enum ExprTypeKind + { + // The order of these matters! + None, + Error, + + BL, + I4, + I8, + R4, + R8, + TX, + +#pragma warning disable MSML_GeneralName // Let's just allow this _ special casing for this internal enum. + _Lim, +#pragma warning restore MSML_GeneralName + Float = R4 + } + + internal abstract class NodeVisitor + { + // Visit methods for leaf node types. + public abstract void Visit(BoolLitNode node); + public abstract void Visit(StrLitNode node); + public abstract void Visit(NumLitNode node); + public abstract void Visit(NameNode node); + public abstract void Visit(IdentNode node); + public abstract void Visit(ParamNode node); + + // Visit methods for non-leaf node types. + // If PreVisit returns true, the children are visited and PostVisit is called. + public virtual bool PreVisit(LambdaNode node) { return true; } + public virtual bool PreVisit(UnaryOpNode node) { return true; } + public virtual bool PreVisit(BinaryOpNode node) { return true; } + public virtual bool PreVisit(ConditionalNode node) { return true; } + public virtual bool PreVisit(CompareNode node) { return true; } + public virtual bool PreVisit(CallNode node) { return true; } + public virtual bool PreVisit(ListNode node) { return true; } + public virtual bool PreVisit(WithNode node) { return true; } + public virtual bool PreVisit(WithLocalNode node) { return true; } + + public abstract void PostVisit(LambdaNode node); + public abstract void PostVisit(UnaryOpNode node); + public abstract void PostVisit(BinaryOpNode node); + public abstract void PostVisit(ConditionalNode node); + public abstract void PostVisit(CompareNode node); + public abstract void PostVisit(CallNode node); + public abstract void PostVisit(ListNode node); + public abstract void PostVisit(WithNode node); + public abstract void PostVisit(WithLocalNode node); + } + + internal abstract class PreVisitor : NodeVisitor + { + // Visit methods for non-leaf node types. + public abstract void Visit(LambdaNode node); + public abstract void Visit(UnaryOpNode node); + public abstract void Visit(BinaryOpNode node); + public abstract void Visit(ConditionalNode node); + public abstract void Visit(CompareNode node); + public abstract void Visit(CallNode node); + public abstract void Visit(ListNode node); + public abstract void Visit(WithNode node); + public abstract void Visit(WithLocalNode node); + + // PreVisit and PostVisit methods for non-leaf node types. + public override bool PreVisit(LambdaNode node) { Visit(node); return false; } + public override bool PreVisit(UnaryOpNode node) { Visit(node); return false; } + public override bool PreVisit(BinaryOpNode node) { Visit(node); return false; } + public override bool PreVisit(ConditionalNode node) { Visit(node); return false; } + public override bool PreVisit(CompareNode node) { Visit(node); return false; } + public override bool PreVisit(CallNode node) { Visit(node); return false; } + public override bool PreVisit(ListNode node) { Visit(node); return false; } + public override bool PreVisit(WithNode node) { Visit(node); return false; } + public override bool PreVisit(WithLocalNode node) { Visit(node); return false; } + + public override void PostVisit(LambdaNode node) { Contracts.Assert(false); } + public override void PostVisit(UnaryOpNode node) { Contracts.Assert(false); } + public override void PostVisit(BinaryOpNode node) { Contracts.Assert(false); } + public override void PostVisit(ConditionalNode node) { Contracts.Assert(false); } + public override void PostVisit(CompareNode node) { Contracts.Assert(false); } + public override void PostVisit(CallNode node) { Contracts.Assert(false); } + public override void PostVisit(ListNode node) { Contracts.Assert(false); } + public override void PostVisit(WithNode node) { Contracts.Assert(false); } + public override void PostVisit(WithLocalNode node) { Contracts.Assert(false); } + } + + internal abstract class ExprVisitor : NodeVisitor + { + // This just provides default implementations for non-expr related node types. + public override void Visit(NameNode node) { Contracts.Assert(false); } + public override void Visit(ParamNode node) { Contracts.Assert(false); } + + public override void PostVisit(LambdaNode node) { Contracts.Assert(false); } + } + + // Base class for all parse nodes. + internal abstract class Node + { + public readonly Token Token; + + protected Node(Token tok) + { + Contracts.AssertValue(tok); + Token = tok; + } + + public abstract NodeKind Kind { get; } + public abstract void Accept(NodeVisitor visitor); + + #region AsXxx and TestXxx members + + private T Cast() where T : Node + { + Contracts.Assert(false); + return (T)this; + } + + // TestXxx returns null if "this" is not of the correct type. + // In contrast AsXxx asserts that the default implementation is not being + // used (the derived type should override). TestXxx is for when you don't know + // and you will check the return result for null. AXxx is for when you do know. + public virtual LambdaNode AsPredicate { get { return Cast(); } } + public virtual LambdaNode TestPredicate { get { return null; } } + public virtual ParamNode AsParam { get { return Cast(); } } + public virtual ParamNode TestParam { get { return null; } } + public virtual ConditionalNode AsConditional { get { return Cast(); } } + public virtual ConditionalNode TestConditional { get { return null; } } + public virtual BinaryOpNode AsBinaryOp { get { return Cast(); } } + public virtual BinaryOpNode TestBinaryOp { get { return null; } } + public virtual UnaryOpNode AsUnaryOp { get { return Cast(); } } + public virtual UnaryOpNode TestUnaryOp { get { return null; } } + public virtual CompareNode AsCompare { get { return Cast(); } } + public virtual CompareNode TestCompare { get { return null; } } + public virtual CallNode AsCall { get { return Cast(); } } + public virtual CallNode TestCall { get { return null; } } + public virtual ListNode AsList { get { return Cast(); } } + public virtual ListNode TestList { get { return null; } } + public virtual WithNode AsWith { get { return Cast(); } } + public virtual WithNode TestWith { get { return null; } } + public virtual WithLocalNode AsWithLocal { get { return Cast(); } } + public virtual WithLocalNode TestWithLocal { get { return null; } } + public virtual NameNode AsName { get { return Cast(); } } + public virtual NameNode TestName { get { return null; } } + public virtual IdentNode AsIdent { get { return Cast(); } } + public virtual IdentNode TestIdent { get { return null; } } + public virtual BoolLitNode AsBoolLit { get { return Cast(); } } + public virtual BoolLitNode TestBoolLit { get { return null; } } + public virtual NumLitNode AsNumLit { get { return Cast(); } } + public virtual NumLitNode TestNumLit { get { return null; } } + public virtual StrLitNode AsStrLit { get { return Cast(); } } + public virtual StrLitNode TestStrLit { get { return null; } } + + // Non-leaf types. + public virtual ExprNode AsExpr { get { return Cast(); } } + public virtual ExprNode TestExpr { get { return null; } } + + #endregion CastXxx and TestXxx members + + public override string ToString() + { + using (var wrt = new StringWriter()) + { + NodePrinter.Print(this, wrt); + return wrt.ToString(); + } + } + } + + internal abstract class ExprNode : Node + { + protected ExprNode(Token tok) + : base(tok) + { + } + + public override ExprNode AsExpr { get { return this; } } + public override ExprNode TestExpr { get { return this; } } + + public ExprTypeKind ExprType { get; private set; } + public object ExprValue { get; private set; } + + private bool IsSimple(ExprTypeKind kind) + { + Contracts.Assert(ExprType != 0); + return ExprType == kind; + } + + public bool HasType { get { return ExprTypeKind.Error < ExprType && ExprType < ExprTypeKind._Lim; } } + public bool IsNone { get { return ExprType == ExprTypeKind.None; } } + public bool IsError { get { return ExprType == ExprTypeKind.Error; } } + + public bool IsBool { get { return IsSimple(ExprTypeKind.BL); } } + public bool IsNumber + { + get + { + return + IsSimple(ExprTypeKind.I4) || IsSimple(ExprTypeKind.I8) || + IsSimple(ExprTypeKind.R4) || IsSimple(ExprTypeKind.R8); + } + } + public bool IsI4 { get { return IsSimple(ExprTypeKind.I4); } } + public bool IsI8 { get { return IsSimple(ExprTypeKind.I8); } } + public bool IsRx { get { return IsSimple(ExprTypeKind.R4) || IsSimple(ExprTypeKind.R8); } } + public bool IsR4 { get { return IsSimple(ExprTypeKind.R4); } } + public bool IsR8 { get { return IsSimple(ExprTypeKind.R8); } } + public bool IsTX { get { return IsSimple(ExprTypeKind.TX); } } + + public ExprTypeKind SrcKind { get; private set; } + public bool NeedsConversion + { + get + { +#if DEBUG + // Assert that the conversion is valid. + if (SrcKind != ExprType) + { + ExprTypeKind kind; + bool tmp = LambdaBinder.CanPromote(false, SrcKind, ExprType, out kind); + Contracts.Assert(tmp && kind == ExprType); + } +#endif + return SrcKind != ExprType; + } + } + + public void SetType(ExprTypeKind kind) + { + Contracts.Assert(kind != 0); + Contracts.Assert(ExprValue == null); + Contracts.Assert(ExprType == 0 || ExprType == kind); + Contracts.Assert(SrcKind == ExprType); + ExprType = kind; + SrcKind = kind; + } + + public void SetType(ExprTypeKind kind, object value) + { + Contracts.Assert(kind != 0); + Contracts.Assert(value == null || value.GetType() == ToSysType(kind)); + Contracts.Assert(ExprValue == null); + Contracts.Assert(ExprType == 0 || ExprType == kind); + Contracts.Assert(SrcKind == ExprType); + ExprType = kind; + SrcKind = kind; + ExprValue = value; + } + + internal static Type ToSysType(ExprTypeKind kind) + { + switch (kind) + { + case ExprTypeKind.BL: + return typeof(BL); + case ExprTypeKind.I4: + return typeof(I4); + case ExprTypeKind.I8: + return typeof(I8); + case ExprTypeKind.R4: + return typeof(R4); + case ExprTypeKind.R8: + return typeof(R8); + case ExprTypeKind.TX: + return typeof(TX); + default: + return null; + } + } + + internal static ExprTypeKind ToExprTypeKind(Type type) + { + if (type == typeof(BL)) + return ExprTypeKind.BL; + if (type == typeof(I4)) + return ExprTypeKind.I4; + if (type == typeof(I8)) + return ExprTypeKind.I8; + if (type == typeof(R4)) + return ExprTypeKind.R4; + if (type == typeof(R8)) + return ExprTypeKind.R8; + if (type == typeof(TX)) + return ExprTypeKind.TX; + return ExprTypeKind.Error; + } + + public void SetValue(ExprNode expr) + { + Contracts.AssertValue(expr); + Contracts.Assert(expr.ExprType != 0); + SetType(expr.ExprType); + ExprValue = expr.ExprValue; + } + + public void SetValue(BL value) + { + SetType(ExprTypeKind.BL); + ExprValue = value; + } + + public void SetValue(BL? value) + { + SetType(ExprTypeKind.BL); + ExprValue = value; + } + + public void SetValue(I4 value) + { + SetType(ExprTypeKind.I4); + ExprValue = value; + } + + public void SetValue(I4? value) + { + SetType(ExprTypeKind.I4); + ExprValue = value; + } + + public void SetValue(I8 value) + { + SetType(ExprTypeKind.I8); + ExprValue = value; + } + + public void SetValue(I8? value) + { + SetType(ExprTypeKind.I8); + ExprValue = value; + } + + public void SetValue(R4 value) + { + SetType(ExprTypeKind.R4); + ExprValue = value; + } + + public void SetValue(R4? value) + { + SetType(ExprTypeKind.R4); + ExprValue = value; + } + + public void SetValue(R8 value) + { + SetType(ExprTypeKind.R8); + ExprValue = value; + } + + public void SetValue(R8? value) + { + SetType(ExprTypeKind.R8); + ExprValue = value; + } + + public void SetValue(TX value) + { + SetType(ExprTypeKind.TX); + ExprValue = value; + } + + public void SetValue(TX? value) + { + SetType(ExprTypeKind.TX); + ExprValue = value; + } + + public void Convert(ExprTypeKind kind) + { + Contracts.Assert(HasType); + + if (kind == ExprType) + return; + + Contracts.Assert(SrcKind == ExprType); + switch (kind) + { + case ExprTypeKind.I8: + Contracts.Assert(ExprType == ExprTypeKind.I4); + if (ExprValue != null) + { + Contracts.Assert(ExprValue is I4); + ExprValue = (I8)(I4)ExprValue; + } + break; + case ExprTypeKind.R4: + Contracts.Assert(ExprType == ExprTypeKind.I4); + if (ExprValue != null) + { + Contracts.Assert(ExprValue is I4); + ExprValue = (R4)(I4)ExprValue; + } + break; + case ExprTypeKind.R8: + Contracts.Assert(ExprType == ExprTypeKind.I4 || ExprType == ExprTypeKind.I8 || + ExprType == ExprTypeKind.R4); + if (ExprValue != null) + { + if (ExprType == ExprTypeKind.I4) + { + Contracts.Assert(ExprValue is I4); + ExprValue = (R8)(I4)ExprValue; + } + else if (ExprType == ExprTypeKind.I8) + { + Contracts.Assert(ExprValue is I8); + ExprValue = (R8)(I8)ExprValue; + } + else + { + Contracts.Assert(ExprValue is R4); + ExprValue = (R8)(R4)ExprValue; + } + } + break; + } + + // Set the new type. + ExprType = kind; + } + + public bool TryGet(out BL? value) + { + if (IsBool) + { + value = (BL?)ExprValue; + return true; + } + value = null; + return false; + } + + public bool TryGet(out I4? value) + { + if (IsI4) + { + value = (I4?)ExprValue; + return true; + } + value = null; + return false; + } + + public bool TryGet(out I8? value) + { + switch (ExprType) + { + default: + value = null; + return false; + case ExprTypeKind.I4: + case ExprTypeKind.I8: + break; + } + Convert(ExprTypeKind.I8); + value = (I8?)ExprValue; + return true; + } + + public bool TryGet(out R4? value) + { + switch (ExprType) + { + default: + value = null; + return false; + case ExprTypeKind.I4: + case ExprTypeKind.R4: + break; + } + Convert(ExprTypeKind.R4); + value = (R4?)ExprValue; + return true; + } + + public bool TryGet(out R8? value) + { + switch (ExprType) + { + default: + value = null; + return false; + case ExprTypeKind.I4: + case ExprTypeKind.I8: + case ExprTypeKind.R4: + case ExprTypeKind.R8: + break; + } + Convert(ExprTypeKind.R8); + value = (R8?)ExprValue; + return true; + } + + public bool TryGet(out TX? value) + { + if (IsTX) + { + value = (TX?)ExprValue; + return true; + } + value = null; + return false; + } + } + + internal sealed class LambdaNode : Node + { + public readonly ParamNode[] Vars; + public readonly ExprNode Expr; + + public DataViewType ResultType; + + public LambdaNode(Token tok, ParamNode[] vars, ExprNode expr) + : base(tok) + { + Contracts.AssertNonEmpty(vars); + Contracts.AssertValue(expr); + Vars = vars; + Expr = expr; + } + + public override NodeKind Kind { get { return NodeKind.Lambda; } } + public override LambdaNode AsPredicate { get { return this; } } + public override LambdaNode TestPredicate { get { return this; } } + + public override void Accept(NodeVisitor visitor) + { + Contracts.AssertValue(visitor); + if (visitor.PreVisit(this)) + { + foreach (var v in Vars) + v.Accept(visitor); + Expr.Accept(visitor); + visitor.PostVisit(this); + } + } + + public ParamNode FindParam(string name) + { + foreach (var v in Vars) + { + if (v.Name == name) + return v; + } + return null; + } + } + + internal sealed class ParamNode : Node + { + public readonly string Name; + public readonly int Index; + public readonly DataViewType Type; + public ExprTypeKind ExprType; + + public ParamNode(Token tok, string name, int index, DataViewType type) + : base(tok) + { + Contracts.AssertNonEmpty(name); + Contracts.Assert(index >= 0); + Contracts.AssertValueOrNull(type); + Name = name; + Index = index; + Type = type; + + if (type == null) + ExprType = ExprTypeKind.Error; + else if (type is TextDataViewType) + ExprType = ExprTypeKind.TX; + else if (type is BooleanDataViewType) + ExprType = ExprTypeKind.BL; + else if (type == NumberDataViewType.Int32) + ExprType = ExprTypeKind.I4; + else if (type == NumberDataViewType.Int64) + ExprType = ExprTypeKind.I8; + else if (type == NumberDataViewType.Single) + ExprType = ExprTypeKind.R4; + else if (type == NumberDataViewType.Double) + ExprType = ExprTypeKind.R8; + } + + public override NodeKind Kind { get { return NodeKind.Param; } } + public override ParamNode AsParam { get { return this; } } + public override ParamNode TestParam { get { return this; } } + + public override void Accept(NodeVisitor visitor) + { + Contracts.AssertValue(visitor); + visitor.Visit(this); + } + } + + // A NameNode identifies the name of something. An IdentNode is an expression node + // consisting of an identifier. + internal sealed class NameNode : Node + { + public readonly string Value; + + public NameNode(IdentToken tok) + : base(tok) + { + Contracts.AssertNonEmpty(tok.Value); + Value = tok.Value; + } + + public override NodeKind Kind { get { return NodeKind.Name; } } + public override NameNode AsName { get { return this; } } + public override NameNode TestName { get { return this; } } + + public override void Accept(NodeVisitor visitor) + { + Contracts.AssertValue(visitor); + visitor.Visit(this); + } + } + + internal sealed class IdentNode : ExprNode + { + public readonly string Value; + public readonly bool IsMissing; + + // If this ident node is a reference to another node, this + // is set to the node (by the Binder). + public Node Referent; + + public IdentNode(IdentToken tok) + : base(tok) + { + Contracts.AssertNonEmpty(tok.Value); + Value = tok.Value; + } + + public IdentNode(Token tok, string value, bool missing = false) + : base(tok) + { + Contracts.AssertNonEmpty(value); + Value = value; + IsMissing = missing; + } + + public override NodeKind Kind { get { return NodeKind.Ident; } } + public override IdentNode AsIdent { get { return this; } } + public override IdentNode TestIdent { get { return this; } } + + public override void Accept(NodeVisitor visitor) + { + Contracts.AssertValue(visitor); + visitor.Visit(this); + } + } + + internal sealed class NumLitNode : ExprNode + { + public NumLitNode(NumLitToken tok) + : base(tok) + { + switch (tok.Kind) + { + default: + Contracts.Assert(false); + SetType(ExprTypeKind.Error); + return; + + case TokKind.FltLit: + SetValue(tok.As().Value); + return; + + case TokKind.DblLit: + { + var t = tok.As(); + if (t.HasSuffix) + SetValue(t.Value); + else + SetValue((float)t.Value); + } + return; + + case TokKind.IntLit: + break; + } + Contracts.Assert(tok.Kind == TokKind.IntLit); + + var ilt = tok.As(); + var uu = ilt.Value; + bool lng = (ilt.IntKind & IntLitKind.Lng) != 0; + bool uns = (ilt.IntKind & IntLitKind.Uns) != 0; + + // If it is in I4 range or it is hex and in uint range, use I4. + // Otherwise, if it is in I8 range or it is hex, use I8. Otherwise, error. + // REVIEW: Should we do NA instead of error? + if (!lng && (uu <= I4.MaxValue || uu <= uint.MaxValue && ilt.IsHex && !uns)) + SetValue((I4)uu); + else if (uu <= I8.MaxValue || ilt.IsHex && !uns) + SetValue((I8)uu); + else + SetType(ExprTypeKind.Error); + } + + public NumLitToken Value + { + get { return Token.As(); } + } + + public override NodeKind Kind { get { return NodeKind.NumLit; } } + public override NumLitNode AsNumLit { get { return this; } } + public override NumLitNode TestNumLit { get { return this; } } + + public override void Accept(NodeVisitor visitor) + { + Contracts.AssertValue(visitor); + visitor.Visit(this); + } + } + + internal sealed class StrLitNode : ExprNode + { + public readonly TX Value; + + public StrLitNode(StrLitToken tok) + : base(tok) + { + Contracts.AssertValue(tok.Value); + Value = tok.Value.AsMemory(); + SetValue(Value); + } + + public override NodeKind Kind { get { return NodeKind.StrLit; } } + public override StrLitNode AsStrLit { get { return this; } } + public override StrLitNode TestStrLit { get { return this; } } + + public override void Accept(NodeVisitor visitor) + { + Contracts.AssertValue(visitor); + visitor.Visit(this); + } + } + + internal sealed class BoolLitNode : ExprNode + { + public BoolLitNode(Token tok) + : base(tok) + { + Contracts.AssertValue(tok); + Contracts.Assert(tok.Kind == TokKind.True || tok.Kind == TokKind.False); + SetValue(tok.Kind == TokKind.True ? true : false); + } + + public bool Value { get { return Token.Kind == TokKind.True; } } + + public override NodeKind Kind { get { return NodeKind.BoolLit; } } + public override BoolLitNode AsBoolLit { get { return this; } } + public override BoolLitNode TestBoolLit { get { return this; } } + + public override void Accept(NodeVisitor visitor) + { + Contracts.AssertValue(visitor); + visitor.Visit(this); + } + } + + internal sealed class UnaryOpNode : ExprNode + { + public readonly ExprNode Arg; + public readonly UnaryOp Op; + + public UnaryOpNode(Token tok, UnaryOp op, ExprNode arg) + : base(tok) + { + Contracts.AssertValue(arg); + Arg = arg; + Op = op; + } + + public override NodeKind Kind { get { return NodeKind.UnaryOp; } } + public override UnaryOpNode AsUnaryOp { get { return this; } } + public override UnaryOpNode TestUnaryOp { get { return this; } } + + public override void Accept(NodeVisitor visitor) + { + Contracts.AssertValue(visitor); + if (visitor.PreVisit(this)) + { + Arg.Accept(visitor); + visitor.PostVisit(this); + } + } + } + + internal sealed class BinaryOpNode : ExprNode + { + public readonly ExprNode Left; + public readonly ExprNode Right; + public readonly BinaryOp Op; + + public bool ReduceToLeft; + public bool ReduceToRight; + + public BinaryOpNode(Token tok, BinaryOp op, ExprNode left, ExprNode right) + : base(tok) + { + Contracts.AssertValue(left); + Contracts.AssertValue(right); + Left = left; + Right = right; + Op = op; + } + + public override NodeKind Kind { get { return NodeKind.BinaryOp; } } + public override BinaryOpNode AsBinaryOp { get { return this; } } + public override BinaryOpNode TestBinaryOp { get { return this; } } + + public override void Accept(NodeVisitor visitor) + { + Contracts.AssertValue(visitor); + if (visitor.PreVisit(this)) + { + Left.Accept(visitor); + Right.Accept(visitor); + visitor.PostVisit(this); + } + } + } + + /// + /// Node for the ternary conditional operator. + /// + internal sealed class ConditionalNode : ExprNode + { + public readonly ExprNode Cond; + public readonly ExprNode Left; + public readonly Token TokColon; + public readonly ExprNode Right; + + public ConditionalNode(Token tok, ExprNode cond, ExprNode left, Token tokColon, ExprNode right) + : base(tok) + { + Contracts.AssertValue(cond); + Contracts.AssertValue(left); + Contracts.AssertValueOrNull(tokColon); + Contracts.AssertValue(right); + Cond = cond; + Left = left; + Right = right; + TokColon = tokColon; + } + + public override NodeKind Kind { get { return NodeKind.Conditional; } } + public override ConditionalNode AsConditional { get { return this; } } + public override ConditionalNode TestConditional { get { return this; } } + + public override void Accept(NodeVisitor visitor) + { + Contracts.AssertValue(visitor); + if (visitor.PreVisit(this)) + { + Cond.Accept(visitor); + Left.Accept(visitor); + Right.Accept(visitor); + visitor.PostVisit(this); + } + } + } + + internal sealed class ListNode : Node + { + public readonly Node[] Items; + public readonly Token[] Delimiters; + + // Assumes ownership of items array and the delimiters array. + public ListNode(Token tok, Node[] items, Token[] delimiters) + : base(tok) + { + Contracts.AssertValue(items); + Contracts.AssertValueOrNull(delimiters); + Contracts.Assert(delimiters == null || delimiters.Length == items.Length - 1); + Items = items; + Delimiters = delimiters; + } + + public override NodeKind Kind { get { return NodeKind.List; } } + public override ListNode AsList { get { return this; } } + public override ListNode TestList { get { return this; } } + + public override void Accept(NodeVisitor visitor) + { + Contracts.AssertValue(visitor); + if (visitor.PreVisit(this)) + { + foreach (var item in Items) + { + Contracts.AssertValue(item); + item.Accept(visitor); + } + visitor.PostVisit(this); + } + } + } + + internal sealed class CallNode : ExprNode + { + // NameSpace and Dot can be null. + public readonly NameNode NameSpace; + public readonly Token Dot; + // Head and Args will never be null. + public readonly NameNode Head; + public readonly ListNode Args; + // CloseToken can be null. + public readonly Token CloseToken; + + public MethodInfo Method { get; private set; } + + public CallNode(Token tok, NameNode head, ListNode args, Token tokClose) + : base(tok) + { + Contracts.AssertValue(head); + Contracts.AssertValue(args); + Contracts.AssertValueOrNull(tokClose); + Head = head; + Args = args; + CloseToken = tokClose; + } + + public CallNode(Token tok, NameNode ns, Token dot, NameNode head, ListNode args, Token tokClose) + : base(tok) + { + Contracts.AssertValue(ns); + Contracts.AssertValue(dot); + Contracts.AssertValue(head); + Contracts.AssertValue(args); + Contracts.AssertValueOrNull(tokClose); + NameSpace = ns; + Dot = dot; + Head = head; + Args = args; + CloseToken = tokClose; + } + + public override NodeKind Kind { get { return NodeKind.Call; } } + public override CallNode AsCall { get { return this; } } + public override CallNode TestCall { get { return this; } } + + public override void Accept(NodeVisitor visitor) + { + Contracts.AssertValue(visitor); + if (visitor.PreVisit(this)) + { + if (NameSpace != null) + NameSpace.Accept(visitor); + Head.Accept(visitor); + Args.Accept(visitor); + visitor.PostVisit(this); + } + } + + public void SetMethod(MethodInfo meth) + { +#if DEBUG + var argCount = Args.Items.Length; + var ps = meth.GetParameters(); + if (Utils.Size(ps) > 0 && ps[ps.Length - 1].ParameterType.IsArray) + { + // Variable case. + Contracts.Assert(argCount >= ps.Length - 1); + Contracts.Assert(meth.ReturnType != typeof(void)); + } + else + Contracts.Assert(Utils.Size(ps) == argCount); +#endif + Method = meth; + } + } + + internal sealed class CompareNode : ExprNode + { + public readonly CompareOp Op; + public readonly ListNode Operands; + public readonly TokKind TidStrict; + public readonly TokKind TidLax; + + public ExprTypeKind ArgTypeKind; + + public CompareNode(Token tok, CompareOp op, ListNode operands) + : base(tok) + { + Contracts.AssertValue(operands); + Contracts.Assert(operands.Items.Length >= 2); + Contracts.AssertValue(operands.Delimiters); + Contracts.Assert(operands.Delimiters.Length == operands.Items.Length - 1); + Op = op; + Operands = operands; + + switch (op) + { + default: + Contracts.Assert(false); + goto case CompareOp.Equal; + case CompareOp.Equal: + TidLax = TokKind.Equ; + TidStrict = TokKind.EquEqu; + break; + case CompareOp.NotEqual: + TidLax = TokKind.LssGrt; + TidStrict = TokKind.BngEqu; + break; + case CompareOp.IncrChain: + TidLax = TokKind.LssEqu; + TidStrict = TokKind.Lss; + break; + case CompareOp.DecrChain: + TidLax = TokKind.GrtEqu; + TidStrict = TokKind.Grt; + break; + } + } + + public override NodeKind Kind { get { return NodeKind.Compare; } } + public override CompareNode AsCompare { get { return this; } } + public override CompareNode TestCompare { get { return this; } } + + public override void Accept(NodeVisitor visitor) + { + Contracts.AssertValue(visitor); + if (visitor.PreVisit(this)) + { + Operands.Accept(visitor); + visitor.PostVisit(this); + } + } + } + + /// + /// The parse node for a "with" expression. The grammar is: + /// + /// WithNode : + /// with ( WithLocalNode [ , WithLocalNode ]* ; Expr ) + /// + /// Note that a with expression with multiple WithLocalNodes gets expanded to multiple + /// nested WithNodes. This makes the code much simpler and easily allows a with-local to + /// reference all previous with-locals. + /// + internal sealed class WithNode : ExprNode + { + public readonly WithLocalNode Local; + public readonly ExprNode Body; + + public WithNode(Token tok, WithLocalNode local, ExprNode body) + : base(tok) + { + Contracts.AssertValue(local); + Contracts.AssertValue(body); + Local = local; + Body = body; + } + + public override NodeKind Kind { get { return NodeKind.With; } } + public override WithNode AsWith { get { return this; } } + public override WithNode TestWith { get { return this; } } + + public override void Accept(NodeVisitor visitor) + { + if (visitor.PreVisit(this)) + { + Local.Accept(visitor); + Body.Accept(visitor); + visitor.PostVisit(this); + } + } + } + + /// + /// The with-expression local assignment node. This contains both the name of the local and the + /// value expression. + /// + internal sealed class WithLocalNode : Node + { + public readonly string Name; + public readonly ExprNode Value; + + // Records whether this variable is used by the code. Set by the binder. + public int UseCount; + + // Index is assigned and used by the code generator. It indicates which local this + // is stored in, when UseCount > 1. Otherwise, it is -1. Note that when UseCount == 1, + // we inline code-gen for this local. + public int Index; + // The number of times the code for this local was generated. + public int GenCount; + + public WithLocalNode(Token tok, string name, ExprNode value) + : base(tok) + { + Contracts.AssertValue(name); + Contracts.AssertValue(value); + Name = name; + Value = value; + Index = -1; + } + + public override NodeKind Kind { get { return NodeKind.WithLocal; } } + public override WithLocalNode AsWithLocal { get { return this; } } + public override WithLocalNode TestWithLocal { get { return this; } } + + public override void Accept(NodeVisitor visitor) + { + if (visitor.PreVisit(this)) + { + Value.Accept(visitor); + visitor.PostVisit(this); + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.ML.Transforms/Expression/Printer.cs b/src/Microsoft.ML.Transforms/Expression/Printer.cs new file mode 100644 index 0000000000..42ccd8a5e0 --- /dev/null +++ b/src/Microsoft.ML.Transforms/Expression/Printer.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.CodeDom.Compiler; +using System.IO; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.Transforms +{ + using BL = System.Boolean; + using I4 = System.Int32; + using I8 = System.Int64; + using R4 = Single; + using R8 = Double; + using TX = ReadOnlyMemory; + + // Simple pretty-printing visitor + internal sealed class NodePrinter : PreVisitor + { + private readonly bool _showTypes; + private readonly bool _showValues; + private readonly IndentedTextWriter _wrt; + + private NodePrinter(IndentedTextWriter wrt, bool showTypes, bool showValues) + { + Contracts.AssertValue(wrt); + + _showTypes = showTypes; + _showValues = showValues; + _wrt = wrt; + } + + // Public entry point for prettyprinting TEXL parse trees + public static void Print(Node node, TextWriter writer, bool showTypes = false, bool showValues = false) + { + Contracts.AssertValue(node); + + var wrt = new IndentedTextWriter(writer, " "); + NodePrinter printer = new NodePrinter(wrt, showTypes, showValues); + node.Accept(printer); + } + + private bool NeedParensLeft(Precedence precLeft, Precedence precOp) + { + if (precLeft < precOp) + return true; + if (precLeft > precOp) + return false; + + // Power is right associative. + return precOp == Precedence.Power; + } + + private bool NeedParensRight(Precedence precOp, Precedence precRight) + { + if (precOp == Precedence.Postfix) + { + // Indexing is the only postfix operator, and it never + // needs parens around the right operand. + return false; + } + + if (precOp > precRight) + return true; + if (precOp < precRight) + return false; + + // Power is right associative. + return precOp != Precedence.Power; + } + + private Precedence GetPrec(Node node) + { + Contracts.Assert(node is ExprNode); + + switch (node.Kind) + { + case NodeKind.BinaryOp: + return GetPrec(node.AsBinaryOp.Op); + + case NodeKind.UnaryOp: + return Precedence.PrefixUnary; + + case NodeKind.Compare: + return Precedence.Compare; + + case NodeKind.Call: + case NodeKind.With: + return Precedence.Primary; + + case NodeKind.Ident: + case NodeKind.BoolLit: + case NodeKind.NumLit: + case NodeKind.StrLit: + return Precedence.Atomic; + + default: + Contracts.Assert(false, "Unexpected node kind in GetPrec - should only see ExprNode kinds"); + return Precedence.None; + } + } + + private Precedence GetPrec(BinaryOp op) + { + switch (op) + { + case BinaryOp.Or: + return Precedence.Or; + case BinaryOp.And: + return Precedence.And; + case BinaryOp.Add: + case BinaryOp.Sub: + return Precedence.Add; + case BinaryOp.Mul: + case BinaryOp.Div: + case BinaryOp.Mod: + return Precedence.Mul; + case BinaryOp.Power: + return Precedence.Power; + case BinaryOp.Error: + return Precedence.None; + default: + Contracts.Assert(false); + return Precedence.None; + } + } + + private string GetString(BinaryOp op) + { + switch (op) + { + case BinaryOp.Or: + return " or "; + case BinaryOp.And: + return " and "; + case BinaryOp.Add: + return " + "; + case BinaryOp.Sub: + return " - "; + case BinaryOp.Mul: + return " * "; + case BinaryOp.Div: + return " / "; + case BinaryOp.Mod: + return " % "; + case BinaryOp.Power: + return " ^ "; + case BinaryOp.Error: + return " "; + default: + Contracts.Assert(false); + return " "; + } + } + + private string GetString(UnaryOp op) + { + switch (op) + { + case UnaryOp.Not: + return "not "; + case UnaryOp.Minus: + return "-"; + default: + Contracts.Assert(false); + return " "; + } + } + + private string GetString(TokKind tidCompare) + { + switch (tidCompare) + { + case TokKind.Equ: + return " = "; + case TokKind.EquEqu: + return " == "; + case TokKind.LssGrt: + return " <> "; + case TokKind.BngEqu: + return " != "; + case TokKind.Lss: + return " < "; + case TokKind.LssEqu: + return " <= "; + case TokKind.GrtEqu: + return " >= "; + case TokKind.Grt: + return " > "; + + default: + Contracts.Assert(false); + return " "; + } + } + + private bool TryShowValue(ExprNode node) + { + if (!_showValues) + return false; + if (node.ExprValue == null) + return false; + + ShowValueCore(node); + ShowType(node); + + return true; + } + + private void ShowValueCore(ExprNode node) + { + Contracts.AssertValue(node); + Contracts.AssertValue(node.ExprValue); + + var value = node.ExprValue; + switch (node.ExprType) + { + case ExprTypeKind.I4: + Show((I4)value); + break; + case ExprTypeKind.I8: + Show((I8)value); + break; + case ExprTypeKind.R4: + Show((R4)value); + break; + case ExprTypeKind.R8: + Show((R8)value); + break; + case ExprTypeKind.BL: + Show((BL)value); + break; + case ExprTypeKind.TX: + Show((TX)value); + break; + default: + Contracts.Assert(false, "Unknown type"); + break; + } + } + + private void Show(I4 x) + { + _wrt.Write(x); + } + + private void Show(I8 x) + { + _wrt.Write(x); + } + + private void Show(R4 x) + { + if (R4.IsNaN(x)) + _wrt.Write("NA"); + else + _wrt.Write("{0:R}", x); + } + + private void Show(R8 x) + { + if (R8.IsNaN(x)) + _wrt.Write("NA"); + else + _wrt.Write("{0:R}", x); + } + + private void Show(BL x) + { + if (!x) + _wrt.Write("false"); + else + _wrt.Write("true"); + } + + private void Show(TX str) + { + int len = str.Length; + if (len > 100) + len = 97; // Leave room for ... + + _wrt.Write('"'); + foreach (var ch in str.Span) + { + // Replace problematic characters with space. + // REVIEW: Which characters should we replace? + if (ch < ' ' || ch == '"') + _wrt.Write(' '); + else + _wrt.Write(ch); + } + if (len < str.Length) + _wrt.Write("..."); + _wrt.Write('"'); + } + + private void ShowType(ExprNode node) + { + if (!_showTypes) + return; + if (node.IsNone) + return; + + _wrt.Write(':'); + _wrt.Write(node.ExprType.ToString()); + } + + private void ShowType(ParamNode node) + { + if (!_showTypes) + return; + if (node.ExprType == ExprTypeKind.None) + return; + + _wrt.Write(':'); + _wrt.Write(node.ExprType.ToString()); + } + + public override void Visit(BoolLitNode node) + { + Contracts.AssertValue(node); + _wrt.Write(node.Value ? "true" : "false"); + ShowType(node); + } + + public override void Visit(StrLitNode node) + { + Contracts.AssertValue(node); + Show(node.Value); + ShowType(node); + } + + public override void Visit(NumLitNode node) + { + Contracts.AssertValue(node); + _wrt.Write(node.Value.ToString()); + ShowType(node); + } + + public override void Visit(NameNode node) + { + Contracts.AssertValue(node); + _wrt.Write(node.Value); + } + + public override void Visit(IdentNode node) + { + Contracts.AssertValue(node); + + if (TryShowValue(node)) + return; + _wrt.Write(node.Value); + ShowType(node); + } + + public override void Visit(ParamNode node) + { + Contracts.AssertValue(node); + _wrt.Write(node.Name); + ShowType(node); + } + + public override void Visit(LambdaNode node) + { + Contracts.AssertValue(node); + if (node.Vars.Length == 1) + node.Vars[0].Accept(this); + else + { + _wrt.Write('('); + var pre = ""; + foreach (var v in node.Vars) + { + _wrt.Write(pre); + v.Accept(this); + pre = ""; + } + _wrt.Write(")"); + } + _wrt.Write(" => "); + node.Expr.Accept(this); + } + + public override void Visit(UnaryOpNode node) + { + Contracts.AssertValue(node); + + if (TryShowValue(node)) + return; + + Precedence prec = GetPrec(node.Arg); + _wrt.Write(GetString(node.Op)); + if (prec < Precedence.PrefixUnary) + _wrt.Write('('); + node.Arg.Accept(this); + if (prec < Precedence.PrefixUnary) + _wrt.Write(')'); + ShowType(node); + } + + public override void Visit(BinaryOpNode node) + { + Contracts.AssertValue(node); + + if (TryShowValue(node)) + return; + + Precedence prec = GetPrec(node.Op); + Precedence prec1 = GetPrec(node.Left); + Precedence prec2 = GetPrec(node.Right); + bool parens1 = NeedParensLeft(prec1, prec); + bool parens2 = NeedParensRight(prec, prec2); + + if (parens1) + _wrt.Write('('); + node.Left.Accept(this); + if (parens1) + _wrt.Write(')'); + + _wrt.Write(GetString(node.Op)); + + if (parens2) + _wrt.Write('('); + node.Right.Accept(this); + if (parens2) + _wrt.Write(')'); + + ShowType(node); + } + + public override void Visit(ConditionalNode node) + { + Contracts.AssertValue(node); + + if (TryShowValue(node)) + return; + + Precedence prec0 = GetPrec(node.Cond); + Precedence prec1 = GetPrec(node.Left); + Precedence prec2 = GetPrec(node.Right); + bool parens0 = NeedParensLeft(prec0, Precedence.Conditional); + + if (parens0) + _wrt.Write('('); + node.Cond.Accept(this); + if (parens0) + _wrt.Write(')'); + + _wrt.Write(" ? "); + node.Left.Accept(this); + _wrt.Write(" : "); + node.Right.Accept(this); + + ShowType(node); + } + + public override void Visit(CompareNode node) + { + Contracts.AssertValue(node); + + if (TryShowValue(node)) + return; + + TokKind tidLax = node.TidLax; + TokKind tidStrict = node.TidStrict; + string strLax = GetString(tidLax); + string strStrict = GetString(tidStrict); + + string str = string.Empty; + string strOp = string.Empty; + for (int i = 0; ;) + { + _wrt.Write(strOp); + var arg = node.Operands.Items[i]; + var prec = GetPrec(arg); + if (prec <= Precedence.Compare) + _wrt.Write('('); + arg.Accept(this); + if (prec <= Precedence.Compare) + _wrt.Write(')'); + if (++i >= node.Operands.Items.Length) + break; + var tid = node.Operands.Delimiters[i - 1].Kind; + Contracts.Assert(tid == tidLax || tid == tidStrict); + strOp = tid == tidLax ? strLax : strStrict; + } + + ShowType(node); + } + + public override void Visit(CallNode node) + { + Contracts.AssertValue(node); + + if (TryShowValue(node)) + return; + + if (node.NameSpace != null) + { + node.NameSpace.Accept(this); + _wrt.Write('.'); + } + node.Head.Accept(this); + _wrt.Write('('); + node.Args.Accept(this); + _wrt.Write(')'); + ShowType(node); + } + + public override void Visit(ListNode node) + { + Contracts.AssertValue(node); + + int count = node.Items.Length; + if (count == 0) + return; + + if (node.Delimiters == null) + { + foreach (var child in node.Items) + child.Accept(this); + } + else if (count <= 6) + { + node.Items[0].Accept(this); + for (int i = 1; i < count; i++) + { + _wrt.Write(", "); + node.Items[i].Accept(this); + } + } + else + { + for (int i = 0; i < 5; i++) + { + node.Items[i].Accept(this); + _wrt.Write(", "); + } + _wrt.Write("..., "); + node.Items[count - 1].Accept(this); + } + } + + public override void Visit(WithNode node) + { + Contracts.AssertValue(node); + + if (TryShowValue(node)) + return; + + _wrt.Write("with("); + node.Local.Accept(this); + _wrt.Write("; "); + node.Body.Accept(this); + _wrt.Write(")"); + + ShowType(node); + } + + public override void Visit(WithLocalNode node) + { + Contracts.AssertValue(node); + + _wrt.Write(node.Name); + _wrt.Write(" = "); + node.Value.Accept(this); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.ML.Transforms/Expression/TokKind.cs b/src/Microsoft.ML.Transforms/Expression/TokKind.cs new file mode 100644 index 0000000000..cc18561922 --- /dev/null +++ b/src/Microsoft.ML.Transforms/Expression/TokKind.cs @@ -0,0 +1,212 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.ML.Internal.Utilities; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.Transforms +{ + internal enum TokKind + { + None, + + // Miscellaneous + Eof, + Error, + ErrorInline, + + // Literals + IntLit, + FltLit, + DblLit, + CharLit, + StrLit, + + // Noise + Comment, + NewLine, + + // Punctuators + + Add, // + + AddAdd, + AddEqu, + Sub, // - + SubSub, + SubEqu, + SubGrt, + Mul, // * + MulEqu, + Div, // / + DivEqu, + Per, // % + PerEqu, + + Car, // ^ + CarEqu, + Amp, // & + AmpAmp, + AmpEqu, + Bar, // | + BarBar, + BarEqu, + + Til, // ~ + Bng, // ! + BngEqu, + + Equ, // = + EquEqu, + EquGrt, + Lss, + LssLss, + LssEqu, + LssGrt, + LssLssEqu, + Grt, + GrtGrt, + GrtEqu, + GrtGrtEqu, + + Que, // ? + QueQue, + + Dot, + Comma, + Colon, + ColonColon, + Semi, + + OpenCurly, + OpenParen, + OpenSquare, + + CloseCurly, + CloseParen, + CloseSquare, + + // Words - identifier and key words + Ident, + + False, + True, + Not, + And, + Or, + + // REVIEW: These are specific to the NetParser. Use a general mechanism. + Const, + Input, + Output, + Hidden, + Share, + Sigmoid, + Linear, + SoftMax, + RectifiedLinear, + Square, + Sqrt, + SoftRectifiedLinear, + Tanh, + BoundedRectifiedLinear, + From, + All, + Where, + Convolve, + Pool, + Abs, + Bittest, + Max, + Mean, + Response, + Norm, + FloatsFromBytes, + Param, + Auto, + + // REVIEW: These are specific to the ExprTransform parser. Use a general mechanism. + With, + } + + public enum ErrId + { + None, + BadChar, + BadEscape, + CharConstEmpty, + CharConstTooLong, + FloatOverflow, + IntOverflow, + NewlineInConst, + UnterminatedComment, + UnterminatedString, + VerbatimLiteralExpected, + + // Pre-processing related errors + BadPreProcPos, + EndOfPreLineExpected, + IdentExpected, + PreProcDirExpected, + UniEscInPreProc, + } + + internal static class ErrIdExt + { + public static string GetMsgFmt(this ErrId eid, out int carg) + { + carg = 0; + switch (eid) + { + case ErrId.BadChar: + carg = 1; + return "Unexpected character '{0}'"; + case ErrId.BadEscape: + return "Unrecognized escape sequence"; + case ErrId.CharConstEmpty: + return "Empty character literal"; + case ErrId.CharConstTooLong: + return "Too many characters in character literal"; + case ErrId.FloatOverflow: + carg = 1; + return "Floating-point constant is outside the range of type '{0}'"; + case ErrId.IntOverflow: + return "Integral constant is too large"; + case ErrId.NewlineInConst: + return "Newline in constant"; + case ErrId.UnterminatedComment: + return "End-of-input found in comment"; + case ErrId.UnterminatedString: + return "End-of-input found in string or character literal"; + case ErrId.VerbatimLiteralExpected: + return @"Keyword, identifier, or string expected after verbatim specifier: @"; + + case ErrId.BadPreProcPos: + return "Preprocessor directives must be on a new line"; + case ErrId.EndOfPreLineExpected: + return "Single-line comment or end-of-line expected"; + case ErrId.IdentExpected: + return "Identifier expected"; + case ErrId.PreProcDirExpected: + return "Preprocessor directive expected"; + case ErrId.UniEscInPreProc: + return "Unicode escapes not permitted in preprocessor directives"; + + default: + Contracts.Assert(false, "Unknown error id: " + eid); + return "Unknown error"; + } + } + + public static string GetMsg(this ErrId eid, params object[] args) + { + int carg; + string fmt = eid.GetMsgFmt(out carg); + Contracts.Assert(carg == Utils.Size(args)); + if (carg == 0) + return fmt; + string msg = string.Format(fmt, args); + return msg; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.ML.Transforms/Expression/TokenCursor.cs b/src/Microsoft.ML.Transforms/Expression/TokenCursor.cs new file mode 100644 index 0000000000..bf59310197 --- /dev/null +++ b/src/Microsoft.ML.Transforms/Expression/TokenCursor.cs @@ -0,0 +1,196 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.Transforms +{ + using Conditional = System.Diagnostics.ConditionalAttribute; + + internal sealed class TokenCursor + { + // This is the token stream. We cache items as we consume them. + // This code assumes that the enumerator will produce an Eof token, + // When the Eof is produced, _tokens is disposed and set to null. + private IEnumerator _tokens; + + // The cache buffer. + private Token[] _buffer; + + // The logical token index of _buffer[0]. + private int _itokBase; + + // The limit of the cached range within _buffer (relative to the buffer). + private int _itokLim; + + // The current position within the buffer. + private int _itokCur; + private Token _tokCur; + private TokKind _tidCur; + + // If this is >= 0, this position is "pinned" - we need to keep it in the buffer. + // This is to support rewinding. + private int _itokPin; + + public TokenCursor(IEnumerable tokens) + { + Contracts.AssertValue(tokens); + _tokens = tokens.GetEnumerator(); + _buffer = new Token[0x0400]; + _itokPin = -1; + + // Get the first token. + FetchCore(); + + _tokCur = _buffer[_itokCur]; + _tidCur = _tokCur.Kind; + + AssertValid(); + } + + [Conditional("DEBUG")] + private void AssertValid() + { + Contracts.AssertValue(_buffer); + + // _itokCur should never reach _itokLim. + Contracts.Assert(0 <= _itokCur && _itokCur < _itokLim && _itokLim <= _buffer.Length); + + // The last token in the buffer is Eof iff _tokens is null. + Contracts.Assert((_tokens != null) == (_buffer[_itokLim - 1].Kind != TokKind.Eof)); + + // _tokCur and _tidCur should match _itokCur. + Contracts.Assert(_tokCur == _buffer[_itokCur]); + Contracts.Assert(_tidCur == _tokCur.Kind); + } + + public Token TokCur + { + get + { + AssertValid(); + return _tokCur; + } + } + + public TokKind TidCur + { + get + { + AssertValid(); + return _tidCur; + } + } + + public TokKind CtxCur + { + get + { + AssertValid(); + return _tokCur.KindContext; + } + } + + // This fetches an additional token from _tokens and caches it. + // If needed, makes room in the cache (_buffer) by either sliding items + // or resizing _buffer. + private void FetchToken() + { + Contracts.Assert(_tokens != null); + + if (_itokLim >= _buffer.Length) + { + // Need more room. See if we can "slide". + if (_itokCur > 0 && _itokPin != 0) + { + int itokMin = _itokCur; + if (0 < _itokPin && _itokPin < itokMin) + itokMin = _itokPin; + int itokSrc = itokMin; + int itokDst = 0; + while (itokSrc < _itokLim) + _buffer[itokDst++] = _buffer[itokSrc++]; + if (0 < _itokPin) + _itokPin -= itokMin; + _itokLim -= itokMin; + _itokCur -= itokMin; + _itokBase += itokMin; + } + else + { + // Need to resize the buffer. + Array.Resize(ref _buffer, 2 * _buffer.Length); + } + } + + FetchCore(); + } + + private void FetchCore() + { + Contracts.Assert(_tokens != null); + Contracts.Assert(_itokLim < _buffer.Length); + + if (!_tokens.MoveNext()) + { + Contracts.Assert(false, "Token stream should end with an Eof token!"); + throw Contracts.Except(); + } + + // Cache the new token. + Token tok = _buffer[_itokLim++] = _tokens.Current; + Contracts.Assert(tok != null); + + // See if we're done pulling items from _tokens. + if (tok.Kind == TokKind.Eof) + { + _tokens.Dispose(); + _tokens = null; + } + } + + // This expects that _itokCur + ditok is either within the buffered token range or + // just at the end of it. In other words, it does not support skipping tokens. + private void MoveBy(int ditok) + { + AssertValid(); + Contracts.Assert(-_itokCur <= ditok && ditok <= _itokLim - _itokCur); + Contracts.Assert(ditok < _itokLim - _itokCur || _tokens != null); + + while (ditok >= _itokLim - _itokCur) + FetchToken(); + + _itokCur += ditok; + _tokCur = _buffer[_itokCur]; + _tidCur = _tokCur.Kind; + AssertValid(); + } + + public TokKind TidNext() + { + AssertValid(); + if (_tidCur != TokKind.Eof) + MoveBy(1); + return _tidCur; + } + + /// + /// This expects that ItokCur + ditok is either within the buffered token range or just + /// at the end of it. In other words, it does not support skipping tokens. + /// + public Token TokPeek(int ditok) + { + AssertValid(); + Contracts.Assert(-_itokCur <= ditok && ditok <= _itokLim - _itokCur); + Contracts.Assert(ditok < _itokLim - _itokCur || _tokens != null); + + while (ditok >= _itokLim - _itokCur) + FetchToken(); + + return _buffer[_itokCur + ditok]; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.ML.Transforms/Expression/Tokens.cs b/src/Microsoft.ML.Transforms/Expression/Tokens.cs new file mode 100644 index 0000000000..be428d1823 --- /dev/null +++ b/src/Microsoft.ML.Transforms/Expression/Tokens.cs @@ -0,0 +1,292 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Globalization; +using System.IO; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.Transforms +{ + internal struct TextSpan + { + public readonly int Min; + public readonly int Lim; + + public TextSpan(int ichMin, int ichLim) + { + Contracts.Assert(0 <= ichMin && ichMin <= ichLim); + Min = ichMin; + Lim = ichLim; + } + + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "({0},{1})", Min, Lim); + } + } + + internal abstract class Token + { + public readonly TokKind Kind; + public readonly TokKind KindContext; + public readonly TextSpan Span; + + protected Token(TextSpan span, TokKind tid) + { + Span = span; + Kind = tid; + KindContext = tid; + } + + protected Token(TextSpan span, TokKind tid, TokKind tidContext) + { + // Currently the only contextual variability is that an identifier might double as a keyword. + Contracts.Assert(tidContext == tid || tid == TokKind.Ident); + Span = span; + Kind = tid; + KindContext = tidContext; + } + + public T As() where T : Token + { + Contracts.Assert(this is T); + return (T)this; + } + + public override string ToString() + { + return Kind.ToString(); + } + } + + // Keyword/punctuation token + internal sealed class KeyToken : Token + { + public static KeyToken Create(TextSpan span, TokKind tid) + { + return new KeyToken(span, tid); + } + + public static Token CreateKeyWord(TextSpan span, string str, TokKind tid, bool isContextKeyWord) + { + if (isContextKeyWord) + return new IdentToken(span, str, tid); + return new KeyToken(span, tid); + } + + private KeyToken(TextSpan span, TokKind tid) + : base(span, tid) + { + } + } + + internal sealed class IdentToken : Token + { + public readonly string Value; + public IdentToken(TextSpan span, string val) : base(span, TokKind.Ident) { Value = val; } + public IdentToken(TextSpan span, string val, TokKind tidContext) : base(span, TokKind.Ident, tidContext) { Value = val; } + public override string ToString() + { + if (KindContext != TokKind.Ident) + return "ContextKeyword: " + Value; + return "Ident: " + Value; + } + } + + [Flags] + internal enum IntLitKind : byte + { + None = 0x00, + Uns = 0x01, + Lng = 0x02, + Hex = 0x04, + + UnsLng = Uns | Lng, + } + + internal abstract class NumLitToken : Token + { + protected NumLitToken(TextSpan span, TokKind tid) + : base(span, tid) + { + } + } + + internal sealed class IntLitToken : NumLitToken + { + public readonly ulong Value; + public readonly IntLitKind IntKind; // The kind specified by suffixes. + + public IntLitToken(TextSpan span, ulong val, IntLitKind ilk) + : base(span, TokKind.IntLit) + { + Value = val; + IntKind = ilk; + } + + public override string ToString() + { + string suff1 = (IntKind & IntLitKind.Uns) != 0 ? "U" : ""; + string suff2 = (IntKind & IntLitKind.Lng) != 0 ? "L" : ""; + string fmt; + + if (IsHex) + fmt = Value < 0x0000000100000000 ? "0x{0:X8}{1}{2}" : "0x{0:X16}{1}{2}"; + else + fmt = "{0}{1}{2}"; + return string.Format(fmt, Value, suff1, suff2); + } + + public bool IsHex { get { return (IntKind & IntLitKind.Hex) != 0; } } + } + + internal sealed class FltLitToken : NumLitToken + { + public readonly float Value; + public FltLitToken(TextSpan span, float val) : base(span, TokKind.FltLit) { Value = val; } + public override string ToString() + { + if (float.IsPositiveInfinity(Value)) + return "1e1000f"; + return Value.ToString("R") + "f"; + } + } + + internal sealed class DblLitToken : NumLitToken + { + public readonly double Value; + // Whether this literal has an explicit d/D suffix. + public readonly bool HasSuffix; + + public DblLitToken(TextSpan span, double val, bool hasSuf) + : base(span, TokKind.DblLit) + { + Value = val; + HasSuffix = hasSuf; + } + + public override string ToString() + { + string res; + if (double.IsPositiveInfinity(Value)) + res = "1e1000"; + else + res = Value.ToString("R"); + if (HasSuffix) + res += "d"; + else if (AllDigits(res)) + res += ".0"; + return res; + } + + private static bool AllDigits(string s) + { + Contracts.AssertNonEmpty(s); + for (int i = 0; i < s.Length; i++) + { + if ((uint)(s[i] - '0') > 9) + return false; + } + return true; + } + } + + internal sealed class CharLitToken : Token + { + public readonly char Value; + public CharLitToken(TextSpan span, char val) : base(span, TokKind.CharLit) { Value = val; } + public override string ToString() + { + if (Value < ' ' || Value >= 0x7F) + return string.Format(@"'\u{0:X4}'", (int)Value); + if (Value == '\'') + return @"'\''"; + return string.Format("'{0}'", Value); + } + } + + internal sealed class StrLitToken : Token + { + public readonly string Value; + public StrLitToken(TextSpan span, string val) : base(span, TokKind.StrLit) { Value = val; } + public override string ToString() + { + StringWriter wrt = new StringWriter(); + Write(wrt, Value); + return wrt.ToString(); + } + + public static void Write(TextWriter wrt, string str) + { + Contracts.AssertValue(str); + + wrt.Write('"'); + int ich = 0; + for (; ich < str.Length; ich++) + { + char ch = str[ich]; + if (ch < ' ' || ch >= 0x7F) + wrt.Write(@"\u{0:X4}", (int)ch); + else + { + if (ch == '\\' || ch == '"') + wrt.Write('\\'); + wrt.Write(ch); + } + } + wrt.Write('"'); + } + } + + internal sealed class CommentToken : Token + { + public readonly string Text; + public readonly int NewLineCount; + public CommentToken(TextSpan span, string val, int lines) + : base(span, TokKind.Comment) + { + Text = val; + NewLineCount = lines; + } + public override string ToString() { return "Comment: " + Text; } + } + + internal sealed class NewLineToken : Token + { + public readonly bool Nested; + public NewLineToken(TextSpan span, bool fNested) + : base(span, TokKind.NewLine) + { + Nested = fNested; + } + public override string ToString() { return Nested ? "NewLine" : "NewLine"; } + } + + internal sealed class ErrorToken : Token + { + public readonly ErrId Id; + public readonly object[] Args; + + public ErrorToken(TextSpan span, ErrId eid, params object[] args) + : base(span, TokKind.Error) + { + Id = eid; + Args = args; + } + + public override string ToString() + { + return Id.GetMsg(Args); + } + } + + internal sealed class EofToken : Token + { + public EofToken(TextSpan span) + : base(span, TokKind.Eof) + { + } + } +} \ No newline at end of file diff --git a/src/Microsoft.ML.Transforms/ExpressionCatalog.cs b/src/Microsoft.ML.Transforms/ExpressionCatalog.cs new file mode 100644 index 0000000000..feb9a60efe --- /dev/null +++ b/src/Microsoft.ML.Transforms/ExpressionCatalog.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.ML.Data; +using Microsoft.ML.Transforms; + +namespace Microsoft.ML +{ + public static class ExpressionCatalog + { + /// + /// Creates an . + /// + /// The . + /// Name of the column resulting from the transformation of . + /// This column's data type will be the same as that of the input column. + /// The expression to apply to to create the column . + /// The names of the input columns. + public static ExpressionEstimator Expression(this TransformsCatalog catalog, string outputColumnName, string expression, params string[] inputColumnNames) + => new ExpressionEstimator(CatalogUtils.GetEnvironment(catalog), new ExpressionEstimator.ColumnOptions(outputColumnName, inputColumnNames, expression)); + } +} diff --git a/src/Microsoft.ML.Transforms/ExpressionTransformer.cs b/src/Microsoft.ML.Transforms/ExpressionTransformer.cs new file mode 100644 index 0000000000..9c52cb417d --- /dev/null +++ b/src/Microsoft.ML.Transforms/ExpressionTransformer.cs @@ -0,0 +1,992 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using Microsoft.ML; +using Microsoft.ML.CommandLine; +using Microsoft.ML.Data; +using Microsoft.ML.Data.Conversion; +using Microsoft.ML.Internal.Utilities; +using Microsoft.ML.Runtime; +using Microsoft.ML.Transforms; + +[assembly: LoadableClass(ExpressionTransformer.Summary, typeof(IDataTransform), typeof(ExpressionTransformer), typeof(ExpressionTransformer.Options), typeof(SignatureDataTransform), + "Expression Transform", "Expression", "ExpressionTransform", ExpressionTransformer.LoaderSignature, "Expr")] + +[assembly: LoadableClass(ExpressionTransformer.Summary, typeof(IDataTransform), typeof(ExpressionTransformer), null, typeof(SignatureLoadDataTransform), + "Expression Transform", ExpressionTransformer.LoaderSignature)] + +[assembly: LoadableClass(ExpressionTransformer.Summary, typeof(ExpressionTransformer), null, typeof(SignatureLoadModel), + "Expression Transform", ExpressionTransformer.LoaderSignature)] + +[assembly: LoadableClass(typeof(IRowMapper), typeof(ExpressionTransformer), null, typeof(SignatureLoadRowMapper), + "Expression Transform", ExpressionTransformer.LoaderSignature)] + +namespace Microsoft.ML.Transforms +{ + /// + /// This estimator applies a user provided expression (specified as a string) to input column values to produce new output column values. + /// + /// creates a new column, + /// named as specified in the output column name parameters, where the expression is applied to the input values. + /// At most one of the input columns can be of type , and when the input contains a vector column, the expression + /// is computed independently on each element of the vector, to create a vector output with the same length as that input. + /// + /// [!include[algorithm](~/../docs/samples/docs/api-reference/expression-estimator.md)] + /// ]]> + /// + /// + /// + public sealed class ExpressionEstimator : IEstimator + { + internal sealed class ColumnOptions + { + /// Name of the column resulting from the transformation of . + public readonly string Name; + public readonly string[] InputColumnNames; + public string Expression; + + public ColumnOptions(string name, string[] inputColumnNames, string expression) + { + Name = name; + InputColumnNames = inputColumnNames; + Expression = expression; + } + } + + private readonly IHost _host; + private readonly ColumnOptions[] _columns; + + internal ExpressionEstimator(IHostEnvironment env, params ColumnOptions[] columns) + { + Contracts.CheckValue(env, nameof(env)); + _host = env.Register(nameof(ExpressionEstimator)); + _host.CheckNonEmpty(columns, nameof(columns)); + _host.Check(columns.All(col => !string.IsNullOrWhiteSpace(col.Expression))); + _host.Check(columns.All(col => !string.IsNullOrWhiteSpace(col.Name))); + _host.Check(columns.All(col => Utils.Size(col.InputColumnNames) > 0)); + _host.CheckParam(columns.All(col => Utils.Size(col.InputColumnNames) <= 5), nameof(ColumnOptions.InputColumnNames), "maximum number of inputs exceeded"); + + _columns = columns; + } + + internal static LambdaNode ParseAndBindLambda(IHostEnvironment env, string expression, int ivec, DataViewType[] inputTypes, out int[] perm) + { + + perm = Utils.GetIdentityPermutation(inputTypes.Length); + if (ivec >= 0) + { + if (ivec > 0) + { + perm[0] = ivec; + for (int i = 1; i <= ivec; i++) + perm[i] = i - 1; + } + } + CharCursor chars = new CharCursor(expression); + + var node = LambdaParser.Parse(out List errors, out List lineMap, chars, perm, inputTypes); + if (Utils.Size(errors) > 0) + throw env.ExceptParam(nameof(expression), $"parsing failed: {errors[0].GetMessage()}"); + + using (var ch = env.Start("LabmdaBinder.Run")) + LambdaBinder.Run(env, ref errors, node, msg => ch.Error(msg)); + + if (Utils.Size(errors) > 0) + throw env.ExceptParam(nameof(expression), $"binding failed: {errors[0].GetMessage()}"); + return node; + } + + private static int FindVectorInputColumn(IHostEnvironment env, IReadOnlyList inputColumnNames, SchemaShape inputSchema, DataViewType[] inputTypes) + { + int ivec = -1; + for (int isrc = 0; isrc < inputColumnNames.Count; isrc++) + { + if (!inputSchema.TryFindColumn(inputColumnNames[isrc], out var col)) + throw env.ExceptSchemaMismatch(nameof(inputSchema), "input", inputColumnNames[isrc]); + + if (col.Kind != SchemaShape.Column.VectorKind.Scalar) + { + if (ivec >= 0) + throw env.ExceptUserArg(nameof(inputColumnNames), "Can have at most one vector-valued source column"); + ivec = isrc; + } + inputTypes[isrc] = col.ItemType; + } + + return ivec; + } + + private static int FindVectorInputColumn(IHostEnvironment env, IReadOnlyList inputColumnNames, DataViewSchema inputSchema, DataViewType[] inputTypes) + { + int ivec = -1; + for (int isrc = 0; isrc < inputColumnNames.Count; isrc++) + { + var col = inputSchema.GetColumnOrNull(inputColumnNames[isrc]); + if (col == null) + throw env.ExceptSchemaMismatch(nameof(inputSchema), "input", inputColumnNames[isrc]); + + if (col.Value.Type is VectorDataViewType) + { + if (ivec >= 0) + throw env.ExceptUserArg(nameof(inputColumnNames), "Can have at most one vector-valued source column"); + ivec = isrc; + } + inputTypes[isrc] = col.Value.Type.GetItemType(); + } + + return ivec; + } + + public ExpressionTransformer Fit(IDataView input) + { + var columns = new ExpressionTransformer.ColumnInfo[_columns.Length]; + for (int i = 0; i < _columns.Length; i++) + { + // Make sure there is at most one vector valued source column. + var inputTypes = new DataViewType[_columns[i].InputColumnNames.Length]; + var ivec = FindVectorInputColumn(_host, _columns[i].InputColumnNames, input.Schema, inputTypes); + var node = ParseAndBindLambda(_host, _columns[i].Expression, ivec, inputTypes, out var perm); + columns[i] = new ExpressionTransformer.ColumnInfo(_host, _columns[i].InputColumnNames, inputTypes, _columns[i].Expression, _columns[i].Name, ivec, node, perm); + } + return new ExpressionTransformer(_host, columns); + } + + public SchemaShape GetOutputSchema(SchemaShape inputSchema) + { + _host.CheckValue(inputSchema, nameof(inputSchema)); + var columnDictionary = inputSchema.ToDictionary(x => x.Name); + for (int i = 0; i < _columns.Length; i++) + { + for (int j=0;j<_columns[i].InputColumnNames.Length;j++) + { + if (!inputSchema.TryFindColumn(_columns[i].InputColumnNames[j], out var inputCol)) + throw _host.ExceptSchemaMismatch(nameof(inputSchema), "input", _columns[i].InputColumnNames[j]); + } + + // Make sure there is at most one vector valued source column. + var inputTypes = new DataViewType[_columns[i].InputColumnNames.Length]; + var ivec = FindVectorInputColumn(_host, _columns[i].InputColumnNames, inputSchema, inputTypes); + var node = ParseAndBindLambda(_host, _columns[i].Expression, ivec, inputTypes, out var perm); + + var typeRes = node.ResultType; + _host.Assert(typeRes is PrimitiveDataViewType); + + // If one of the input columns is a vector column, we pass through the slot names metadata. + SchemaShape.Column.VectorKind outputVectorKind; + var metadata = new List(); + if (ivec == -1) + outputVectorKind = SchemaShape.Column.VectorKind.Scalar; + else + { + inputSchema.TryFindColumn(_columns[i].InputColumnNames[ivec], out var vectorCol); + outputVectorKind = vectorCol.Kind; + if (vectorCol.HasSlotNames()) + { + var b = vectorCol.Annotations.TryFindColumn(AnnotationUtils.Kinds.SlotNames, out var slotNames); + _host.Assert(b); + metadata.Add(slotNames); + } + } + var outputSchemaShapeColumn = new SchemaShape.Column(_columns[i].Name, outputVectorKind, typeRes, false, new SchemaShape(metadata)); + columnDictionary[_columns[i].Name] = outputSchemaShapeColumn; + } + return new SchemaShape(columnDictionary.Values); + } + } + + public sealed class ExpressionTransformer : RowToRowTransformerBase + { + internal sealed class Options + { + [Argument(ArgumentType.Multiple | ArgumentType.Required, HelpText = "New column definition(s)", ShortName = "col", SortOrder = 1)] + public Column[] Column; + + [Argument(ArgumentType.AtMostOnce, ShortName = "expr", SortOrder = 2, HelpText = "Lambda expression which will be applied.")] + public string Expression = "(x) : x"; + } + + internal sealed class Column : ManyToOneColumn + { + [Argument(ArgumentType.AtMostOnce, ShortName = "expr", SortOrder = 2, HelpText = "Lambda expression which will be applied.")] + public string Expression; + + internal static Column Parse(string str) + { + Contracts.AssertNonEmpty(str); + + var res = new Column(); + if (res.TryParse(str)) + return res; + return null; + } + + internal bool TryUnparse(StringBuilder sb) + { + Contracts.AssertValue(sb); + if (Expression != null) + return false; + return TryUnparseCore(sb); + } + } + + internal sealed class ColumnInfo + { + public readonly string OutputColumnName; + public readonly string[] InputColumnNames; + public readonly PrimitiveDataViewType OutputColumnItemType; + public readonly int VectorInputColumn; + public readonly Delegate Del; + public readonly int[] Perm; + public readonly string Expression; + public readonly InternalDataKind[] InputKinds; + + public ColumnInfo(IExceptionContext ectx, string[] inputColumnNames, DataViewType[] inputTypes, string expression, string outputColumnName, int vectorInputColumn, LambdaNode node, int[] perm) + { + ectx.AssertNonEmpty(inputTypes); + ectx.Assert(Utils.Size(inputTypes) == Utils.Size(inputColumnNames)); + ectx.AssertNonWhiteSpace(expression); + ectx.AssertNonWhiteSpace(outputColumnName); + ectx.AssertValue(node); + + InputColumnNames = inputColumnNames; + OutputColumnName = outputColumnName; + OutputColumnItemType = node.ResultType as PrimitiveDataViewType; + ectx.AssertValue(OutputColumnItemType); + VectorInputColumn = vectorInputColumn; + Perm = perm; + Expression = expression; + + InputKinds = new InternalDataKind[inputTypes.Length]; + for (int i = 0; i < inputTypes.Length; i++) + InputKinds[i] = inputTypes[i].GetRawKind(); + + Del = LambdaCompiler.Compile(out var errors, node); + if (Utils.Size(errors) > 0) + throw ectx.Except($"generating code failed: {errors[0].GetMessage()}"); + } + } + + private readonly ColumnInfo[] _columns; + + internal const string Summary = "Executes a given lambda expression on input column values to produce an output column value. " + + "Here are some examples to demonstrate the syntax: " + + "1) expr={x : x / 256} divides the input value by 256 " + + "2) expr={x : x ?? -1} replaces missing values with -1. " + + "3) expr={(x, y) : log(x / y)} computes log odds. " + + "For more details see the documentation."; + + public const string LoaderSignature = "ExprTransform"; + private static VersionInfo GetVersionInfo() + { + return new VersionInfo( + modelSignature: "EXPRTRNF", + verWrittenCur: 0x00010001, // Initial + verReadableCur: 0x00010001, + verWeCanReadBack: 0x00010001, + loaderSignature: LoaderSignature, + loaderAssemblyName: typeof(ExpressionTransformer).Assembly.FullName); + } + + internal ExpressionTransformer(IHostEnvironment env, ColumnInfo[] columns) + : base(Contracts.CheckRef(env, nameof(env)).Register(nameof(ExpressionTransformer))) + { + Host.AssertNonEmpty(columns); + _columns = columns; + } + + // Factory method corresponding to SignatureDataTransform. + private static IDataTransform Create(IHostEnvironment env, Options options, IDataView input) + { + Contracts.CheckValue(env, nameof(env)); + env.CheckValue(options, nameof(options)); + env.CheckNonEmpty(options.Column, nameof(options.Column)); + + var columns = new ExpressionEstimator.ColumnOptions[options.Column.Length]; + for (int i = 0; i < options.Column.Length; i++) + { + columns[i] = new ExpressionEstimator.ColumnOptions(options.Column[i].Name, + Utils.Size(options.Column[i].Source) == 0 ? new[] { options.Column[i].Name } : options.Column[i].Source, + options.Column[i].Expression ?? options.Expression); + } + + return new ExpressionEstimator(env, columns).Fit(input).MakeDataTransform(input); + } + + // Factory method for SignatureLoadDataTransform. + private static IDataTransform Create(IHostEnvironment env, ModelLoadContext ctx, IDataView input) + => Create(env, ctx).MakeDataTransform(input); + + // Factory method for SignatureLoadRowMapper. + private static IRowMapper Create(IHostEnvironment env, ModelLoadContext ctx, DataViewSchema inputSchema) + => Create(env, ctx).MakeRowMapper(inputSchema); + + private static ExpressionTransformer Create(IHostEnvironment env, ModelLoadContext ctx) + { + Contracts.CheckValue(env, nameof(env)); + env.CheckValue(ctx, nameof(ctx)); + ctx.CheckAtModel(GetVersionInfo()); + + // *** Binary format *** + // int: number of output columns + // for each output column: + // int: number of inputs + // foreach input + // int: Id of the input column name + // int: Id of the expression + // int: Id of the output column name + // int: the index of the vector input (or -1) + // int[]: The data kinds of the input columns + + var columnCount = ctx.Reader.ReadInt32(); + env.CheckDecode(columnCount > 0); + + var columns = new ColumnInfo[columnCount]; + for (int i = 0; i < columnCount; i++) + { + var inputSize = ctx.Reader.ReadInt32(); + env.CheckDecode(inputSize >= 0); + var inputColumnNames = new string[inputSize]; + for (int j = 0; j < inputSize; j++) + inputColumnNames[j] = ctx.LoadNonEmptyString(); + var expression = ctx.LoadNonEmptyString(); + var outputColumnName = ctx.LoadNonEmptyString(); + var vectorInputColumn = ctx.Reader.ReadInt32(); + env.CheckDecode(vectorInputColumn >= -1); + + var inputTypes = new DataViewType[inputSize]; + for (int j = 0; j < inputSize; j++) + { + var dataKindIndex = ctx.Reader.ReadInt32(); + var kind = InternalDataKindExtensions.FromIndex(dataKindIndex); + inputTypes[j] = ColumnTypeExtensions.PrimitiveTypeFromKind(kind); + } + var node = ExpressionEstimator.ParseAndBindLambda(env, expression, vectorInputColumn, inputTypes, out var perm); + columns[i] = new ColumnInfo(env, inputColumnNames, inputTypes, expression, outputColumnName, vectorInputColumn, node, perm); + } + return new ExpressionTransformer(env, columns); + } + + private protected override void SaveModel(ModelSaveContext ctx) + { + Host.CheckValue(ctx, nameof(ctx)); + ctx.CheckAtModel(); + ctx.SetVersionInfo(GetVersionInfo()); + + // *** Binary format *** + // int: number of output columns + // for each output column: + // int: number of inputs + // foreach input + // int: Id of the input column name + // int: Id of the expression + // int: Id of the output column name + // int: the index of the vector input (or -1) + // int[]: The data kinds of the input columns + + ctx.Writer.Write(_columns.Length); + + for (int i = 0; i < _columns.Length; i++) + { + var inputColumnNames = _columns[i].InputColumnNames; + ctx.Writer.Write(inputColumnNames.Length); + for (int j = 0; j < inputColumnNames.Length; j++) + ctx.SaveNonEmptyString(inputColumnNames[j]); + + ctx.SaveNonEmptyString(_columns[i].Expression); + ctx.SaveNonEmptyString(_columns[i].OutputColumnName); + Host.Assert(_columns[i].VectorInputColumn >= -1); + ctx.Writer.Write(_columns[i].VectorInputColumn); + for (int j = 0; j < _columns[i].InputKinds.Length; j++) + ctx.Writer.Write(_columns[i].InputKinds[j].ToIndex()); + } + } + + private protected override IRowMapper MakeRowMapper(DataViewSchema schema) + { + return new Mapper(this, schema); + } + + private Delegate MakeGetter(IExceptionContext ectx, DataViewRow input, int iinfo) + { + Func> d; + var types = _columns[iinfo].Del.GetType().GetGenericArguments(); + switch (types.Length - 1) + { + case 1: + d = GetGetter; + break; + case 2: + d = GetGetter; + break; + case 3: + d = GetGetter; + break; + case 4: + d = GetGetter; + break; + case 5: + d = GetGetter; + break; + default: + ectx.Assert(false, "Unsupported src cardinality"); + throw ectx.ExceptNotSupp(); + } + + var inputColumnNames = _columns[iinfo].InputColumnNames; + var inputColumns = new DataViewSchema.Column[inputColumnNames.Length]; + for (int i = 0; i < inputColumnNames.Length; i++) + inputColumns[i] = input.Schema[inputColumnNames[i]]; + + var meth = d.GetMethodInfo().GetGenericMethodDefinition().MakeGenericMethod(types); + return (Delegate)meth.Invoke(this, new object[] { ectx, input, inputColumns, _columns[iinfo].Del }); + } + + private ValueGetter GetGetter(IExceptionContext ectx, DataViewRow input, DataViewSchema.Column[] inputColumns, Delegate del) + { + ectx.Assert(inputColumns.Length == 1); + + var fn = (Func)del; + var getSrc0 = input.GetGetter(inputColumns[0]); + var src0 = default(T0); + return + (ref TDst dst) => + { + getSrc0(ref src0); + dst = fn(src0); + }; + } + + private ValueGetter GetGetter(IExceptionContext ectx, DataViewRow input, DataViewSchema.Column[] inputColumns, Delegate del) + { + ectx.Assert(inputColumns.Length == 2); + + var fn = (Func)del; + var getSrc0 = input.GetGetter(inputColumns[0]); + var getSrc1 = input.GetGetter(inputColumns[1]); + var src0 = default(T0); + var src1 = default(T1); + return + (ref TDst dst) => + { + getSrc0(ref src0); + getSrc1(ref src1); + dst = fn(src0, src1); + }; + } + + private ValueGetter GetGetter(IExceptionContext ectx, DataViewRow input, DataViewSchema.Column[] inputColumns, Delegate del) + { + ectx.Assert(inputColumns.Length == 3); + + var fn = (Func)del; + var getSrc0 = input.GetGetter(inputColumns[0]); + var getSrc1 = input.GetGetter(inputColumns[1]); + var getSrc2 = input.GetGetter(inputColumns[2]); + var src0 = default(T0); + var src1 = default(T1); + var src2 = default(T2); + return + (ref TDst dst) => + { + getSrc0(ref src0); + getSrc1(ref src1); + getSrc2(ref src2); + dst = fn(src0, src1, src2); + }; + } + + private ValueGetter GetGetter(IExceptionContext ectx, DataViewRow input, DataViewSchema.Column[] inputColumns, Delegate del) + { + ectx.Assert(inputColumns.Length == 4); + + var fn = (Func)del; + var getSrc0 = input.GetGetter(inputColumns[0]); + var getSrc1 = input.GetGetter(inputColumns[1]); + var getSrc2 = input.GetGetter(inputColumns[2]); + var getSrc3 = input.GetGetter(inputColumns[3]); + var src0 = default(T0); + var src1 = default(T1); + var src2 = default(T2); + var src3 = default(T3); + return + (ref TDst dst) => + { + getSrc0(ref src0); + getSrc1(ref src1); + getSrc2(ref src2); + getSrc3(ref src3); + dst = fn(src0, src1, src2, src3); + }; + } + + private ValueGetter GetGetter(IExceptionContext ectx, DataViewRow input, DataViewSchema.Column[] inputColumns, Delegate del) + { + ectx.Assert(inputColumns.Length == 5); + + var fn = (Func)del; + var getSrc0 = input.GetGetter(inputColumns[0]); + var getSrc1 = input.GetGetter(inputColumns[1]); + var getSrc2 = input.GetGetter(inputColumns[2]); + var getSrc3 = input.GetGetter(inputColumns[3]); + var getSrc4 = input.GetGetter(inputColumns[4]); + var src0 = default(T0); + var src1 = default(T1); + var src2 = default(T2); + var src3 = default(T3); + var src4 = default(T4); + return + (ref TDst dst) => + { + getSrc0(ref src0); + getSrc1(ref src1); + getSrc2(ref src2); + getSrc3(ref src3); + getSrc4(ref src4); + dst = fn(src0, src1, src2, src3, src4); + }; + } + + private Delegate MakeGetterVec(IExceptionContext ectx, DataViewRow input, int iinfo) + { + ectx.Assert(_columns[iinfo].VectorInputColumn >= 0); + + Func>> d; + var types = _columns[iinfo].Del.GetType().GetGenericArguments(); + switch (types.Length - 1) + { + case 1: + d = GetGetterVec; + break; + case 2: + d = GetGetterVec; + break; + case 3: + d = GetGetterVec; + break; + case 4: + d = GetGetterVec; + break; + case 5: + d = GetGetterVec; + break; + default: + ectx.Assert(false, "Unsupported src cardinality"); + throw ectx.ExceptNotSupp(); + } + + var inputColumnNames = _columns[iinfo].InputColumnNames; + var inputColumns = new DataViewSchema.Column[inputColumnNames.Length]; + for (int i = 0; i < inputColumnNames.Length; i++) + inputColumns[i] = input.Schema[inputColumnNames[i]]; + + var meth = d.GetMethodInfo().GetGenericMethodDefinition().MakeGenericMethod(types); + return (Delegate)meth.Invoke(this, new object[] { ectx, input, inputColumns, _columns[iinfo].Perm, _columns[iinfo].Del, _columns[iinfo].OutputColumnItemType }); + } + + private ValueGetter> GetGetterVec(IExceptionContext ectx, DataViewRow input, DataViewSchema.Column[] inputColumns, int[] perm, Delegate del, DataViewType outputColumnItemType) + { + ectx.Assert(inputColumns.Length == 1); + ectx.Assert(perm.Length == 1); + ectx.Assert(perm[0] == 0); + + var fn = (Func)del; + var getSrc0 = input.GetGetter>(inputColumns[0]); + var src0 = default(VBuffer); + + var dstDef = fn(default(T0)); + var isDef = Conversions.Instance.GetIsDefaultPredicate(outputColumnItemType); + if (isDef(in dstDef)) + { + // Sparsity is preserved. + return + (ref VBuffer dst) => + { + getSrc0(ref src0); + int count = src0.GetValues().Length; + + var editor = VBufferEditor.Create(ref dst, src0.Length, count); + for (int i = 0; i < count; i++) + editor.Values[i] = fn(src0.GetValues()[i]); + + if (!src0.IsDense) + src0.GetIndices().CopyTo(editor.Indices); + dst = editor.Commit(); + }; + } + else + { + // Densifies - default(T0) maps to dstDef, which is not default(TDst). + return + (ref VBuffer dst) => + { + getSrc0(ref src0); + int len = src0.Length; + var editor = VBufferEditor.Create(ref dst, len); + if (src0.IsDense) + { + for (int i = 0; i < len; i++) + editor.Values[i] = fn(src0.GetValues()[i]); + } + else + { + int count = src0.GetValues().Length; + for (int i = 0, ii = 0; i < len; i++) + { + ectx.Assert(0 <= ii && ii <= count); + ectx.Assert(ii == count || src0.GetIndices()[ii] >= i); + if (ii < count && src0.GetIndices()[ii] == i) + { + editor.Values[i] = fn(src0.GetValues()[ii]); + ii++; + } + else + editor.Values[i] = dstDef; + } + } + dst = editor.Commit(); + }; + } + } + + private ValueGetter> GetGetterVec(IExceptionContext ectx, DataViewRow input, DataViewSchema.Column[] inputColumns, int[] perm, Delegate del, DataViewType outputColumnItemType) + { + ectx.Assert(inputColumns.Length == 2); + ectx.Assert(perm.Length == 2); + + var isDef = Conversions.Instance.GetIsDefaultPredicate(outputColumnItemType); + var fn = (Func)del; + var getSrc0 = input.GetGetter>(inputColumns[perm[0]]); + var getSrc1 = input.GetGetter(inputColumns[perm[1]]); + var src0 = default(VBuffer); + var src1 = default(T1); + + return + (ref VBuffer dst) => + { + getSrc0(ref src0); + getSrc1(ref src1); + if (src0.IsDense) + { + int len = src0.Length; + var editor = VBufferEditor.Create(ref dst, len); + for (int i = 0; i < len; i++) + editor.Values[i] = fn(src0.GetValues()[i], src1); + dst = editor.Commit(); + } + else + { + int len = src0.Length; + int count = src0.GetValues().Length; + var dstDef = fn(default(T0), src1); + if (isDef(in dstDef)) + { + var editor = VBufferEditor.Create(ref dst, len, count); + for (int i = 0; i < count; i++) + editor.Values[i] = fn(src0.GetValues()[i], src1); + src0.GetIndices().CopyTo(editor.Indices); + dst = editor.Commit(); + } + else + { + // Densifies - default(T0) maps to dstDef, which is not default(TDst). + var editor = VBufferEditor.Create(ref dst, len); + for (int i = 0, ii = 0; i < len; i++) + { + ectx.Assert(0 <= ii && ii <= count); + ectx.Assert(ii == count || src0.GetIndices()[ii] >= i); + if (ii < count && src0.GetIndices()[ii] == i) + { + editor.Values[i] = fn(src0.GetValues()[ii], src1); + ii++; + } + else + editor.Values[i] = dstDef; + } + dst = editor.Commit(); + } + } + }; + } + + private ValueGetter> GetGetterVec(IExceptionContext ectx, DataViewRow input, DataViewSchema.Column[] inputColumns, int[] perm, Delegate del, DataViewType outputColumnItemType) + { + ectx.Assert(inputColumns.Length == 3); + ectx.Assert(perm.Length == 3); + + var isDef = Conversions.Instance.GetIsDefaultPredicate(outputColumnItemType); + var fn = (Func)del; + var getSrc0 = input.GetGetter>(inputColumns[perm[0]]); + var getSrc1 = input.GetGetter(inputColumns[perm[1]]); + var getSrc2 = input.GetGetter(inputColumns[perm[2]]); + var src0 = default(VBuffer); + var src1 = default(T1); + var src2 = default(T2); + + return + (ref VBuffer dst) => + { + getSrc0(ref src0); + getSrc1(ref src1); + getSrc2(ref src2); + if (src0.IsDense) + { + int len = src0.Length; + var editor = VBufferEditor.Create(ref dst, len); + for (int i = 0; i < len; i++) + editor.Values[i] = fn(src0.GetValues()[i], src1, src2); + dst = editor.Commit(); + } + else + { + int len = src0.Length; + int count = src0.GetValues().Length; + var dstDef = fn(default(T0), src1, src2); + if (isDef(in dstDef)) + { + var editor = VBufferEditor.Create(ref dst, len, count); + for (int i = 0; i < count; i++) + editor.Values[i] = fn(src0.GetValues()[i], src1, src2); + src0.GetIndices().CopyTo(editor.Indices); + dst = editor.Commit(); + } + else + { + // Densifies - default(T0) maps to dstDef, which is not default(TDst). + var editor = VBufferEditor.Create(ref dst, len); + for (int i = 0, ii = 0; i < len; i++) + { + ectx.Assert(0 <= ii && ii <= count); + ectx.Assert(ii == count || src0.GetIndices()[ii] >= i); + if (ii < count && src0.GetIndices()[ii] == i) + { + editor.Values[i] = fn(src0.GetValues()[ii], src1, src2); + ii++; + } + else + editor.Values[i] = dstDef; + } + dst = editor.Commit(); + } + } + }; + } + + private ValueGetter> GetGetterVec(IExceptionContext ectx, DataViewRow input, DataViewSchema.Column[] inputColumns, int[] perm, Delegate del, DataViewType outputColumnItemType) + { + ectx.Assert(inputColumns.Length == 4); + ectx.Assert(perm.Length == 4); + + var isDef = Conversions.Instance.GetIsDefaultPredicate(outputColumnItemType); + var fn = (Func)del; + var getSrc0 = input.GetGetter>(inputColumns[perm[0]]); + var getSrc1 = input.GetGetter(inputColumns[perm[1]]); + var getSrc2 = input.GetGetter(inputColumns[perm[2]]); + var getSrc3 = input.GetGetter(inputColumns[perm[3]]); + var src0 = default(VBuffer); + var src1 = default(T1); + var src2 = default(T2); + var src3 = default(T3); + + return + (ref VBuffer dst) => + { + getSrc0(ref src0); + getSrc1(ref src1); + getSrc2(ref src2); + getSrc3(ref src3); + if (src0.IsDense) + { + int len = src0.Length; + var editor = VBufferEditor.Create(ref dst, len); + for (int i = 0; i < len; i++) + editor.Values[i] = fn(src0.GetValues()[i], src1, src2, src3); + dst = editor.Commit(); + } + else + { + int len = src0.Length; + int count = src0.GetValues().Length; + var dstDef = fn(default(T0), src1, src2, src3); + if (isDef(in dstDef)) + { + var editor = VBufferEditor.Create(ref dst, len, count); + for (int i = 0; i < count; i++) + editor.Values[i] = fn(src0.GetValues()[i], src1, src2, src3); + src0.GetIndices().CopyTo(editor.Indices); + dst = editor.Commit(); + } + else + { + // Densifies - default(T0) maps to dstDef, which is not default(TDst). + var editor = VBufferEditor.Create(ref dst, len); + for (int i = 0, ii = 0; i < len; i++) + { + ectx.Assert(0 <= ii && ii <= count); + ectx.Assert(ii == count || src0.GetIndices()[ii] >= i); + if (ii < count && src0.GetIndices()[ii] == i) + { + editor.Values[i] = fn(src0.GetValues()[ii], src1, src2, src3); + ii++; + } + else + editor.Values[i] = dstDef; + } + dst = editor.Commit(); + } + } + }; + } + + private ValueGetter> GetGetterVec(IExceptionContext ectx, DataViewRow input, DataViewSchema.Column[] inputColumns, int[] perm, Delegate del, DataViewType outputColumnItemType) + { + ectx.Assert(inputColumns.Length == 5); + ectx.Assert(perm.Length == 5); + + var isDef = Conversions.Instance.GetIsDefaultPredicate(outputColumnItemType); + var fn = (Func)del; + var getSrc0 = input.GetGetter>(inputColumns[perm[0]]); + var getSrc1 = input.GetGetter(inputColumns[perm[1]]); + var getSrc2 = input.GetGetter(inputColumns[perm[2]]); + var getSrc3 = input.GetGetter(inputColumns[perm[3]]); + var getSrc4 = input.GetGetter(inputColumns[perm[4]]); + var src0 = default(VBuffer); + var src1 = default(T1); + var src2 = default(T2); + var src3 = default(T3); + var src4 = default(T4); + + return + (ref VBuffer dst) => + { + getSrc0(ref src0); + getSrc1(ref src1); + getSrc2(ref src2); + getSrc3(ref src3); + getSrc4(ref src4); + if (src0.IsDense) + { + int len = src0.Length; + var editor = VBufferEditor.Create(ref dst, len); + for (int i = 0; i < len; i++) + editor.Values[i] = fn(src0.GetValues()[i], src1, src2, src3, src4); + dst = editor.Commit(); + } + else + { + int len = src0.Length; + int count = src0.GetValues().Length; + var dstDef = fn(default(T0), src1, src2, src3, src4); + if (isDef(in dstDef)) + { + var editor = VBufferEditor.Create(ref dst, len, count); + for (int i = 0; i < count; i++) + editor.Values[i] = fn(src0.GetValues()[i], src1, src2, src3, src4); + src0.GetIndices().CopyTo(editor.Indices); + dst = editor.Commit(); + } + else + { + // Densifies - default(T0) maps to dstDef, which is not default(TDst). + var editor = VBufferEditor.Create(ref dst, len); + for (int i = 0, ii = 0; i < len; i++) + { + ectx.Assert(0 <= ii && ii <= count); + ectx.Assert(ii == count || src0.GetIndices()[ii] >= i); + if (ii < count && src0.GetIndices()[ii] == i) + { + editor.Values[i] = fn(src0.GetValues()[ii], src1, src2, src3, src4); + ii++; + } + else + editor.Values[i] = dstDef; + } + dst = editor.Commit(); + } + } + }; + } + + private sealed class Mapper : MapperBase + { + private readonly ExpressionTransformer _parent; + private readonly int[][] _inputColumnIndices; + + public Mapper(ExpressionTransformer parent, DataViewSchema inputSchema) + : base(parent.Host, inputSchema, parent) + { + _parent = parent; + _inputColumnIndices = new int[_parent._columns.Length][]; + for (int i = 0; i < _parent._columns.Length; i++) + { + var inputColumnNames = _parent._columns[i].InputColumnNames; + _inputColumnIndices[i] = new int[inputColumnNames.Length]; + for (int j = 0; j < inputColumnNames.Length; j++) + { + if (!InputSchema.TryGetColumnIndex(inputColumnNames[j], out _inputColumnIndices[i][j])) + throw Host.Except($"Column {inputColumnNames[j]} does not exist in the input schema"); + } + } + } + + protected override DataViewSchema.DetachedColumn[] GetOutputColumnsCore() + { + var outputColumns = new DataViewSchema.DetachedColumn[_parent._columns.Length]; + for (int i = 0; i < outputColumns.Length; i++) + { + var builder = new DataViewSchema.Annotations.Builder(); + DataViewType type; + if (_parent._columns[i].VectorInputColumn >= 0) + { + var vectorColumn = InputSchema[_parent._columns[i].InputColumnNames[_parent._columns[i].VectorInputColumn]]; + builder.Add(vectorColumn.Annotations, name => name == AnnotationUtils.Kinds.SlotNames); + type = new VectorDataViewType(_parent._columns[i].OutputColumnItemType, vectorColumn.Type.GetValueCount()); + } + else + type = _parent._columns[i].OutputColumnItemType; + outputColumns[i] = new DataViewSchema.DetachedColumn(_parent._columns[i].OutputColumnName, type, builder.ToAnnotations()); + } + return outputColumns; + } + + protected override Delegate MakeGetter(DataViewRow input, int iinfo, Func activeOutput, out Action disposer) + { + _parent.Host.Assert(0 <= iinfo && iinfo < _parent._columns.Length); + disposer = null; + + if (_parent._columns[iinfo].VectorInputColumn >= 0) + return _parent.MakeGetterVec(_parent.Host, input, iinfo); + return _parent.MakeGetter(_parent.Host, input, iinfo); + } + + private protected override Func GetDependenciesCore(Func activeOutput) + { + return col => + { + for (int i = 0; i < _inputColumnIndices.Length; i++) + { + if (activeOutput(i) && _inputColumnIndices[i].Any(index => index == col)) + return true; + } + return false; + }; + } + + private protected override void SaveModel(ModelSaveContext ctx) => _parent.SaveModel(ctx); + } + } +} diff --git a/src/Microsoft.ML.Transforms/Microsoft.ML.Transforms.csproj b/src/Microsoft.ML.Transforms/Microsoft.ML.Transforms.csproj index 4aa4a4eb79..0f964c5e53 100644 --- a/src/Microsoft.ML.Transforms/Microsoft.ML.Transforms.csproj +++ b/src/Microsoft.ML.Transforms/Microsoft.ML.Transforms.csproj @@ -45,6 +45,10 @@ + + + + diff --git a/test/BaselineOutput/Common/ExprParser/ExprBindExOutput.txt b/test/BaselineOutput/Common/ExprParser/ExprBindExOutput.txt new file mode 100644 index 0000000000..b054251826 --- /dev/null +++ b/test/BaselineOutput/Common/ExprParser/ExprBindExOutput.txt @@ -0,0 +1,714 @@ +===== Start Script 1, lines 1 to 4 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +===== End Script 1, lines 1 to 4 ===== +===== Start Script 2, lines 5 to 8 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +===== End Script 2, lines 5 to 8 ===== +===== Start Script 3, lines 9 to 15 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +-1 +0 +1 +*** Parsing ? Failed *** 0 +===== End Script 3, lines 9 to 15 ===== +===== Start Script 4, lines 16 to 22 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +-1 +0 +1 +*** Parsing ? Failed *** 0 +===== End Script 4, lines 16 to 22 ===== +===== Start Script 5, lines 23 to 30 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +-1 +0 +0 +1 +? +===== End Script 5, lines 23 to 30 ===== +===== Start Script 6, lines 31 to 38 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +-1 +0 +0 +1 +? +===== End Script 6, lines 31 to 38 ===== +===== Start Script 7, lines 39 to 45 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +1 +0 +-1 +*** Parsing ? Failed *** 0 +===== End Script 7, lines 39 to 45 ===== +===== Start Script 8, lines 46 to 52 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +1 +0 +-1 +*** Parsing ? Failed *** 0 +===== End Script 8, lines 46 to 52 ===== +===== Start Script 9, lines 53 to 60 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +1 +0 +0 +-1 +? +===== End Script 9, lines 53 to 60 ===== +===== Start Script 10, lines 61 to 68 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +1 +0 +0 +-1 +? +===== End Script 10, lines 61 to 68 ===== +===== Start Script 11, lines 69 to 76 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +-1 +1 +-1 +1 +? +===== End Script 11, lines 69 to 76 ===== +===== Start Script 12, lines 77 to 84 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +-1 +1 +-1 +1 +? +===== End Script 12, lines 77 to 84 ===== +===== Start Script 13, lines 85 to 88 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +*** Parsing ? Failed *** -1 +===== End Script 13, lines 85 to 88 ===== +===== Start Script 14, lines 89 to 92 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +*** Parsing ? Failed *** 1 +===== End Script 14, lines 89 to 92 ===== +===== Start Script 15, lines 93 to 96 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +0 +===== End Script 15, lines 93 to 96 ===== +===== Start Script 16, lines 97 to 100 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +0 +===== End Script 16, lines 97 to 100 ===== +===== Start Script 17, lines 101 to 104 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +1 +===== End Script 17, lines 101 to 104 ===== +===== Start Script 18, lines 105 to 108 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +-1 +===== End Script 18, lines 105 to 108 ===== +===== Start Script 19, lines 109 to 112 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +? +===== End Script 19, lines 109 to 112 ===== +===== Start Script 20, lines 113 to 114 ===== + ExprBindExInput.txt(113,10)-(113,11): error: at 'OpenParen': The best overload of 'min' has some invalid arguments + ExprBindExInput.txt(113,11)-(113,12): error: at 'Ident: x': Invalid integer operand + ExprBindExInput.txt(113,14)-(113,19): error: at '"hey"': Invalid integer operand + ExprBindExInput.txt(113,26)-(113,27): error: at 'OpenParen': The best overload of 'max' has some invalid arguments + ExprBindExInput.txt(113,27)-(113,28): error: at 'Ident: x': Invalid integer operand + ExprBindExInput.txt(113,30)-(113,35): error: at '"hey"': Invalid integer operand +===== End Script 20, lines 113 to 114 ===== +===== Start Script 21, lines 115 to 125 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +-3 +2 +2 +17 +0 +2 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 2 +===== End Script 21, lines 115 to 125 ===== +===== Start Script 22, lines 126 to 138 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +-3 +15 +12 +15 +15 +17 +0 +15 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 15 +===== End Script 22, lines 126 to 138 ===== +===== Start Script 23, lines 139 to 140 ===== + ExprBindExInput.txt(139,10)-(139,11): error: at 'OpenParen': Expected 2 arguments to function 'min' + ExprBindExInput.txt(139,19)-(139,20): error: at 'OpenParen': Expected 2 arguments to function 'min' + ExprBindExInput.txt(139,35)-(139,36): error: at 'OpenParen': The best overload of 'min' has some invalid arguments + ExprBindExInput.txt(139,39)-(139,43): error: at 'True': Invalid integer operand + ExprBindExInput.txt(139,50)-(139,51): error: at 'OpenParen': The best overload of 'min' has some invalid arguments + ExprBindExInput.txt(139,51)-(139,55): error: at '"hi"': Invalid integer operand + ExprBindExInput.txt(139,65)-(139,66): error: at 'OpenParen': Expected 2 arguments to function 'max' + ExprBindExInput.txt(139,74)-(139,75): error: at 'OpenParen': Expected 2 arguments to function 'max' + ExprBindExInput.txt(139,90)-(139,91): error: at 'OpenParen': The best overload of 'max' has some invalid arguments + ExprBindExInput.txt(139,94)-(139,98): error: at 'True': Invalid integer operand + ExprBindExInput.txt(139,105)-(139,106): error: at 'OpenParen': The best overload of 'max' has some invalid arguments + ExprBindExInput.txt(139,106)-(139,110): error: at '"hi"': Invalid integer operand +===== End Script 23, lines 139 to 140 ===== +===== Start Script 24, lines 141 to 145 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +*** Parsing ? Failed *** 35 +*** Parsing ? Failed *** 67 +===== End Script 24, lines 141 to 145 ===== +===== Start Script 25, lines 146 to 149 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +===== End Script 25, lines 146 to 149 ===== +===== Start Script 26, lines 150 to 160 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +-3 +2 +2 +17 +0 +2 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 2 +===== End Script 26, lines 150 to 160 ===== +===== Start Script 27, lines 161 to 173 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +-3 +15 +12 +15 +15 +17 +0 +15 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 15 +===== End Script 27, lines 161 to 173 ===== +===== Start Script 28, lines 174 to 175 ===== + ExprBindExInput.txt(174,10)-(174,11): error: at 'OpenParen': Expected 2 arguments to function 'min' + ExprBindExInput.txt(174,19)-(174,20): error: at 'OpenParen': Expected 2 arguments to function 'min' + ExprBindExInput.txt(174,35)-(174,36): error: at 'OpenParen': The best overload of 'min' has some invalid arguments + ExprBindExInput.txt(174,39)-(174,43): error: at 'True': Invalid integer operand + ExprBindExInput.txt(174,50)-(174,51): error: at 'OpenParen': The best overload of 'min' has some invalid arguments + ExprBindExInput.txt(174,51)-(174,55): error: at '"hi"': Invalid integer operand + ExprBindExInput.txt(174,65)-(174,66): error: at 'OpenParen': Expected 2 arguments to function 'max' + ExprBindExInput.txt(174,74)-(174,75): error: at 'OpenParen': Expected 2 arguments to function 'max' + ExprBindExInput.txt(174,90)-(174,91): error: at 'OpenParen': The best overload of 'max' has some invalid arguments + ExprBindExInput.txt(174,94)-(174,98): error: at 'True': Invalid integer operand + ExprBindExInput.txt(174,105)-(174,106): error: at 'OpenParen': The best overload of 'max' has some invalid arguments + ExprBindExInput.txt(174,106)-(174,110): error: at '"hi"': Invalid integer operand +===== End Script 28, lines 174 to 175 ===== +===== Start Script 29, lines 176 to 180 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +*** Parsing ? Failed *** 35 +*** Parsing ? Failed *** 67 +===== End Script 29, lines 176 to 180 ===== +===== Start Script 30, lines 181 to 184 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +===== End Script 30, lines 181 to 184 ===== +===== Start Script 31, lines 185 to 195 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +-3 +2 +2 +17 +0 +2 +? +? +===== End Script 31, lines 185 to 195 ===== +===== Start Script 32, lines 196 to 208 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +-3 +15 +12 +15 +15 +17 +0 +15 +? +? +===== End Script 32, lines 196 to 208 ===== +===== Start Script 33, lines 209 to 210 ===== + ExprBindExInput.txt(209,10)-(209,11): error: at 'OpenParen': Expected 2 arguments to function 'min' + ExprBindExInput.txt(209,19)-(209,20): error: at 'OpenParen': Expected 2 arguments to function 'min' + ExprBindExInput.txt(209,35)-(209,36): error: at 'OpenParen': The best overload of 'min' has some invalid arguments + ExprBindExInput.txt(209,39)-(209,43): error: at 'True': Invalid numeric operand + ExprBindExInput.txt(209,50)-(209,51): error: at 'OpenParen': The best overload of 'min' has some invalid arguments + ExprBindExInput.txt(209,51)-(209,55): error: at '"hi"': Invalid numeric operand + ExprBindExInput.txt(209,65)-(209,66): error: at 'OpenParen': Expected 2 arguments to function 'max' + ExprBindExInput.txt(209,74)-(209,75): error: at 'OpenParen': Expected 2 arguments to function 'max' + ExprBindExInput.txt(209,90)-(209,91): error: at 'OpenParen': The best overload of 'max' has some invalid arguments + ExprBindExInput.txt(209,94)-(209,98): error: at 'True': Invalid numeric operand + ExprBindExInput.txt(209,105)-(209,106): error: at 'OpenParen': The best overload of 'max' has some invalid arguments + ExprBindExInput.txt(209,106)-(209,110): error: at '"hi"': Invalid numeric operand +===== End Script 33, lines 209 to 210 ===== +===== Start Script 34, lines 211 to 215 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +35 +67 +===== End Script 34, lines 211 to 215 ===== +===== Start Script 35, lines 216 to 219 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +===== End Script 35, lines 216 to 219 ===== +===== Start Script 36, lines 220 to 230 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +-3 +2 +2 +17 +0 +2 +? +? +===== End Script 36, lines 220 to 230 ===== +===== Start Script 37, lines 231 to 243 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +-3 +15 +12 +15 +15 +17 +0 +15 +? +? +===== End Script 37, lines 231 to 243 ===== +===== Start Script 38, lines 244 to 245 ===== + ExprBindExInput.txt(244,10)-(244,11): error: at 'OpenParen': Expected 2 arguments to function 'min' + ExprBindExInput.txt(244,19)-(244,20): error: at 'OpenParen': Expected 2 arguments to function 'min' + ExprBindExInput.txt(244,35)-(244,36): error: at 'OpenParen': The best overload of 'min' has some invalid arguments + ExprBindExInput.txt(244,39)-(244,43): error: at 'True': Invalid numeric operand + ExprBindExInput.txt(244,50)-(244,51): error: at 'OpenParen': The best overload of 'min' has some invalid arguments + ExprBindExInput.txt(244,51)-(244,55): error: at '"hi"': Invalid numeric operand + ExprBindExInput.txt(244,65)-(244,66): error: at 'OpenParen': Expected 2 arguments to function 'max' + ExprBindExInput.txt(244,74)-(244,75): error: at 'OpenParen': Expected 2 arguments to function 'max' + ExprBindExInput.txt(244,90)-(244,91): error: at 'OpenParen': The best overload of 'max' has some invalid arguments + ExprBindExInput.txt(244,94)-(244,98): error: at 'True': Invalid numeric operand + ExprBindExInput.txt(244,105)-(244,106): error: at 'OpenParen': The best overload of 'max' has some invalid arguments + ExprBindExInput.txt(244,106)-(244,110): error: at '"hi"': Invalid numeric operand +===== End Script 38, lines 244 to 245 ===== +===== Start Script 39, lines 246 to 250 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +35 +67 +===== End Script 39, lines 246 to 250 ===== +===== Start Script 40, lines 251 to 254 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +===== End Script 40, lines 251 to 254 ===== +===== Start Script 41, lines 255 to 256 ===== + ExprBindExInput.txt(255,16)-(255,17): error: at 'OpenParen': Expected 2 arguments to function 'atan2' + ExprBindExInput.txt(255,27)-(255,28): error: at 'OpenParen': Expected 2 arguments to function 'atan2' + ExprBindExInput.txt(255,45)-(255,46): error: at 'OpenParen': The best overload of 'atanyx' has some invalid arguments + ExprBindExInput.txt(255,51)-(255,53): error: at 'EquEqu': Invalid numeric operand + ExprBindExInput.txt(255,65)-(255,66): error: at 'OpenParen': The best overload of 'atanyx' has some invalid arguments + ExprBindExInput.txt(255,66)-(255,70): error: at '"hi"': Invalid numeric operand +===== End Script 41, lines 255 to 256 ===== +===== Start Script 42, lines 257 to 258 ===== + ExprBindExInput.txt(257,16)-(257,17): error: at 'OpenParen': Expected 2 arguments to function 'atan2' + ExprBindExInput.txt(257,27)-(257,28): error: at 'OpenParen': Expected 2 arguments to function 'atan2' + ExprBindExInput.txt(257,45)-(257,46): error: at 'OpenParen': The best overload of 'atanyx' has some invalid arguments + ExprBindExInput.txt(257,51)-(257,53): error: at 'EquEqu': Invalid numeric operand + ExprBindExInput.txt(257,65)-(257,66): error: at 'OpenParen': The best overload of 'atanyx' has some invalid arguments + ExprBindExInput.txt(257,66)-(257,70): error: at '"hi"': Invalid numeric operand +===== End Script 42, lines 257 to 258 ===== +===== Start Script 43, lines 259 to 289 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +0 +180 +-180 +0 +0 +45 +90 +135 +180 +-135 +-90 +-45 +0 +? +? +? +0 +90 +90 +180 +-180 +-90 +-90 +0 +? +? +? +? +===== End Script 43, lines 259 to 289 ===== +===== Start Script 44, lines 290 to 320 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +0 +180 +-180 +0 +0 +45 +90 +135 +180 +-135 +-90 +-45 +0 +? +? +? +0 +90 +90 +180 +-180 +-90 +-90 +0 +? +? +? +? +===== End Script 44, lines 290 to 320 ===== +===== Start Script 45, lines 321 to 345 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +0 +45 +90 +135 +180 +-135 +-90 +? +? +? +1234567 +===== End Script 45, lines 321 to 345 ===== +===== Start Script 46, lines 346 to 349 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +===== End Script 46, lines 346 to 349 ===== +===== Start Script 47, lines 350 to 374 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +0 +45 +90 +135 +180 +-135 +-90 +? +? +? +1234567 +===== End Script 47, lines 350 to 374 ===== +===== Start Script 48, lines 375 to 378 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +===== End Script 48, lines 375 to 378 ===== +===== Start Script 49, lines 379 to 380 ===== + ExprBindExInput.txt(379,10)-(379,11): error: at 'OpenParen': Expected one argument to function 'deg' + ExprBindExInput.txt(379,18)-(379,19): error: at 'OpenParen': Expected one argument to function 'deg' + ExprBindExInput.txt(379,29)-(379,30): error: at 'OpenParen': Expected one argument to function 'rad' + ExprBindExInput.txt(379,37)-(379,38): error: at 'OpenParen': Expected one argument to function 'rad' + ExprBindExInput.txt(379,48)-(379,49): error: at 'OpenParen': The best overload of 'rad' has some invalid arguments + ExprBindExInput.txt(379,53)-(379,54): error: at 'OpenParen': Invalid numeric operand +===== End Script 49, lines 379 to 380 ===== +===== Start Script 50, lines 381 to 394 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +0 +90 +30 +-45 +? +===== End Script 50, lines 381 to 394 ===== +===== Start Script 51, lines 395 to 408 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +0 +90 +29.999999999999996 +-45 +? +===== End Script 51, lines 395 to 408 ===== +===== Start Script 52, lines 409 to 422 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +0 +1.57079637 +0.5235988 +-0.7853982 +? +===== End Script 52, lines 409 to 422 ===== +===== Start Script 53, lines 423 to 436 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +0 +1.5707963267948966 +0.52359877559829882 +-0.78539816339744828 +? +===== End Script 53, lines 423 to 436 ===== +===== Start Script 54, lines 437 to 445 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +0 +30 +45 +-60 +90 +? +===== End Script 54, lines 437 to 445 ===== +===== Start Script 55, lines 446 to 454 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +0 +29.999999999999996 +45 +-59.999999999999993 +90 +? +===== End Script 55, lines 446 to 454 ===== +===== Start Script 56, lines 455 to 463 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +0 +0 +0 +0 +0 +? +===== End Script 56, lines 455 to 463 ===== +===== Start Script 57, lines 464 to 472 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +0 +0 +0 +0 +0 +? +===== End Script 57, lines 464 to 472 ===== +===== Start Script 58, lines 473 to 478 ===== + ExprBindExInput.txt(477,43)-(477,44): error: at 'Semi': Expected end of input +===== End Script 58, lines 473 to 478 ===== +===== Start Script 59, lines 479 to 484 ===== + ExprBindExInput.txt(480,14)-(480,15): error: at 'OpenParen': Expected one argument to function 'trunc' + ExprBindExInput.txt(480,24)-(480,25): error: at 'OpenParen': Expected one argument to function 'trunc' + ExprBindExInput.txt(480,37)-(480,38): error: at 'OpenParen': The best overload of 'trunc' has some invalid arguments + ExprBindExInput.txt(480,38)-(480,42): error: at 'True': Invalid numeric operand + ExprBindExInput.txt(481,14)-(481,15): error: at 'OpenParen': Expected one argument to function 'ceil' + ExprBindExInput.txt(481,24)-(481,25): error: at 'OpenParen': Expected one argument to function 'ceil' + ExprBindExInput.txt(481,37)-(481,38): error: at 'OpenParen': The best overload of 'ceil' has some invalid arguments + ExprBindExInput.txt(481,38)-(481,42): error: at 'True': Invalid numeric operand + ExprBindExInput.txt(482,14)-(482,15): error: at 'OpenParen': Expected one argument to function 'floor' + ExprBindExInput.txt(482,24)-(482,25): error: at 'OpenParen': Expected one argument to function 'floor' + ExprBindExInput.txt(482,37)-(482,38): error: at 'OpenParen': The best overload of 'floor' has some invalid arguments + ExprBindExInput.txt(482,38)-(482,42): error: at 'True': Invalid numeric operand + ExprBindExInput.txt(483,14)-(483,15): error: at 'OpenParen': Expected one argument to function 'round' + ExprBindExInput.txt(483,24)-(483,25): error: at 'OpenParen': Expected one argument to function 'round' + ExprBindExInput.txt(483,37)-(483,38): error: at 'OpenParen': The best overload of 'round' has some invalid arguments + ExprBindExInput.txt(483,38)-(483,42): error: at 'True': Invalid numeric operand +===== End Script 59, lines 479 to 484 ===== +===== Start Script 60, lines 485 to 494 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +-1 +-1 +3 +3 +Infinity +-Infinity +? +===== End Script 60, lines 485 to 494 ===== +===== Start Script 61, lines 495 to 504 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +-2 +-2 +3 +3 +Infinity +-Infinity +? +===== End Script 61, lines 495 to 504 ===== +===== Start Script 62, lines 505 to 514 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +-1 +-1 +4 +4 +Infinity +-Infinity +? +===== End Script 62, lines 505 to 514 ===== +===== Start Script 63, lines 515 to 530 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +-1 +-2 +-2 +-2 +-4 +3 +4 +4 +2 +2 +Infinity +-Infinity +? +===== End Script 63, lines 515 to 530 ===== +===== Start Script 64, lines 531 to 532 ===== + ExprBindExInput.txt(531,10)-(531,11): error: at 'OpenParen': Ambiguous invocation of function '_aa' +===== End Script 64, lines 531 to 532 ===== +===== Start Script 65, lines 533 to 538 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +34 +-24 +*** Parsing ? Failed *** 0 +===== End Script 65, lines 533 to 538 ===== +===== Start Script 66, lines 539 to 544 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +-17 +12 +*** Parsing ? Failed *** 0 +===== End Script 66, lines 539 to 544 ===== +===== Start Script 67, lines 545 to 546 ===== + ExprBindExInput.txt(545,10)-(545,11): error: at 'OpenParen': Ambiguous invocation of function '_ab' +===== End Script 67, lines 545 to 546 ===== +===== Start Script 68, lines 547 to 552 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +34 +-24 +*** Parsing ? Failed *** 0 +===== End Script 68, lines 547 to 552 ===== +===== Start Script 69, lines 553 to 558 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +-170 +120 +*** Parsing ? Failed *** 0 +===== End Script 69, lines 553 to 558 ===== +===== Start Script 70, lines 559 to 560 ===== + ExprBindExInput.txt(559,10)-(559,11): error: at 'OpenParen': Duplicate candidate functions in namespaces '__test1' and '__test2' +===== End Script 70, lines 559 to 560 ===== +===== Start Script 71, lines 561 to 566 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +34 +-24 +*** Parsing ? Failed *** 0 +===== End Script 71, lines 561 to 566 ===== +===== Start Script 72, lines 567 to 572 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +510 +-360 +*** Parsing ? Failed *** 0 +===== End Script 72, lines 567 to 572 ===== +===== Start Script 73, lines 573 to 578 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +34 +-24 +*** Parsing ? Failed *** 0 +===== End Script 73, lines 573 to 578 ===== +===== Start Script 74, lines 579 to 592 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +1 +-1 +2 +-3 +4 +? +? +*** Parsing ? Failed *** 3 +*** Parsing ? Failed *** 1 +*** Parsing ? Failed *** *** Parsing ? Failed *** 1 +===== End Script 74, lines 579 to 592 ===== +===== Start Script 75, lines 593 to 598 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +321 +*** Parsing ? Failed *** 321 +===== End Script 75, lines 593 to 598 ===== +===== Start Script 76, lines 599 to 601 ===== + ExprBindExInput.txt(600,9)-(600,10): error: at 'OpenParen': No overload of function '_ba' takes 3 arguments +===== End Script 76, lines 599 to 601 ===== +===== Start Script 77, lines 602 to 609 ===== +Error in ExprTransform: Function '_bad' in namespace '__test1' has invalid return type 'System.Object' +Error in ExprTransform: Function '_bad' in namespace '__test1' has invalid parameter type 'System.String' +Error in ExprTransform: Function '_bad' in namespace '__test1' must be static and public +Error in ExprTransform: Function '_bad' in namespace '__test1' must be static and public +Binding succeeded. Output type: Int32 +Compiling succeeded. +3 +3 +3 +*** Parsing ? Failed *** 3 +===== End Script 77, lines 602 to 609 ===== +===== Start Script 78, lines 610 to 613 ===== + ExprBindExInput.txt(610,11)-(610,15): error: at 'Ident: blah': Unknown function +===== End Script 78, lines 610 to 613 ===== diff --git a/test/BaselineOutput/Common/ExprParser/ExprBindOutput.txt b/test/BaselineOutput/Common/ExprParser/ExprBindOutput.txt new file mode 100644 index 0000000000..2ab47844ab --- /dev/null +++ b/test/BaselineOutput/Common/ExprParser/ExprBindOutput.txt @@ -0,0 +1,1473 @@ +===== Start Script 1, lines 1 to 3 ===== +Binding succeeded. Output type: String +Compiling succeeded. +hello +===== End Script 1, lines 1 to 3 ===== +===== Start Script 2, lines 4 to 8 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +3 +3 +===== End Script 2, lines 4 to 8 ===== +===== Start Script 3, lines 9 to 16 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +-1 +0 +8 +27 +1073741824 +===== End Script 3, lines 9 to 16 ===== +===== Start Script 4, lines 17 to 22 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +256 +429981696 +16777216 +===== End Script 4, lines 17 to 22 ===== +===== Start Script 5, lines 23 to 31 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +8 +2147483652 +-9223372036854775806 +9223372036854775807 +9223372036854775804 +===== End Script 5, lines 23 to 31 ===== +===== Start Script 6, lines 32 to 39 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +8 +2.14748365E+09 +9.223372E+18 +1E+30 +===== End Script 6, lines 32 to 39 ===== +===== Start Script 7, lines 40 to 47 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +8 +2147483652 +9.2233720368547758E+18 +1E+30 +===== End Script 7, lines 40 to 47 ===== +===== Start Script 8, lines 48 to 50 ===== + ExprBindInput.txt(49,6)-(49,7): error: at 'Ident: y': Unresolved identifier 'y' +===== End Script 8, lines 48 to 50 ===== +===== Start Script 9, lines 51 to 53 ===== + ExprBindInput.txt(52,7)-(52,8): error: at 'Ident: x': Invalid numeric operand +===== End Script 9, lines 51 to 53 ===== +===== Start Script 10, lines 54 to 56 ===== + ExprBindInput.txt(55,7)-(55,8): error: at 'Ident: x': Invalid boolean operand +===== End Script 10, lines 54 to 56 ===== +===== Start Script 11, lines 57 to 61 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +===== End Script 11, lines 57 to 61 ===== +===== Start Script 12, lines 62 to 68 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +-3 +? +-6 +===== End Script 12, lines 62 to 68 ===== +===== Start Script 13, lines 69 to 75 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +-3 +? +-6 +===== End Script 13, lines 69 to 75 ===== +===== Start Script 14, lines 76 to 82 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +-3 +? +-6 +===== End Script 14, lines 76 to 82 ===== +===== Start Script 15, lines 83 to 89 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +-3 +? +-6 +===== End Script 15, lines 83 to 89 ===== +===== Start Script 16, lines 90 to 92 ===== + ExprBindInput.txt(91,14)-(91,15): error: at 'Ident: y': Invalid integer operand +===== End Script 16, lines 90 to 92 ===== +===== Start Script 17, lines 93 to 95 ===== + ExprBindInput.txt(94,14)-(94,15): error: at 'Ident: y': Invalid numeric operand +===== End Script 17, lines 93 to 95 ===== +===== Start Script 18, lines 96 to 98 ===== + ExprBindInput.txt(97,17)-(97,18): error: at 'Ident: x': Invalid text operand +===== End Script 18, lines 96 to 98 ===== +===== Start Script 19, lines 99 to 101 ===== + ExprBindInput.txt(100,13)-(100,15): error: at 'QueQue': Invalid boolean operand + ExprBindInput.txt(100,24)-(100,26): error: at 'QueQue': Invalid integer operand + ExprBindInput.txt(100,41)-(100,43): error: at 'QueQue': Invalid text operand +===== End Script 19, lines 99 to 101 ===== +===== Start Script 20, lines 102 to 104 ===== + ExprBindInput.txt(103,9)-(103,11): error: at 'QueQue': Invalid boolean operand + ExprBindInput.txt(103,33)-(103,35): error: at 'QueQue': Invalid text operand +===== End Script 20, lines 102 to 104 ===== +===== Start Script 21, lines 105 to 107 ===== + ExprBindInput.txt(105,18)-(105,20): error: at 'QueQue': Invalid text operand +===== End Script 21, lines 105 to 107 ===== +===== Start Script 22, lines 108 to 117 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +2222 +2222 +*** Parsing ? Failed *** 2222 +===== End Script 22, lines 108 to 117 ===== +===== Start Script 23, lines 118 to 124 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +233 +233 +*** Parsing ? Failed *** 233 +===== End Script 23, lines 118 to 124 ===== +===== Start Script 24, lines 125 to 127 ===== + ExprBindInput.txt(126,6)-(126,7): error: at 'Ident: x': Invalid numeric operand +===== End Script 24, lines 125 to 127 ===== +===== Start Script 25, lines 128 to 134 ===== + ExprBindInput.txt(130,10)-(130,11): error: at 'Ident: a': Invalid numeric operand + ExprBindInput.txt(130,29)-(130,30): error: at 'Ident: a': Invalid numeric operand + ExprBindInput.txt(131,10)-(131,11): error: at 'Ident: a': Invalid numeric operand + ExprBindInput.txt(131,29)-(131,30): error: at 'Ident: a': Invalid numeric operand + ExprBindInput.txt(132,10)-(132,11): error: at 'Ident: a': Invalid numeric operand + ExprBindInput.txt(132,29)-(132,30): error: at 'Ident: a': Invalid numeric operand + ExprBindInput.txt(133,10)-(133,11): error: at 'Ident: a': Invalid numeric operand + ExprBindInput.txt(133,29)-(133,30): error: at 'Ident: a': Invalid numeric operand +===== End Script 25, lines 128 to 134 ===== +===== Start Script 26, lines 135 to 145 ===== + ExprBindInput.txt(137,28)-(137,30): error: at 'QueQue': Invalid boolean operand + ExprBindInput.txt(138,24)-(138,26): error: at 'QueQue': Invalid integer operand + ExprBindInput.txt(139,23)-(139,25): error: at 'QueQue': Invalid integer operand + ExprBindInput.txt(140,22)-(140,24): error: at 'QueQue': Invalid integer operand + ExprBindInput.txt(141,21)-(141,23): error: at 'QueQue': Invalid integer operand +===== End Script 26, lines 135 to 145 ===== +===== Start Script 27, lines 146 to 153 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +-13 +2147483633 +-2147483647 +-2147483648 +*** Parsing ? Failed *** -14 +===== End Script 27, lines 146 to 153 ===== +===== Start Script 28, lines 154 to 165 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +2 +2 +-2 +-2 +===== End Script 28, lines 154 to 165 ===== +===== Start Script 29, lines 166 to 229 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +-8 +-9223372036854775808 +9223372036854775806 +-9223372036854775806 +-9223372036854775808 +0 +0 +98 +9223372036854775806 +-9223372036854775808 +-9223372036854775808 +-9223372036854775806 +0 +0 +-2385 +-446744073709551616 +-9000000000000000000 +0 +0 +2 +2 +-2 +-2 +8 +-32 +0 +0 +0 +0 +0 +0 +0 +===== End Script 29, lines 166 to 229 ===== +===== Start Script 30, lines 230 to 288 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +8 +? +? +-2 +? +? +15 +? +? +0.6 +? +? +2 +2 +-2 +-2 +? +? +8 +11.3137083 +? +? +===== End Script 30, lines 230 to 288 ===== +===== Start Script 31, lines 289 to 347 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +8 +? +? +-2 +? +? +15 +? +? +0.59999999999999998 +? +? +2 +2 +-2 +-2 +? +? +8 +11.313708498984761 +? +? +===== End Script 31, lines 289 to 347 ===== +===== Start Script 32, lines 348 to 356 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +1 +0 +0 +*** Parsing ? Failed *** 1 +===== End Script 32, lines 348 to 356 ===== +===== Start Script 33, lines 357 to 373 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +*** Parsing ? Failed *** 0 +0 +*** Parsing ? Failed *** 0 +1 +0 +0 +*** Parsing ? Failed *** 1 +*** Parsing ? Failed *** 1 +===== End Script 33, lines 357 to 373 ===== +===== Start Script 34, lines 374 to 382 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +1 +0 +===== End Script 34, lines 374 to 382 ===== +===== Start Script 35, lines 383 to 385 ===== + ExprBindInput.txt(384,12)-(384,14): error: at 'LssEqu': Bad operands for comparison +===== End Script 35, lines 383 to 385 ===== +===== Start Script 36, lines 386 to 387 ===== + ExprBindInput.txt(386,10)-(386,11): error: at 'OpenParen': The best overload of 'abs' has some invalid arguments + ExprBindInput.txt(386,11)-(386,12): error: at 'Ident: x': Invalid integer operand +===== End Script 36, lines 386 to 387 ===== +===== Start Script 37, lines 388 to 397 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +-1 +-1 +3 +9223372036854775807 +===== End Script 37, lines 388 to 397 ===== +===== Start Script 38, lines 398 to 438 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +? +3.5 +Infinity +? +-Infinity +0 +0.6931472 +? +Infinity +? +-Infinity +0 +1 +? +Infinity +2 +===== End Script 38, lines 398 to 438 ===== +===== Start Script 39, lines 439 to 479 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +? +3.5 +Infinity +? +-Infinity +0 +0.69314718055994529 +? +Infinity +? +-Infinity +0 +1 +? +Infinity +2 +===== End Script 39, lines 439 to 479 ===== +===== Start Script 40, lines 480 to 481 ===== + ExprBindInput.txt(480,11)-(480,12): error: at 'OpenParen': Expected one argument to function 'isna' +===== End Script 40, lines 480 to 481 ===== +===== Start Script 41, lines 482 to 483 ===== + ExprBindInput.txt(482,10)-(482,11): error: at 'OpenParen': Expected 1 or 2 arguments to function 'log' + ExprBindInput.txt(482,18)-(482,19): error: at 'OpenParen': Expected 1 or 2 arguments to function 'log' + ExprBindInput.txt(482,31)-(482,32): error: at 'OpenParen': The best overload of 'log' has some invalid arguments + ExprBindInput.txt(482,34)-(482,38): error: at 'True': Invalid numeric operand + ExprBindInput.txt(482,45)-(482,46): error: at 'OpenParen': The best overload of 'log' has some invalid arguments + ExprBindInput.txt(482,46)-(482,50): error: at 'True': Invalid numeric operand +===== End Script 41, lines 482 to 483 ===== +===== Start Script 42, lines 484 to 592 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +1 +0.36787945 +2.71828175 +Infinity +? +0 +0.5 +0.866025448 +-0.5 +-0.791163445 +? +? +1 +0.8660254 +0.49999997 +0.8660254 +-0.6116048 +? +? +0 +0.577350259 +1.7320509 +-0.577350259 +1.29358613 +? +? +0 +0.5 +0.8660254 +-0.5 +-0.951500058 +? +? +1 +0.8660254 +0.5 +0.8660254 +-0.307648659 +? +? +0 +0.577350259 +1.73205078 +-0.577350259 +3.092814 +? +? +0 +1.17520118 +-1.17520118 +-Infinity +Infinity +? +1 +1.54308069 +1.54308069 +Infinity +Infinity +? +0 +0.7615942 +-0.7615942 +-1 +1 +? +0 +0.5235988 +-0.5235988 +1.57079637 +? +? +1.57079637 +1.04719758 +2.09439516 +0 +? +? +0 +0.7853982 +-0.7853982 +-1.57079637 +1.57079637 +? +0 +1 +1.41421354 +5 +Infinity +? +? +===== End Script 42, lines 484 to 592 ===== +===== Start Script 43, lines 593 to 701 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +1 +0.36787944117144233 +2.7182818284590451 +Infinity +? +0 +0.5 +0.86602540378443871 +-0.5 +0.0093314689311758247 +? +? +1 +0.8660254037844386 +0.49999999999999989 +0.8660254037844386 +-0.99995646089596646 +? +? +0 +0.57735026918962584 +1.7320508075688776 +-0.57735026918962584 +-0.0093318752326624066 +? +? +0 +0.49999999999999994 +0.8660254037844386 +-0.49999999999999994 +-0.14472535369360071 +? +? +1 +0.86602540378443871 +0.50000000000000011 +0.86602540378443871 +-0.98947186518781938 +? +? +0 +0.57735026918962573 +1.7320508075688767 +-0.57735026918962573 +0.14626525400611495 +? +? +0 +1.1752011936438014 +-1.1752011936438014 +-Infinity +Infinity +? +1 +1.5430806348152437 +1.5430806348152437 +Infinity +Infinity +? +0 +0.76159415595576485 +-0.76159415595576485 +-1 +1 +? +0 +0.52359877559829893 +-0.52359877559829893 +1.5707963267948966 +? +? +1.5707963267948966 +1.0471975511965979 +2.0943951023931957 +0 +? +? +0 +0.78539816339744828 +-0.78539816339744828 +-1.5707963267948966 +1.5707963267948966 +? +0 +1 +1.4142135623730951 +5 +Infinity +? +? +===== End Script 43, lines 593 to 701 ===== +===== Start Script 44, lines 702 to 703 ===== + ExprBindInput.txt(702,10)-(702,11): error: at 'OpenParen': Expected one argument to function 'sin' + ExprBindInput.txt(702,21)-(702,22): error: at 'OpenParen': The best overload of 'sin' has some invalid arguments + ExprBindInput.txt(702,24)-(702,26): error: at 'EquEqu': Invalid numeric operand +===== End Script 44, lines 702 to 703 ===== +===== Start Script 45, lines 704 to 707 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +3 +===== End Script 45, lines 704 to 707 ===== +===== Start Script 46, lines 708 to 709 ===== + ExprBindInput.txt(708,10)-(708,11): error: at 'OpenParen': Expected one argument to function 'int' + ExprBindInput.txt(708,22)-(708,23): error: at 'OpenParen': Expected one argument to function 'long' + ExprBindInput.txt(708,36)-(708,37): error: at 'OpenParen': Expected one argument to function 'single' + ExprBindInput.txt(708,49)-(708,50): error: at 'OpenParen': Expected one argument to function 'float' + ExprBindInput.txt(708,63)-(708,64): error: at 'OpenParen': Expected one argument to function 'double' +===== End Script 46, lines 708 to 709 ===== +===== Start Script 47, lines 710 to 715 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +0 +5 +*** Parsing ? Failed *** 0 +===== End Script 47, lines 710 to 715 ===== +===== Start Script 48, lines 716 to 726 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +374400 +===== End Script 48, lines 716 to 726 ===== +===== Start Script 49, lines 727 to 737 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +374400 +===== End Script 49, lines 727 to 737 ===== +===== Start Script 50, lines 738 to 748 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +373300 +===== End Script 50, lines 738 to 748 ===== +===== Start Script 51, lines 749 to 759 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +373300.00000000099 +===== End Script 51, lines 749 to 759 ===== +===== Start Script 52, lines 760 to 766 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +111 +101 +111 +===== End Script 52, lines 760 to 766 ===== +===== Start Script 53, lines 767 to 775 ===== + ExprBindInput.txt(769,10)-(769,11): error: at 'Ident: x': Invalid numeric operand + ExprBindInput.txt(769,28)-(769,29): error: at 'Ident: x': Invalid numeric operand + ExprBindInput.txt(770,10)-(770,11): error: at 'Ident: x': Invalid numeric operand + ExprBindInput.txt(770,30)-(770,31): error: at 'Ident: x': Invalid numeric operand + ExprBindInput.txt(771,10)-(771,11): error: at 'Ident: x': Invalid numeric operand + ExprBindInput.txt(771,30)-(771,31): error: at 'Ident: x': Invalid numeric operand + ExprBindInput.txt(772,10)-(772,11): error: at 'Ident: x': Invalid numeric operand + ExprBindInput.txt(772,30)-(772,31): error: at 'Ident: x': Invalid numeric operand + ExprBindInput.txt(773,14)-(773,18): error: at '"hi"': Invalid boolean operand + ExprBindInput.txt(773,8)-(773,9): error: at 'Que': Invalid numeric operand + ExprBindInput.txt(773,34)-(773,35): error: at 'Ident: x': Invalid text operand + ExprBindInput.txt(773,25)-(773,26): error: at 'Que': Invalid numeric operand + ExprBindInput.txt(774,11)-(774,15): error: at '"hi"': Invalid numeric operand + ExprBindInput.txt(774,8)-(774,9): error: at 'Que': Invalid numeric operand + ExprBindInput.txt(774,29)-(774,33): error: at '"hi"': Invalid numeric operand + ExprBindInput.txt(774,37)-(774,42): error: at '"bye"': Invalid numeric operand + ExprBindInput.txt(774,26)-(774,27): error: at 'Que': Invalid conditional expression +===== End Script 53, lines 767 to 775 ===== +===== Start Script 54, lines 776 to 789 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +1.011011E+09 +===== End Script 54, lines 776 to 789 ===== +===== Start Script 55, lines 790 to 800 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +1011011 +===== End Script 55, lines 790 to 800 ===== +===== Start Script 56, lines 801 to 803 ===== + ExprBindInput.txt(802,6)-(802,9): error: at 'Ident: foo': Unknown function +===== End Script 56, lines 801 to 803 ===== +===== Start Script 57, lines 804 to 806 ===== + ExprBindInput.txt(805,7)-(805,11): error: at '"hi"': Invalid numeric operand +===== End Script 57, lines 804 to 806 ===== +===== Start Script 58, lines 807 to 835 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +===== End Script 58, lines 807 to 835 ===== +===== Start Script 59, lines 836 to 860 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +===== End Script 59, lines 836 to 860 ===== +===== Start Script 60, lines 861 to 885 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +===== End Script 60, lines 861 to 885 ===== +===== Start Script 61, lines 886 to 890 ===== +Binding succeeded. Output type: String +Compiling succeeded. +hello +goodbye +===== End Script 61, lines 886 to 890 ===== +===== Start Script 62, lines 891 to 896 ===== +Binding succeeded. Output type: String +Compiling succeeded. +b +a +*** Parsing ? Failed *** b +===== End Script 62, lines 891 to 896 ===== +===== Start Script 63, lines 897 to 900 ===== +Binding succeeded. Output type: String +Compiling succeeded. +b +===== End Script 63, lines 897 to 900 ===== +===== Start Script 64, lines 901 to 904 ===== +Binding succeeded. Output type: String +Compiling succeeded. +b +===== End Script 64, lines 901 to 904 ===== +===== Start Script 65, lines 905 to 910 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +1 +*** Parsing ? Failed *** 0 +===== End Script 65, lines 905 to 910 ===== +===== Start Script 66, lines 911 to 918 ===== +Binding succeeded. Output type: String +Compiling succeeded. +hello +hello +blah +"" +*** Parsing ? Failed *** whatever +===== End Script 66, lines 911 to 918 ===== +===== Start Script 67, lines 919 to 926 ===== +Binding succeeded. Output type: String +Compiling succeeded. +HELLO +HELLO +BLAH +"" +*** Parsing ? Failed *** WHATEVER +===== End Script 67, lines 919 to 926 ===== +===== Start Script 68, lines 927 to 936 ===== +Binding succeeded. Output type: String +Compiling succeeded. +hello +"" +b +===== End Script 68, lines 927 to 936 ===== +===== Start Script 69, lines 937 to 946 ===== +Binding succeeded. Output type: String +Compiling succeeded. +HELLO +"" +B +===== End Script 69, lines 937 to 946 ===== +===== Start Script 70, lines 947 to 960 ===== +Binding succeeded. Output type: String +Compiling succeeded. +Hello There Tom +Howdy Nizar +Hola NA!y +"" +"Hola Whoever" +===== End Script 70, lines 947 to 960 ===== +===== Start Script 71, lines 961 to 968 ===== +Binding succeeded. Output type: String +Compiling succeeded. +Mary|Joe|Tom +Cat|Dog|Zebra +Cat||Zebra +Cat||Zebra +===== End Script 71, lines 961 to 968 ===== +===== Start Script 72, lines 969 to 971 ===== + ExprBindInput.txt(970,16)-(970,17): error: at 'OpenParen': The best overload of 'concat' has some invalid arguments + ExprBindInput.txt(970,19)-(970,20): error: at 'Ident: y': Invalid text operand +===== End Script 72, lines 969 to 971 ===== +===== Start Script 73, lines 972 to 975 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +3.1415926535897931 +===== End Script 73, lines 972 to 975 ===== +===== Start Script 74, lines 976 to 984 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +0 +30.000000000000004 +90 +-30.000000000000004 +-90 +? +===== End Script 74, lines 976 to 984 ===== +===== Start Script 75, lines 985 to 993 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +0 +30.000000000000004 +45.000000000000007 +59.999999999999993 +90 +? +===== End Script 75, lines 985 to 993 ===== +===== Start Script 76, lines 994 to 995 ===== + ExprBindInput.txt(994,12)-(994,13): error: at 'OpenParen': The best overload of 'lower' has some invalid arguments + ExprBindInput.txt(994,13)-(994,14): error: at 'Ident: x': Invalid text operand + ExprBindInput.txt(994,23)-(994,24): error: at 'OpenParen': Expected one argument to function 'upper' + ExprBindInput.txt(994,12)-(994,13): error: at 'OpenParen': Invalid numeric operand +===== End Script 76, lines 994 to 995 ===== +===== Start Script 77, lines 996 to 1002 ===== + ExprBindInput.txt(997,12)-(997,14): error: at 'QueQue': Invalid text operand +===== End Script 77, lines 996 to 1002 ===== +===== Start Script 78, lines 1003 to 1014 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +0 +1 +1.5 +-1 +? +? +0 +0 +===== End Script 78, lines 1003 to 1014 ===== +===== Start Script 79, lines 1015 to 1017 ===== + ExprBindInput.txt(1016,13)-(1016,17): error: at 'Ident: blah': Unknown function + ExprBindInput.txt(1016,21)-(1016,23): error: at 'QueQue': Invalid operand + ExprBindInput.txt(1016,30)-(1016,34): error: at 'Ident: blah': Unknown function + ExprBindInput.txt(1016,38)-(1016,40): error: at 'QueQue': Invalid operand + ExprBindInput.txt(1016,47)-(1016,51): error: at 'Ident: blah': Unknown function + ExprBindInput.txt(1016,55)-(1016,57): error: at 'QueQue': Invalid operand + ExprBindInput.txt(1016,64)-(1016,68): error: at 'Ident: blah': Unknown function + ExprBindInput.txt(1016,75)-(1016,79): error: at 'Ident: blah': Unknown function + ExprBindInput.txt(1016,72)-(1016,74): error: at 'QueQue': Invalid operand +===== End Script 79, lines 1015 to 1017 ===== +===== Start Script 80, lines 1018 to 1022 ===== +Binding succeeded. Output type: String +Compiling succeeded. +b +===== End Script 80, lines 1018 to 1022 ===== +===== Start Script 81, lines 1023 to 1025 ===== + ExprBindInput.txt(1024,10)-(1024,14): error: at 'Ident: blah': Unknown function +===== End Script 81, lines 1023 to 1025 ===== +===== Start Script 82, lines 1026 to 1030 ===== +Binding succeeded. Output type: String +Compiling succeeded. +a +===== End Script 82, lines 1026 to 1030 ===== +===== Start Script 83, lines 1031 to 1033 ===== + ExprBindInput.txt(1032,10)-(1032,14): error: at 'Ident: blah': Unknown function + ExprBindInput.txt(1032,9)-(1032,10): error: at 'OpenParen': Ambiguous invocation of function 'int' + ExprBindInput.txt(1032,26)-(1032,30): error: at 'Ident: blah': Unknown function + ExprBindInput.txt(1032,25)-(1032,26): error: at 'OpenParen': Ambiguous invocation of function 'long' + ExprBindInput.txt(1032,44)-(1032,48): error: at 'Ident: blah': Unknown function + ExprBindInput.txt(1032,43)-(1032,44): error: at 'OpenParen': Ambiguous invocation of function 'single' + ExprBindInput.txt(1032,62)-(1032,66): error: at 'Ident: blah': Unknown function + ExprBindInput.txt(1032,61)-(1032,62): error: at 'OpenParen': Ambiguous invocation of function 'double' +===== End Script 83, lines 1031 to 1033 ===== +===== Start Script 84, lines 1034 to 1040 ===== + ExprBindInput.txt(1035,10)-(1035,11): error: at 'OpenParen': The best overload of 'isna' has some invalid arguments + ExprBindInput.txt(1035,11)-(1035,12): error: at 'Ident: x': Invalid numeric operand + ExprBindInput.txt(1035,21)-(1035,22): error: at 'OpenParen': The best overload of 'isna' has some invalid arguments + ExprBindInput.txt(1035,22)-(1035,29): error: at '"hello"': Invalid numeric operand + ExprBindInput.txt(1035,39)-(1035,40): error: at 'OpenParen': The best overload of 'isna' has some invalid arguments + ExprBindInput.txt(1035,51)-(1035,52): error: at 'Que': Invalid numeric operand +===== End Script 84, lines 1034 to 1040 ===== +===== Start Script 85, lines 1041 to 1043 ===== + ExprBindInput.txt(1042,8)-(1042,9): error: at 'OpenParen': Expected 0 arguments to function 'pi' +===== End Script 85, lines 1041 to 1043 ===== +===== Start Script 86, lines 1044 to 1047 ===== + ExprBindInput.txt(1044,9)-(1044,10): error: at 'OpenParen': The best overload of 'na' has some invalid arguments + ExprBindInput.txt(1044,10)-(1044,11): error: at 'Ident: x': Invalid numeric operand +===== End Script 86, lines 1044 to 1047 ===== +===== Start Script 87, lines 1048 to 1051 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +? +===== End Script 87, lines 1048 to 1051 ===== +===== Start Script 88, lines 1052 to 1055 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +? +===== End Script 88, lines 1052 to 1055 ===== +===== Start Script 89, lines 1056 to 1059 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +? +===== End Script 89, lines 1056 to 1059 ===== +===== Start Script 90, lines 1060 to 1063 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +? +===== End Script 90, lines 1060 to 1063 ===== +===== Start Script 91, lines 1064 to 1067 ===== + ExprBindInput.txt(1064,9)-(1064,10): error: at 'OpenParen': The best overload of 'na' has some invalid arguments + ExprBindInput.txt(1064,10)-(1064,11): error: at 'Ident: x': Invalid numeric operand +===== End Script 91, lines 1064 to 1067 ===== +===== Start Script 92, lines 1068 to 1071 ===== + ExprBindInput.txt(1068,10)-(1068,14): error: at 'Ident: blah': Unknown function +===== End Script 92, lines 1068 to 1071 ===== +===== Start Script 93, lines 1072 to 1075 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +===== End Script 93, lines 1072 to 1075 ===== +===== Start Script 94, lines 1076 to 1079 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +0 +===== End Script 94, lines 1076 to 1079 ===== +===== Start Script 95, lines 1080 to 1083 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +0 +===== End Script 95, lines 1080 to 1083 ===== +===== Start Script 96, lines 1084 to 1087 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +0 +===== End Script 96, lines 1084 to 1087 ===== +===== Start Script 97, lines 1088 to 1091 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +0 +===== End Script 97, lines 1088 to 1091 ===== +===== Start Script 98, lines 1092 to 1095 ===== +Binding succeeded. Output type: String +Compiling succeeded. +"" +===== End Script 98, lines 1092 to 1095 ===== +===== Start Script 99, lines 1096 to 1099 ===== + ExprBindInput.txt(1096,15)-(1096,19): error: at 'Ident: blah': Unknown function + ExprBindInput.txt(1096,14)-(1096,15): error: at 'OpenParen': Ambiguous invocation of function 'default' +===== End Script 99, lines 1096 to 1099 ===== +===== Start Script 100, lines 1100 to 1101 ===== + ExprBindInput.txt(1100,11)-(1100,12): error: at 'OpenParen': Expected one argument to function 'bool' + ExprBindInput.txt(1100,21)-(1100,22): error: at 'OpenParen': Expected one argument to function 'bool' + ExprBindInput.txt(1100,35)-(1100,36): error: at 'OpenParen': The best overload of 'bool' has some invalid arguments + ExprBindInput.txt(1100,39)-(1100,40): error: at 'OpenParen': Invalid text operand + ExprBindInput.txt(1100,51)-(1100,52): error: at 'OpenParen': The best overload of 'bool' has some invalid arguments + ExprBindInput.txt(1100,52)-(1100,53): error: at '3': Invalid text operand +===== End Script 100, lines 1100 to 1101 ===== +===== Start Script 101, lines 1102 to 1107 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +1 +*** Parsing ? Failed *** 0 +===== End Script 101, lines 1102 to 1107 ===== +===== Start Script 102, lines 1108 to 1113 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +1 +0 +===== End Script 102, lines 1108 to 1113 ===== +===== Start Script 103, lines 1114 to 1119 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +1 +*** Parsing NA Failed *** 0 +===== End Script 103, lines 1114 to 1119 ===== +===== Start Script 104, lines 1120 to 1125 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +1 +*** Parsing ? Failed *** 0 +===== End Script 104, lines 1120 to 1125 ===== +===== Start Script 105, lines 1126 to 1127 ===== + ExprBindInput.txt(1126,18)-(1126,19): error: at 'OpenParen': Expected one argument to function 'text' + ExprBindInput.txt(1126,26)-(1126,27): error: at 'OpenParen': Expected one argument to function 'text' + ExprBindInput.txt(1126,39)-(1126,43): error: at 'Ident: blah': Unknown function + ExprBindInput.txt(1126,38)-(1126,39): error: at 'OpenParen': Ambiguous invocation of function 'text' +===== End Script 105, lines 1126 to 1127 ===== +===== Start Script 106, lines 1128 to 1131 ===== +Binding succeeded. Output type: String +Compiling succeeded. +1|-3|17|2.5|-3.25|end +===== End Script 106, lines 1128 to 1131 ===== +===== Start Script 107, lines 1132 to 1136 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +ExprDump: 17 +17 +*** Parsing ? Failed *** ExprDump: 0 +0 +===== End Script 107, lines 1132 to 1136 ===== +===== Start Script 108, lines 1137 to 1141 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +Hello from _dump: 17 +17 +*** Parsing ? Failed *** Hello from _dump: 0 +0 +===== End Script 108, lines 1137 to 1141 ===== +===== Start Script 109, lines 1142 to 1143 ===== + ExprBindInput.txt(1142,12)-(1142,13): error: at 'OpenParen': Expected 1 or 2 arguments to function '_dump' +===== End Script 109, lines 1142 to 1143 ===== +===== Start Script 110, lines 1144 to 1145 ===== + ExprBindInput.txt(1144,12)-(1144,13): error: at 'OpenParen': Expected 1 or 2 arguments to function '_dump' +===== End Script 110, lines 1144 to 1145 ===== +===== Start Script 111, lines 1146 to 1147 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +===== End Script 111, lines 1146 to 1147 ===== +===== Start Script 112, lines 1148 to 1149 ===== + ExprBindInput.txt(1148,16)-(1148,17): error: at 'OpenParen': The best overload of '_dump' has some invalid arguments + ExprBindInput.txt(1148,17)-(1148,18): error: at 'Ident: x': Invalid text operand +===== End Script 112, lines 1148 to 1149 ===== +===== Start Script 113, lines 1150 to 1151 ===== + ExprBindInput.txt(1150,12)-(1150,13): error: at 'OpenParen': The best overload of '_dump' has some invalid arguments + ExprBindInput.txt(1150,13)-(1150,14): error: at '1': Invalid text operand +===== End Script 113, lines 1150 to 1151 ===== +===== Start Script 114, lines 1152 to 1153 ===== + ExprBindInput.txt(1152,24)-(1152,25): error: at 'OpenParen': The best overload of '_dump' has some invalid arguments + ExprBindInput.txt(1152,25)-(1152,26): error: at 'Ident: x': Invalid text operand +===== End Script 114, lines 1152 to 1153 ===== +===== Start Script 115, lines 1154 to 1158 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +Hello from _dump: -17 +-17 +*** Parsing ? Failed *** Hello from _dump: 0 +0 +===== End Script 115, lines 1154 to 1158 ===== +===== Start Script 116, lines 1159 to 1165 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. + Eval[y]: 1 + Eval[z]: 2 +2 + Eval[y]: 18 + Eval[z]: 19 +19 + Eval[y]: -1 + Eval[z]: 0 +0 +*** Parsing ? Failed *** Eval[y]: 1 + Eval[z]: 2 +2 +===== End Script 116, lines 1159 to 1165 ===== +===== Start Script 117, lines 1166 to 1174 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +ExprDump: 1 +1 +ExprDump: 0 +0 +ExprDump: 2 +4 +ExprDump: 3 +9 +*** Parsing ? Failed *** ExprDump: 1 +1 +===== End Script 117, lines 1166 to 1174 ===== +===== Start Script 118, lines 1175 to 1194 ===== + ExprBindInput.txt(1182,18)-(1182,20): error: at 'QueQue': Invalid text operand + ExprBindInput.txt(1182,37)-(1182,39): error: at 'QueQue': Invalid text operand + ExprBindInput.txt(1182,56)-(1182,58): error: at 'QueQue': Invalid text operand + ExprBindInput.txt(1182,75)-(1182,77): error: at 'QueQue': Invalid text operand +===== End Script 118, lines 1175 to 1194 ===== +===== Start Script 119, lines 1195 to 1208 ===== + ExprBindInput.txt(1196,60)-(1196,62): error: at 'QueQue': Invalid text operand + ExprBindInput.txt(1196,119)-(1196,121): error: at 'QueQue': Invalid text operand +===== End Script 119, lines 1195 to 1208 ===== +===== Start Script 120, lines 1209 to 1212 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +2 +===== End Script 120, lines 1209 to 1212 ===== +===== Start Script 121, lines 1213 to 1216 ===== + ExprBindInput.txt(1213,13)-(1213,14): error: at 'OpenParen': The best overload of 'na' has some invalid arguments + ExprBindInput.txt(1213,14)-(1213,16): error: at '""': Invalid numeric operand + ExprBindInput.txt(1213,10)-(1213,11): error: at 'OpenParen': The best overload of 'len' has some invalid arguments + ExprBindInput.txt(1213,13)-(1213,14): error: at 'OpenParen': Invalid text operand + ExprBindInput.txt(1213,19)-(1213,21): error: at 'QueQue': Invalid integer operand +===== End Script 121, lines 1213 to 1216 ===== +===== Start Script 122, lines 1217 to 1222 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +5 +0 +0 +===== End Script 122, lines 1217 to 1222 ===== +===== Start Script 123, lines 1223 to 1226 ===== +Binding succeeded. Output type: String +Compiling succeeded. +llo|he|el +===== End Script 123, lines 1223 to 1226 ===== +===== Start Script 124, lines 1227 to 1232 ===== +Binding succeeded. Output type: String +Compiling succeeded. +ello|h|el +*** Parsing ? Failed *** hello||hel +lo|hel| +===== End Script 124, lines 1227 to 1232 ===== +===== Start Script 125, lines 1233 to 1236 ===== + ExprBindInput.txt(1233,22)-(1233,23): error: at 'OpenParen': The best overload of 'na' has some invalid arguments + ExprBindInput.txt(1233,23)-(1233,25): error: at '""': Invalid numeric operand + ExprBindInput.txt(1233,19)-(1233,20): error: at 'OpenParen': The best overload of 'right' has some invalid arguments + ExprBindInput.txt(1233,22)-(1233,23): error: at 'OpenParen': Invalid text operand + ExprBindInput.txt(1233,31)-(1233,33): error: at 'QueQue': Invalid text operand + ExprBindInput.txt(1233,51)-(1233,52): error: at 'OpenParen': The best overload of 'na' has some invalid arguments + ExprBindInput.txt(1233,52)-(1233,54): error: at '""': Invalid numeric operand + ExprBindInput.txt(1233,48)-(1233,49): error: at 'OpenParen': The best overload of 'left' has some invalid arguments + ExprBindInput.txt(1233,51)-(1233,52): error: at 'OpenParen': Invalid text operand + ExprBindInput.txt(1233,60)-(1233,62): error: at 'QueQue': Invalid text operand + ExprBindInput.txt(1233,79)-(1233,80): error: at 'OpenParen': The best overload of 'na' has some invalid arguments + ExprBindInput.txt(1233,80)-(1233,82): error: at '""': Invalid numeric operand + ExprBindInput.txt(1233,76)-(1233,77): error: at 'OpenParen': The best overload of 'mid' has some invalid arguments + ExprBindInput.txt(1233,79)-(1233,80): error: at 'OpenParen': Invalid text operand + ExprBindInput.txt(1233,91)-(1233,93): error: at 'QueQue': Invalid text operand +===== End Script 125, lines 1233 to 1236 ===== +===== Start Script 126, lines 1237 to 1240 ===== + ExprBindInput.txt(1237,19)-(1237,20): error: at 'OpenParen': The best overload of 'right' has some invalid arguments + ExprBindInput.txt(1237,25)-(1237,26): error: at 'OpenParen': Invalid integer operand + ExprBindInput.txt(1237,30)-(1237,32): error: at 'QueQue': Invalid text operand + ExprBindInput.txt(1237,47)-(1237,48): error: at 'OpenParen': The best overload of 'left' has some invalid arguments + ExprBindInput.txt(1237,53)-(1237,54): error: at 'OpenParen': Invalid integer operand + ExprBindInput.txt(1237,58)-(1237,60): error: at 'QueQue': Invalid text operand + ExprBindInput.txt(1237,74)-(1237,75): error: at 'OpenParen': The best overload of 'mid' has some invalid arguments + ExprBindInput.txt(1237,80)-(1237,81): error: at 'OpenParen': Invalid integer operand + ExprBindInput.txt(1237,88)-(1237,90): error: at 'QueQue': Invalid text operand + ExprBindInput.txt(1237,104)-(1237,105): error: at 'OpenParen': The best overload of 'mid' has some invalid arguments + ExprBindInput.txt(1237,113)-(1237,114): error: at 'OpenParen': Invalid integer operand + ExprBindInput.txt(1237,118)-(1237,120): error: at 'QueQue': Invalid text operand +===== End Script 126, lines 1237 to 1240 ===== +===== Start Script 127, lines 1241 to 1242 ===== + ExprBindInput.txt(1241,14)-(1241,15): error: at 'OpenParen': Expected one argument to function 'len' + ExprBindInput.txt(1241,26)-(1241,27): error: at 'OpenParen': The best overload of 'len' has some invalid arguments + ExprBindInput.txt(1241,27)-(1241,28): error: at 'Ident: i': Invalid text operand + ExprBindInput.txt(1241,39)-(1241,40): error: at 'OpenParen': Expected one argument to function 'len' +===== End Script 127, lines 1241 to 1242 ===== +===== Start Script 128, lines 1243 to 1244 ===== + ExprBindInput.txt(1243,23)-(1243,24): error: at 'OpenParen': Expected 2 arguments to function 'right' + ExprBindInput.txt(1243,32)-(1243,33): error: at 'OpenParen': Expected 2 arguments to function 'right' + ExprBindInput.txt(1243,42)-(1243,43): error: at 'OpenParen': The best overload of 'right' has some invalid arguments + ExprBindInput.txt(1243,43)-(1243,44): error: at 'Ident: i': Invalid text operand + ExprBindInput.txt(1243,45)-(1243,46): error: at 'Ident: t': Invalid integer operand + ExprBindInput.txt(1243,54)-(1243,55): error: at 'OpenParen': The best overload of 'right' has some invalid arguments + ExprBindInput.txt(1243,57)-(1243,58): error: at 'Ident: t': Invalid integer operand + ExprBindInput.txt(1243,66)-(1243,67): error: at 'OpenParen': Expected 2 arguments to function 'right' +===== End Script 128, lines 1243 to 1244 ===== +===== Start Script 129, lines 1245 to 1246 ===== + ExprBindInput.txt(1245,22)-(1245,23): error: at 'OpenParen': Expected 2 arguments to function 'left' + ExprBindInput.txt(1245,30)-(1245,31): error: at 'OpenParen': Expected 2 arguments to function 'left' + ExprBindInput.txt(1245,39)-(1245,40): error: at 'OpenParen': The best overload of 'left' has some invalid arguments + ExprBindInput.txt(1245,40)-(1245,41): error: at 'Ident: i': Invalid text operand + ExprBindInput.txt(1245,42)-(1245,43): error: at 'Ident: t': Invalid integer operand + ExprBindInput.txt(1245,50)-(1245,51): error: at 'OpenParen': The best overload of 'left' has some invalid arguments + ExprBindInput.txt(1245,53)-(1245,54): error: at 'Ident: t': Invalid integer operand + ExprBindInput.txt(1245,61)-(1245,62): error: at 'OpenParen': Expected 2 arguments to function 'left' +===== End Script 129, lines 1245 to 1246 ===== +===== Start Script 130, lines 1247 to 1248 ===== + ExprBindInput.txt(1247,21)-(1247,22): error: at 'OpenParen': Expected 3 arguments to function 'mid' + ExprBindInput.txt(1247,28)-(1247,29): error: at 'OpenParen': Expected 3 arguments to function 'mid' + ExprBindInput.txt(1247,36)-(1247,37): error: at 'OpenParen': The best overload of 'mid' has some invalid arguments + ExprBindInput.txt(1247,37)-(1247,38): error: at 'Ident: i': Invalid text operand + ExprBindInput.txt(1247,39)-(1247,40): error: at 'Ident: t': Invalid integer operand + ExprBindInput.txt(1247,48)-(1247,49): error: at 'OpenParen': The best overload of 'mid' has some invalid arguments + ExprBindInput.txt(1247,51)-(1247,52): error: at 'Ident: t': Invalid integer operand + ExprBindInput.txt(1247,60)-(1247,61): error: at 'OpenParen': The best overload of 'mid' has some invalid arguments + ExprBindInput.txt(1247,65)-(1247,66): error: at 'Ident: t': Invalid integer operand + ExprBindInput.txt(1247,72)-(1247,73): error: at 'OpenParen': Expected 3 arguments to function 'mid' + ExprBindInput.txt(1247,82)-(1247,83): error: at 'OpenParen': Expected 3 arguments to function 'mid' +===== End Script 130, lines 1247 to 1248 ===== +===== Start Script 131, lines 1249 to 1254 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +1 +*** Parsing ? Failed *** 0 +===== End Script 131, lines 1249 to 1254 ===== +===== Start Script 132, lines 1255 to 1260 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +1 +*** Parsing ? Failed *** 0 +===== End Script 132, lines 1255 to 1260 ===== +===== Start Script 133, lines 1261 to 1266 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +1 +*** Parsing ? Failed *** 0 +===== End Script 133, lines 1261 to 1266 ===== +===== Start Script 134, lines 1267 to 1272 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +0 +0 +*** Parsing ? Failed *** 0 +===== End Script 134, lines 1267 to 1272 ===== +===== Start Script 135, lines 1273 to 1278 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +0 +0 +*** Parsing ? Failed *** 0 +===== End Script 135, lines 1273 to 1278 ===== +===== Start Script 136, lines 1279 to 1284 ===== +Binding succeeded. Output type: String +Compiling succeeded. +hello +hello +hello +===== End Script 136, lines 1279 to 1284 ===== +===== Start Script 137, lines 1285 to 1290 ===== + ExprBindInput.txt(1285,14)-(1285,15): error: at 'OpenParen': The best overload of 'na' has some invalid arguments + ExprBindInput.txt(1285,15)-(1285,22): error: at '"hello"': Invalid numeric operand + ExprBindInput.txt(1285,9)-(1285,11): error: at 'QueQue': Invalid text operand +===== End Script 137, lines 1285 to 1290 ===== +===== Start Script 138, lines 1291 to 1296 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +? +? +*** Parsing ? Failed *** ? +===== End Script 138, lines 1291 to 1296 ===== +===== Start Script 139, lines 1297 to 1302 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +? +? +*** Parsing ? Failed *** ? +===== End Script 139, lines 1297 to 1302 ===== +===== Start Script 140, lines 1303 to 1308 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +2 +-2 +*** Parsing ? Failed *** 0 +===== End Script 140, lines 1303 to 1308 ===== +===== Start Script 141, lines 1309 to 1314 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +2 +-2 +*** Parsing ? Failed *** 0 +===== End Script 141, lines 1309 to 1314 ===== +===== Start Script 142, lines 1315 to 1320 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +? +? +*** Parsing ? Failed *** ? +===== End Script 142, lines 1315 to 1320 ===== +===== Start Script 143, lines 1321 to 1326 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +? +? +*** Parsing ? Failed *** ? +===== End Script 143, lines 1321 to 1326 ===== +===== Start Script 144, lines 1327 to 1332 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +2 +-2 +*** Parsing ? Failed *** 0 +===== End Script 144, lines 1327 to 1332 ===== +===== Start Script 145, lines 1333 to 1338 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +? +? +*** Parsing ? Failed *** ? +===== End Script 145, lines 1333 to 1338 ===== +===== Start Script 146, lines 1339 to 1344 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +? +? +*** Parsing ? Failed *** ? +===== End Script 146, lines 1339 to 1344 ===== +===== Start Script 147, lines 1345 to 1350 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +2 +-2 +? +===== End Script 147, lines 1345 to 1350 ===== +===== Start Script 148, lines 1351 to 1356 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +? +? +*** Parsing ? Failed *** ? +===== End Script 148, lines 1351 to 1356 ===== +===== Start Script 149, lines 1357 to 1362 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +? +? +*** Parsing ? Failed *** ? +===== End Script 149, lines 1357 to 1362 ===== +===== Start Script 150, lines 1363 to 1368 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +2 +-2 +*** Parsing ? Failed *** 0 +===== End Script 150, lines 1363 to 1368 ===== +===== Start Script 151, lines 1369 to 1374 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +2 +-2 +*** Parsing ? Failed *** 0 +===== End Script 151, lines 1369 to 1374 ===== +===== Start Script 152, lines 1375 to 1380 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +? +? +*** Parsing ? Failed *** ? +===== End Script 152, lines 1375 to 1380 ===== +===== Start Script 153, lines 1381 to 1386 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +? +? +*** Parsing ? Failed *** ? +===== End Script 153, lines 1381 to 1386 ===== +===== Start Script 154, lines 1387 to 1392 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +2 +-2 +*** Parsing ? Failed *** 0 +===== End Script 154, lines 1387 to 1392 ===== +===== Start Script 155, lines 1393 to 1398 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +? +? +*** Parsing ? Failed *** ? +===== End Script 155, lines 1393 to 1398 ===== +===== Start Script 156, lines 1399 to 1404 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +? +? +*** Parsing ? Failed *** ? +===== End Script 156, lines 1399 to 1404 ===== +===== Start Script 157, lines 1405 to 1410 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +2 +-2 +? +===== End Script 157, lines 1405 to 1410 ===== +===== Start Script 158, lines 1411 to 1416 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +? +? +? +===== End Script 158, lines 1411 to 1416 ===== +===== Start Script 159, lines 1417 to 1422 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +? +? +? +===== End Script 159, lines 1417 to 1422 ===== +===== Start Script 160, lines 1423 to 1428 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +2 +-2 +? +===== End Script 160, lines 1423 to 1428 ===== +===== Start Script 161, lines 1429 to 1434 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +2 +-2 +? +===== End Script 161, lines 1429 to 1434 ===== +===== Start Script 162, lines 1435 to 1440 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +? +? +? +===== End Script 162, lines 1435 to 1440 ===== +===== Start Script 163, lines 1441 to 1446 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +? +? +? +===== End Script 163, lines 1441 to 1446 ===== +===== Start Script 164, lines 1447 to 1452 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +2 +-2 +? +===== End Script 164, lines 1447 to 1452 ===== +===== Start Script 165, lines 1453 to 1458 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +? +? +? +===== End Script 165, lines 1453 to 1458 ===== +===== Start Script 166, lines 1459 to 1464 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +? +? +? +===== End Script 166, lines 1459 to 1464 ===== +===== Start Script 167, lines 1465 to 1470 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +2 +-2 +? +===== End Script 167, lines 1465 to 1470 ===== +===== Start Script 168, lines 1471 to 1476 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +? +? +? +===== End Script 168, lines 1471 to 1476 ===== +===== Start Script 169, lines 1477 to 1482 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +? +? +? +===== End Script 169, lines 1477 to 1482 ===== +===== Start Script 170, lines 1483 to 1488 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +2 +-2 +? +===== End Script 170, lines 1483 to 1488 ===== +===== Start Script 171, lines 1489 to 1494 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +2 +-2 +? +===== End Script 171, lines 1489 to 1494 ===== +===== Start Script 172, lines 1495 to 1500 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +? +? +? +===== End Script 172, lines 1495 to 1500 ===== +===== Start Script 173, lines 1501 to 1506 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +? +? +? +===== End Script 173, lines 1501 to 1506 ===== +===== Start Script 174, lines 1507 to 1512 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +2 +-2 +? +===== End Script 174, lines 1507 to 1512 ===== +===== Start Script 175, lines 1513 to 1518 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +? +? +? +===== End Script 175, lines 1513 to 1518 ===== +===== Start Script 176, lines 1519 to 1524 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +? +? +? +===== End Script 176, lines 1519 to 1524 ===== +===== Start Script 177, lines 1525 to 1530 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +2 +-2 +? +===== End Script 177, lines 1525 to 1530 ===== +===== Start Script 178, lines 1531 to 1534 ===== + ExprBindInput.txt(1531,10)-(1531,12): error: at 'QueQue': Invalid integer operand +===== End Script 178, lines 1531 to 1534 ===== +===== Start Script 179, lines 1535 to 1538 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +*** Parsing ? Failed *** 2 +===== End Script 179, lines 1535 to 1538 ===== +===== Start Script 180, lines 1539 to 1542 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +1 +===== End Script 180, lines 1539 to 1542 ===== +===== Start Script 181, lines 1543 to 1546 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +2 +===== End Script 181, lines 1543 to 1546 ===== +===== Start Script 182, lines 1547 to 1550 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +1 +===== End Script 182, lines 1547 to 1550 ===== +===== Start Script 183, lines 1551 to 1554 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +2 +===== End Script 183, lines 1551 to 1554 ===== +===== Start Script 184, lines 1555 to 1558 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +===== End Script 184, lines 1555 to 1558 ===== +===== Start Script 185, lines 1559 to 1560 ===== + ExprBindInput.txt(1559,9)-(1559,10): error: at 'OpenParen': Expected one argument to function 'na' +===== End Script 185, lines 1559 to 1560 ===== diff --git a/test/BaselineOutput/Common/ExprParser/ExprCodeGenOutput.txt b/test/BaselineOutput/Common/ExprParser/ExprCodeGenOutput.txt new file mode 100644 index 0000000000..ac4452811e --- /dev/null +++ b/test/BaselineOutput/Common/ExprParser/ExprCodeGenOutput.txt @@ -0,0 +1,682 @@ +===== Start Script 1, lines 1 to 7 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +0 +*** Parsing ? Failed *** 1 +===== End Script 1, lines 1 to 7 ===== +===== Start Script 2, lines 8 to 49 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +1 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 0 +1600000000 +-1600000000 +2000000000 +-2000000000 +*** Parsing ? Failed *** 0 +1 +*** Parsing ? Failed *** 0 +2 +2 +-2 +-2 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 1 +1 +1 +1 +1 +-1 +-1 +1 +-2000000000 +*** Parsing ? Failed *** 1 +536870912 +-536870912 +1073741824 +1073741824 +2146689000 +===== End Script 2, lines 8 to 49 ===== +===== Start Script 3, lines 50 to 127 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +-9223372036854775808 +9223372036854775806 +-9223372036854775806 +-9223372036854775808 +*** Parsing ? Failed *** 1 +*** Parsing ? Failed *** 1 +9223372036854775806 +-9223372036854775808 +-9223372036854775808 +-9223372036854775806 +*** Parsing ? Failed *** -1 +*** Parsing ? Failed *** 1 +0 +9223372036854775807 +*** Parsing ? Failed *** 0 +0 +9223372036854775807 +*** Parsing ? Failed *** 0 +-9223372036854775807 +-6446744073709551616 +-2446744073709551616 +0 +-2446744073709551616 +9223372032559808512 +-9223372036854775808 +9223372032559808512 +-9223372032559808512 +-9223372032559808512 +9223372032559808512 +-9223372036854775808 +*** Parsing ? Failed *** 0 +2147483647 +-2147483647 +-2147483647 +2147483647 +*** Parsing ? Failed *** 0 +2 +2 +-2 +-2 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 1 +1 +1 +1 +1 +-1 +-1 +1 +-2000000000 +*** Parsing ? Failed *** 1 +536870912 +-536870912 +1073741824 +1073741824 +2147483648 +-2147483648 +2305843009213693952 +-2305843009213693952 +4611686018427387904 +4611686018427387904 +9223358842721533951 +===== End Script 3, lines 50 to 127 ===== +===== Start Script 4, lines 128 to 147 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +3 +2 +-60 +-2.4 +2 +-2 +-2 +2 +Infinity +===== End Script 4, lines 128 to 147 ===== +===== Start Script 5, lines 148 to 168 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +3 +2 +-60 +-2.3999999999999999 +2 +-2 +-2 +2 +1E+100 +Infinity +===== End Script 5, lines 148 to 168 ===== +===== Start Script 6, lines 169 to 172 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +3 +===== End Script 6, lines 169 to 172 ===== +===== Start Script 7, lines 173 to 176 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +2 +===== End Script 7, lines 173 to 176 ===== +===== Start Script 8, lines 177 to 180 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +2 +===== End Script 8, lines 177 to 180 ===== +===== Start Script 9, lines 181 to 187 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +0 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 1 +===== End Script 9, lines 181 to 187 ===== +===== Start Script 10, lines 188 to 194 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +1 +*** Parsing ? Failed *** 1 +*** Parsing ? Failed *** 0 +===== End Script 10, lines 188 to 194 ===== +===== Start Script 11, lines 195 to 202 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +1 +0 +*** Parsing ? Failed *** 1 +*** Parsing ? Failed *** 1 +===== End Script 11, lines 195 to 202 ===== +===== Start Script 12, lines 203 to 212 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +1 +1 +0 +0 +1 +1 +===== End Script 12, lines 203 to 212 ===== +===== Start Script 13, lines 213 to 222 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +1 +0 +0 +0 +0 +0 +===== End Script 13, lines 213 to 222 ===== +===== Start Script 14, lines 223 to 233 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +0 +1 +1 +0 +0 +0 +0 +===== End Script 14, lines 223 to 233 ===== +===== Start Script 15, lines 234 to 241 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +0 +0.6931472 +-Infinity +Infinity +? +===== End Script 15, lines 234 to 241 ===== +===== Start Script 16, lines 242 to 250 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +0 +0.69314718055994529 +-Infinity +230.25850929940458 +Infinity +? +===== End Script 16, lines 242 to 250 ===== +===== Start Script 17, lines 251 to 261 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +0 +1 +-Infinity +10 +-10 +Infinity +? +? +===== End Script 17, lines 251 to 261 ===== +===== Start Script 18, lines 262 to 273 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +0 +1 +-Infinity +10 +-10 +332.19280948873626 +Infinity +? +? +===== End Script 18, lines 262 to 273 ===== +===== Start Script 19, lines 274 to 289 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +1 +1 +*** Parsing ? Failed *** 0 +2 +2 +*** Parsing ? Failed *** 0 +3 +3 +? +4 +4 +? +===== End Script 19, lines 274 to 289 ===== +===== Start Script 20, lines 290 to 312 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +0 +1 +*** Parsing ? Failed *** 0 +2 +-2 +*** Parsing ? Failed *** 0 +3 +-3 +*** Parsing ? Failed *** 0 +2147483647 +-2147483647 +4 +-4 +2147483520 +-2147483520 +5 +-5 +2147483647 +-2147483647 +===== End Script 20, lines 290 to 312 ===== +===== Start Script 21, lines 313 to 335 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +0 +1 +*** Parsing ? Failed *** 0 +2 +-2 +*** Parsing ? Failed *** 0 +3 +-3 +*** Parsing ? Failed *** 0 +9223372036854775807 +-9223372036854775807 +4 +-4 +9223371487098961920 +-9223371487098961920 +5 +-5 +9223372036854774784 +-9223372036854774784 +===== End Script 21, lines 313 to 335 ===== +===== Start Script 22, lines 336 to 370 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +0 +1 +*** Parsing ? Failed *** 0 +2 +-2 +*** Parsing ? Failed *** 0 +3 +-3 +*** Parsing ? Failed *** 0 +9.223372E+18 +-9.223372E+18 +4 +-4 +? +9.22337149E+18 +9.223372E+18 +Infinity +-9.22337149E+18 +-9.223372E+18 +-Infinity +5 +-5 +? +9.223372E+18 +9.223372E+18 +Infinity +Infinity +-9.223372E+18 +-9.223372E+18 +-Infinity +-Infinity +===== End Script 22, lines 336 to 370 ===== +===== Start Script 23, lines 371 to 405 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +0 +1 +*** Parsing ? Failed *** 0 +2 +-2 +*** Parsing ? Failed *** 0 +3 +-3 +*** Parsing ? Failed *** 0 +9.2233720368547758E+18 +-9.2233720368547758E+18 +4 +-4 +? +9.2233714870989619E+18 +9.2233720368547758E+18 +Infinity +-9.2233714870989619E+18 +-9.2233720368547758E+18 +-Infinity +5 +-5 +? +9.2233720368547748E+18 +9.2233720368547758E+18 +1E+100 +Infinity +-9.2233720368547748E+18 +-9.2233720368547758E+18 +-1E+100 +-Infinity +===== End Script 23, lines 371 to 405 ===== +===== Start Script 24, lines 406 to 411 ===== + ExprCodeGenInput.txt(406,11)-(406,12): error: at 'OpenParen': The best overload of 'isna' has some invalid arguments + ExprCodeGenInput.txt(406,12)-(406,13): error: at 'Ident: x': Invalid numeric operand +===== End Script 24, lines 406 to 411 ===== +===== Start Script 25, lines 412 to 421 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +1 +0 +0 +0 +*** Parsing ? Failed *** 1 +*** Parsing ? Failed *** 1 +===== End Script 25, lines 412 to 421 ===== +===== Start Script 26, lines 422 to 435 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +0 +0 +0 +0 +0 +0 +1 +*** Parsing ? Failed *** 1 +*** Parsing ? Failed *** 1 +*** Parsing ? Failed *** 1 +===== End Script 26, lines 422 to 435 ===== +===== Start Script 27, lines 436 to 449 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +0 +0 +0 +0 +0 +0 +0 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 0 +===== End Script 27, lines 436 to 449 ===== +===== Start Script 28, lines 450 to 461 ===== + ExprCodeGenInput.txt(452,15)-(452,17): error: at 'QueQue': Invalid boolean operand + ExprCodeGenInput.txt(453,15)-(453,17): error: at 'QueQue': Invalid boolean operand +===== End Script 28, lines 450 to 461 ===== +===== Start Script 29, lines 462 to 476 ===== + ExprCodeGenInput.txt(469,18)-(469,19): error: at 'OpenParen': The best overload of 'isna' has some invalid arguments + ExprCodeGenInput.txt(469,19)-(469,20): error: at 'Ident: e': Invalid numeric operand + ExprCodeGenInput.txt(470,17)-(470,18): error: at 'OpenParen': The best overload of 'isna' has some invalid arguments + ExprCodeGenInput.txt(470,18)-(470,19): error: at 'Ident: f': Invalid numeric operand +===== End Script 29, lines 462 to 476 ===== +===== Start Script 30, lines 477 to 484 ===== + ExprCodeGenInput.txt(478,24)-(478,26): error: at 'QueQue': Invalid integer operand +===== End Script 30, lines 477 to 484 ===== +===== Start Script 31, lines 485 to 497 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. + Eval[z]: 15 +15 + Eval[z]: -15 +15 + Eval[z]: -15 +-15 + Eval[z]: 15 +-15 +*** Parsing ? Failed *** Eval[z]: 0 +0 +*** Parsing ? Failed *** Eval[z]: 0 +0 +*** Parsing ? Failed *** Eval[z]: 0 +0 +*** Parsing ? Failed *** Eval[z]: 0 +0 +*** Parsing ? Failed *** *** Parsing ? Failed *** Eval[z]: 0 +0 +===== End Script 31, lines 485 to 497 ===== +===== Start Script 32, lines 498 to 512 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +25 + Eval[y]: 10 +100 + Eval[z]: 15 +225 +*** Parsing ? Failed *** 25 +===== End Script 32, lines 498 to 512 ===== +===== Start Script 33, lines 513 to 527 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +25 + Eval[y]: 10 +100 + Eval[y]: 10 + Eval[z]: 30 +900 +*** Parsing ? Failed *** 25 +===== End Script 33, lines 513 to 527 ===== +===== Start Script 34, lines 528 to 539 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +B +0 +B +33554432 +B +-67108864 +B +100663296 +*** Parsing ? Failed *** B +0 +===== End Script 34, lines 528 to 539 ===== +===== Start Script 35, lines 540 to 553 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +B +0 +B +320 +B +-640 +B +960 +*** Parsing ? Failed *** B +0 +===== End Script 35, lines 540 to 553 ===== +===== Start Script 36, lines 554 to 571 ===== + ExprCodeGenInput.txt(556,22)-(556,24): error: at 'QueQue': Invalid text operand + ExprCodeGenInput.txt(557,23)-(557,25): error: at 'QueQue': Invalid text operand + ExprCodeGenInput.txt(558,23)-(558,25): error: at 'QueQue': Invalid text operand +===== End Script 36, lines 554 to 571 ===== +===== Start Script 37, lines 572 to 577 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +0 +0 +===== End Script 37, lines 572 to 577 ===== +===== Start Script 38, lines 578 to 583 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +1 +0 +===== End Script 38, lines 578 to 583 ===== +===== Start Script 39, lines 584 to 589 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +0 +0 +===== End Script 39, lines 584 to 589 ===== +===== Start Script 40, lines 590 to 596 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +0 +1 +1 +===== End Script 40, lines 590 to 596 ===== +===== Start Script 41, lines 597 to 602 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +0 +0 +===== End Script 41, lines 597 to 602 ===== +===== Start Script 42, lines 603 to 608 ===== + ExprCodeGenInput.txt(603,22)-(603,23): error: at 'OpenParen': The best overload of 'na' has some invalid arguments + ExprCodeGenInput.txt(603,23)-(603,24): error: at 'Ident: x': Invalid numeric operand + ExprCodeGenInput.txt(603,22)-(603,23): error: at 'OpenParen': Invalid text operand +===== End Script 42, lines 603 to 608 ===== +===== Start Script 43, lines 609 to 614 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +1 +*** Parsing ? Failed *** 0 +===== End Script 43, lines 609 to 614 ===== +===== Start Script 44, lines 615 to 620 ===== + ExprCodeGenInput.txt(615,9)-(615,11): error: at 'QueQue': Invalid integer operand +===== End Script 44, lines 615 to 620 ===== +===== Start Script 45, lines 621 to 626 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +-1 +3 +17 +===== End Script 45, lines 621 to 626 ===== +===== Start Script 46, lines 627 to 632 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +0 +1 +===== End Script 46, lines 627 to 632 ===== +===== Start Script 47, lines 633 to 639 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +0 +0 +0 +===== End Script 47, lines 633 to 639 ===== +===== Start Script 48, lines 640 to 646 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +1 +0 +0 +===== End Script 48, lines 640 to 646 ===== +===== Start Script 49, lines 647 to 653 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +1 +1 +0 +===== End Script 49, lines 647 to 653 ===== +===== Start Script 50, lines 654 to 660 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +0 +1 +0 +===== End Script 50, lines 654 to 660 ===== +===== Start Script 51, lines 661 to 669 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +0 +1 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** *** Parsing ? Failed *** 0 +===== End Script 51, lines 661 to 669 ===== +===== Start Script 52, lines 670 to 678 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +0 +1 +0 +0 +0 +===== End Script 52, lines 670 to 678 ===== +===== Start Script 53, lines 679 to 684 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +3 +-12 +0 +===== End Script 53, lines 679 to 684 ===== +===== Start Script 54, lines 685 to 691 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +3 +-12.5 +? +0 +===== End Script 54, lines 685 to 691 ===== +===== Start Script 55, lines 692 to 698 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +3 +-12.5 +? +0 +===== End Script 55, lines 692 to 698 ===== +===== Start Script 56, lines 699 to 705 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +0 +0 +0 +===== End Script 56, lines 699 to 705 ===== +===== Start Script 57, lines 706 to 712 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +1 +1 +*** Parsing ? Failed *** 0 +===== End Script 57, lines 706 to 712 ===== +===== Start Script 58, lines 713 to 719 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +0 +1 +*** Parsing ? Failed *** 0 +===== End Script 58, lines 713 to 719 ===== diff --git a/test/BaselineOutput/Common/ExprParser/ExprEvalOutput.txt b/test/BaselineOutput/Common/ExprParser/ExprEvalOutput.txt new file mode 100644 index 0000000000..712c57f755 --- /dev/null +++ b/test/BaselineOutput/Common/ExprParser/ExprEvalOutput.txt @@ -0,0 +1,197 @@ +===== Start Script 1, lines 1 to 13 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +1 +1 +1 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 1 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 1 +*** Parsing ? Failed *** *** Parsing ? Failed *** 0 +===== End Script 1, lines 1 to 13 ===== +===== Start Script 2, lines 14 to 28 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9011101010 +===== End Script 2, lines 14 to 28 ===== +===== Start Script 3, lines 29 to 41 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +0 +0 +1 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** *** Parsing ? Failed *** 0 +===== End Script 3, lines 29 to 41 ===== +===== Start Script 4, lines 42 to 56 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9000100000 +===== End Script 4, lines 42 to 56 ===== +===== Start Script 5, lines 57 to 69 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +1 +0 +0 +1 +*** Parsing ? Failed *** 1 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 1 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** *** Parsing ? Failed *** 1 +===== End Script 5, lines 57 to 69 ===== +===== Start Script 6, lines 70 to 84 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9100110101 +===== End Script 6, lines 70 to 84 ===== +===== Start Script 7, lines 85 to 97 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +1 +1 +0 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 1 +*** Parsing ? Failed *** 0 +*** Parsing ? Failed *** 1 +*** Parsing ? Failed *** *** Parsing ? Failed *** 0 +===== End Script 7, lines 85 to 97 ===== +===== Start Script 8, lines 98 to 112 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9011001010 +===== End Script 8, lines 98 to 112 ===== +===== Start Script 9, lines 114 to 128 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9100100000 +===== End Script 9, lines 114 to 128 ===== +===== Start Script 10, lines 129 to 143 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9011011111 +===== End Script 10, lines 129 to 143 ===== +===== Start Script 11, lines 144 to 158 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9010000000 +===== End Script 11, lines 144 to 158 ===== +===== Start Script 12, lines 159 to 173 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9110100000 +===== End Script 12, lines 159 to 173 ===== +===== Start Script 13, lines 174 to 188 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9101100000 +===== End Script 13, lines 174 to 188 ===== +===== Start Script 14, lines 189 to 203 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9001000000 +===== End Script 14, lines 189 to 203 ===== +===== Start Script 15, lines 205 to 219 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9100100000 +===== End Script 15, lines 205 to 219 ===== +===== Start Script 16, lines 220 to 234 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9011011111 +===== End Script 16, lines 220 to 234 ===== +===== Start Script 17, lines 235 to 249 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9010000000 +===== End Script 17, lines 235 to 249 ===== +===== Start Script 18, lines 250 to 264 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9110100000 +===== End Script 18, lines 250 to 264 ===== +===== Start Script 19, lines 265 to 279 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9101100000 +===== End Script 19, lines 265 to 279 ===== +===== Start Script 20, lines 280 to 294 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9001000000 +===== End Script 20, lines 280 to 294 ===== +===== Start Script 21, lines 296 to 310 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9100100000 +===== End Script 21, lines 296 to 310 ===== +===== Start Script 22, lines 311 to 325 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9011011111 +===== End Script 22, lines 311 to 325 ===== +===== Start Script 23, lines 326 to 340 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9010000000 +===== End Script 23, lines 326 to 340 ===== +===== Start Script 24, lines 341 to 355 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9110100000 +===== End Script 24, lines 341 to 355 ===== +===== Start Script 25, lines 356 to 370 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9101100000 +===== End Script 25, lines 356 to 370 ===== +===== Start Script 26, lines 371 to 385 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9001000000 +===== End Script 26, lines 371 to 385 ===== +===== Start Script 27, lines 387 to 401 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9100100000 +===== End Script 27, lines 387 to 401 ===== +===== Start Script 28, lines 402 to 416 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9011011111 +===== End Script 28, lines 402 to 416 ===== +===== Start Script 29, lines 417 to 431 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9010000000 +===== End Script 29, lines 417 to 431 ===== +===== Start Script 30, lines 432 to 446 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9110100000 +===== End Script 30, lines 432 to 446 ===== +===== Start Script 31, lines 447 to 461 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9101100000 +===== End Script 31, lines 447 to 461 ===== +===== Start Script 32, lines 462 to 476 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +9001000000 +===== End Script 32, lines 462 to 476 ===== +===== Start Script 33, lines 477 to 485 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +9101 +===== End Script 33, lines 477 to 485 ===== diff --git a/test/BaselineOutput/Common/ExprParser/ExprParseOutput.txt b/test/BaselineOutput/Common/ExprParser/ExprParseOutput.txt new file mode 100644 index 0000000000..f49797e77d --- /dev/null +++ b/test/BaselineOutput/Common/ExprParser/ExprParseOutput.txt @@ -0,0 +1,255 @@ +===== Start Script 1, lines 1 to 10 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +4 +6 +-1 +*** Parsing ? Failed *** 1 +-2147483648 +-2147483646 +===== End Script 1, lines 1 to 10 ===== +===== Start Script 2, lines 11 to 20 ===== +Binding succeeded. Output type: Int64 +Compiling succeeded. +4 +6 +-1 +*** Parsing ? Failed *** 1 +-9223372036854775808 +-9223372036854775806 +===== End Script 2, lines 11 to 20 ===== +===== Start Script 3, lines 21 to 29 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +4 +6.25 +-1.5 +? +1E+30 +===== End Script 3, lines 21 to 29 ===== +===== Start Script 4, lines 30 to 38 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +4 +6.25 +-1.5 +? +1E+30 +===== End Script 4, lines 30 to 38 ===== +===== Start Script 5, lines 39 to 46 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +100 +3.1622777 +? +1E+30 +===== End Script 5, lines 39 to 46 ===== +===== Start Script 6, lines 47 to 54 ===== +Binding succeeded. Output type: Double +Compiling succeeded. +100 +3.1622776601683795 +? +1E+30 +===== End Script 6, lines 47 to 54 ===== +===== Start Script 7, lines 55 to 57 ===== + ExprParseInput.txt(56,12)-(56,15): error: at 'Ident: foo': Expected end of input +===== End Script 7, lines 55 to 57 ===== +===== Start Script 8, lines 58 to 60 ===== + ExprParseInput.txt(59,6)-(59,12): error: at 'Newline in constant': Newline in constant +===== End Script 8, lines 58 to 60 ===== +===== Start Script 9, lines 61 to 62 ===== + ExprParseInput.txt(61,9)-(62,1): error: at 'End-of-input found in comment': End-of-input found in comment +===== End Script 9, lines 61 to 62 ===== +===== Start Script 10, lines 63 to 65 ===== + ExprParseInput.txt(64,8)-(64,9): error: at 'Ident: x': Expected end of input +===== End Script 10, lines 63 to 65 ===== +===== Start Script 11, lines 66 to 67 ===== + ExprParseInput.txt(66,13)-(66,15): error: at 'GrtEqu': Mixed direction not allowed +===== End Script 11, lines 66 to 67 ===== +===== Start Script 12, lines 68 to 70 ===== + ExprParseInput.txt(70,1)-(70,1): error: at 'Eof': Expected: ')', Found: '' +===== End Script 12, lines 68 to 70 ===== +===== Start Script 13, lines 71 to 73 ===== + ExprParseInput.txt(72,3)-(72,4): error: at 'CloseParen': Expected: '', Found: ')' +===== End Script 13, lines 71 to 73 ===== +===== Start Script 14, lines 74 to 75 ===== + ExprParseInput.txt(74,4)-(74,7): error: at '123': Expected: '=>', Found: '' +===== End Script 14, lines 74 to 75 ===== +===== Start Script 15, lines 76 to 77 ===== + ExprParseInput.txt(76,6)-(76,9): error: at '123': Expected: '=>', Found: '' +===== End Script 15, lines 76 to 77 ===== +===== Start Script 16, lines 78 to 79 ===== + ExprParseInput.txt(79,1)-(79,1): error: at 'Eof': Expected: ')', Found: '' +===== End Script 16, lines 78 to 79 ===== +===== Start Script 17, lines 80 to 82 ===== + ExprParseInput.txt(81,6)-(81,25): error: at '9223372036854775808': Overflow +===== End Script 17, lines 80 to 82 ===== +===== Start Script 18, lines 83 to 85 ===== + ExprParseInput.txt(84,9)-(84,10): error: at 'Add': Expected: '', Found: '+' +===== End Script 18, lines 83 to 85 ===== +===== Start Script 19, lines 86 to 90 ===== + ExprParseInput.txt(87,9)-(87,10): error: at 'OpenParen': Expected one argument to function 'abs' + ExprParseInput.txt(89,6)-(89,7): error: at 'OpenParen': Expected one argument to function 'abs' +===== End Script 19, lines 86 to 90 ===== +===== Start Script 20, lines 91 to 97 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +3 +3 +*** Parsing ? Failed *** 0 +===== End Script 20, lines 91 to 97 ===== +===== Start Script 21, lines 98 to 106 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +12 +*** Parsing ? Failed *** 12 +===== End Script 21, lines 98 to 106 ===== +===== Start Script 22, lines 107 to 109 ===== + ExprParseInput.txt(108,8)-(108,12): error: at 'True': Operator expected +===== End Script 22, lines 107 to 109 ===== +===== Start Script 23, lines 110 to 112 ===== + ExprParseInput.txt(111,16)-(111,19): error: at 'Ident: xyz': Expected: ':', Found: 'xyz' +===== End Script 23, lines 110 to 112 ===== +===== Start Script 24, lines 113 to 126 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +8 +8 +*** Parsing ? Failed *** 5 +*** Parsing ? Failed *** 3 +2147483647 +-2147483648 +-2147483648 +-2147483647 +-2147483648 +-2147483648 +===== End Script 24, lines 113 to 126 ===== +===== Start Script 25, lines 127 to 129 ===== + ExprParseInput.txt(128,6)-(128,7): error: at 'Ident: z': Too many parameters, expected 2 + ExprParseInput.txt(128,1)-(128,2): error: at 'OpenParen': Wrong number of parameters, expected: 2 +===== End Script 25, lines 127 to 129 ===== +===== Start Script 26, lines 130 to 132 ===== + ExprParseInput.txt(131,1)-(131,2): error: at 'OpenParen': Wrong number of parameters, expected: 3 +===== End Script 26, lines 130 to 132 ===== +===== Start Script 27, lines 133 to 138 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +5 +1 +===== End Script 27, lines 133 to 138 ===== +===== Start Script 28, lines 139 to 144 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +161 +404 +===== End Script 28, lines 139 to 144 ===== +===== Start Script 29, lines 145 to 150 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +2 +3 +===== End Script 29, lines 145 to 150 ===== +===== Start Script 30, lines 151 to 156 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +78 +75 +===== End Script 30, lines 151 to 156 ===== +===== Start Script 31, lines 157 to 162 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +0 +1 +===== End Script 31, lines 157 to 162 ===== +===== Start Script 32, lines 163 to 169 ===== +Binding succeeded. Output type: Single +Compiling succeeded. +*** Parsing ? Failed *** -5 +-3 +*** Parsing NA Failed *** -5 +===== End Script 32, lines 163 to 169 ===== +===== Start Script 33, lines 170 to 176 ===== +Binding succeeded. Output type: Boolean +Compiling succeeded. +*** Parsing ? Failed *** 1 +1 +0 +===== End Script 33, lines 170 to 176 ===== +===== Start Script 34, lines 177 to 179 ===== + ExprParseInput.txt(178,11)-(178,14): error: at ''x'': Expected: '', Found: '' +===== End Script 34, lines 177 to 179 ===== +===== Start Script 35, lines 180 to 186 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +0 +17 +-2 +*** Parsing ? Failed *** 0 +===== End Script 35, lines 180 to 186 ===== +===== Start Script 36, lines 187 to 188 ===== + ExprParseInput.txt(187,12)-(187,13): error: at 'Ident: y': Expected: '(', Found: 'y' +===== End Script 36, lines 187 to 188 ===== +===== Start Script 37, lines 189 to 190 ===== + ExprParseInput.txt(189,14)-(189,15): error: at 'Equ': Expected: '', Found: '=' +===== End Script 37, lines 189 to 190 ===== +===== Start Script 38, lines 191 to 192 ===== + ExprParseInput.txt(191,16)-(191,17): error: at 'Ident: x': Expected: '=', Found: 'x' +===== End Script 38, lines 191 to 192 ===== +===== Start Script 39, lines 193 to 194 ===== + ExprParseInput.txt(193,17)-(193,18): error: at 'Semi': Expected: '', Found: ';' +===== End Script 39, lines 193 to 194 ===== +===== Start Script 40, lines 195 to 196 ===== + ExprParseInput.txt(195,19)-(195,20): error: at 'Ident: y': Expected: ';', Found: 'y' +===== End Script 40, lines 195 to 196 ===== +===== Start Script 41, lines 197 to 198 ===== + ExprParseInput.txt(197,20)-(197,21): error: at 'CloseParen': Expected: '', Found: ')' +===== End Script 41, lines 197 to 198 ===== +===== Start Script 42, lines 199 to 200 ===== + ExprParseInput.txt(200,1)-(200,1): error: at 'Eof': Expected: ')', Found: '' +===== End Script 42, lines 199 to 200 ===== +===== Start Script 43, lines 201 to 207 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +2 +19 +0 +*** Parsing ? Failed *** 2 +===== End Script 43, lines 201 to 207 ===== +===== Start Script 44, lines 208 to 215 ===== + ExprParseInput.txt(209,43)-(209,45): error: at 'QueQue': Invalid text operand + ExprParseInput.txt(209,62)-(209,64): error: at 'QueQue': Invalid text operand + ExprParseInput.txt(209,81)-(209,83): error: at 'QueQue': Invalid text operand +===== End Script 44, lines 208 to 215 ===== +===== Start Script 45, lines 216 to 217 ===== + ExprParseInput.txt(216,17)-(216,18): error: at 'Semi': Expected end of input +===== End Script 45, lines 216 to 217 ===== +===== Start Script 46, lines 218 to 225 ===== +Binding succeeded. Output type: Int32 +Compiling succeeded. +-1 +0 +1 +*** Parsing ? Failed *** 0 +===== End Script 46, lines 218 to 225 ===== +===== Start Script 47, lines 226 to 228 ===== + ExprParseInput.txt(227,12)-(227,13): error: at 'Dot': Expected end of input +===== End Script 47, lines 226 to 228 ===== +===== Start Script 48, lines 229 to 232 ===== +Binding succeeded. Output type: String +Compiling succeeded. +ExprDumpChars: 0058 0041 000A 0042 0058 +XA +===== End Script 48, lines 229 to 232 ===== +===== Start Script 49, lines 233 to 236 ===== +Binding succeeded. Output type: String +Compiling succeeded. +ExprDumpChars: 0058 0041 000D 0042 0058 +BX +===== End Script 49, lines 233 to 236 ===== +===== Start Script 50, lines 237 to 240 ===== +Binding succeeded. Output type: String +Compiling succeeded. +ExprDumpChars: 0058 0041 000D 000A 0042 0058 +XA +===== End Script 50, lines 237 to 240 ===== diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExpr-All-Data.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExpr-All-Data.txt new file mode 100644 index 0000000000..64755e736f --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExpr-All-Data.txt @@ -0,0 +1,720 @@ +#@ TextLoader{ +#@ header+ +#@ sep=tab +#@ col=I4:I4:0 +#@ col=I8:I8:1 +#@ col=R4:R4:2 +#@ col=R8:R8:3 +#@ col=BL:BL:4 +#@ col=T1:TX:5 +#@ col=IR4:I4:6 +#@ col=IR8:I4:7 +#@ col=JR4:R4:8 +#@ col=JR8:R8:9 +#@ col=KI4:R4:10 +#@ col=KI8:R4:11 +#@ col=KR4:R4:12 +#@ col=KR8:R4:13 +#@ col=KBL:R4:14 +#@ col=KT1:R4:15 +#@ } +I4 I8 R4 R8 BL T1 IR4 IR8 JR4 JR8 KI4 KI8 KR4 KR8 KBL KT1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +7 7 5 5 0 10 0 0 5 5 7 7 5 5 0 10 +2 2 1 1 0 2 0 0 1 1 2 2 1 1 0 2 +3 3 1 1 0 4 0 0 1 1 3 3 1 1 0 4 +2 2 3 3 0 1 0 0 3 3 2 2 3 3 0 1 +7 7 8 8 1 10 0 0 8 8 7 7 8 8 1 10 +2 2 1 1 0 10 0 0 1 1 2 2 1 1 0 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 3 3 1 3 0 0 3 3 2 2 3 3 1 3 +2 2 1 1 0 3 0 0 1 1 2 2 1 1 0 3 +7 7 10 10 1 9 0 0 10 10 7 7 10 10 1 9 +6 6 4 4 1 1 0 0 4 4 6 6 4 4 1 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +4 4 6 6 1 10 0 0 6 6 4 4 6 6 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +5 5 10 10 1 10 0 0 10 10 5 5 10 10 1 10 +6 6 3 3 1 7 0 0 3 3 6 6 3 3 1 7 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 1 ? 0 0 1 1 2 2 1 1 1 -1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 4 4 1 7 0 0 4 4 2 2 4 4 1 7 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +8 8 3 3 1 5 0 0 3 3 8 8 3 3 1 5 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +6 6 8 8 1 1 0 0 8 8 6 6 8 8 1 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +2 2 9 9 1 10 0 0 9 9 2 2 9 9 1 10 +6 6 3 3 1 7 0 0 3 3 6 6 3 3 1 7 +6 6 9 9 0 ? 0 0 9 9 6 6 9 9 0 -1 +3 3 1 1 1 3 0 0 1 1 3 3 1 1 1 3 +8 8 2 2 1 10 0 0 2 2 8 8 2 2 1 10 +10 10 6 6 1 1 0 0 6 6 10 10 6 6 1 1 +8 8 4 4 1 1 0 0 4 4 8 8 4 4 1 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +4 4 4 4 1 9 0 0 4 4 4 4 4 4 1 9 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 3 3 0 1 0 0 3 3 2 2 3 3 0 1 +4 4 2 2 1 8 0 0 2 2 4 4 2 2 1 8 +2 2 1 1 1 3 0 0 1 1 2 2 1 1 1 3 +2 2 4 4 1 4 0 0 4 4 2 2 4 4 1 4 +3 3 2 2 1 5 0 0 2 2 3 3 2 2 1 5 +10 10 8 8 1 8 0 0 8 8 10 10 8 8 1 8 +8 8 6 6 1 8 0 0 6 6 8 8 6 6 1 8 +4 4 3 3 1 5 0 0 3 3 4 4 3 3 1 5 +3 3 1 1 1 6 0 0 1 1 3 3 1 1 1 6 +5 5 1 1 1 1 0 0 1 1 5 5 1 1 1 1 +6 6 1 1 1 10 0 0 1 1 6 6 1 1 1 10 +2 2 2 2 1 2 0 0 2 2 2 2 2 2 1 2 +3 3 5 5 1 3 0 0 5 5 3 3 5 5 1 3 +2 2 1 1 0 2 0 0 1 1 2 2 1 1 0 2 +10 10 1 1 1 8 0 0 1 1 10 10 1 1 1 8 +5 5 1 1 1 2 0 0 1 1 5 5 1 1 1 2 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 1 1 1 2 0 0 1 1 3 3 1 1 1 2 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +8 8 1 1 1 10 0 0 1 1 8 8 1 1 1 10 +4 4 3 3 1 9 0 0 3 3 4 4 3 3 1 9 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +10 10 8 8 1 2 0 0 8 8 10 10 8 8 1 2 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +6 6 10 10 1 10 0 0 10 10 6 6 10 10 1 10 +3 3 1 1 1 4 0 0 1 1 3 3 1 1 1 4 +2 2 1 1 0 2 0 0 1 1 2 2 1 1 0 2 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +2 2 1 1 0 3 0 0 1 1 2 2 1 1 0 3 +3 3 1 1 0 1 0 0 1 1 3 3 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 2 0 0 1 1 2 2 1 1 0 2 +8 8 8 8 1 9 0 0 8 8 8 8 8 8 1 9 +10 10 1 1 1 4 0 0 1 1 10 10 1 1 1 4 +5 5 4 4 1 8 0 0 4 4 5 5 4 4 1 8 +5 5 6 6 1 10 0 0 6 6 5 5 6 6 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 2 2 0 1 0 0 2 2 3 3 2 2 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +10 10 2 2 1 6 0 0 2 2 10 10 2 2 1 6 +5 5 10 10 1 10 0 0 10 10 5 5 10 10 1 10 +10 10 1 1 1 5 0 0 1 1 10 10 1 1 1 5 +2 2 4 4 1 5 0 0 4 4 2 2 4 4 1 5 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +6 6 1 1 1 3 0 0 1 1 6 6 1 1 1 3 +10 10 10 10 1 1 0 0 10 10 10 10 10 10 1 1 +3 3 4 4 1 3 0 0 4 4 3 3 4 4 1 3 +2 2 8 8 1 10 0 0 8 8 2 2 8 8 1 10 +8 8 10 10 1 10 0 0 10 10 8 8 10 10 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 4 4 1 9 0 0 4 4 3 3 4 4 1 9 +2 2 2 2 0 2 0 0 2 2 2 2 2 2 0 2 +5 5 3 3 1 9 0 0 3 3 5 5 3 3 1 9 +2 2 10 10 1 10 0 0 10 10 2 2 10 10 1 10 +10 10 3 3 1 8 0 0 3 3 10 10 3 3 1 8 +2 2 1 1 0 3 0 0 1 1 2 2 1 1 0 3 +2 2 1 1 0 5 0 0 1 1 2 2 1 1 0 5 +2 2 1 1 0 2 0 0 1 1 2 2 1 1 0 2 +4 4 10 10 1 10 0 0 10 10 4 4 10 10 1 10 +4 4 1 1 0 3 0 0 1 1 4 4 1 1 0 3 +2 2 1 1 0 2 0 0 1 1 2 2 1 1 0 2 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +2 2 1 1 0 2 0 0 1 1 2 2 1 1 0 2 +10 10 2 2 1 10 0 0 2 2 10 10 2 2 1 10 +8 8 1 1 1 10 0 0 1 1 8 8 1 1 1 10 +9 9 7 7 1 7 0 0 7 7 9 9 7 7 1 7 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +4 4 7 7 1 10 0 0 7 7 4 4 7 7 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +5 5 4 4 1 10 0 0 4 4 5 5 4 4 1 10 +10 10 1 1 0 1 0 0 1 1 10 10 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +8 8 10 10 1 10 0 0 10 10 8 8 10 10 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 1 1 0 1 0 0 1 1 3 3 1 1 0 1 +2 2 1 1 0 2 0 0 1 1 2 2 1 1 0 2 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 1 1 0 ? 0 0 1 1 1 1 1 1 0 -1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +4 4 4 4 1 5 0 0 4 4 4 4 4 4 1 5 +2 2 1 1 0 5 0 0 1 1 2 2 1 1 0 5 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 ? 0 0 1 1 2 2 1 1 0 -1 +6 6 2 2 1 8 0 0 2 2 6 6 2 2 1 8 +3 3 1 1 0 2 0 0 1 1 3 3 1 1 0 2 +8 8 3 3 0 1 0 0 3 3 8 8 3 3 0 1 +10 10 4 4 1 10 0 0 4 4 10 10 4 4 1 10 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +6 6 1 1 1 10 0 0 1 1 6 6 1 1 1 10 +4 4 6 6 1 5 0 0 6 6 4 4 6 6 1 5 +2 2 1 1 0 3 0 0 1 1 2 2 1 1 0 3 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 6 6 1 10 0 0 6 6 3 3 6 6 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 1 1 0 ? 0 0 1 1 3 3 1 1 0 -1 +6 6 3 3 1 10 0 0 3 3 6 6 3 3 1 10 +5 5 4 4 1 10 0 0 4 4 5 5 4 4 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 2 2 0 3 0 0 2 2 1 1 2 2 0 3 +2 2 1 1 0 ? 0 0 1 1 2 2 1 1 0 -1 +2 2 1 1 0 2 0 0 1 1 2 2 1 1 0 2 +8 8 8 8 1 10 0 0 8 8 8 8 8 8 1 10 +6 6 10 10 1 1 0 0 10 10 6 6 10 10 1 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 2 2 0 1 0 0 2 2 1 1 2 2 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +8 8 10 10 1 10 0 0 10 10 8 8 10 10 1 10 +3 3 4 4 1 10 0 0 4 4 3 3 4 4 1 10 +10 10 7 7 1 10 0 0 7 7 10 10 7 7 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +8 8 3 3 1 1 0 0 3 3 8 8 3 3 1 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +6 6 3 3 1 10 0 0 3 3 6 6 3 3 1 10 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +5 5 8 8 1 10 0 0 8 8 5 5 8 8 1 10 +4 4 4 4 1 10 0 0 4 4 4 4 4 4 1 10 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +5 5 6 6 1 8 0 0 6 6 5 5 6 6 1 8 +6 6 10 10 1 10 0 0 10 10 6 6 10 10 1 10 +5 5 10 10 1 8 0 0 10 10 5 5 10 10 1 8 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +6 6 8 8 1 8 0 0 8 8 6 6 8 8 1 8 +10 10 10 10 1 10 0 0 10 10 10 10 10 10 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +4 4 5 5 0 7 0 0 5 5 4 4 5 5 0 7 +2 2 4 4 0 1 0 0 4 4 2 2 4 4 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +5 5 5 5 1 10 0 0 5 5 5 5 5 5 1 10 +10 10 4 4 1 10 0 0 4 4 10 10 4 4 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +6 6 9 9 1 10 0 0 9 9 6 6 9 9 1 10 +7 7 3 3 1 5 0 0 3 3 7 7 3 3 1 5 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +5 5 10 10 1 10 0 0 10 10 5 5 10 10 1 10 +4 4 8 8 1 8 0 0 8 8 4 4 8 8 1 8 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +7 7 10 10 1 10 0 0 10 10 7 7 10 10 1 10 +3 3 10 10 1 10 0 0 10 10 3 3 10 10 1 10 +5 5 7 7 1 5 0 0 7 7 5 5 7 7 1 5 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +6 6 7 7 1 4 0 0 7 7 6 6 7 7 1 4 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +10 10 3 3 1 10 0 0 3 3 10 10 3 3 1 10 +1 1 3 3 1 5 0 0 3 3 1 1 3 3 1 5 +3 3 3 3 1 8 0 0 3 3 3 3 3 3 1 8 +3 3 6 6 1 10 0 0 6 6 3 3 6 6 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +4 4 4 4 1 10 0 0 4 4 4 4 4 4 1 10 +3 3 5 5 1 5 0 0 5 5 3 3 5 5 1 5 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +10 10 3 3 1 10 0 0 3 3 10 10 3 3 1 10 +3 3 4 4 1 7 0 0 4 4 3 3 4 4 1 7 +6 6 5 5 1 8 0 0 5 5 6 6 5 5 1 8 +3 3 3 3 0 1 0 0 3 3 3 3 3 3 0 1 +5 5 5 5 1 10 0 0 5 5 5 5 5 5 1 10 +3 3 1 1 0 1 0 0 1 1 3 3 1 1 0 1 +2 2 1 1 0 ? 0 0 1 1 2 2 1 1 0 -1 +8 8 2 2 1 10 0 0 2 2 8 8 2 2 1 10 +6 6 5 5 1 2 0 0 5 5 6 6 5 5 1 2 +6 6 8 8 1 9 0 0 8 8 6 6 8 8 1 9 +3 3 2 2 1 10 0 0 2 2 3 3 2 2 1 10 +2 2 3 3 0 2 0 0 3 3 2 2 3 3 0 2 +1 1 3 3 0 1 0 0 3 3 1 1 3 3 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 5 0 0 1 1 2 2 1 1 0 5 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 2 2 0 2 0 0 2 2 2 2 2 2 0 2 +5 5 8 8 1 10 0 0 8 8 5 5 8 8 1 10 +2 2 1 1 1 9 0 0 1 1 2 2 1 1 1 9 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 ? 0 0 1 1 2 2 1 1 0 -1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 10 10 1 10 0 0 10 10 2 2 10 10 1 10 +3 3 5 5 0 10 0 0 5 5 3 3 5 5 0 10 +8 8 2 2 1 10 0 0 2 2 8 8 2 2 1 10 +10 10 1 1 1 8 0 0 1 1 10 10 1 1 1 8 +4 4 2 2 1 10 0 0 2 2 4 4 2 2 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +5 5 1 1 0 8 0 0 1 1 5 5 1 1 0 8 +3 3 10 10 1 10 0 0 10 10 3 3 10 10 1 10 +10 10 6 6 1 10 0 0 6 6 10 10 6 6 1 10 +5 5 4 4 1 10 0 0 4 4 5 5 4 4 1 10 +6 6 10 10 1 10 0 0 10 10 6 6 10 10 1 10 +10 10 10 10 1 3 0 0 10 10 10 10 10 10 1 3 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 3 3 1 10 0 0 3 3 3 3 3 3 1 10 +3 3 2 2 1 10 0 0 2 2 3 3 2 2 1 10 +3 3 2 2 1 4 0 0 2 2 3 3 2 2 1 4 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 1 1 1 10 0 0 1 1 3 3 1 1 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 2 2 1 10 0 0 2 2 3 3 2 2 1 10 +3 3 1 1 1 4 0 0 1 1 3 3 1 1 1 4 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 ? 0 0 1 1 2 2 1 1 0 -1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 3 3 1 7 0 0 3 3 3 3 3 3 1 7 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +4 4 10 10 1 10 0 0 10 10 4 4 10 10 1 10 +2 2 1 1 1 10 0 0 1 1 2 2 1 1 1 10 +2 2 10 10 1 10 0 0 10 10 2 2 10 10 1 10 +8 8 10 10 1 10 0 0 10 10 8 8 10 10 1 10 +10 10 10 10 1 10 0 0 10 10 10 10 10 10 1 10 +3 3 1 1 0 1 0 0 1 1 3 3 1 1 0 1 +4 4 1 1 1 5 0 0 1 1 4 4 1 1 1 5 +6 6 8 8 1 10 0 0 8 8 6 6 8 8 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 1 ? 0 0 1 1 2 2 1 1 1 -1 +2 2 6 6 1 10 0 0 6 6 2 2 6 6 1 10 +2 2 1 1 0 ? 0 0 1 1 2 2 1 1 0 -1 +6 6 8 8 1 10 0 0 8 8 6 6 8 8 1 10 +4 4 3 3 0 5 0 0 3 3 4 4 3 3 0 5 +2 2 1 1 0 ? 0 0 1 1 2 2 1 1 0 -1 +5 5 1 1 0 1 0 0 1 1 5 5 1 1 0 1 +4 4 6 6 1 10 0 0 6 6 4 4 6 6 1 10 +4 4 5 5 1 4 0 0 5 5 4 4 5 5 1 4 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +9 9 7 7 1 10 0 0 7 7 9 9 7 7 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 9 9 1 10 0 0 9 9 3 3 9 9 1 10 +4 4 4 4 1 10 0 0 4 4 4 4 4 4 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +4 4 6 6 1 3 0 0 6 6 4 4 6 6 1 3 +2 2 1 1 0 5 0 0 1 1 2 2 1 1 0 5 +3 3 1 1 0 1 0 0 1 1 3 3 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +10 10 10 10 1 1 0 0 10 10 10 10 10 10 1 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +7 7 6 6 0 ? 0 0 6 6 7 7 6 6 0 -1 +5 5 2 2 1 10 0 0 2 2 5 5 2 2 1 10 +6 6 8 8 1 8 0 0 8 8 6 6 8 8 1 8 +5 5 1 1 0 1 0 0 1 1 5 5 1 1 0 1 +6 6 4 4 0 5 0 0 4 4 6 6 4 4 0 5 +5 5 2 2 1 10 0 0 2 2 5 5 2 2 1 10 +2 2 1 1 0 ? 0 0 1 1 2 2 1 1 0 -1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 10 10 1 10 0 0 10 10 2 2 10 10 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 1 10 0 0 1 1 2 2 1 1 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +6 6 2 2 1 4 0 0 2 2 6 6 2 2 1 4 +5 5 4 4 1 10 0 0 4 4 5 5 4 4 1 10 +2 2 2 2 1 8 0 0 2 2 2 2 2 2 1 8 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +4 4 6 6 1 10 0 0 6 6 4 4 6 6 1 10 +3 3 3 3 1 10 0 0 3 3 3 3 3 3 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +4 4 8 8 1 10 0 0 8 8 4 4 8 8 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +2 2 5 5 1 10 0 0 5 5 2 2 5 5 1 10 +2 2 1 1 1 10 0 0 1 1 2 2 1 1 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +10 10 8 8 1 10 0 0 8 8 10 10 8 8 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 2 2 0 1 0 0 2 2 3 3 2 2 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +5 5 10 10 1 1 0 0 10 10 5 5 10 10 1 1 +3 3 5 5 1 8 0 0 5 5 3 3 5 5 1 8 +2 2 3 3 0 1 0 0 3 3 2 2 3 3 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +7 7 3 3 0 3 0 0 3 3 7 7 3 3 0 3 +7 7 10 10 1 10 0 0 10 10 7 7 10 10 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 1 1 0 1 0 0 1 1 3 3 1 1 0 1 +3 3 1 1 1 3 0 0 1 1 3 3 1 1 1 3 +10 10 7 7 1 10 0 0 7 7 10 10 7 7 1 10 +8 8 3 3 1 4 0 0 3 3 8 8 3 3 1 4 +3 3 4 4 1 7 0 0 4 4 3 3 4 4 1 7 +10 10 10 10 1 10 0 0 10 10 10 10 10 10 1 10 +6 6 10 10 1 10 0 0 10 10 6 6 10 10 1 10 +4 4 1 1 0 3 0 0 1 1 4 4 1 1 0 3 +2 2 2 2 0 3 0 0 2 2 2 2 2 2 0 3 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +8 8 10 10 1 10 0 0 10 10 8 8 10 10 1 10 +5 5 10 10 1 10 0 0 10 10 5 5 10 10 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +3 3 1 1 0 1 0 0 1 1 3 3 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +3 3 4 4 0 1 0 0 4 4 3 3 4 4 0 1 +4 4 1 1 0 1 0 0 1 1 4 4 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +4 4 6 6 1 10 0 0 6 6 4 4 6 6 1 10 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 2 2 0 1 0 0 2 2 3 3 2 2 0 1 +2 2 3 3 1 10 0 0 3 3 2 2 3 3 1 10 +3 3 2 2 0 1 0 0 2 2 3 3 2 2 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 1 1 0 2 0 0 1 1 3 3 1 1 0 2 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +3 3 4 4 1 10 0 0 4 4 3 3 4 4 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +6 6 7 7 1 9 0 0 7 7 6 6 7 7 1 9 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 4 0 0 1 1 2 2 1 1 0 4 +2 2 3 3 0 1 0 0 3 3 2 2 3 3 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 2 2 0 2 0 0 2 2 2 2 2 2 0 2 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 1 1 0 ? 0 0 1 1 1 1 1 1 0 -1 +8 8 6 6 1 4 0 0 6 6 8 8 6 6 1 4 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 2 2 1 10 0 0 2 2 3 3 2 2 1 10 +3 3 6 6 0 3 0 0 6 6 3 3 6 6 0 3 +10 10 5 5 1 10 0 0 5 5 10 10 5 5 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 2 2 0 2 0 0 2 2 2 2 2 2 0 2 +5 5 1 1 0 1 0 0 1 1 5 5 1 1 0 1 +2 2 3 3 0 3 0 0 3 3 2 2 3 3 0 3 +10 10 7 7 1 10 0 0 7 7 10 10 7 7 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +10 10 10 10 1 10 0 0 10 10 10 10 10 10 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +4 4 2 2 1 2 0 0 2 2 4 4 2 2 1 2 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +4 4 3 3 0 1 0 0 3 3 4 4 3 3 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 3 3 0 1 0 0 3 3 2 2 3 3 0 1 +5 5 5 5 0 8 0 0 5 5 5 5 5 5 0 8 +3 3 1 1 1 10 0 0 1 1 3 3 1 1 1 10 +6 6 1 1 1 1 0 0 1 1 6 6 1 1 1 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 3 3 0 1 0 0 3 3 2 2 3 3 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +4 4 10 10 1 10 0 0 10 10 4 4 10 10 1 10 +2 2 4 4 0 4 0 0 4 4 2 2 4 4 0 4 +2 2 3 3 0 3 0 0 3 3 2 2 3 3 0 3 +2 2 1 1 0 2 0 0 1 1 2 2 1 1 0 2 +3 3 6 6 0 1 0 0 6 6 3 3 6 6 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +6 6 8 8 1 10 0 0 8 8 6 6 8 8 1 10 +1 1 3 3 0 1 0 0 3 3 1 1 3 3 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 3 3 0 1 0 0 3 3 2 2 3 3 0 1 +6 6 8 8 1 10 0 0 8 8 6 6 8 8 1 10 +3 3 1 1 0 1 0 0 1 1 3 3 1 1 0 1 +2 2 1 1 1 6 0 0 1 1 2 2 1 1 1 6 +5 5 8 8 1 10 0 0 8 8 5 5 8 8 1 10 +6 6 6 6 1 3 0 0 6 6 6 6 6 6 1 3 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 3 3 0 1 0 0 3 3 2 2 3 3 0 1 +2 2 1 1 0 5 0 0 1 1 2 2 1 1 0 5 +2 2 3 3 0 1 0 0 3 3 2 2 3 3 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +6 6 7 7 1 4 0 0 7 7 6 6 7 7 1 4 +4 4 2 2 1 10 0 0 2 2 4 4 2 2 1 10 +4 4 5 5 1 10 0 0 5 5 4 4 5 5 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +2 2 3 3 0 1 0 0 3 3 2 2 3 3 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +4 4 10 10 1 10 0 0 10 10 4 4 10 10 1 10 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +2 2 4 4 0 1 0 0 4 4 2 2 4 4 0 1 +10 10 10 10 1 5 0 0 10 10 10 10 10 10 1 5 +5 5 5 5 1 10 0 0 5 5 5 5 5 5 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 3 3 0 3 0 0 3 3 1 1 3 3 0 3 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +6 6 10 10 1 10 0 0 10 10 6 6 10 10 1 10 +3 3 10 10 1 3 0 0 10 10 3 3 10 10 1 3 +3 3 1 1 1 4 0 0 1 1 3 3 1 1 1 4 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 4 4 1 10 0 0 4 4 3 3 4 4 1 10 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +6 6 10 10 1 10 0 0 10 10 6 6 10 10 1 10 +4 4 10 10 0 5 0 0 10 10 4 4 10 10 0 5 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +7 7 10 10 1 5 0 0 10 10 7 7 10 10 1 5 +2 2 1 1 0 4 0 0 1 1 2 2 1 1 0 4 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +3 3 10 10 1 10 0 0 10 10 3 3 10 10 1 10 +3 3 7 7 1 10 0 0 7 7 3 3 7 7 1 10 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +4 4 3 3 1 10 0 0 3 3 4 4 3 3 1 10 +3 3 1 1 0 1 0 0 1 1 3 3 1 1 0 1 +3 3 1 1 0 1 0 0 1 1 3 3 1 1 0 1 +3 3 4 4 1 5 0 0 4 4 3 3 4 4 1 5 +4 4 10 10 1 10 0 0 10 10 4 4 10 10 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +4 4 3 3 1 10 0 0 3 3 4 4 3 3 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 2 0 0 1 1 2 2 1 1 0 2 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +4 4 10 10 1 10 0 0 10 10 4 4 10 10 1 10 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +4 4 7 7 1 5 0 0 7 7 4 4 7 7 1 5 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +2 2 1 1 0 5 0 0 1 1 2 2 1 1 0 5 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 2 2 0 1 0 0 2 2 1 1 2 2 0 1 +2 2 3 3 0 1 0 0 3 3 2 2 3 3 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +5 5 10 10 1 10 0 0 10 10 5 5 10 10 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 3 0 0 1 1 2 2 1 1 0 3 +6 6 1 1 1 10 0 0 1 1 6 6 1 1 1 10 +6 6 10 10 1 5 0 0 10 10 6 6 10 10 1 5 +8 8 4 4 1 10 0 0 4 4 8 8 4 4 1 10 +3 3 5 5 1 10 0 0 5 5 3 3 5 5 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +4 4 3 3 1 2 0 0 3 3 4 4 3 3 1 2 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +5 5 6 6 1 10 0 0 6 6 5 5 6 6 1 10 +4 4 5 5 1 10 0 0 5 5 4 4 5 5 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 6 6 0 1 0 0 6 6 3 3 6 6 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +6 6 10 10 1 10 0 0 10 10 6 6 10 10 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +6 6 9 9 1 3 0 0 9 9 6 6 9 9 1 3 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +4 4 5 5 1 1 0 0 5 5 4 4 5 5 1 1 +4 4 6 6 1 10 0 0 6 6 4 4 6 6 1 10 +3 3 5 5 1 10 0 0 5 5 3 3 5 5 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +4 4 3 3 1 10 0 0 3 3 4 4 3 3 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +4 4 8 8 1 1 0 0 8 8 4 4 8 8 1 1 +5 5 8 8 1 10 0 0 8 8 5 5 8 8 1 10 +5 5 3 3 1 8 0 0 3 3 5 5 3 3 1 8 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +10 10 10 10 1 10 0 0 10 10 10 10 10 10 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 10 10 1 10 0 0 10 10 3 3 10 10 1 10 +5 5 10 10 1 2 0 0 10 10 5 5 10 10 1 2 +6 6 10 10 1 10 0 0 10 10 6 6 10 10 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 1 1 0 ? 0 0 1 1 1 1 1 1 0 -1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 3 3 0 2 0 0 3 3 3 3 3 3 0 2 +2 2 3 3 0 1 0 0 3 3 2 2 3 3 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +1 1 2 2 0 1 0 0 2 2 1 1 2 2 0 1 +3 3 1 1 0 4 0 0 1 1 3 3 1 1 0 4 +7 7 5 5 1 6 0 0 5 5 7 7 5 5 1 6 +2 2 1 1 0 5 0 0 1 1 2 2 1 1 0 5 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +5 5 4 4 1 3 0 0 4 4 5 5 4 4 1 3 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +7 7 8 8 1 1 0 0 8 8 7 7 8 8 1 1 +2 2 3 3 0 2 0 0 3 3 2 2 3 3 0 2 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 3 3 0 1 0 0 3 3 2 2 3 3 0 1 +2 2 3 3 0 1 0 0 3 3 2 2 3 3 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 3 3 0 1 0 0 3 3 2 2 3 3 0 1 +10 10 10 10 1 2 0 0 10 10 10 10 10 10 1 2 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 2 2 0 4 0 0 2 2 3 3 2 2 0 4 +2 2 3 3 0 1 0 0 3 3 2 2 3 3 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +8 8 1 1 0 1 0 0 1 1 8 8 1 1 0 1 +3 3 7 7 1 10 0 0 7 7 3 3 7 7 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 3 3 0 1 0 0 3 3 2 2 3 3 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +6 6 1 1 1 1 0 0 1 1 6 6 1 1 1 1 +5 5 8 8 1 5 0 0 8 8 5 5 8 8 1 5 +5 5 8 8 1 8 0 0 8 8 5 5 8 8 1 8 +2 2 2 2 0 1 0 0 2 2 2 2 2 2 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 1 1 0 1 0 0 1 1 3 3 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +5 5 10 10 1 10 0 0 10 10 5 5 10 10 1 10 +4 4 10 10 1 10 0 0 10 10 4 4 10 10 1 10 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 3 3 0 1 0 0 3 3 2 2 3 3 0 1 +4 4 5 5 1 5 0 0 5 5 4 4 5 5 1 5 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +3 3 1 1 0 2 0 0 1 1 3 3 1 1 0 2 +2 2 1 1 0 1 0 0 1 1 2 2 1 1 0 1 +7 7 3 3 1 3 0 0 3 3 7 7 3 3 1 3 +3 3 4 4 1 4 0 0 4 4 3 3 4 4 1 4 +4 4 5 5 1 5 0 0 5 5 4 4 5 5 1 5 diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExpr-All-Schema.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExpr-All-Schema.txt new file mode 100644 index 0000000000..45820c605a --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExpr-All-Schema.txt @@ -0,0 +1,80 @@ +---- BoundLoader ---- +6 columns: + I4: Int32 + I8: Int64 + R4: Single + R8: Double + BL: Boolean + T1: String +---- RowToRowMapperTransform ---- +12 columns: + I4: Int32 + I4: Int32 + I8: Int64 + I8: Int64 + R4: Single + R4: Single + R8: Double + R8: Double + BL: Boolean + BL: Boolean + T1: String + T1: String +---- RowToRowMapperTransform ---- +14 columns: + I4: Int32 + I4: Int32 + I8: Int64 + I8: Int64 + R4: Single + R4: Single + R8: Double + R8: Double + BL: Boolean + BL: Boolean + T1: String + T1: String + IR4: Int32 + IR8: Int32 +---- RowToRowMapperTransform ---- +16 columns: + I4: Int32 + I4: Int32 + I8: Int64 + I8: Int64 + R4: Single + R4: Single + R8: Double + R8: Double + BL: Boolean + BL: Boolean + T1: String + T1: String + IR4: Int32 + IR8: Int32 + JR4: Single + JR8: Double +---- RowToRowMapperTransform ---- +22 columns: + I4: Int32 + I4: Int32 + I8: Int64 + I8: Int64 + R4: Single + R4: Single + R8: Double + R8: Double + BL: Boolean + BL: Boolean + T1: String + T1: String + IR4: Int32 + IR8: Int32 + JR4: Single + JR8: Double + KI4: Single + KI8: Single + KR4: Single + KR8: Single + KBL: Single + KT1: Single diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExpr-CursLog.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExpr-CursLog.txt new file mode 100644 index 0000000000..25bb2caf5a --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExpr-CursLog.txt @@ -0,0 +1 @@ +Cursored through 699 rows diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExpr-Data.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExpr-Data.txt new file mode 100644 index 0000000000..96dcced193 --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExpr-Data.txt @@ -0,0 +1,720 @@ +#@ TextLoader{ +#@ header+ +#@ sep=tab +#@ col=A:BL:0 +#@ col=B:BL:1 +#@ col=C:I4:2 +#@ col=D:I4:3 +#@ col=M1:BL:4 +#@ col=N1:BL:5 +#@ col=M2:BL:6 +#@ col=N2:BL:7 +#@ col=U:I4:8 +#@ col=V:R4:9 +#@ col=W:R4:10 +#@ col=X1:I4:11 +#@ col=Y1:I4:12 +#@ col=X2:R4:13 +#@ col=Y2:R4:14 +#@ col=Z:I4:15 +#@ } +A B C D M1 N1 M2 N2 U V W X1 Y1 X2 Y2 Z +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 4 6 0 1 0 1 46 1.609438 1.58496249 0 0 0.5 0.7 106 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 5 2 0 1 0 1 52 1.79175949 2 0 0 0.6 0.3 102 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +1 1 7 6 0 1 0 1 76 2.07944155 1 0 0 0.8 0.7 106 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +16 5:1 7:1 13:0.1 14:0.1 15:100 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +1 1 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 7 6 0 1 0 1 76 2.07944155 1 0 0 0.8 0.7 106 +1 1 6 5 0 1 0 1 65 1.9459101 1 0 0 0.7 0.6 105 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +1 1 9 3 0 1 0 1 93 2.30258512 2.807355 1 0 1 0.4 103 +0 0 5 1 0 1 0 1 51 1.79175949 2.321928 0 0 0.6 0.2 101 +1 1 6 4 0 1 0 1 64 1.9459101 1.58496249 0 0 0.7 0.5 104 +1 1 9 5 0 1 0 1 95 2.30258512 2.321928 1 0 1 0.6 105 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +1 1 7 1 0 1 0 1 71 2.07944155 2.807355 0 0 0.8 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 2 0 0 1 0 1 20 1.09861231 1.58496249 0 0 0.3 0.1 100 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 2 0 0 1 0 1 20 1.09861231 1.58496249 0 0 0.3 0.1 100 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +1 1 9 7 0 1 0 1 97 2.30258512 1.58496249 1 0 1 0.8 107 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +1 1 9 5 0 1 0 1 95 2.30258512 2.321928 1 0 1 0.6 105 +0 0 5 0 0 1 0 1 50 1.79175949 2.58496261 0 0 0.6 0.1 100 +1 1 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 1 5 0 1 0 1 15 0.6931472 2.321928 0 0 0.2 0.6 105 +0 0 5 5 0 1 0 1 55 1.79175949 0 0 0 0.6 0.6 105 +1 1 9 2 0 1 0 1 92 2.30258512 3 1 0 1 0.3 102 +1 1 5 7 0 1 0 1 57 1.79175949 1.58496249 0 0 0.6 0.8 107 +1 1 4 9 0 1 0 1 49 1.609438 2.58496261 0 1 0.5 1 109 +1 1 9 7 0 1 0 1 97 2.30258512 1.58496249 1 0 1 0.8 107 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 2 3 0 1 0 1 23 1.09861231 1 0 0 0.3 0.4 103 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +1 1 6 3 0 1 0 1 63 1.9459101 2 0 0 0.7 0.4 103 +1 1 8 1 0 1 0 1 81 2.19722462 3 0 0 0.9 0.2 101 +1 1 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 9 2 0 1 0 1 92 2.30258512 3 1 0 1 0.3 102 +1 1 4 9 0 1 0 1 49 1.609438 2.58496261 0 1 0.5 1 109 +1 1 9 7 0 1 0 1 97 2.30258512 1.58496249 1 0 1 0.8 107 +1 1 9 3 0 1 0 1 93 2.30258512 2.807355 1 0 1 0.4 103 +1 1 7 2 0 1 0 1 72 2.07944155 2.58496261 0 0 0.8 0.3 102 +1 1 7 4 0 1 0 1 74 2.07944155 2 0 0 0.8 0.5 104 +1 1 4 5 0 1 0 1 45 1.609438 1 0 0 0.5 0.6 105 +1 1 8 1 0 1 0 1 81 2.19722462 3 0 0 0.9 0.2 101 +1 1 4 2 0 1 0 1 42 1.609438 1.58496249 0 0 0.5 0.3 102 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 8 9 0 1 0 1 89 2.19722462 1 0 1 0.9 1 109 +1 1 5 4 0 1 0 1 54 1.79175949 1 0 0 0.6 0.5 104 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 9 2 0 1 0 1 92 2.30258512 3 1 0 1 0.3 102 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +1 1 4 7 0 1 0 1 47 1.609438 2 0 0 0.5 0.8 107 +1 1 7 3 0 1 0 1 73 2.07944155 2.321928 0 0 0.8 0.4 103 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 5 9 0 1 0 1 59 1.79175949 2.321928 0 1 0.6 1 109 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 8 5 0 1 0 1 85 2.19722462 2 0 0 0.9 0.6 105 +1 1 9 2 0 1 0 1 92 2.30258512 3 1 0 1 0.3 102 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 1 2 0 1 0 1 12 0.6931472 1 0 0 0.2 0.3 102 +0 0 1 0 0 1 0 1 10 0.6931472 1 0 0 0.2 0.1 100 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +1 1 2 7 0 1 0 1 27 1.09861231 2.58496261 0 0 0.3 0.8 107 +1 1 4 9 0 1 0 1 49 1.609438 2.58496261 0 1 0.5 1 109 +1 1 2 4 0 1 0 1 24 1.09861231 1.58496249 0 0 0.3 0.5 104 +1 1 2 4 0 1 0 1 24 1.09861231 1.58496249 0 0 0.3 0.5 104 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 1 2 0 1 0 1 12 0.6931472 1 0 0 0.2 0.3 102 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 8 9 0 1 0 1 89 2.19722462 1 0 1 0.9 1 109 +1 1 6 4 0 1 0 1 64 1.9459101 1.58496249 0 0 0.7 0.5 104 +1 1 9 9 0 1 0 1 99 2.30258512 0 1 1 1 1 109 +1 1 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +1 1 7 5 0 1 0 1 75 2.07944155 1.58496249 0 0 0.8 0.6 105 +1 1 9 9 0 1 0 1 99 2.30258512 0 1 1 1 1 109 +1 1 6 2 0 1 0 1 62 1.9459101 2.321928 0 0 0.7 0.3 102 +1 1 9 1 0 1 0 1 91 2.30258512 3.169925 1 0 1 0.2 101 +1 1 0 7 0 1 0 1 7 0 3 0 0 0.1 0.8 107 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 5 2 0 1 0 1 52 1.79175949 2 0 0 0.6 0.3 102 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 7 4 0 1 0 1 74 2.07944155 2 0 0 0.8 0.5 104 +1 1 9 1 0 1 0 1 91 2.30258512 3.169925 1 0 1 0.2 101 +1 1 9 9 0 1 0 1 99 2.30258512 0 1 1 1 1 109 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 7 1 0 1 0 1 71 2.07944155 2.807355 0 0 0.8 0.2 101 +1 1 3 3 0 1 0 1 33 1.38629436 0 0 0 0.4 0.4 103 +0 0 0 3 0 1 0 1 3 0 2 0 0 0.1 0.4 103 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +1 1 9 9 0 1 0 1 99 2.30258512 0 1 1 1 1 109 +1 1 4 7 0 1 0 1 47 1.609438 2 0 0 0.5 0.8 107 +1 1 4 8 0 1 0 1 48 1.609438 2.321928 0 0 0.5 0.9 108 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 6 3 0 1 0 1 63 1.9459101 2 0 0 0.7 0.4 103 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +1 1 7 4 0 1 0 1 74 2.07944155 2 0 0 0.8 0.5 104 +0 0 0 9 0 1 0 1 9 0 3.321928 0 1 0.1 1 109 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +1 1 4 7 0 1 0 1 47 1.609438 2 0 0 0.5 0.8 107 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 2 2 0 1 0 1 22 1.09861231 0 0 0 0.3 0.3 102 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +16 5:1 7:1 13:0.1 14:0.1 15:100 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +1 1 8 3 0 1 0 1 83 2.19722462 2.58496261 0 0 0.9 0.4 103 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 2 5 0 1 0 1 25 1.09861231 2 0 0 0.3 0.6 105 +0 0 0 2 0 1 0 1 2 0 1.58496249 0 0 0.1 0.3 102 +0 0 2 7 0 1 0 1 27 1.09861231 2.58496261 0 0 0.3 0.8 107 +1 1 7 9 0 1 0 1 79 2.07944155 1.58496249 0 1 0.8 1 109 +16 5:1 7:1 13:0.1 14:0.1 15:100 +1 1 6 5 0 1 0 1 65 1.9459101 1 0 0 0.7 0.6 105 +1 1 9 3 0 1 0 1 93 2.30258512 2.807355 1 0 1 0.4 103 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 4 2 0 1 0 1 42 1.609438 1.58496249 0 0 0.5 0.3 102 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 0 2 0 1 0 1 2 0 1.58496249 0 0 0.1 0.3 102 +1 1 8 5 0 1 0 1 85 2.19722462 2 0 0 0.9 0.6 105 +1 1 9 4 0 1 0 1 94 2.30258512 2.58496261 1 0 1 0.5 104 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +16 5:1 7:1 13:0.1 14:0.1 15:100 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +1 1 4 7 0 1 0 1 47 1.609438 2 0 0 0.5 0.8 107 +1 1 9 5 0 1 0 1 95 2.30258512 2.321928 1 0 1 0.6 105 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +16 5:1 7:1 13:0.1 14:0.1 15:100 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 5 7 0 1 0 1 57 1.79175949 1.58496249 0 0 0.6 0.8 107 +1 1 7 2 0 1 0 1 72 2.07944155 2.58496261 0 0 0.8 0.3 102 +1 1 4 9 0 1 0 1 49 1.609438 2.58496261 0 1 0.5 1 109 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +1 1 4 7 0 1 0 1 47 1.609438 2 0 0 0.5 0.8 107 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +1 1 4 5 0 1 0 1 45 1.609438 1 0 0 0.5 0.6 105 +16 5:1 7:1 13:0.1 14:0.1 15:100 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 5 1 0 1 0 1 51 1.79175949 2.321928 0 0 0.6 0.2 101 +1 1 4 4 0 1 0 1 44 1.609438 0 0 0 0.5 0.5 104 +1 1 7 3 0 1 0 1 73 2.07944155 2.321928 0 0 0.8 0.4 103 +0 0 1 0 0 1 0 1 10 0.6931472 1 0 0 0.2 0.1 100 +1 1 0 4 0 1 0 1 4 0 2.321928 0 0 0.1 0.5 104 +1 1 9 5 0 1 0 1 95 2.30258512 2.321928 1 0 1 0.6 105 +1 1 4 4 0 1 0 1 44 1.609438 0 0 0 0.5 0.5 104 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 9 5 0 1 0 1 95 2.30258512 2.321928 1 0 1 0.6 105 +1 1 6 9 0 1 0 1 69 1.9459101 2 0 1 0.7 1 109 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 7 3 0 1 0 1 73 2.07944155 2.321928 0 0 0.8 0.4 103 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +1 1 8 4 0 1 0 1 84 2.19722462 2.321928 0 0 0.9 0.5 104 +1 1 9 9 0 1 0 1 99 2.30258512 0 1 1 1 1 109 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 4 5 0 1 0 1 45 1.609438 1 0 0 0.5 0.6 105 +1 1 9 6 0 1 0 1 96 2.30258512 2 1 0 1 0.7 106 +16 5:1 7:1 13:0.1 14:0.1 15:100 +16 5:1 7:1 13:0.1 14:0.1 15:100 +0 0 4 0 0 1 0 1 40 1.609438 2.321928 0 0 0.5 0.1 100 +1 1 7 4 0 1 0 1 74 2.07944155 2 0 0 0.8 0.5 104 +1 1 7 3 0 1 0 1 73 2.07944155 2.321928 0 0 0.8 0.4 103 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 9 6 0 1 0 1 96 2.30258512 2 1 0 1 0.7 106 +1 1 9 2 0 1 0 1 92 2.30258512 3 1 0 1 0.3 102 +1 1 7 4 0 1 0 1 74 2.07944155 2 0 0 0.8 0.5 104 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 5 5 0 1 0 1 55 1.79175949 0 0 0 0.6 0.6 105 +0 0 5 1 0 1 0 1 51 1.79175949 2.321928 0 0 0.6 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 9 9 0 1 0 1 99 2.30258512 0 1 1 1 1 109 +1 1 3 0 0 1 0 1 30 1.38629436 2 0 0 0.4 0.1 100 +1 1 6 2 0 1 0 1 62 1.9459101 2.321928 0 0 0.7 0.3 102 +1 1 9 2 0 1 0 1 92 2.30258512 3 1 0 1 0.3 102 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 9 3 0 1 0 1 93 2.30258512 2.807355 1 0 1 0.4 103 +1 1 7 2 0 1 0 1 72 2.07944155 2.58496261 0 0 0.8 0.3 102 +16 5:1 7:1 13:0.1 14:0.1 15:100 +1 1 9 9 0 1 0 1 99 2.30258512 0 1 1 1 1 109 +1 1 6 2 0 1 0 1 62 1.9459101 2.321928 0 0 0.7 0.3 102 +1 1 5 5 0 1 0 1 55 1.79175949 0 0 0 0.6 0.6 105 +0 0 7 2 0 1 0 1 72 2.07944155 2.58496261 0 0 0.8 0.3 102 +1 1 9 4 0 1 0 1 94 2.30258512 2.58496261 1 0 1 0.5 104 +0 0 2 2 0 1 0 1 22 1.09861231 0 0 0 0.3 0.3 102 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +1 1 9 7 0 1 0 1 97 2.30258512 1.58496249 1 0 1 0.8 107 +1 1 8 5 0 1 0 1 85 2.19722462 2 0 0 0.9 0.6 105 +1 1 7 5 0 1 0 1 75 2.07944155 1.58496249 0 0 0.8 0.6 105 +1 1 9 2 0 1 0 1 92 2.30258512 3 1 0 1 0.3 102 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 2 0 0 1 0 1 20 1.09861231 1.58496249 0 0 0.3 0.1 100 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 7 4 0 1 0 1 74 2.07944155 2 0 0 0.8 0.5 104 +1 1 7 1 0 1 0 1 71 2.07944155 2.807355 0 0 0.8 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 9 1 0 1 0 1 91 2.30258512 3.169925 1 0 1 0.2 101 +0 0 5 2 0 1 0 1 52 1.79175949 2 0 0 0.6 0.3 102 +1 1 5 7 0 1 0 1 57 1.79175949 1.58496249 0 0 0.6 0.8 107 +1 1 8 9 0 1 0 1 89 2.19722462 1 0 1 0.9 1 109 +1 1 4 3 0 1 0 1 43 1.609438 1 0 0 0.5 0.4 103 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 4 4 0 1 0 1 44 1.609438 0 0 0 0.5 0.5 104 +1 1 9 2 0 1 0 1 92 2.30258512 3 1 0 1 0.3 102 +1 1 4 9 0 1 0 1 49 1.609438 2.58496261 0 1 0.5 1 109 +1 1 7 4 0 1 0 1 74 2.07944155 2 0 0 0.8 0.5 104 +1 1 9 5 0 1 0 1 95 2.30258512 2.321928 1 0 1 0.6 105 +1 1 6 9 0 1 0 1 69 1.9459101 2 0 1 0.7 1 109 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 9 2 0 1 0 1 92 2.30258512 3 1 0 1 0.3 102 +1 1 2 2 0 1 0 1 22 1.09861231 0 0 0 0.3 0.3 102 +1 1 9 2 0 1 0 1 92 2.30258512 3 1 0 1 0.3 102 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 7 2 0 1 0 1 72 2.07944155 2.58496261 0 0 0.8 0.3 102 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 2 2 0 1 0 1 22 1.09861231 0 0 0 0.3 0.3 102 +1 1 6 2 0 1 0 1 62 1.9459101 2.321928 0 0 0.7 0.3 102 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 9 2 0 1 0 1 92 2.30258512 3 1 0 1 0.3 102 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +1 1 0 3 0 1 0 1 3 0 2 0 0 0.1 0.4 103 +1 1 9 1 0 1 0 1 91 2.30258512 3.169925 1 0 1 0.2 101 +1 1 6 1 0 1 0 1 61 1.9459101 2.58496261 0 0 0.7 0.2 101 +1 1 7 7 0 1 0 1 77 2.07944155 0 0 0 0.8 0.8 107 +1 1 9 9 0 1 0 1 99 2.30258512 0 1 1 1 1 109 +0 0 2 2 0 1 0 1 22 1.09861231 0 0 0 0.3 0.3 102 +1 1 5 3 0 1 0 1 53 1.79175949 1.58496249 0 0 0.6 0.4 103 +1 1 4 5 0 1 0 1 45 1.609438 1 0 0 0.5 0.6 105 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 7 1 0 1 0 1 71 2.07944155 2.807355 0 0 0.8 0.2 101 +1 1 9 1 0 1 0 1 91 2.30258512 3.169925 1 0 1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 4 5 0 1 0 1 45 1.609438 1 0 0 0.5 0.6 105 +0 0 4 3 0 1 0 1 43 1.609438 1 0 0 0.5 0.4 103 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 7 4 0 1 0 1 74 2.07944155 2 0 0 0.8 0.5 104 +1 1 8 3 0 1 0 1 83 2.19722462 2.58496261 0 0 0.9 0.4 103 +1 1 7 3 0 1 0 1 73 2.07944155 2.321928 0 0 0.8 0.4 103 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 9 8 0 1 0 1 98 2.30258512 1 1 0 1 0.9 108 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 7 2 0 1 0 1 72 2.07944155 2.58496261 0 0 0.8 0.3 102 +1 1 9 3 0 1 0 1 93 2.30258512 2.807355 1 0 1 0.4 103 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 6 3 0 1 0 1 63 1.9459101 2 0 0 0.7 0.4 103 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 1 2 0 1 0 1 12 0.6931472 1 0 0 0.2 0.3 102 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 7 9 0 1 0 1 79 2.07944155 1.58496249 0 1 0.8 1 109 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +16 5:1 7:1 13:0.1 14:0.1 15:100 +0 0 3 6 0 1 0 1 36 1.38629436 2 0 0 0.4 0.7 106 +1 1 4 4 0 1 0 1 44 1.609438 0 0 0 0.5 0.5 104 +1 1 5 5 0 1 0 1 55 1.79175949 0 0 0 0.6 0.6 105 +0 0 0 4 0 1 0 1 4 0 2.321928 0 0 0.1 0.5 104 +0 0 3 5 0 1 0 1 35 1.38629436 1.58496249 0 0 0.4 0.6 105 +1 1 6 4 0 1 0 1 64 1.9459101 1.58496249 0 0 0.7 0.5 104 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +1 1 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +1 1 9 1 0 1 0 1 91 2.30258512 3.169925 1 0 1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 7 5 0 1 0 1 75 2.07944155 1.58496249 0 0 0.8 0.6 105 +1 1 9 4 0 1 0 1 94 2.30258512 2.58496261 1 0 1 0.5 104 +1 1 9 1 0 1 0 1 91 2.30258512 3.169925 1 0 1 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 4 3 0 1 0 1 43 1.609438 1 0 0 0.5 0.4 103 +1 1 7 2 0 1 0 1 72 2.07944155 2.58496261 0 0 0.8 0.3 102 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 5 3 0 1 0 1 53 1.79175949 1.58496249 0 0 0.6 0.4 103 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +16 5:1 7:1 13:0.1 14:0.1 15:100 +1 1 7 1 0 1 0 1 71 2.07944155 2.807355 0 0 0.8 0.2 101 +1 1 9 1 0 1 0 1 91 2.30258512 3.169925 1 0 1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 6 9 0 1 0 1 69 1.9459101 2 0 1 0.7 1 109 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 4 2 0 1 0 1 42 1.609438 1.58496249 0 0 0.5 0.3 102 +16 5:1 7:1 13:0.1 14:0.1 15:100 +1 1 2 4 0 1 0 1 24 1.09861231 1.58496249 0 0 0.3 0.5 104 +1 1 3 2 0 1 0 1 32 1.38629436 1 0 0 0.4 0.3 102 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 2 6 0 1 0 1 26 1.09861231 2.321928 0 0 0.3 0.7 106 +1 1 1 6 0 1 0 1 16 0.6931472 2.58496261 0 0 0.2 0.7 106 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 3 2 0 1 0 1 32 1.38629436 1 0 0 0.4 0.3 102 +1 1 4 2 0 1 0 1 42 1.609438 1.58496249 0 0 0.5 0.3 102 +1 1 7 9 0 1 0 1 79 2.07944155 1.58496249 0 1 0.8 1 109 +1 1 7 7 0 1 0 1 77 2.07944155 0 0 0 0.8 0.8 107 +1 1 9 2 0 1 0 1 92 2.30258512 3 1 0 1 0.3 102 +1 1 5 9 0 1 0 1 59 1.79175949 2.321928 0 1 0.6 1 109 +1 1 2 5 0 1 0 1 25 1.09861231 2 0 0 0.3 0.6 105 +0 0 2 3 0 1 0 1 23 1.09861231 1 0 0 0.3 0.4 103 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +1 1 5 7 0 1 0 1 57 1.79175949 1.58496249 0 0 0.6 0.8 107 +1 1 4 4 0 1 0 1 44 1.609438 0 0 0 0.5 0.5 104 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +16 5:1 7:1 13:0.1 14:0.1 15:100 +0 0 3 2 0 1 0 1 32 1.38629436 1 0 0 0.4 0.3 102 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +16 5:1 7:1 13:0.1 14:0.1 15:100 +0 0 2 2 0 1 0 1 22 1.09861231 0 0 0 0.3 0.3 102 +0 0 4 3 0 1 0 1 43 1.609438 1 0 0 0.5 0.4 103 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 9 3 0 1 0 1 93 2.30258512 2.807355 1 0 1 0.4 103 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 2 2 0 1 0 1 22 1.09861231 0 0 0 0.3 0.3 102 +1 1 6 1 0 1 0 1 61 1.9459101 2.58496261 0 0 0.7 0.2 101 +0 0 4 2 0 1 0 1 42 1.609438 1.58496249 0 0 0.5 0.3 102 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 4 2 0 1 0 1 42 1.609438 1.58496249 0 0 0.5 0.3 102 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 9 2 0 1 0 1 92 2.30258512 3 1 0 1 0.3 102 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +16 5:1 7:1 13:0.1 14:0.1 15:100 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 2 5 0 1 0 1 25 1.09861231 2 0 0 0.3 0.6 105 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +16 5:1 7:1 13:0.1 14:0.1 15:100 +1 1 9 7 0 1 0 1 97 2.30258512 1.58496249 1 0 1 0.8 107 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 7 2 0 1 0 1 72 2.07944155 2.58496261 0 0 0.8 0.3 102 +0 0 2 2 0 1 0 1 22 1.09861231 0 0 0 0.3 0.3 102 +1 1 7 9 0 1 0 1 79 2.07944155 1.58496249 0 1 0.8 1 109 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 1 4 0 1 0 1 14 0.6931472 2 0 0 0.2 0.5 104 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +1 1 9 9 0 1 0 1 99 2.30258512 0 1 1 1 1 109 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +1 1 8 9 0 1 0 1 89 2.19722462 1 0 1 0.9 1 109 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 7 3 0 1 0 1 73 2.07944155 2.321928 0 0 0.8 0.4 103 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 4 3 0 1 0 1 43 1.609438 1 0 0 0.5 0.4 103 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 5 4 0 1 0 1 54 1.79175949 1 0 0 0.6 0.5 104 +1 1 9 2 0 1 0 1 92 2.30258512 3 1 0 1 0.3 102 +1 1 9 5 0 1 0 1 95 2.30258512 2.321928 1 0 1 0.6 105 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 9 3 0 1 0 1 93 2.30258512 2.807355 1 0 1 0.4 103 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 4 2 0 1 0 1 42 1.609438 1.58496249 0 0 0.5 0.3 102 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +16 5:1 7:1 13:0.1 14:0.1 15:100 +1 1 4 5 0 1 0 1 45 1.609438 1 0 0 0.5 0.6 105 +0 0 3 0 0 1 0 1 30 1.38629436 2 0 0 0.4 0.1 100 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +1 1 3 5 0 1 0 1 35 1.38629436 1.58496249 0 0 0.4 0.6 105 +0 0 1 2 0 1 0 1 12 0.6931472 1 0 0 0.2 0.3 102 +1 1 9 1 0 1 0 1 91 2.30258512 3.169925 1 0 1 0.2 101 +1 1 9 4 0 1 0 1 94 2.30258512 2.58496261 1 0 1 0.5 104 +1 1 7 5 0 1 0 1 75 2.07944155 1.58496249 0 0 0.8 0.6 105 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 5 1 0 1 0 1 51 1.79175949 2.321928 0 0 0.6 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +1 1 9 5 0 1 0 1 95 2.30258512 2.321928 1 0 1 0.6 105 +1 1 9 3 0 1 0 1 93 2.30258512 2.807355 1 0 1 0.4 103 +1 1 5 3 0 1 0 1 53 1.79175949 1.58496249 0 0 0.6 0.4 103 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 2 0 0 1 0 1 20 1.09861231 1.58496249 0 0 0.3 0.1 100 +0 0 5 1 0 1 0 1 51 1.79175949 2.321928 0 0 0.6 0.2 101 +0 0 5 0 0 1 0 1 50 1.79175949 2.58496261 0 0 0.6 0.1 100 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 3 3 0 1 0 1 33 1.38629436 0 0 0 0.4 0.4 103 +0 0 4 0 0 1 0 1 40 1.609438 2.321928 0 0 0.5 0.1 100 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 8 9 0 1 0 1 89 2.19722462 1 0 1 0.9 1 109 +1 1 7 4 0 1 0 1 74 2.07944155 2 0 0 0.8 0.5 104 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +16 5:1 7:1 13:0.1 14:0.1 15:100 +0 0 2 0 0 1 0 1 20 1.09861231 1.58496249 0 0 0.3 0.1 100 +1 1 9 5 0 1 0 1 95 2.30258512 2.321928 1 0 1 0.6 105 +1 1 2 2 0 1 0 1 22 1.09861231 0 0 0 0.3 0.3 102 +1 1 5 2 0 1 0 1 52 1.79175949 2 0 0 0.6 0.3 102 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 4 2 0 1 0 1 42 1.609438 1.58496249 0 0 0.5 0.3 102 +0 0 3 0 0 1 0 1 30 1.38629436 2 0 0 0.4 0.1 100 +1 1 4 5 0 1 0 1 45 1.609438 1 0 0 0.5 0.6 105 +0 0 4 3 0 1 0 1 43 1.609438 1 0 0 0.5 0.4 103 +0 0 2 0 0 1 0 1 20 1.09861231 1.58496249 0 0 0.3 0.1 100 +16 5:1 7:1 13:0.1 14:0.1 15:100 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 5 1 0 1 0 1 51 1.79175949 2.321928 0 0 0.6 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +1 1 7 6 0 1 0 1 76 2.07944155 1 0 0 0.8 0.7 106 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 2 0 0 1 0 1 20 1.09861231 1.58496249 0 0 0.3 0.1 100 +1 1 5 2 0 1 0 1 52 1.79175949 2 0 0 0.6 0.3 102 +1 1 3 2 0 1 0 1 32 1.38629436 1 0 0 0.4 0.3 102 +16 5:1 7:1 13:0.1 14:0.1 15:100 +16 5:1 7:1 13:0.1 14:0.1 15:100 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +1 1 3 3 0 1 0 1 33 1.38629436 0 0 0 0.4 0.4 103 +0 0 0 2 0 1 0 1 2 0 1.58496249 0 0 0.1 0.3 102 +0 0 3 2 0 1 0 1 32 1.38629436 1 0 0 0.4 0.3 102 +1 1 9 2 0 1 0 1 92 2.30258512 3 1 0 1 0.3 102 +1 1 6 3 0 1 0 1 63 1.9459101 2 0 0 0.7 0.4 103 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 5 1 0 1 0 1 51 1.79175949 2.321928 0 0 0.6 0.2 101 +0 0 3 0 0 1 0 1 30 1.38629436 2 0 0 0.4 0.1 100 +1 1 6 3 0 1 0 1 63 1.9459101 2 0 0 0.7 0.4 103 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +16 5:1 7:1 13:0.1 14:0.1 15:100 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 5 1 0 1 0 1 51 1.79175949 2.321928 0 0 0.6 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 5 3 0 1 0 1 53 1.79175949 1.58496249 0 0 0.6 0.4 103 +0 0 1 0 0 1 0 1 10 0.6931472 1 0 0 0.2 0.1 100 +0 0 2 0 0 1 0 1 20 1.09861231 1.58496249 0 0 0.3 0.1 100 +1 1 6 3 0 1 0 1 63 1.9459101 2 0 0 0.7 0.4 103 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 4 0 0 1 0 1 40 1.609438 2.321928 0 0 0.5 0.1 100 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +1 1 4 4 0 1 0 1 44 1.609438 0 0 0 0.5 0.5 104 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +1 1 7 5 0 1 0 1 75 2.07944155 1.58496249 0 0 0.8 0.6 105 +1 1 9 5 0 1 0 1 95 2.30258512 2.321928 1 0 1 0.6 105 +1 1 7 7 0 1 0 1 77 2.07944155 0 0 0 0.8 0.8 107 +1 1 6 2 0 1 0 1 62 1.9459101 2.321928 0 0 0.7 0.3 102 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 9 3 0 1 0 1 93 2.30258512 2.807355 1 0 1 0.4 103 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 4 4 0 1 0 1 44 1.609438 0 0 0 0.5 0.5 104 +1 1 5 3 0 1 0 1 53 1.79175949 1.58496249 0 0 0.6 0.4 103 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 4 2 0 1 0 1 42 1.609438 1.58496249 0 0 0.5 0.3 102 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 7 5 0 1 0 1 75 2.07944155 1.58496249 0 0 0.8 0.6 105 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 8 5 0 1 0 1 85 2.19722462 2 0 0 0.9 0.6 105 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 3 3 0 1 0 1 33 1.38629436 0 0 0 0.4 0.4 103 +1 1 1 3 0 1 0 1 13 0.6931472 1.58496249 0 0 0.2 0.4 103 +1 1 9 2 0 1 0 1 92 2.30258512 3 1 0 1 0.3 102 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 3 3 0 1 0 1 33 1.38629436 0 0 0 0.4 0.4 103 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 4 0 0 1 0 1 40 1.609438 2.321928 0 0 0.5 0.1 100 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +16 5:1 7:1 13:0.1 14:0.1 15:100 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +1 1 4 3 0 1 0 1 43 1.609438 1 0 0 0.5 0.4 103 +1 1 4 4 0 1 0 1 44 1.609438 0 0 0 0.5 0.5 104 +1 1 9 4 0 1 0 1 94 2.30258512 2.58496261 1 0 1 0.5 104 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 4 9 0 1 0 1 49 1.609438 2.58496261 0 1 0.5 1 109 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +1 1 9 2 0 1 0 1 92 2.30258512 3 1 0 1 0.3 102 +1 1 4 4 0 1 0 1 44 1.609438 0 0 0 0.5 0.5 104 +1 1 7 5 0 1 0 1 75 2.07944155 1.58496249 0 0 0.8 0.6 105 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 1 0 0 1 0 1 10 0.6931472 1 0 0 0.2 0.1 100 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +16 5:1 7:1 13:0.1 14:0.1 15:100 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 5 2 0 1 0 1 52 1.79175949 2 0 0 0.6 0.3 102 +0 0 6 1 0 1 0 1 61 1.9459101 2.58496261 0 0 0.7 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 4 0 0 1 0 1 40 1.609438 2.321928 0 0 0.5 0.1 100 +0 0 2 2 0 1 0 1 22 1.09861231 0 0 0 0.3 0.3 102 +1 1 3 6 0 1 0 1 36 1.38629436 2 0 0 0.4 0.7 106 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 5 1 0 1 0 1 51 1.79175949 2.321928 0 0 0.6 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 7 4 0 1 0 1 74 2.07944155 2 0 0 0.8 0.5 104 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +1 1 9 6 0 1 0 1 96 2.30258512 2 1 0 1 0.7 106 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 4 9 0 1 0 1 49 1.609438 2.58496261 0 1 0.5 1 109 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 2 2 0 1 0 1 22 1.09861231 0 0 0 0.3 0.3 102 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 4 7 0 1 0 1 47 1.609438 2 0 0 0.5 0.8 107 +1 1 6 2 0 1 0 1 62 1.9459101 2.321928 0 0 0.7 0.3 102 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +1 1 4 5 0 1 0 1 45 1.609438 1 0 0 0.5 0.6 105 +1 1 4 4 0 1 0 1 44 1.609438 0 0 0 0.5 0.5 104 +1 1 2 4 0 1 0 1 24 1.09861231 1.58496249 0 0 0.3 0.5 104 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +0 0 4 2 0 1 0 1 42 1.609438 1.58496249 0 0 0.5 0.3 102 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +1 1 9 4 0 1 0 1 94 2.30258512 2.58496261 1 0 1 0.5 104 +1 1 4 3 0 1 0 1 43 1.609438 1 0 0 0.5 0.4 103 +0 0 4 1 0 1 0 1 41 1.609438 2 0 0 0.5 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 3 1 0 1 0 1 31 1.38629436 1.58496249 0 0 0.4 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +0 0 0 1 0 1 0 1 1 0 1 0 0 0.1 0.2 101 +1 1 4 3 0 1 0 1 43 1.609438 1 0 0 0.5 0.4 103 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 2 1 0 1 0 1 21 1.09861231 1 0 0 0.3 0.2 101 +0 0 2 2 0 1 0 1 22 1.09861231 0 0 0 0.3 0.3 102 +0 0 1 1 0 1 0 1 11 0.6931472 0 0 0 0.2 0.2 101 +1 1 4 6 0 1 0 1 46 1.609438 1.58496249 0 0 0.5 0.7 106 +1 1 3 2 0 1 0 1 32 1.38629436 1 0 0 0.4 0.3 102 +1 1 3 3 0 1 0 1 33 1.38629436 0 0 0 0.4 0.4 103 diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExpr-Extra-Data.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExpr-Extra-Data.txt new file mode 100644 index 0000000000..a288530fdd --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExpr-Extra-Data.txt @@ -0,0 +1,716 @@ +#@ TextLoader{ +#@ header+ +#@ sep=tab +#@ col=A:BL:0 +#@ col=B:BL:1 +#@ col=C:I4:2 +#@ col=D:R4:3 +#@ col=ID:BL:4 +#@ col=JD:R4:5 +#@ col=KA:R4:6 +#@ col=KB:R4:7 +#@ col=KC:R4:8 +#@ col=KD:R4:9 +#@ col=LA:BL:10 +#@ col=LC:BL:11 +#@ } +A B C D ID JD KA KB KC KD LA LC +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 7 10 0 10 0 0 3.5 5 0 0 +0 0 2 2 0 2 0 0 1 1 0 0 +0 0 3 4 0 4 0 0 1.5 2 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 7 10 0 10 0.5 0.5 3.5 5 0 0 +0 0 2 10 0 10 0 0 1 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 2 3 0 3 0.5 0.5 1 1.5 0 0 +0 0 2 3 0 3 0 0 1 1.5 0 0 +1 1 7 9 0 9 0.5 0.5 3.5 4.5 0 0 +1 1 6 1 0 1 0.5 0.5 3 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +1 1 6 7 0 7 0.5 0.5 3 3.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 2 ? 1 -1 0.5 0.5 1 ? 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 2 7 0 7 0.5 0.5 1 3.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 8 5 0 5 0.5 0.5 4 2.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 6 1 0 1 0.5 0.5 3 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +1 1 2 10 0 10 0.5 0.5 1 5 0 0 +1 1 6 7 0 7 0.5 0.5 3 3.5 0 0 +0 0 6 ? 1 -1 0 0 3 ? 0 0 +1 1 3 3 0 3 0.5 0.5 1.5 1.5 0 0 +1 1 8 10 0 10 0.5 0.5 4 5 0 0 +1 1 10 1 0 1 0.5 0.5 5 0.5 0 0 +1 1 8 1 0 1 0.5 0.5 4 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 9 0 9 0.5 0.5 2 4.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 8 0 8 0.5 0.5 2 4 0 0 +1 1 2 3 0 3 0.5 0.5 1 1.5 0 0 +1 1 2 4 0 4 0.5 0.5 1 2 0 0 +1 1 3 5 0 5 0.5 0.5 1.5 2.5 0 0 +1 1 10 8 0 8 0.5 0.5 5 4 0 0 +1 1 8 8 0 8 0.5 0.5 4 4 0 0 +1 1 4 5 0 5 0.5 0.5 2 2.5 0 0 +1 1 3 6 0 6 0.5 0.5 1.5 3 0 0 +1 1 5 1 0 1 0.5 0.5 2.5 0.5 0 0 +1 1 6 10 0 10 0.5 0.5 3 5 0 0 +1 1 2 2 0 2 0.5 0.5 1 1 0 0 +1 1 3 3 0 3 0.5 0.5 1.5 1.5 0 0 +0 0 2 2 0 2 0 0 1 1 0 0 +1 1 10 8 0 8 0.5 0.5 5 4 0 0 +1 1 5 2 0 2 0.5 0.5 2.5 1 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 3 2 0 2 0.5 0.5 1.5 1 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 8 10 0 10 0.5 0.5 4 5 0 0 +1 1 4 9 0 9 0.5 0.5 2 4.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 10 2 0 2 0.5 0.5 5 1 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 6 10 0 10 0.5 0.5 3 5 0 0 +1 1 3 4 0 4 0.5 0.5 1.5 2 0 0 +0 0 2 2 0 2 0 0 1 1 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 3 0 3 0 0 1 1.5 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 2 0 2 0 0 1 1 0 0 +1 1 8 9 0 9 0.5 0.5 4 4.5 0 0 +1 1 10 4 0 4 0.5 0.5 5 2 0 0 +1 1 5 8 0 8 0.5 0.5 2.5 4 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 10 6 0 6 0.5 0.5 5 3 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +1 1 10 5 0 5 0.5 0.5 5 2.5 0 0 +1 1 2 5 0 5 0.5 0.5 1 2.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 6 3 0 3 0.5 0.5 3 1.5 0 0 +1 1 10 1 0 1 0.5 0.5 5 0.5 0 0 +1 1 3 3 0 3 0.5 0.5 1.5 1.5 0 0 +1 1 2 10 0 10 0.5 0.5 1 5 0 0 +1 1 8 10 0 10 0.5 0.5 4 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 3 9 0 9 0.5 0.5 1.5 4.5 0 0 +0 0 2 2 0 2 0 0 1 1 0 0 +1 1 5 9 0 9 0.5 0.5 2.5 4.5 0 0 +1 1 2 10 0 10 0.5 0.5 1 5 0 0 +1 1 10 8 0 8 0.5 0.5 5 4 0 0 +0 0 2 3 0 3 0 0 1 1.5 0 0 +0 0 2 5 0 5 0 0 1 2.5 0 0 +0 0 2 2 0 2 0 0 1 1 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +0 0 4 3 0 3 0 0 2 1.5 0 0 +0 0 2 2 0 2 0 0 1 1 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 2 0 2 0 0 1 1 0 0 +1 1 10 10 0 10 0.5 0.5 5 5 0 0 +1 1 8 10 0 10 0.5 0.5 4 5 0 0 +1 1 9 7 0 7 0.5 0.5 4.5 3.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +0 0 10 1 0 1 0 0 5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 8 10 0 10 0.5 0.5 4 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +0 0 2 2 0 2 0 0 1 1 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 ? 1 -1 0 0 0.5 ? 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 5 0 5 0.5 0.5 2 2.5 0 0 +0 0 2 5 0 5 0 0 1 2.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 ? 1 -1 0 0 1 ? 0 0 +1 1 6 8 0 8 0.5 0.5 3 4 0 0 +0 0 3 2 0 2 0 0 1.5 1 0 0 +0 0 8 1 0 1 0 0 4 0.5 0 0 +1 1 10 10 0 10 0.5 0.5 5 5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +1 1 6 10 0 10 0.5 0.5 3 5 0 0 +1 1 4 5 0 5 0.5 0.5 2 2.5 0 0 +0 0 2 3 0 3 0 0 1 1.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 3 ? 1 -1 0 0 1.5 ? 0 0 +1 1 6 10 0 10 0.5 0.5 3 5 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 3 0 3 0 0 0.5 1.5 0 0 +0 0 2 ? 1 -1 0 0 1 ? 0 0 +0 0 2 2 0 2 0 0 1 1 0 0 +1 1 8 10 0 10 0.5 0.5 4 5 0 0 +1 1 6 1 0 1 0.5 0.5 3 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 8 10 0 10 0.5 0.5 4 5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +1 1 10 10 0 10 0.5 0.5 5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 8 1 0 1 0.5 0.5 4 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 6 10 0 10 0.5 0.5 3 5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +1 1 5 8 0 8 0.5 0.5 2.5 4 0 0 +1 1 6 10 0 10 0.5 0.5 3 5 0 0 +1 1 5 8 0 8 0.5 0.5 2.5 4 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 6 8 0 8 0.5 0.5 3 4 0 0 +1 1 10 10 0 10 0.5 0.5 5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 4 7 0 7 0 0 2 3.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +1 1 10 10 0 10 0.5 0.5 5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 6 10 0 10 0.5 0.5 3 5 0 0 +1 1 7 5 0 5 0.5 0.5 3.5 2.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +1 1 4 8 0 8 0.5 0.5 2 4 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 7 10 0 10 0.5 0.5 3.5 5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +1 1 5 5 0 5 0.5 0.5 2.5 2.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 6 4 0 4 0.5 0.5 3 2 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 10 10 0 10 0.5 0.5 5 5 0 0 +1 1 1 5 0 5 0.5 0.5 0.5 2.5 0 0 +1 1 3 8 0 8 0.5 0.5 1.5 4 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +1 1 3 5 0 5 0.5 0.5 1.5 2.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +1 1 10 10 0 10 0.5 0.5 5 5 0 0 +1 1 3 7 0 7 0.5 0.5 1.5 3.5 0 0 +1 1 6 8 0 8 0.5 0.5 3 4 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +0 0 2 ? 1 -1 0 0 1 ? 0 0 +1 1 8 10 0 10 0.5 0.5 4 5 0 0 +1 1 6 2 0 2 0.5 0.5 3 1 0 0 +1 1 6 9 0 9 0.5 0.5 3 4.5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +0 0 2 2 0 2 0 0 1 1 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 5 0 5 0 0 1 2.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 2 0 2 0 0 1 1 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +1 1 2 9 0 9 0.5 0.5 1 4.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 ? 1 -1 0 0 1 ? 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 2 10 0 10 0.5 0.5 1 5 0 0 +0 0 3 10 0 10 0 0 1.5 5 0 0 +1 1 8 10 0 10 0.5 0.5 4 5 0 0 +1 1 10 8 0 8 0.5 0.5 5 4 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 5 8 0 8 0 0 2.5 4 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +1 1 10 10 0 10 0.5 0.5 5 5 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +1 1 6 10 0 10 0.5 0.5 3 5 0 0 +1 1 10 3 0 3 0.5 0.5 5 1.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +1 1 3 4 0 4 0.5 0.5 1.5 2 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +1 1 3 4 0 4 0.5 0.5 1.5 2 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 ? 1 -1 0 0 1 ? 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 3 7 0 7 0.5 0.5 1.5 3.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +1 1 2 10 0 10 0.5 0.5 1 5 0 0 +1 1 2 10 0 10 0.5 0.5 1 5 0 0 +1 1 8 10 0 10 0.5 0.5 4 5 0 0 +1 1 10 10 0 10 0.5 0.5 5 5 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +1 1 4 5 0 5 0.5 0.5 2 2.5 0 0 +1 1 6 10 0 10 0.5 0.5 3 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 2 ? 1 -1 0.5 0.5 1 ? 0 0 +1 1 2 10 0 10 0.5 0.5 1 5 0 0 +0 0 2 ? 1 -1 0 0 1 ? 0 0 +1 1 6 10 0 10 0.5 0.5 3 5 0 0 +0 0 4 5 0 5 0 0 2 2.5 0 0 +0 0 2 ? 1 -1 0 0 1 ? 0 0 +0 0 5 1 0 1 0 0 2.5 0.5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +1 1 4 4 0 4 0.5 0.5 2 2 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 9 10 0 10 0.5 0.5 4.5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 3 0 3 0.5 0.5 2 1.5 0 0 +0 0 2 5 0 5 0 0 1 2.5 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 10 1 0 1 0.5 0.5 5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 7 ? 1 -1 0 0 3.5 ? 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +1 1 6 8 0 8 0.5 0.5 3 4 0 0 +0 0 5 1 0 1 0 0 2.5 0.5 0 0 +0 0 6 5 0 5 0 0 3 2.5 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +0 0 2 ? 1 -1 0 0 1 ? 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 2 10 0 10 0.5 0.5 1 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 2 10 0 10 0.5 0.5 1 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 6 4 0 4 0.5 0.5 3 2 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +1 1 2 8 0 8 0.5 0.5 1 4 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +1 1 2 10 0 10 0.5 0.5 1 5 0 0 +1 1 2 10 0 10 0.5 0.5 1 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 10 10 0 10 0.5 0.5 5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +1 1 5 1 0 1 0.5 0.5 2.5 0.5 0 0 +1 1 3 8 0 8 0.5 0.5 1.5 4 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 7 3 0 3 0 0 3.5 1.5 0 0 +1 1 7 10 0 10 0.5 0.5 3.5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +1 1 3 3 0 3 0.5 0.5 1.5 1.5 0 0 +1 1 10 10 0 10 0.5 0.5 5 5 0 0 +1 1 8 4 0 4 0.5 0.5 4 2 0 0 +1 1 3 7 0 7 0.5 0.5 1.5 3.5 0 0 +1 1 10 10 0 10 0.5 0.5 5 5 0 0 +1 1 6 10 0 10 0.5 0.5 3 5 0 0 +0 0 4 3 0 3 0 0 2 1.5 0 0 +0 0 2 3 0 3 0 0 1 1.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 8 10 0 10 0.5 0.5 4 5 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +0 0 4 1 0 1 0 0 2 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +1 1 2 10 0 10 0.5 0.5 1 5 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 3 2 0 2 0 0 1.5 1 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 6 9 0 9 0.5 0.5 3 4.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 4 0 4 0 0 1 2 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 2 0 2 0 0 1 1 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 ? 1 -1 0 0 0.5 ? 0 0 +1 1 8 4 0 4 0.5 0.5 4 2 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +0 0 3 3 0 3 0 0 1.5 1.5 0 0 +1 1 10 10 0 10 0.5 0.5 5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 2 0 2 0 0 1 1 0 0 +0 0 5 1 0 1 0 0 2.5 0.5 0 0 +0 0 2 3 0 3 0 0 1 1.5 0 0 +1 1 10 10 0 10 0.5 0.5 5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 10 10 0 10 0.5 0.5 5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 2 0 2 0.5 0.5 2 1 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 4 1 0 1 0 0 2 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 5 8 0 8 0 0 2.5 4 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +1 1 6 1 0 1 0.5 0.5 3 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +0 0 2 4 0 4 0 0 1 2 0 0 +0 0 2 3 0 3 0 0 1 1.5 0 0 +0 0 2 2 0 2 0 0 1 1 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +1 1 6 10 0 10 0.5 0.5 3 5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 6 10 0 10 0.5 0.5 3 5 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +1 1 2 6 0 6 0.5 0.5 1 3 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +1 1 6 3 0 3 0.5 0.5 3 1.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 5 0 5 0 0 1 2.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 6 4 0 4 0.5 0.5 3 2 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 10 5 0 5 0.5 0.5 5 2.5 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 3 0 3 0 0 0.5 1.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +1 1 6 10 0 10 0.5 0.5 3 5 0 0 +1 1 3 3 0 3 0.5 0.5 1.5 1.5 0 0 +1 1 3 4 0 4 0.5 0.5 1.5 2 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +1 1 6 10 0 10 0.5 0.5 3 5 0 0 +0 0 4 5 0 5 0 0 2 2.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 7 5 0 5 0.5 0.5 3.5 2.5 0 0 +0 0 2 4 0 4 0 0 1 2 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +1 1 3 5 0 5 0.5 0.5 1.5 2.5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 2 0 2 0 0 1 1 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +1 1 4 5 0 5 0.5 0.5 2 2.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 5 0 5 0 0 1 2.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 3 0 3 0 0 1 1.5 0 0 +1 1 6 10 0 10 0.5 0.5 3 5 0 0 +1 1 6 5 0 5 0.5 0.5 3 2.5 0 0 +1 1 8 10 0 10 0.5 0.5 4 5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 2 0 2 0.5 0.5 2 1 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 6 10 0 10 0.5 0.5 3 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 6 3 0 3 0.5 0.5 3 1.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 1 0 1 0.5 0.5 2 0.5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 1 0 1 0.5 0.5 2 0.5 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +1 1 5 8 0 8 0.5 0.5 2.5 4 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 10 10 0 10 0.5 0.5 5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +1 1 5 2 0 2 0.5 0.5 2.5 1 0 0 +1 1 6 10 0 10 0.5 0.5 3 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 ? 1 -1 0 0 0.5 ? 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 3 2 0 2 0 0 1.5 1 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 1 1 0 1 0 0 0.5 0.5 0 0 +0 0 3 4 0 4 0 0 1.5 2 0 0 +1 1 7 6 0 6 0.5 0.5 3.5 3 0 0 +0 0 2 5 0 5 0 0 1 2.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 5 3 0 3 0.5 0.5 2.5 1.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 7 1 0 1 0.5 0.5 3.5 0.5 0 0 +0 0 2 2 0 2 0 0 1 1 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 10 2 0 2 0.5 0.5 5 1 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 3 4 0 4 0 0 1.5 2 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 8 1 0 1 0 0 4 0.5 0 0 +1 1 3 10 0 10 0.5 0.5 1.5 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 6 1 0 1 0.5 0.5 3 0.5 0 0 +1 1 5 5 0 5 0.5 0.5 2.5 2.5 0 0 +1 1 5 8 0 8 0.5 0.5 2.5 4 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 3 1 0 1 0 0 1.5 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 5 10 0 10 0.5 0.5 2.5 5 0 0 +1 1 4 10 0 10 0.5 0.5 2 5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 4 5 0 5 0.5 0.5 2 2.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +0 0 3 2 0 2 0 0 1.5 1 0 0 +0 0 2 1 0 1 0 0 1 0.5 0 0 +1 1 7 3 0 3 0.5 0.5 3.5 1.5 0 0 +1 1 3 4 0 4 0.5 0.5 1.5 2 0 0 +1 1 4 5 0 5 0.5 0.5 2 2.5 0 0 diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExpr-Extra-Schema.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExpr-Extra-Schema.txt new file mode 100644 index 0000000000..959d560c4e --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExpr-Extra-Schema.txt @@ -0,0 +1,47 @@ +---- BoundLoader ---- +4 columns: + A: Boolean + B: Boolean + C: Int32 + D: Single +---- RowToRowMapperTransform ---- +5 columns: + A: Boolean + B: Boolean + C: Int32 + D: Single + ID: Boolean +---- RowToRowMapperTransform ---- +6 columns: + A: Boolean + B: Boolean + C: Int32 + D: Single + ID: Boolean + JD: Single +---- RowToRowMapperTransform ---- +10 columns: + A: Boolean + B: Boolean + C: Int32 + D: Single + ID: Boolean + JD: Single + KA: Single + KB: Single + KC: Single + KD: Single +---- RowToRowMapperTransform ---- +12 columns: + A: Boolean + B: Boolean + C: Int32 + D: Single + ID: Boolean + JD: Single + KA: Single + KB: Single + KC: Single + KD: Single + LA: Boolean + LC: Boolean diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExpr-Schema.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExpr-Schema.txt new file mode 100644 index 0000000000..56ba4c5782 --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExpr-Schema.txt @@ -0,0 +1,134 @@ +---- BoundLoader ---- +4 columns: + A: Boolean + B: Boolean + C: Int32 + D: Int32 +---- RowToRowMapperTransform ---- +6 columns: + A: Boolean + B: Boolean + C: Int32 + C: Int32 + D: Int32 + D: Int32 +---- RowToRowMapperTransform ---- +8 columns: + A: Boolean + B: Boolean + C: Int32 + C: Int32 + D: Int32 + D: Int32 + M1: Boolean + N1: Boolean +---- RowToRowMapperTransform ---- +10 columns: + A: Boolean + B: Boolean + C: Int32 + C: Int32 + D: Int32 + D: Int32 + M1: Boolean + N1: Boolean + M2: Boolean + N2: Boolean +---- RowToRowMapperTransform ---- +11 columns: + A: Boolean + B: Boolean + C: Int32 + C: Int32 + D: Int32 + D: Int32 + M1: Boolean + N1: Boolean + M2: Boolean + N2: Boolean + U: Int32 +---- RowToRowMapperTransform ---- +12 columns: + A: Boolean + B: Boolean + C: Int32 + C: Int32 + D: Int32 + D: Int32 + M1: Boolean + N1: Boolean + M2: Boolean + N2: Boolean + U: Int32 + V: Single +---- RowToRowMapperTransform ---- +13 columns: + A: Boolean + B: Boolean + C: Int32 + C: Int32 + D: Int32 + D: Int32 + M1: Boolean + N1: Boolean + M2: Boolean + N2: Boolean + U: Int32 + V: Single + W: Single +---- RowToRowMapperTransform ---- +15 columns: + A: Boolean + B: Boolean + C: Int32 + C: Int32 + D: Int32 + D: Int32 + M1: Boolean + N1: Boolean + M2: Boolean + N2: Boolean + U: Int32 + V: Single + W: Single + X1: Int32 + Y1: Int32 +---- RowToRowMapperTransform ---- +17 columns: + A: Boolean + B: Boolean + C: Int32 + C: Int32 + D: Int32 + D: Int32 + M1: Boolean + N1: Boolean + M2: Boolean + N2: Boolean + U: Int32 + V: Single + W: Single + X1: Int32 + Y1: Int32 + X2: Single + Y2: Single +---- RowToRowMapperTransform ---- +18 columns: + A: Boolean + B: Boolean + C: Int32 + C: Int32 + D: Int32 + D: Int32 + M1: Boolean + N1: Boolean + M2: Boolean + N2: Boolean + U: Int32 + V: Single + W: Single + X1: Int32 + Y1: Int32 + X2: Single + Y2: Single + Z: Int32 diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExprTextDef-Data.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExprTextDef-Data.txt new file mode 100644 index 0000000000..af4bed85e7 --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExprTextDef-Data.txt @@ -0,0 +1,109 @@ +#@ TextLoader{ +#@ header+ +#@ sep=tab +#@ col=A:I4:0 +#@ col=N:TX:1 +#@ col=VI:TX:2-30 +#@ col=VR:TX:31-59 +#@ } +A N 58 0:"" +60 10:76 11:253 12:253 24:61 25:232 26:24 39:76 40:253 41:253 53:61 54:232 55:24 +60 11:44 12:253 13:253 14:97 22:244 23:188 40:44 41:253 42:253 43:97 51:244 52:188 +60 12:233 13:252 14:61 22:253 23:252 24:20 41:233 42:252 43:61 51:253 52:252 53:20 +60 11:254 12:253 13:194 20:195 21:253 22:253 40:254 41:253 42:194 49:195 50:253 51:253 +60 8:114 9:253 10:185 25:207 26:253 37:114 38:253 39:185 54:207 55:253 +60 9:56 10:254 11:254 12:94 24:99 25:254 26:254 27:51 38:56 39:254 40:254 41:94 53:99 54:254 55:254 56:51 +60 10:148 11:253 12:150 23:12 24:234 25:87 39:148 40:253 41:150 52:12 53:234 54:87 +60 8:169 9:252 10:115 23:116 24:252 25:168 37:169 38:252 39:115 52:116 53:252 54:168 +60 9:55 10:254 11:170 24:236 25:217 38:55 39:254 40:170 53:236 54:217 +60 8:34 9:253 10:253 11:10 23:12 24:187 25:209 37:34 38:253 39:253 40:10 52:12 53:187 54:209 +60 8:95 9:246 10:252 11:200 12:128 13:8 24:70 25:252 26:252 37:95 38:246 39:252 40:200 41:128 42:8 53:70 54:252 55:252 +0 81 58 9:3 10:186 11:254 12:254 13:250 14:81 19:24 20:217 21:254 22:169 38:3 39:186 40:254 41:254 42:250 43:81 48:24 49:217 50:254 51:169 +60 10:190 11:254 12:120 21:9 22:193 23:254 24:53 39:190 40:254 41:120 50:9 51:193 52:254 53:53 +60 9:36 10:253 11:253 12:233 13:22 22:9 23:192 24:253 25:253 26:35 38:36 39:253 40:253 41:233 42:22 51:9 52:192 53:253 54:253 55:35 +60 9:248 10:253 11:116 24:150 25:240 38:248 39:253 40:116 53:150 54:240 +60 8:114 9:255 10:255 13:255 14:255 15:57 19:86 20:170 25:255 26:255 27:114 37:114 38:255 39:255 42:255 43:255 44:57 48:86 49:170 54:255 55:255 56:114 +60 11:26 12:240 13:254 14:254 15:94 20:8 21:238 22:254 23:152 40:26 41:240 42:254 43:254 44:94 49:8 50:238 51:254 52:152 +60 10:26 11:240 12:232 13:58 22:8 23:180 24:235 39:26 40:240 41:232 42:58 51:8 52:180 53:235 +60 10:85 11:252 12:244 13:56 22:159 23:252 24:253 25:84 39:85 40:252 41:244 42:56 51:159 52:252 53:253 54:84 +60 9:76 10:253 11:232 12:33 22:23 23:207 24:253 25:159 26:5 38:76 39:253 40:232 41:33 51:23 52:207 53:253 54:159 55:5 +60 11:29 12:252 13:253 14:27 21:29 22:252 23:253 24:27 40:29 41:252 42:253 43:27 50:29 51:252 52:253 53:27 +60 10:46 11:226 12:8 23:156 24:226 25:13 39:46 40:226 41:8 52:156 53:226 54:13 +9 59 11:102 12:234 13:51 16:173 17:253 18:254 19:91 40:102 41:234 42:51 45:173 46:253 47:254 48:91 +60 13:229 14:254 15:195 22:26 23:254 24:120 42:229 43:254 44:195 51:26 52:254 53:120 +60 11:189 12:253 13:253 14:47 22:30 23:253 24:188 40:189 41:253 42:253 43:47 51:30 52:253 53:188 +60 9:254 10:198 27:199 28:214 38:254 39:198 56:199 57:214 +60 12:43 13:253 14:214 15:13 21:207 22:252 23:253 24:92 41:43 42:253 43:214 44:13 50:207 51:252 52:253 53:92 +0 "" "" "" "" "" "" "" 32 212 253 253 253 253 191 "" "" "" "" "" "" 37 253 255 253 237 62 "" "" "" "" "" "" "" "" "" "" 32 212 253 253 253 253 191 "" "" "" "" "" "" 37 253 255 253 237 62 "" "" "" "" +60 10:57 11:253 12:253 13:255 14:168 21:29 22:253 23:255 24:253 25:56 39:57 40:253 41:253 42:255 43:168 50:29 51:253 52:255 53:253 54:56 +60 10:129 11:254 12:251 13:85 21:28 22:254 23:254 24:5 39:129 40:254 41:251 42:85 50:28 51:254 52:254 53:5 +60 8:130 9:250 10:82 23:132 24:253 25:253 26:12 37:130 38:250 39:82 52:132 53:253 54:253 55:12 +60 8:191 9:253 10:253 11:84 24:50 25:236 26:253 27:190 37:191 38:253 39:253 40:84 53:50 54:236 55:253 56:190 +60 11:149 12:230 21:8 22:238 23:211 40:149 41:230 50:8 51:238 52:211 +60 11:44 12:253 13:253 14:253 15:98 22:244 23:253 24:150 40:44 41:253 42:253 43:253 44:98 51:244 52:253 53:150 +60 10:153 11:254 12:254 13:51 20:106 21:254 22:254 23:152 39:153 40:254 41:254 42:51 49:106 50:254 51:254 52:152 +60 9:27 10:244 11:253 12:155 22:54 23:228 24:253 25:243 26:30 38:27 39:244 40:253 41:155 51:54 52:228 53:253 54:243 55:30 +60 9:27 10:144 11:254 12:254 13:254 14:155 15:11 23:157 24:254 25:245 26:31 38:27 39:144 40:254 41:254 42:254 43:155 44:11 52:157 53:254 54:245 55:31 +60 8:50 9:242 10:253 11:117 23:12 24:253 25:100 37:50 38:242 39:253 40:117 52:12 53:253 54:100 +60 11:104 12:253 13:117 22:226 23:253 24:191 40:104 41:253 42:117 51:226 52:253 53:191 +60 8:4 9:179 10:253 11:253 12:51 24:41 25:253 26:253 27:190 37:4 38:179 39:253 40:253 41:51 53:41 54:253 55:253 56:190 +60 10:40 11:252 12:228 13:56 20:89 21:253 22:253 23:121 39:40 40:252 41:228 42:56 49:89 50:253 51:253 52:121 +60 9:190 10:251 11:251 12:94 23:96 24:251 25:251 26:188 38:190 39:251 40:251 41:94 52:96 53:251 54:251 55:188 +60 11:189 12:253 13:253 14:11 22:148 23:253 24:70 40:189 41:253 42:253 43:11 51:148 52:253 53:70 +60 10:128 11:255 12:255 13:255 14:64 23:255 24:255 25:255 39:128 40:255 41:255 42:255 43:64 52:255 53:255 54:255 +60 9:87 10:254 11:85 23:8 24:203 25:179 38:87 39:254 40:85 52:8 53:203 54:179 +60 7:117 8:252 9:252 10:164 24:57 25:252 26:252 36:117 37:252 38:252 39:164 53:57 54:252 55:252 +0 117 "" "" "" "" 137 36 5 "" "" "" 16 147 239 245 117 "" "" "" "" "" 1 77 215 72 "" "" "" "" "" "" "" "" "" 137 36 5 "" "" "" 16 147 239 245 117 "" "" "" "" "" 1 77 215 72 "" "" "" "" "" +60 12:89 13:253 14:129 21:12 22:253 23:206 41:89 42:253 43:129 50:12 51:253 52:206 +5 59 10:8 11:199 12:254 13:113 39:8 40:199 41:254 42:113 +0 9 58 11:253 12:252 13:195 14:9 19:93 20:252 21:230 40:253 41:252 42:195 43:9 48:93 49:252 50:230 +60 8:194 9:253 10:174 24:118 25:253 26:253 27:80 37:194 38:253 39:174 53:118 54:253 55:253 56:80 +60 12:168 13:253 14:210 15:6 21:144 22:252 23:126 41:168 42:253 43:210 44:6 50:144 51:252 52:126 +60 11:126 12:254 13:93 21:39 22:254 23:86 40:126 41:254 42:93 50:39 51:254 52:86 +60 10:147 11:254 12:254 13:116 21:171 22:254 23:254 24:247 39:147 40:254 41:254 42:116 50:171 51:254 52:254 53:247 +60 7:133 8:253 9:253 10:205 22:38 23:231 24:253 25:253 26:253 36:133 37:253 38:253 39:205 51:38 52:231 53:253 54:253 55:253 +60 8:101 9:253 10:253 11:253 12:61 24:83 25:253 26:253 27:99 37:101 38:253 39:253 40:253 41:61 53:83 54:253 55:253 56:99 +60 10:228 11:253 12:253 13:66 22:68 23:253 24:253 25:253 26:107 39:228 40:253 41:253 42:66 51:68 52:253 53:253 54:253 55:107 +60 8:255 9:255 10:128 25:255 26:255 27:128 37:255 38:255 39:128 54:255 55:255 56:128 +60 9:187 10:253 11:253 12:253 13:253 14:253 15:82 23:62 24:253 25:253 26:253 27:253 38:187 39:253 40:253 41:253 42:253 43:253 44:82 52:62 53:253 54:253 55:253 56:253 +60 8:164 9:253 10:200 13:119 25:119 26:253 27:190 37:164 38:253 39:200 42:119 54:119 55:253 56:190 +0 8 58 6:169 7:253 8:227 9:76 11:35 12:253 13:198 14:8 23:33 24:253 25:253 35:169 36:253 37:227 38:76 40:35 41:253 42:198 43:8 52:33 53:253 54:253 +6 253 "" "" "" "" "" "" "" 10 52 221 253 253 253 253 253 253 253 253 253 253 202 177 177 79 "" "" "" "" "" "" "" "" "" "" "" "" 10 52 221 253 253 253 253 253 253 253 253 253 253 202 177 177 79 "" "" "" "" "" +60 8:64 9:255 10:255 11:255 12:191 25:128 26:255 27:255 37:64 38:255 39:255 40:255 41:191 54:128 55:255 56:255 +0 186 "" "" "" "" "" "" "" 101 253 253 253 253 253 253 186 20 "" "" "" "" "" "" 133 253 253 165 "" "" "" "" "" "" "" "" "" "" 101 253 253 253 253 253 253 186 20 "" "" "" "" "" "" 133 253 253 165 "" "" "" +0 252 58 8:168 9:248 10:252 11:253 12:252 13:252 14:252 15:32 23:184 24:252 25:252 37:168 38:248 39:252 40:253 41:252 42:252 43:252 44:32 52:184 53:252 54:252 +0 102 "" "" "" "" "" "" "" 83 205 253 215 23 "" 41 102 23 "" "" "" "" "" "" 8 205 229 23 "" "" "" "" "" "" "" "" "" "" 83 205 253 215 23 "" 41 102 23 "" "" "" "" "" "" 8 205 229 23 "" "" "" +60 9:96 10:251 11:251 12:251 13:251 14:253 15:140 24:96 25:251 26:251 27:188 38:96 39:251 40:251 41:251 42:251 43:253 44:140 53:96 54:251 55:251 56:188 +60 12:255 13:255 14:255 21:128 22:255 23:255 24:128 41:255 42:255 43:255 50:128 51:255 52:255 53:128 +60 10:32 11:229 12:253 13:226 24:163 25:254 26:253 27:56 39:32 40:229 41:253 42:226 53:163 54:254 55:253 56:56 +5 169 58 9:51 10:197 11:182 12:74 13:74 14:169 15:253 16:253 17:233 18:39 38:51 39:197 40:182 41:74 42:74 43:169 44:253 45:253 46:233 47:39 +1 251 58 12:41 13:226 14:251 15:251 16:253 17:107 41:41 42:226 43:251 44:251 45:253 46:107 +60 9:47 10:253 11:253 12:241 13:80 20:176 21:253 22:253 23:253 24:138 38:47 39:253 40:253 41:241 42:80 49:176 50:253 51:253 52:253 53:138 +7 59 17:120 18:252 19:252 20:252 21:64 46:120 47:252 48:252 49:252 50:64 +60 9:217 10:252 11:252 12:103 22:57 23:252 24:253 25:200 26:21 38:217 39:252 40:252 41:103 51:57 52:252 53:253 54:200 55:21 +4 1 58 10:130 11:254 12:239 13:123 14:1 16:23 17:230 18:254 19:192 39:130 40:254 41:239 42:123 43:1 45:23 46:230 47:254 48:192 +0 138 "" "" "" "" "" "" "" "" 1 232 252 252 252 253 138 "" "" "" 217 252 252 253 231 71 "" "" "" "" "" "" "" "" "" "" "" "" "" 1 232 252 252 252 253 138 "" "" "" 217 252 252 253 231 71 "" "" "" "" "" +0 38 58 11:38 12:103 13:9 14:38 22:216 23:196 40:38 41:103 42:9 43:38 51:216 52:196 +0 "" "" "" "" "" "" "" "" 255 255 255 255 255 64 "" "" "" "" "" "" 64 191 255 255 255 255 255 "" "" "" "" "" "" "" "" "" "" 255 255 255 255 255 64 "" "" "" "" "" "" 64 191 255 255 255 255 255 "" "" "" +60 9:11 10:155 11:252 12:252 13:179 14:15 21:32 22:237 23:253 24:231 25:51 38:11 39:155 40:252 41:252 42:179 43:15 50:32 51:237 52:253 53:231 54:51 +60 11:43 12:227 13:252 14:252 15:154 22:200 23:252 24:149 40:43 41:227 42:252 43:252 44:154 51:200 52:252 53:149 +0 11 58 9:29 10:143 11:253 12:253 13:187 14:11 22:156 23:253 24:110 38:29 39:143 40:253 41:253 42:187 43:11 51:156 52:253 53:110 +0 120 58 9:120 10:253 11:253 12:253 13:253 14:120 19:72 20:241 21:253 22:253 23:163 38:120 39:253 40:253 41:253 42:253 43:120 48:72 49:241 50:253 51:253 52:163 +60 8:11 9:206 10:252 11:162 25:22 26:252 27:252 37:11 38:206 39:252 40:162 54:22 55:252 56:252 +6 59 12:166 13:253 14:170 17:25 18:43 19:139 20:174 21:122 41:166 42:253 43:170 46:25 47:43 48:139 49:174 50:122 +0 253 "" "" "" "" "" "" "" "" "" 1 232 252 252 252 253 35 "" "" 109 252 252 252 144 "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" 1 232 252 252 252 253 35 "" "" 109 252 252 252 144 "" "" "" "" "" "" +0 17 58 11:201 12:253 13:253 14:17 18:24 19:211 20:253 21:53 40:201 41:253 42:253 43:17 47:24 48:211 49:253 50:53 +60 12:201 13:253 14:253 15:155 21:38 22:225 23:253 24:253 25:163 41:201 42:253 43:253 44:155 50:38 51:225 52:253 53:253 54:163 +1 237 58 13:42 14:237 15:254 16:254 17:49 42:42 43:237 44:254 45:254 46:49 +60 10:107 11:252 12:253 13:252 14:118 23:225 24:252 25:252 26:112 39:107 40:252 41:253 42:252 43:118 52:225 53:252 54:252 55:112 +0 "" "" "" "" "" "" 5 87 254 254 254 254 253 128 29 "" "" "" "" 3 138 254 254 254 254 227 "" "" "" "" "" "" "" "" "" 5 87 254 254 254 254 253 128 29 "" "" "" "" 3 138 254 254 254 254 227 "" "" "" "" +60 8:92 9:253 10:253 11:253 12:254 13:253 14:253 15:190 24:254 25:253 26:253 27:253 37:92 38:253 39:253 40:253 41:254 42:253 43:253 44:190 53:254 54:253 55:253 56:253 +0 "" "" "" "" "" "" "" 109 229 253 253 253 253 248 108 "" "" "" "" 3 137 253 253 253 253 226 "" "" "" "" "" "" "" "" "" "" 109 229 253 253 253 253 248 108 "" "" "" "" 3 137 253 253 253 253 226 "" "" "" "" +60 7:113 8:252 9:252 10:252 11:252 12:63 21:140 22:253 23:252 24:252 25:252 26:252 36:113 37:252 38:252 39:252 40:252 41:63 50:140 51:253 52:252 53:252 54:252 55:252 +60 9:225 10:252 11:252 12:173 25:197 26:252 27:252 38:225 39:252 40:252 41:173 54:197 55:252 56:252 +60 9:26 10:206 11:253 12:253 13:253 14:164 15:13 24:114 25:248 26:29 38:26 39:206 40:253 41:253 42:253 43:164 44:13 53:114 54:248 55:29 +60 8:21 9:181 10:252 11:252 12:138 24:217 25:252 26:252 37:21 38:181 39:252 40:252 41:138 53:217 54:252 55:252 +60 9:9 10:132 11:246 12:253 13:137 14:4 23:36 24:223 25:252 26:59 38:9 39:132 40:246 41:253 42:137 43:4 52:36 53:223 54:252 55:59 +60 7:19 8:216 9:252 10:252 11:252 12:222 21:75 22:252 23:252 24:252 25:207 36:19 37:216 38:252 39:252 40:252 41:222 50:75 51:252 52:252 53:252 54:207 +60 10:13 11:169 12:253 13:228 14:9 22:66 23:253 24:253 25:135 39:13 40:169 41:253 42:228 43:9 51:66 52:253 53:253 54:135 +60 10:117 11:254 12:254 13:222 14:55 21:218 22:254 23:254 24:18 39:117 40:254 41:254 42:222 43:55 50:218 51:254 52:254 53:18 diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExprTextDef-Schema.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExprTextDef-Schema.txt new file mode 100644 index 0000000000..c0a10a36f0 --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExprTextDef-Schema.txt @@ -0,0 +1,15 @@ +---- BoundLoader ---- +4 columns: + A: Int32 + N: Int32 + VI: Vector + VR: Vector +---- RowToRowMapperTransform ---- +7 columns: + A: Int32 + N: Int32 + N: String + VI: Vector + VI: Vector + VR: Vector + VR: Vector diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExprTextDef-b-Schema.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExprTextDef-b-Schema.txt new file mode 100644 index 0000000000..b3bb91f243 --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExprTextDef-b-Schema.txt @@ -0,0 +1,6 @@ +---- BoundLoader ---- +4 columns: + A: Int32 + N: String + VI: Vector + VR: Vector diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExprTextFull-Data.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExprTextFull-Data.txt new file mode 100644 index 0000000000..febf9d6937 --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExprTextFull-Data.txt @@ -0,0 +1,109 @@ +#@ TextLoader{ +#@ header+ +#@ sep=tab +#@ col=A:I4:0 +#@ col=N:TX:1 +#@ col=VI:TX:2-30 +#@ col=VR:TX:31-59 +#@ } +A N 58 0:"" +0 0 0 0 0 0 0 0 0 0 76 253 253 0 0 0 0 0 0 0 0 0 0 0 61 232 24 0 0 0 0 0 0 0 0 0 0 0 0 76 253 253 0 0 0 0 0 0 0 0 0 0 0 61 232 24 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 44 253 253 97 0 0 0 0 0 0 0 244 188 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 44 253 253 97 0 0 0 0 0 0 0 244 188 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 233 252 61 0 0 0 0 0 0 0 253 252 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 233 252 61 0 0 0 0 0 0 0 253 252 20 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 254 253 194 0 0 0 0 0 0 195 253 253 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 254 253 194 0 0 0 0 0 0 195 253 253 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 114 253 185 0 0 0 0 0 0 0 0 0 0 0 0 0 0 207 253 0 0 0 0 0 0 0 0 0 0 114 253 185 0 0 0 0 0 0 0 0 0 0 0 0 0 0 207 253 0 0 0 0 +0 0 0 0 0 0 0 0 0 56 254 254 94 0 0 0 0 0 0 0 0 0 0 0 99 254 254 51 0 0 0 0 0 0 0 0 0 0 56 254 254 94 0 0 0 0 0 0 0 0 0 0 0 99 254 254 51 0 0 0 +0 0 0 0 0 0 0 0 0 0 148 253 150 0 0 0 0 0 0 0 0 0 0 12 234 87 0 0 0 0 0 0 0 0 0 0 0 0 0 148 253 150 0 0 0 0 0 0 0 0 0 0 12 234 87 0 0 0 0 0 +0 0 0 0 0 0 0 0 169 252 115 0 0 0 0 0 0 0 0 0 0 0 0 116 252 168 0 0 0 0 0 0 0 0 0 0 0 169 252 115 0 0 0 0 0 0 0 0 0 0 0 0 116 252 168 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 55 254 170 0 0 0 0 0 0 0 0 0 0 0 0 236 217 0 0 0 0 0 0 0 0 0 0 0 0 55 254 170 0 0 0 0 0 0 0 0 0 0 0 0 236 217 0 0 0 0 0 +0 0 0 0 0 0 0 0 34 253 253 10 0 0 0 0 0 0 0 0 0 0 0 12 187 209 0 0 0 0 0 0 0 0 0 0 0 34 253 253 10 0 0 0 0 0 0 0 0 0 0 0 12 187 209 0 0 0 0 0 +0 0 0 0 0 0 0 0 95 246 252 200 128 8 0 0 0 0 0 0 0 0 0 0 70 252 252 0 0 0 0 0 0 0 0 0 0 95 246 252 200 128 8 0 0 0 0 0 0 0 0 0 0 70 252 252 0 0 0 0 +0 81 0 0 0 0 0 0 0 0 0 3 186 254 254 250 81 0 0 0 0 24 217 254 169 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 186 254 254 250 81 0 0 0 0 24 217 254 169 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 190 254 120 0 0 0 0 0 0 0 0 9 193 254 53 0 0 0 0 0 0 0 0 0 0 0 0 0 0 190 254 120 0 0 0 0 0 0 0 0 9 193 254 53 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 36 253 253 233 22 0 0 0 0 0 0 0 0 9 192 253 253 35 0 0 0 0 0 0 0 0 0 0 0 36 253 253 233 22 0 0 0 0 0 0 0 0 9 192 253 253 35 0 0 0 0 +0 0 0 0 0 0 0 0 0 248 253 116 0 0 0 0 0 0 0 0 0 0 0 0 150 240 0 0 0 0 0 0 0 0 0 0 0 0 248 253 116 0 0 0 0 0 0 0 0 0 0 0 0 150 240 0 0 0 0 0 +0 0 0 0 0 0 0 0 114 255 255 0 0 255 255 57 0 0 0 86 170 0 0 0 0 255 255 114 0 0 0 0 0 0 0 0 0 114 255 255 0 0 255 255 57 0 0 0 86 170 0 0 0 0 255 255 114 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 26 240 254 254 94 0 0 0 0 8 238 254 152 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 26 240 254 254 94 0 0 0 0 8 238 254 152 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 26 240 232 58 0 0 0 0 0 0 0 0 8 180 235 0 0 0 0 0 0 0 0 0 0 0 0 0 0 26 240 232 58 0 0 0 0 0 0 0 0 8 180 235 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 85 252 244 56 0 0 0 0 0 0 0 0 159 252 253 84 0 0 0 0 0 0 0 0 0 0 0 0 0 85 252 244 56 0 0 0 0 0 0 0 0 159 252 253 84 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 76 253 232 33 0 0 0 0 0 0 0 0 0 23 207 253 159 5 0 0 0 0 0 0 0 0 0 0 0 76 253 232 33 0 0 0 0 0 0 0 0 0 23 207 253 159 5 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 29 252 253 27 0 0 0 0 0 0 29 252 253 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 29 252 253 27 0 0 0 0 0 0 29 252 253 27 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 46 226 8 0 0 0 0 0 0 0 0 0 0 156 226 13 0 0 0 0 0 0 0 0 0 0 0 0 0 46 226 8 0 0 0 0 0 0 0 0 0 0 156 226 13 0 0 0 0 0 +9 0 0 0 0 0 0 0 0 0 0 0 102 234 51 0 0 173 253 254 91 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 102 234 51 0 0 173 253 254 91 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 229 254 195 0 0 0 0 0 0 26 254 120 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 229 254 195 0 0 0 0 0 0 26 254 120 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 189 253 253 47 0 0 0 0 0 0 0 30 253 188 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 189 253 253 47 0 0 0 0 0 0 0 30 253 188 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 254 198 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 199 214 0 0 0 0 0 0 0 0 0 254 198 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 199 214 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 43 253 214 13 0 0 0 0 0 207 252 253 92 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 43 253 214 13 0 0 0 0 0 207 252 253 92 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 32 212 253 253 253 253 191 0 0 0 0 0 0 37 253 255 253 237 62 0 0 0 0 0 0 0 0 0 0 32 212 253 253 253 253 191 0 0 0 0 0 0 37 253 255 253 237 62 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 57 253 253 255 168 0 0 0 0 0 0 29 253 255 253 56 0 0 0 0 0 0 0 0 0 0 0 0 0 57 253 253 255 168 0 0 0 0 0 0 29 253 255 253 56 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 129 254 251 85 0 0 0 0 0 0 0 28 254 254 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 129 254 251 85 0 0 0 0 0 0 0 28 254 254 5 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 130 250 82 0 0 0 0 0 0 0 0 0 0 0 0 132 253 253 12 0 0 0 0 0 0 0 0 0 0 130 250 82 0 0 0 0 0 0 0 0 0 0 0 0 132 253 253 12 0 0 0 0 +0 0 0 0 0 0 0 0 191 253 253 84 0 0 0 0 0 0 0 0 0 0 0 0 50 236 253 190 0 0 0 0 0 0 0 0 0 191 253 253 84 0 0 0 0 0 0 0 0 0 0 0 0 50 236 253 190 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 149 230 0 0 0 0 0 0 0 0 8 238 211 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 149 230 0 0 0 0 0 0 0 0 8 238 211 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 44 253 253 253 98 0 0 0 0 0 0 244 253 150 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 44 253 253 253 98 0 0 0 0 0 0 244 253 150 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 153 254 254 51 0 0 0 0 0 0 106 254 254 152 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 153 254 254 51 0 0 0 0 0 0 106 254 254 152 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 27 244 253 155 0 0 0 0 0 0 0 0 0 54 228 253 243 30 0 0 0 0 0 0 0 0 0 0 0 27 244 253 155 0 0 0 0 0 0 0 0 0 54 228 253 243 30 0 0 0 0 +0 0 0 0 0 0 0 0 0 27 144 254 254 254 155 11 0 0 0 0 0 0 0 157 254 245 31 0 0 0 0 0 0 0 0 0 0 0 27 144 254 254 254 155 11 0 0 0 0 0 0 0 157 254 245 31 0 0 0 0 +0 0 0 0 0 0 0 0 50 242 253 117 0 0 0 0 0 0 0 0 0 0 0 12 253 100 0 0 0 0 0 0 0 0 0 0 0 50 242 253 117 0 0 0 0 0 0 0 0 0 0 0 12 253 100 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 104 253 117 0 0 0 0 0 0 0 0 226 253 191 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 104 253 117 0 0 0 0 0 0 0 0 226 253 191 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 4 179 253 253 51 0 0 0 0 0 0 0 0 0 0 0 41 253 253 190 0 0 0 0 0 0 0 0 0 4 179 253 253 51 0 0 0 0 0 0 0 0 0 0 0 41 253 253 190 0 0 0 +0 0 0 0 0 0 0 0 0 0 40 252 228 56 0 0 0 0 0 0 89 253 253 121 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 40 252 228 56 0 0 0 0 0 0 89 253 253 121 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 190 251 251 94 0 0 0 0 0 0 0 0 0 0 96 251 251 188 0 0 0 0 0 0 0 0 0 0 0 190 251 251 94 0 0 0 0 0 0 0 0 0 0 96 251 251 188 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 189 253 253 11 0 0 0 0 0 0 0 148 253 70 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 189 253 253 11 0 0 0 0 0 0 0 148 253 70 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 128 255 255 255 64 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 128 255 255 255 64 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 87 254 85 0 0 0 0 0 0 0 0 0 0 0 8 203 179 0 0 0 0 0 0 0 0 0 0 0 0 87 254 85 0 0 0 0 0 0 0 0 0 0 0 8 203 179 0 0 0 0 0 +0 0 0 0 0 0 0 117 252 252 164 0 0 0 0 0 0 0 0 0 0 0 0 0 57 252 252 0 0 0 0 0 0 0 0 0 117 252 252 164 0 0 0 0 0 0 0 0 0 0 0 0 0 57 252 252 0 0 0 0 +0 117 0 0 0 0 137 36 5 0 0 0 16 147 239 245 117 0 0 0 0 0 1 77 215 72 0 0 0 0 0 0 0 0 0 137 36 5 0 0 0 16 147 239 245 117 0 0 0 0 0 1 77 215 72 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 89 253 129 0 0 0 0 0 0 12 253 206 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 253 129 0 0 0 0 0 0 12 253 206 0 0 0 0 0 0 0 +5 0 0 0 0 0 0 0 0 0 0 8 199 254 113 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 199 254 113 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 9 0 0 0 0 0 0 0 0 0 0 0 253 252 195 9 0 0 0 0 93 252 230 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 253 252 195 9 0 0 0 0 93 252 230 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 194 253 174 0 0 0 0 0 0 0 0 0 0 0 0 0 118 253 253 80 0 0 0 0 0 0 0 0 0 194 253 174 0 0 0 0 0 0 0 0 0 0 0 0 0 118 253 253 80 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 168 253 210 6 0 0 0 0 0 144 252 126 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 168 253 210 6 0 0 0 0 0 144 252 126 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 126 254 93 0 0 0 0 0 0 0 39 254 86 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 126 254 93 0 0 0 0 0 0 0 39 254 86 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 147 254 254 116 0 0 0 0 0 0 0 171 254 254 247 0 0 0 0 0 0 0 0 0 0 0 0 0 0 147 254 254 116 0 0 0 0 0 0 0 171 254 254 247 0 0 0 0 0 0 +0 0 0 0 0 0 0 133 253 253 205 0 0 0 0 0 0 0 0 0 0 0 38 231 253 253 253 0 0 0 0 0 0 0 0 0 133 253 253 205 0 0 0 0 0 0 0 0 0 0 0 38 231 253 253 253 0 0 0 0 +0 0 0 0 0 0 0 0 101 253 253 253 61 0 0 0 0 0 0 0 0 0 0 0 83 253 253 99 0 0 0 0 0 0 0 0 0 101 253 253 253 61 0 0 0 0 0 0 0 0 0 0 0 83 253 253 99 0 0 0 +0 0 0 0 0 0 0 0 0 0 228 253 253 66 0 0 0 0 0 0 0 0 68 253 253 253 107 0 0 0 0 0 0 0 0 0 0 0 0 228 253 253 66 0 0 0 0 0 0 0 0 68 253 253 253 107 0 0 0 0 +0 0 0 0 0 0 0 0 255 255 128 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 128 0 0 0 0 0 0 0 0 0 255 255 128 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 128 0 0 0 +0 0 0 0 0 0 0 0 0 187 253 253 253 253 253 82 0 0 0 0 0 0 0 62 253 253 253 253 0 0 0 0 0 0 0 0 0 0 187 253 253 253 253 253 82 0 0 0 0 0 0 0 62 253 253 253 253 0 0 0 +0 0 0 0 0 0 0 0 164 253 200 0 0 119 0 0 0 0 0 0 0 0 0 0 0 119 253 190 0 0 0 0 0 0 0 0 0 164 253 200 0 0 119 0 0 0 0 0 0 0 0 0 0 0 119 253 190 0 0 0 +0 8 0 0 0 0 0 0 169 253 227 76 0 35 253 198 8 0 0 0 0 0 0 0 0 33 253 253 0 0 0 0 0 0 0 0 0 169 253 227 76 0 35 253 198 8 0 0 0 0 0 0 0 0 33 253 253 0 0 0 +6 253 0 0 0 0 0 0 0 10 52 221 253 253 253 253 253 253 253 253 253 253 202 177 177 79 0 0 0 0 0 0 0 0 0 0 0 0 10 52 221 253 253 253 253 253 253 253 253 253 253 202 177 177 79 0 0 0 0 0 +0 0 0 0 0 0 0 0 64 255 255 255 191 0 0 0 0 0 0 0 0 0 0 0 0 128 255 255 0 0 0 0 0 0 0 0 0 64 255 255 255 191 0 0 0 0 0 0 0 0 0 0 0 0 128 255 255 0 0 0 +0 186 0 0 0 0 0 0 0 101 253 253 253 253 253 253 186 20 0 0 0 0 0 0 133 253 253 165 0 0 0 0 0 0 0 0 0 0 101 253 253 253 253 253 253 186 20 0 0 0 0 0 0 133 253 253 165 0 0 0 +0 252 0 0 0 0 0 0 0 0 168 248 252 253 252 252 252 32 0 0 0 0 0 0 0 184 252 252 0 0 0 0 0 0 0 0 0 0 0 168 248 252 253 252 252 252 32 0 0 0 0 0 0 0 184 252 252 0 0 0 +0 102 0 0 0 0 0 0 0 83 205 253 215 23 0 41 102 23 0 0 0 0 0 0 8 205 229 23 0 0 0 0 0 0 0 0 0 0 83 205 253 215 23 0 41 102 23 0 0 0 0 0 0 8 205 229 23 0 0 0 +0 0 0 0 0 0 0 0 0 96 251 251 251 251 253 140 0 0 0 0 0 0 0 0 96 251 251 188 0 0 0 0 0 0 0 0 0 0 96 251 251 251 251 253 140 0 0 0 0 0 0 0 0 96 251 251 188 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 128 255 255 128 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 128 255 255 128 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 32 229 253 226 0 0 0 0 0 0 0 0 0 0 163 254 253 56 0 0 0 0 0 0 0 0 0 0 0 32 229 253 226 0 0 0 0 0 0 0 0 0 0 163 254 253 56 0 0 0 +5 169 0 0 0 0 0 0 0 0 0 51 197 182 74 74 169 253 253 233 39 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 51 197 182 74 74 169 253 253 233 39 0 0 0 0 0 0 0 0 0 0 +1 251 0 0 0 0 0 0 0 0 0 0 0 0 41 226 251 251 253 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 41 226 251 251 253 107 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 47 253 253 241 80 0 0 0 0 0 0 176 253 253 253 138 0 0 0 0 0 0 0 0 0 0 0 0 0 47 253 253 241 80 0 0 0 0 0 0 176 253 253 253 138 0 0 0 0 0 0 +7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 120 252 252 252 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 120 252 252 252 64 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 217 252 252 103 0 0 0 0 0 0 0 0 0 57 252 253 200 21 0 0 0 0 0 0 0 0 0 0 0 217 252 252 103 0 0 0 0 0 0 0 0 0 57 252 253 200 21 0 0 0 0 +4 1 0 0 0 0 0 0 0 0 0 0 130 254 239 123 1 0 23 230 254 192 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 130 254 239 123 1 0 23 230 254 192 0 0 0 0 0 0 0 0 0 +0 138 0 0 0 0 0 0 0 0 1 232 252 252 252 253 138 0 0 0 217 252 252 253 231 71 0 0 0 0 0 0 0 0 0 0 0 0 0 1 232 252 252 252 253 138 0 0 0 217 252 252 253 231 71 0 0 0 0 0 +0 38 0 0 0 0 0 0 0 0 0 0 0 38 103 9 38 0 0 0 0 0 0 0 216 196 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 38 103 9 38 0 0 0 0 0 0 0 216 196 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 255 255 255 255 255 64 0 0 0 0 0 0 64 191 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 64 0 0 0 0 0 0 64 191 255 255 255 255 255 0 0 0 +0 0 0 0 0 0 0 0 0 11 155 252 252 179 15 0 0 0 0 0 0 32 237 253 231 51 0 0 0 0 0 0 0 0 0 0 0 0 11 155 252 252 179 15 0 0 0 0 0 0 32 237 253 231 51 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 43 227 252 252 154 0 0 0 0 0 0 200 252 149 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 43 227 252 252 154 0 0 0 0 0 0 200 252 149 0 0 0 0 0 0 +0 11 0 0 0 0 0 0 0 0 0 29 143 253 253 187 11 0 0 0 0 0 0 0 156 253 110 0 0 0 0 0 0 0 0 0 0 0 0 0 29 143 253 253 187 11 0 0 0 0 0 0 0 156 253 110 0 0 0 0 +0 120 0 0 0 0 0 0 0 0 0 120 253 253 253 253 120 0 0 0 0 72 241 253 253 163 0 0 0 0 0 0 0 0 0 0 0 0 0 0 120 253 253 253 253 120 0 0 0 0 72 241 253 253 163 0 0 0 0 0 +0 0 0 0 0 0 0 0 11 206 252 162 0 0 0 0 0 0 0 0 0 0 0 0 0 22 252 252 0 0 0 0 0 0 0 0 0 11 206 252 162 0 0 0 0 0 0 0 0 0 0 0 0 0 22 252 252 0 0 0 +6 0 0 0 0 0 0 0 0 0 0 0 0 166 253 170 0 0 25 43 139 174 122 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 166 253 170 0 0 25 43 139 174 122 0 0 0 0 0 0 0 0 +0 253 0 0 0 0 0 0 0 0 0 1 232 252 252 252 253 35 0 0 109 252 252 252 144 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 232 252 252 252 253 35 0 0 109 252 252 252 144 0 0 0 0 0 0 +0 17 0 0 0 0 0 0 0 0 0 0 0 201 253 253 17 0 0 0 24 211 253 53 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 201 253 253 17 0 0 0 24 211 253 53 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 201 253 253 155 0 0 0 0 0 38 225 253 253 163 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 201 253 253 155 0 0 0 0 0 38 225 253 253 163 0 0 0 0 0 +1 237 0 0 0 0 0 0 0 0 0 0 0 0 0 42 237 254 254 49 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 42 237 254 254 49 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 107 252 253 252 118 0 0 0 0 0 0 0 0 225 252 252 112 0 0 0 0 0 0 0 0 0 0 0 0 107 252 253 252 118 0 0 0 0 0 0 0 0 225 252 252 112 0 0 0 0 +0 0 0 0 0 0 0 5 87 254 254 254 254 253 128 29 0 0 0 0 3 138 254 254 254 254 227 0 0 0 0 0 0 0 0 0 5 87 254 254 254 254 253 128 29 0 0 0 0 3 138 254 254 254 254 227 0 0 0 0 +0 0 0 0 0 0 0 0 92 253 253 253 254 253 253 190 0 0 0 0 0 0 0 0 254 253 253 253 0 0 0 0 0 0 0 0 0 92 253 253 253 254 253 253 190 0 0 0 0 0 0 0 0 254 253 253 253 0 0 0 +0 0 0 0 0 0 0 0 109 229 253 253 253 253 248 108 0 0 0 0 3 137 253 253 253 253 226 0 0 0 0 0 0 0 0 0 0 109 229 253 253 253 253 248 108 0 0 0 0 3 137 253 253 253 253 226 0 0 0 0 +0 0 0 0 0 0 0 113 252 252 252 252 63 0 0 0 0 0 0 0 0 140 253 252 252 252 252 0 0 0 0 0 0 0 0 0 113 252 252 252 252 63 0 0 0 0 0 0 0 0 140 253 252 252 252 252 0 0 0 0 +0 0 0 0 0 0 0 0 0 225 252 252 173 0 0 0 0 0 0 0 0 0 0 0 0 197 252 252 0 0 0 0 0 0 0 0 0 0 225 252 252 173 0 0 0 0 0 0 0 0 0 0 0 0 197 252 252 0 0 0 +0 0 0 0 0 0 0 0 0 26 206 253 253 253 164 13 0 0 0 0 0 0 0 0 114 248 29 0 0 0 0 0 0 0 0 0 0 0 26 206 253 253 253 164 13 0 0 0 0 0 0 0 0 114 248 29 0 0 0 0 +0 0 0 0 0 0 0 0 21 181 252 252 138 0 0 0 0 0 0 0 0 0 0 0 217 252 252 0 0 0 0 0 0 0 0 0 0 21 181 252 252 138 0 0 0 0 0 0 0 0 0 0 0 217 252 252 0 0 0 0 +0 0 0 0 0 0 0 0 0 9 132 246 253 137 4 0 0 0 0 0 0 0 0 36 223 252 59 0 0 0 0 0 0 0 0 0 0 0 9 132 246 253 137 4 0 0 0 0 0 0 0 0 36 223 252 59 0 0 0 0 +0 0 0 0 0 0 0 19 216 252 252 252 222 0 0 0 0 0 0 0 0 75 252 252 252 207 0 0 0 0 0 0 0 0 0 0 19 216 252 252 252 222 0 0 0 0 0 0 0 0 75 252 252 252 207 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 13 169 253 228 9 0 0 0 0 0 0 0 66 253 253 135 0 0 0 0 0 0 0 0 0 0 0 0 0 13 169 253 228 9 0 0 0 0 0 0 0 66 253 253 135 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 117 254 254 222 55 0 0 0 0 0 0 218 254 254 18 0 0 0 0 0 0 0 0 0 0 0 0 0 0 117 254 254 222 55 0 0 0 0 0 0 218 254 254 18 0 0 0 0 0 0 diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExprTextFull-Schema.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExprTextFull-Schema.txt new file mode 100644 index 0000000000..c0a10a36f0 --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExprTextFull-Schema.txt @@ -0,0 +1,15 @@ +---- BoundLoader ---- +4 columns: + A: Int32 + N: Int32 + VI: Vector + VR: Vector +---- RowToRowMapperTransform ---- +7 columns: + A: Int32 + N: Int32 + N: String + VI: Vector + VI: Vector + VR: Vector + VR: Vector diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExprTextFull-b-Schema.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExprTextFull-b-Schema.txt new file mode 100644 index 0000000000..3dfc5fae84 --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExprTextFull-b-Schema.txt @@ -0,0 +1,15 @@ +---- BoundLoader ---- +4 columns: + A: Int32 + N: String + VI: Vector + VR: Vector +---- RowToRowMapperTransform ---- +7 columns: + A: Int32 + N: String + N: String + VI: Vector + VI: Vector + VR: Vector + VR: Vector diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExprVec1-Data.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExprVec1-Data.txt new file mode 100644 index 0000000000..e1d05c26bc --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExprVec1-Data.txt @@ -0,0 +1,110 @@ +#@ TextLoader{ +#@ header+ +#@ sep=tab +#@ col=A:I4:0 +#@ col=M:I4:1 +#@ col=N:I4:2 +#@ col=VI:I4:3-31 +#@ col=VR:R4:32-60 +#@ } +A M N 58 0:"" +0 0 1 1 1 1 1 1 1 1 1 8 26 26 1 1 1 1 1 1 1 1 1 1 1 7 24 3 1 1 1 1 29 8:7.6 9:25.3 10:25.3 22:6.1 23:23.2 24:2.4 +0 0 1 1 1 1 1 1 1 1 1 1 5 26 26 10 1 1 1 1 1 1 1 25 19 1 1 1 1 1 1 1 29 9:4.4 10:25.3 11:25.3 12:9.7 20:24.4 21:18.8 +0 0 1 1 1 1 1 1 1 1 1 1 1 24 26 7 1 1 1 1 1 1 1 26 26 3 1 1 1 1 1 1 29 10:23.3 11:25.2 12:6.1 20:25.3 21:25.2 22:2 +0 0 1 1 1 1 1 1 1 1 1 1 26 26 20 1 1 1 1 1 1 20 26 26 1 1 1 1 1 1 1 1 29 9:25.4 10:25.3 11:19.4 18:19.5 19:25.3 20:25.3 +0 0 1 1 1 1 1 1 1 12 26 19 1 1 1 1 1 1 1 1 1 1 1 1 1 1 21 26 1 1 1 1 29 6:11.4 7:25.3 8:18.5 23:20.7 24:25.3 +0 0 1 1 1 1 1 1 1 1 6 26 26 10 1 1 1 1 1 1 1 1 1 1 1 10 26 26 6 1 1 1 29 7:5.6 8:25.4 9:25.4 10:9.4 22:9.9 23:25.4 24:25.4 25:5.1 +0 0 1 1 1 1 1 1 1 1 1 15 26 16 1 1 1 1 1 1 1 1 1 1 2 24 9 1 1 1 1 1 29 8:14.8 9:25.3 10:15 21:1.2 22:23.4 23:8.7 +0 0 1 1 1 1 1 1 1 17 26 12 1 1 1 1 1 1 1 1 1 1 1 1 12 26 17 1 1 1 1 1 29 6:16.9 7:25.2 8:11.5 21:11.6 22:25.2 23:16.8 +0 0 1 1 1 1 1 1 1 1 6 26 18 1 1 1 1 1 1 1 1 1 1 1 1 24 22 1 1 1 1 1 29 7:5.5 8:25.4 9:17 22:23.6 23:21.7 +0 0 1 1 1 1 1 1 1 4 26 26 2 1 1 1 1 1 1 1 1 1 1 1 2 19 21 1 1 1 1 1 29 6:3.4 7:25.3 8:25.3 9:1 21:1.2 22:18.7 23:20.9 +0 0 1 1 1 1 1 1 1 10 25 26 21 13 1 1 1 1 1 1 1 1 1 1 1 8 26 26 1 1 1 1 29 6:9.5 7:24.6 8:25.2 9:20 10:12.8 11:0.8 22:7 23:25.2 24:25.2 +0 81 9 1 1 1 1 1 1 1 1 1 1 19 26 26 26 9 1 1 1 1 3 22 26 17 1 1 1 1 1 1 29 9:0.3 10:18.6 11:25.4 12:25.4 13:25 14:8.1 19:2.4 20:21.7 21:25.4 22:16.9 +0 0 1 1 1 1 1 1 1 1 1 20 26 13 1 1 1 1 1 1 1 1 1 20 26 6 1 1 1 1 1 1 29 8:19 9:25.4 10:12 19:0.9 20:19.3 21:25.4 22:5.3 +0 0 1 1 1 1 1 1 1 1 4 26 26 24 3 1 1 1 1 1 1 1 1 1 20 26 26 4 1 1 1 1 29 7:3.6 8:25.3 9:25.3 10:23.3 11:2.2 20:0.9 21:19.2 22:25.3 23:25.3 24:3.5 +0 0 1 1 1 1 1 1 1 1 25 26 12 1 1 1 1 1 1 1 1 1 1 1 1 16 25 1 1 1 1 1 29 7:24.8 8:25.3 9:11.6 22:15 23:24 +0 0 1 1 1 1 1 1 1 12 26 26 1 1 26 26 6 1 1 1 9 18 1 1 1 1 26 26 12 1 1 1 29 6:11.4 7:25.5 8:25.5 11:25.5 12:25.5 13:5.7 17:8.6 18:17 23:25.5 24:25.5 25:11.4 +0 0 1 1 1 1 1 1 1 1 1 1 3 25 26 26 10 1 1 1 1 1 24 26 16 1 1 1 1 1 1 1 29 9:2.6 10:24 11:25.4 12:25.4 13:9.4 18:0.8 19:23.8 20:25.4 21:15.2 +0 0 1 1 1 1 1 1 1 1 1 3 25 24 6 1 1 1 1 1 1 1 1 1 19 24 1 1 1 1 1 1 29 8:2.6 9:24 10:23.2 11:5.8 20:0.8 21:18 22:23.5 +0 0 1 1 1 1 1 1 1 1 1 9 26 25 6 1 1 1 1 1 1 1 1 16 26 26 9 1 1 1 1 1 29 8:8.5 9:25.2 10:24.4 11:5.6 20:15.9 21:25.2 22:25.3 23:8.4 +0 0 1 1 1 1 1 1 1 1 8 26 24 4 1 1 1 1 1 1 1 1 1 3 21 26 16 1 1 1 1 1 29 7:7.6 8:25.3 9:23.2 10:3.3 20:2.3 21:20.7 22:25.3 23:15.9 24:0.5 +0 0 1 1 1 1 1 1 1 1 1 1 3 26 26 3 1 1 1 1 1 1 3 26 26 3 1 1 1 1 1 1 29 9:2.9 10:25.2 11:25.3 12:2.7 19:2.9 20:25.2 21:25.3 22:2.7 +0 0 1 1 1 1 1 1 1 1 1 5 23 1 1 1 1 1 1 1 1 1 1 1 16 23 2 1 1 1 1 1 29 8:4.6 9:22.6 10:0.8 21:15.6 22:22.6 23:1.3 +9 0 1 1 1 1 1 1 1 1 1 1 1 11 24 6 1 1 18 26 26 10 1 1 1 1 1 1 1 1 1 1 29 10:10.2 11:23.4 12:5.1 15:17.3 16:25.3 17:25.4 18:9.1 +0 0 1 1 1 1 1 1 1 1 1 1 1 1 23 26 20 1 1 1 1 1 1 3 26 13 1 1 1 1 1 1 29 11:22.9 12:25.4 13:19.5 20:2.6 21:25.4 22:12 +0 0 1 1 1 1 1 1 1 1 1 1 19 26 26 5 1 1 1 1 1 1 1 4 26 19 1 1 1 1 1 1 29 9:18.9 10:25.3 11:25.3 12:4.7 20:3 21:25.3 22:18.8 +0 0 1 1 1 1 1 1 1 1 26 20 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 20 22 1 1 29 7:25.4 8:19.8 25:19.9 26:21.4 +0 0 1 1 1 1 1 1 1 1 1 1 1 5 26 22 2 1 1 1 1 1 21 26 26 10 1 1 1 1 1 1 29 10:4.3 11:25.3 12:21.4 13:1.3 19:20.7 20:25.2 21:25.3 22:9.2 +0 0 1 1 1 1 1 1 1 4 22 26 26 26 26 20 1 1 1 1 1 1 4 26 26 26 24 7 1 1 1 1 0 0 0 0 0 0 3.2 21.2 25.3 25.3 25.3 25.3 19.1 0 0 0 0 0 0 3.7 25.3 25.5 25.3 23.7 6.2 0 0 0 0 +0 0 1 1 1 1 1 1 1 1 1 6 26 26 26 17 1 1 1 1 1 1 3 26 26 26 6 1 1 1 1 1 29 8:5.7 9:25.3 10:25.3 11:25.5 12:16.8 19:2.9 20:25.3 21:25.5 22:25.3 23:5.6 +0 0 1 1 1 1 1 1 1 1 1 13 26 26 9 1 1 1 1 1 1 1 3 26 26 1 1 1 1 1 1 1 29 8:12.9 9:25.4 10:25.1 11:8.5 19:2.8 20:25.4 21:25.4 22:0.5 +0 0 1 1 1 1 1 1 1 14 26 9 1 1 1 1 1 1 1 1 1 1 1 1 14 26 26 2 1 1 1 1 29 6:13 7:25 8:8.2 21:13.2 22:25.3 23:25.3 24:1.2 +0 0 1 1 1 1 1 1 1 20 26 26 9 1 1 1 1 1 1 1 1 1 1 1 1 6 24 26 20 1 1 1 29 6:19.1 7:25.3 8:25.3 9:8.4 22:5 23:23.6 24:25.3 25:19 +0 0 1 1 1 1 1 1 1 1 1 1 15 24 1 1 1 1 1 1 1 1 1 24 22 1 1 1 1 1 1 1 29 9:14.9 10:23 19:0.8 20:23.8 21:21.1 +0 0 1 1 1 1 1 1 1 1 1 1 5 26 26 26 10 1 1 1 1 1 1 25 26 16 1 1 1 1 1 1 29 9:4.4 10:25.3 11:25.3 12:25.3 13:9.8 20:24.4 21:25.3 22:15 +0 0 1 1 1 1 1 1 1 1 1 16 26 26 6 1 1 1 1 1 1 11 26 26 16 1 1 1 1 1 1 1 29 8:15.3 9:25.4 10:25.4 11:5.1 18:10.6 19:25.4 20:25.4 21:15.2 +0 0 1 1 1 1 1 1 1 1 3 25 26 16 1 1 1 1 1 1 1 1 1 6 23 26 25 4 1 1 1 1 29 7:2.7 8:24.4 9:25.3 10:15.5 20:5.4 21:22.8 22:25.3 23:24.3 24:3 +0 0 1 1 1 1 1 1 1 1 3 15 26 26 26 16 2 1 1 1 1 1 1 1 16 26 25 4 1 1 1 1 29 7:2.7 8:14.4 9:25.4 10:25.4 11:25.4 12:15.5 13:1.1 21:15.7 22:25.4 23:24.5 24:3.1 +0 0 1 1 1 1 1 1 1 6 25 26 12 1 1 1 1 1 1 1 1 1 1 1 2 26 11 1 1 1 1 1 29 6:5 7:24.2 8:25.3 9:11.7 21:1.2 22:25.3 23:10 +0 0 1 1 1 1 1 1 1 1 1 1 11 26 12 1 1 1 1 1 1 1 1 23 26 20 1 1 1 1 1 1 29 9:10.4 10:25.3 11:11.7 20:22.6 21:25.3 22:19.1 +0 0 1 1 1 1 1 1 1 1 18 26 26 6 1 1 1 1 1 1 1 1 1 1 1 5 26 26 20 1 1 1 29 6:0.4 7:17.9 8:25.3 9:25.3 10:5.1 22:4.1 23:25.3 24:25.3 25:19 +0 0 1 1 1 1 1 1 1 1 1 5 26 23 6 1 1 1 1 1 1 9 26 26 13 1 1 1 1 1 1 1 29 8:4 9:25.2 10:22.8 11:5.6 18:8.9 19:25.3 20:25.3 21:12.1 +0 0 1 1 1 1 1 1 1 1 20 26 26 10 1 1 1 1 1 1 1 1 1 1 10 26 26 19 1 1 1 1 29 7:19 8:25.1 9:25.1 10:9.4 21:9.6 22:25.1 23:25.1 24:18.8 +0 0 1 1 1 1 1 1 1 1 1 1 19 26 26 2 1 1 1 1 1 1 1 15 26 8 1 1 1 1 1 1 29 9:18.9 10:25.3 11:25.3 12:1.1 20:14.8 21:25.3 22:7 +0 0 1 1 1 1 1 1 1 1 1 13 26 26 26 7 1 1 1 1 1 1 1 1 26 26 26 1 1 1 1 1 29 8:12.8 9:25.5 10:25.5 11:25.5 12:6.4 21:25.5 22:25.5 23:25.5 +0 0 1 1 1 1 1 1 1 1 9 26 9 1 1 1 1 1 1 1 1 1 1 1 1 21 18 1 1 1 1 1 29 7:8.7 8:25.4 9:8.5 21:0.8 22:20.3 23:17.9 +0 0 1 1 1 1 1 1 12 26 26 17 1 1 1 1 1 1 1 1 1 1 1 1 1 6 26 26 1 1 1 1 29 5:11.7 6:25.2 7:25.2 8:16.4 22:5.7 23:25.2 24:25.2 +0 117 12 1 1 1 1 14 4 1 1 1 1 2 15 24 25 12 1 1 1 1 1 1 8 22 8 1 1 1 1 1 0 0 0 0 13.7 3.6 0.5 0 0 0 1.6 14.7 23.9 24.5 11.7 0 0 0 0 0 0.1 7.7 21.5 7.2 0 0 0 0 0 +0 0 1 1 1 1 1 1 1 1 1 1 1 9 26 13 1 1 1 1 1 1 2 26 21 1 1 1 1 1 1 1 29 10:8.9 11:25.3 12:12.9 19:1.2 20:25.3 21:20.6 +5 0 1 1 1 1 1 1 1 1 1 1 1 20 26 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 29 9:0.8 10:19.9 11:25.4 12:11.3 +0 9 1 1 1 1 1 1 1 1 1 1 1 1 26 26 20 1 1 1 1 1 10 26 24 1 1 1 1 1 1 1 29 11:25.3 12:25.2 13:19.5 14:0.9 19:9.3 20:25.2 21:23 +0 0 1 1 1 1 1 1 1 20 26 18 1 1 1 1 1 1 1 1 1 1 1 1 1 12 26 26 9 1 1 1 29 6:19.4 7:25.3 8:17.4 22:11.8 23:25.3 24:25.3 25:8 +0 0 1 1 1 1 1 1 1 1 1 1 1 17 26 22 1 1 1 1 1 1 15 26 13 1 1 1 1 1 1 1 29 10:16.8 11:25.3 12:21 13:0.6 19:14.4 20:25.2 21:12.6 +0 0 1 1 1 1 1 1 1 1 1 1 13 26 10 1 1 1 1 1 1 1 4 26 9 1 1 1 1 1 1 1 29 9:12.6 10:25.4 11:9.3 19:3.9 20:25.4 21:8.6 +0 0 1 1 1 1 1 1 1 1 1 15 26 26 12 1 1 1 1 1 1 1 18 26 26 25 1 1 1 1 1 1 29 8:14.7 9:25.4 10:25.4 11:11.6 19:17.1 20:25.4 21:25.4 22:24.7 +0 0 1 1 1 1 1 1 14 26 26 21 1 1 1 1 1 1 1 1 1 1 1 4 24 26 26 26 1 1 1 1 29 5:13.3 6:25.3 7:25.3 8:20.5 20:3.8 21:23.1 22:25.3 23:25.3 24:25.3 +0 0 1 1 1 1 1 1 1 11 26 26 26 7 1 1 1 1 1 1 1 1 1 1 1 9 26 26 10 1 1 1 29 6:10.1 7:25.3 8:25.3 9:25.3 10:6.1 22:8.3 23:25.3 24:25.3 25:9.9 +0 0 1 1 1 1 1 1 1 1 1 23 26 26 7 1 1 1 1 1 1 1 1 7 26 26 26 11 1 1 1 1 29 8:22.8 9:25.3 10:25.3 11:6.6 20:6.8 21:25.3 22:25.3 23:25.3 24:10.7 +0 0 1 1 1 1 1 1 1 26 26 13 1 1 1 1 1 1 1 1 1 1 1 1 1 1 26 26 13 1 1 1 29 6:25.5 7:25.5 8:12.8 23:25.5 24:25.5 25:12.8 +0 0 1 1 1 1 1 1 1 1 19 26 26 26 26 26 9 1 1 1 1 1 1 1 7 26 26 26 26 1 1 1 0 0 0 0 0 0 0 18.7 25.3 25.3 25.3 25.3 25.3 8.2 0 0 0 0 0 0 0 6.2 25.3 25.3 25.3 25.3 0 0 0 +0 0 1 1 1 1 1 1 1 17 26 21 1 1 12 1 1 1 1 1 1 1 1 1 1 1 12 26 20 1 1 1 29 6:16.4 7:25.3 8:20 11:11.9 23:11.9 24:25.3 25:19 +0 8 1 1 1 1 1 1 1 17 26 23 8 1 4 26 20 1 1 1 1 1 1 1 1 1 4 26 26 1 1 1 29 6:16.9 7:25.3 8:22.7 9:7.6 11:3.5 12:25.3 13:19.8 14:0.8 23:3.3 24:25.3 25:25.3 +6 253 26 1 1 1 1 1 1 1 2 6 23 26 26 26 26 26 26 26 26 26 26 21 18 18 8 1 1 1 1 1 0 0 0 0 0 0 0 1 5.2 22.1 25.3 25.3 25.3 25.3 25.3 25.3 25.3 25.3 25.3 25.3 20.2 17.7 17.7 7.9 0 0 0 0 0 +0 0 1 1 1 1 1 1 1 7 26 26 26 20 1 1 1 1 1 1 1 1 1 1 1 1 13 26 26 1 1 1 29 6:6.4 7:25.5 8:25.5 9:25.5 10:19.1 23:12.8 24:25.5 25:25.5 +0 186 19 1 1 1 1 1 1 1 11 26 26 26 26 26 26 19 3 1 1 1 1 1 1 14 26 26 17 1 1 1 0 0 0 0 0 0 0 10.1 25.3 25.3 25.3 25.3 25.3 25.3 18.6 2 0 0 0 0 0 0 13.3 25.3 25.3 16.5 0 0 0 +0 252 26 1 1 1 1 1 1 1 1 17 25 26 26 26 26 26 4 1 1 1 1 1 1 1 19 26 26 1 1 1 29 8:16.8 9:24.8 10:25.2 11:25.3 12:25.2 13:25.2 14:25.2 15:3.2 23:18.4 24:25.2 25:25.2 +0 102 11 1 1 1 1 1 1 1 9 21 26 22 3 1 5 11 3 1 1 1 1 1 1 1 21 23 3 1 1 1 0 0 0 0 0 0 0 8.3 20.5 25.3 21.5 2.3 0 4.1 10.2 2.3 0 0 0 0 0 0 0.8 20.5 22.9 2.3 0 0 0 +0 0 1 1 1 1 1 1 1 1 10 26 26 26 26 26 15 1 1 1 1 1 1 1 1 10 26 26 19 1 1 1 29 7:9.6 8:25.1 9:25.1 10:25.1 11:25.1 12:25.3 13:14 22:9.6 23:25.1 24:25.1 25:18.8 +0 0 1 1 1 1 1 1 1 1 1 1 1 26 26 26 1 1 1 1 1 1 13 26 26 13 1 1 1 1 1 1 29 10:25.5 11:25.5 12:25.5 19:12.8 20:25.5 21:25.5 22:12.8 +0 0 1 1 1 1 1 1 1 1 1 4 23 26 23 1 1 1 1 1 1 1 1 1 1 17 26 26 6 1 1 1 29 8:3.2 9:22.9 10:25.3 11:22.6 22:16.3 23:25.4 24:25.3 25:5.6 +5 169 17 1 1 1 1 1 1 1 1 1 6 20 19 8 8 17 26 26 24 4 1 1 1 1 1 1 1 1 1 1 29 9:5.1 10:19.7 11:18.2 12:7.4 13:7.4 14:16.9 15:25.3 16:25.3 17:23.3 18:3.9 +1 251 26 1 1 1 1 1 1 1 1 1 1 1 1 5 23 26 26 26 11 1 1 1 1 1 1 1 1 1 1 1 29 12:4.1 13:22.6 14:25.1 15:25.1 16:25.3 17:10.7 +0 0 1 1 1 1 1 1 1 1 5 26 26 25 9 1 1 1 1 1 1 18 26 26 26 14 1 1 1 1 1 1 29 7:4.7 8:25.3 9:25.3 10:24.1 11:8 18:17.6 19:25.3 20:25.3 21:25.3 22:13.8 +7 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 13 26 26 26 7 1 1 1 1 1 1 1 1 29 16:12 17:25.2 18:25.2 19:25.2 20:6.4 +0 0 1 1 1 1 1 1 1 1 22 26 26 11 1 1 1 1 1 1 1 1 1 6 26 26 21 3 1 1 1 1 29 7:21.7 8:25.2 9:25.2 10:10.3 20:5.7 21:25.2 22:25.3 23:20 24:2.1 +4 1 1 1 1 1 1 1 1 1 1 1 1 14 26 24 13 1 1 3 24 26 20 1 1 1 1 1 1 1 1 1 29 10:13 11:25.4 12:23.9 13:12.3 14:0.1 16:2.3 17:23 18:25.4 19:19.2 +0 138 14 1 1 1 1 1 1 1 1 1 24 26 26 26 26 14 1 1 1 22 26 26 26 24 8 1 1 1 1 1 0 0 0 0 0 0 0 0 0.1 23.2 25.2 25.2 25.2 25.3 13.8 0 0 0 21.7 25.2 25.2 25.3 23.1 7.1 0 0 0 0 0 +0 38 4 1 1 1 1 1 1 1 1 1 1 1 4 11 1 4 1 1 1 1 1 1 1 22 20 1 1 1 1 1 29 11:3.8 12:10.3 13:0.9 14:3.8 22:21.6 23:19.6 +0 0 1 1 1 1 1 1 1 1 26 26 26 26 26 7 1 1 1 1 1 1 7 20 26 26 26 26 26 1 1 1 0 0 0 0 0 0 0 25.5 25.5 25.5 25.5 25.5 6.4 0 0 0 0 0 0 6.4 19.1 25.5 25.5 25.5 25.5 25.5 0 0 0 +0 0 1 1 1 1 1 1 1 1 2 16 26 26 18 2 1 1 1 1 1 1 4 24 26 24 6 1 1 1 1 1 29 7:1.1 8:15.5 9:25.2 10:25.2 11:17.9 12:1.5 19:3.2 20:23.7 21:25.3 22:23.1 23:5.1 +0 0 1 1 1 1 1 1 1 1 1 1 5 23 26 26 16 1 1 1 1 1 1 21 26 15 1 1 1 1 1 1 29 9:4.3 10:22.7 11:25.2 12:25.2 13:15.4 20:20 21:25.2 22:14.9 +0 11 2 1 1 1 1 1 1 1 1 1 3 15 26 26 19 2 1 1 1 1 1 1 1 16 26 12 1 1 1 1 29 9:2.9 10:14.3 11:25.3 12:25.3 13:18.7 14:1.1 22:15.6 23:25.3 24:11 +0 120 13 1 1 1 1 1 1 1 1 1 13 26 26 26 26 13 1 1 1 1 8 25 26 26 17 1 1 1 1 1 29 9:12 10:25.3 11:25.3 12:25.3 13:25.3 14:12 19:7.2 20:24.1 21:25.3 22:25.3 23:16.3 +0 0 1 1 1 1 1 1 1 2 21 26 17 1 1 1 1 1 1 1 1 1 1 1 1 1 3 26 26 1 1 1 29 6:1.1 7:20.6 8:25.2 9:16.2 23:2.2 24:25.2 25:25.2 +6 0 1 1 1 1 1 1 1 1 1 1 1 1 17 26 18 1 1 3 5 14 18 13 1 1 1 1 1 1 1 1 29 11:16.6 12:25.3 13:17 16:2.5 17:4.3 18:13.9 19:17.4 20:12.2 +0 253 26 1 1 1 1 1 1 1 1 1 1 24 26 26 26 26 4 1 1 11 26 26 26 15 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0.1 23.2 25.2 25.2 25.2 25.3 3.5 0 0 10.9 25.2 25.2 25.2 14.4 0 0 0 0 0 0 +0 17 2 1 1 1 1 1 1 1 1 1 1 1 21 26 26 2 1 1 1 3 22 26 6 1 1 1 1 1 1 1 29 11:20.1 12:25.3 13:25.3 14:1.7 18:2.4 19:21.1 20:25.3 21:5.3 +0 0 1 1 1 1 1 1 1 1 1 1 1 21 26 26 16 1 1 1 1 1 4 23 26 26 17 1 1 1 1 1 29 10:20.1 11:25.3 12:25.3 13:15.5 19:3.8 20:22.5 21:25.3 22:25.3 23:16.3 +1 237 24 1 1 1 1 1 1 1 1 1 1 1 1 1 5 24 26 26 5 1 1 1 1 1 1 1 1 1 1 1 29 13:4.2 14:23.7 15:25.4 16:25.4 17:4.9 +0 0 1 1 1 1 1 1 1 1 1 11 26 26 26 12 1 1 1 1 1 1 1 1 23 26 26 12 1 1 1 1 29 8:10.7 9:25.2 10:25.3 11:25.2 12:11.8 21:22.5 22:25.2 23:25.2 24:11.2 +0 0 1 1 1 1 1 1 1 9 26 26 26 26 26 13 3 1 1 1 1 1 14 26 26 26 26 23 1 1 1 1 0 0 0 0 0 0.5 8.7 25.4 25.4 25.4 25.4 25.3 12.8 2.9 0 0 0 0 0.3 13.8 25.4 25.4 25.4 25.4 22.7 0 0 0 0 +0 0 1 1 1 1 1 1 1 10 26 26 26 26 26 26 20 1 1 1 1 1 1 1 1 26 26 26 26 1 1 1 0 0 0 0 0 0 9.2 25.3 25.3 25.3 25.4 25.3 25.3 19 0 0 0 0 0 0 0 0 25.4 25.3 25.3 25.3 0 0 0 +0 0 1 1 1 1 1 1 1 11 23 26 26 26 26 25 11 1 1 1 1 1 14 26 26 26 26 23 1 1 1 1 0 0 0 0 0 0 10.9 22.9 25.3 25.3 25.3 25.3 24.8 10.8 0 0 0 0 0.3 13.7 25.3 25.3 25.3 25.3 22.6 0 0 0 0 +0 0 1 1 1 1 1 1 12 26 26 26 26 7 1 1 1 1 1 1 1 1 15 26 26 26 26 26 1 1 1 1 0 0 0 0 0 11.3 25.2 25.2 25.2 25.2 6.3 0 0 0 0 0 0 0 0 14 25.3 25.2 25.2 25.2 25.2 0 0 0 0 +0 0 1 1 1 1 1 1 1 1 23 26 26 18 1 1 1 1 1 1 1 1 1 1 1 1 20 26 26 1 1 1 29 7:22.5 8:25.2 9:25.2 10:17.3 23:19.7 24:25.2 25:25.2 +0 0 1 1 1 1 1 1 1 1 3 21 26 26 26 17 2 1 1 1 1 1 1 1 1 12 25 3 1 1 1 1 29 7:2.6 8:20.6 9:25.3 10:25.3 11:25.3 12:16.4 13:1.3 22:11.4 23:24.8 24:2.9 +0 0 1 1 1 1 1 1 1 3 19 26 26 14 1 1 1 1 1 1 1 1 1 1 1 22 26 26 1 1 1 1 29 6:2.1 7:18.1 8:25.2 9:25.2 10:13.8 22:21.7 23:25.2 24:25.2 +0 0 1 1 1 1 1 1 1 1 1 14 25 26 14 1 1 1 1 1 1 1 1 1 4 23 26 6 1 1 1 1 29 7:0.9 8:13.2 9:24.6 10:25.3 11:13.7 12:0.4 21:3.6 22:22.3 23:25.2 24:5.9 +0 0 1 1 1 1 1 1 2 22 26 26 26 23 1 1 1 1 1 1 1 1 8 26 26 26 21 1 1 1 1 1 29 5:1.9 6:21.6 7:25.2 8:25.2 9:25.2 10:22.2 19:7.5 20:25.2 21:25.2 22:25.2 23:20.7 +0 0 1 1 1 1 1 1 1 1 1 2 17 26 23 1 1 1 1 1 1 1 1 7 26 26 14 1 1 1 1 1 29 8:1.3 9:16.9 10:25.3 11:22.8 12:0.9 20:6.6 21:25.3 22:25.3 23:13.5 +0 0 1 1 1 1 1 1 1 1 1 12 26 26 23 6 1 1 1 1 1 1 22 26 26 2 1 1 1 1 1 1 29 8:11.7 9:25.4 10:25.4 11:22.2 12:5.5 19:21.8 20:25.4 21:25.4 22:1.8 diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExprVec1-Schema.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExprVec1-Schema.txt new file mode 100644 index 0000000000..dccb8f1223 --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExprVec1-Schema.txt @@ -0,0 +1,29 @@ +---- BoundLoader ---- +5 columns: + A: Int32 + M: Int32 + N: Int32 + VI: Vector + VR: Vector +---- RowToRowMapperTransform ---- +8 columns: + A: Int32 + M: Int32 + N: Int32 + N: Int32 + VI: Vector + VI: Vector + VR: Vector + VR: Vector +---- RowToRowMapperTransform ---- +10 columns: + A: Int32 + M: Int32 + N: Int32 + N: Int32 + N: Int32 + VI: Vector + VI: Vector + VI: Vector + VR: Vector + VR: Vector diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExprVec1-b-Schema.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExprVec1-b-Schema.txt new file mode 100644 index 0000000000..3e73dd8908 --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExprVec1-b-Schema.txt @@ -0,0 +1,26 @@ +---- BoundLoader ---- +5 columns: + A: Int32 + M: Int32 + N: Int32 + VI: Vector + VR: Vector +---- RowToRowMapperTransform ---- +7 columns: + A: Int32 + M: Int32 + N: Int32 + N: Int32 + VI: Vector + VR: Vector + VR: Vector +---- RowToRowMapperTransform ---- +8 columns: + A: Int32 + M: Int32 + N: Int32 + N: Int32 + VI: Vector + VI: Vector + VR: Vector + VR: Vector diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-Data.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-Data.txt new file mode 100644 index 0000000000..60730bfbdd --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-Data.txt @@ -0,0 +1,112 @@ +#@ TextLoader{ +#@ header+ +#@ sep=tab +#@ col=A:I4:0 +#@ col=B:I4:1 +#@ col=C:I4:2 +#@ col=D:I4:3 +#@ col=M:I4:4 +#@ col=N:I4:5 +#@ col=VR:R4:6-34 +#@ } +A B C D M N 29 0:"" +0 2 4 6 0 384 384 384 384 384 384 384 384 384 460 637 637 384 384 384 384 384 384 384 384 384 384 384 445 616 408 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 384 428 637 637 481 384 384 384 384 384 384 384 628 572 384 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 384 384 617 636 445 384 384 384 384 384 384 384 637 636 404 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 384 638 637 578 384 384 384 384 384 384 579 637 637 384 384 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 498 637 569 384 384 384 384 384 384 384 384 384 384 384 384 384 384 591 637 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 440 638 638 478 384 384 384 384 384 384 384 384 384 384 384 483 638 638 435 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 532 637 534 384 384 384 384 384 384 384 384 384 384 396 618 471 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 553 636 499 384 384 384 384 384 384 384 384 384 384 384 384 500 636 552 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 439 638 554 384 384 384 384 384 384 384 384 384 384 384 384 620 601 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 418 637 637 394 384 384 384 384 384 384 384 384 384 384 384 396 571 593 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 479 630 636 584 512 392 384 384 384 384 384 384 384 384 384 384 454 636 636 384 384 384 384 +0 2 4 6 81 465 384 384 384 384 384 384 384 384 384 387 570 638 638 634 465 384 384 384 384 408 601 638 553 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 574 638 504 384 384 384 384 384 384 384 384 393 577 638 437 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 420 637 637 617 406 384 384 384 384 384 384 384 384 393 576 637 637 419 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 632 637 500 384 384 384 384 384 384 384 384 384 384 384 384 534 624 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 498 639 639 384 384 639 639 441 384 384 384 470 554 384 384 384 384 639 639 498 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 384 410 624 638 638 478 384 384 384 384 392 622 638 536 384 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 410 624 616 442 384 384 384 384 384 384 384 384 392 564 619 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 469 636 628 440 384 384 384 384 384 384 384 384 543 636 637 468 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 460 637 616 417 384 384 384 384 384 384 384 384 384 407 591 637 543 389 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 384 413 636 637 411 384 384 384 384 384 384 413 636 637 411 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 430 610 392 384 384 384 384 384 384 384 384 384 384 540 610 397 384 384 384 384 384 +9 11 13 15 0 105 105 105 105 105 105 105 105 105 105 105 207 339 156 105 105 278 358 359 196 105 105 105 105 105 105 105 105 105 105 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 384 384 384 613 638 579 384 384 384 384 384 384 410 638 504 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 384 573 637 637 431 384 384 384 384 384 384 384 414 637 572 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 638 582 384 384 384 384 384 384 384 384 384 384 384 384 384 384 384 384 583 598 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 384 384 427 637 598 397 384 384 384 384 384 591 636 637 476 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 416 596 637 637 637 637 575 384 384 384 384 384 384 421 637 639 637 621 446 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 441 637 637 639 552 384 384 384 384 384 384 413 637 639 637 440 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 513 638 635 469 384 384 384 384 384 384 384 412 638 638 389 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 514 634 466 384 384 384 384 384 384 384 384 384 384 384 384 516 637 637 396 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 575 637 637 468 384 384 384 384 384 384 384 384 384 384 384 384 434 620 637 574 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 384 533 614 384 384 384 384 384 384 384 384 392 622 595 384 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 384 428 637 637 637 482 384 384 384 384 384 384 628 637 534 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 537 638 638 435 384 384 384 384 384 384 490 638 638 536 384 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 411 628 637 539 384 384 384 384 384 384 384 384 384 438 612 637 627 414 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 411 528 638 638 638 539 395 384 384 384 384 384 384 384 541 638 629 415 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 434 626 637 501 384 384 384 384 384 384 384 384 384 384 384 396 637 484 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 384 488 637 501 384 384 384 384 384 384 384 384 610 637 575 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 388 563 637 637 435 384 384 384 384 384 384 384 384 384 384 384 425 637 637 574 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 424 636 612 440 384 384 384 384 384 384 473 637 637 505 384 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 574 635 635 478 384 384 384 384 384 384 384 384 384 384 480 635 635 572 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 384 573 637 637 395 384 384 384 384 384 384 384 532 637 454 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 512 639 639 639 448 384 384 384 384 384 384 384 384 639 639 639 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 471 638 469 384 384 384 384 384 384 384 384 384 384 384 392 587 563 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 501 636 636 548 384 384 384 384 384 384 384 384 384 384 384 384 384 441 636 636 384 384 384 384 +0 2 4 6 117 501 384 384 384 384 521 420 389 384 384 384 400 531 623 629 501 384 384 384 384 384 385 461 599 456 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 384 384 473 637 513 384 384 384 384 384 384 396 637 590 384 384 384 384 384 384 384 +5 7 9 11 0 9 9 9 9 9 9 9 9 9 9 17 208 263 122 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 +0 2 4 6 9 393 384 384 384 384 384 384 384 384 384 384 384 637 636 579 393 384 384 384 384 477 636 614 384 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 578 637 558 384 384 384 384 384 384 384 384 384 384 384 384 384 502 637 637 464 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 384 384 552 637 594 390 384 384 384 384 384 528 636 510 384 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 384 510 638 477 384 384 384 384 384 384 384 423 638 470 384 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 531 638 638 500 384 384 384 384 384 384 384 555 638 638 631 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 517 637 637 589 384 384 384 384 384 384 384 384 384 384 384 422 615 637 637 637 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 485 637 637 637 445 384 384 384 384 384 384 384 384 384 384 384 467 637 637 483 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 612 637 637 450 384 384 384 384 384 384 384 384 452 637 637 637 491 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 639 639 512 384 384 384 384 384 384 384 384 384 384 384 384 384 384 639 639 512 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 571 637 637 637 637 637 466 384 384 384 384 384 384 384 446 637 637 637 637 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 548 637 584 384 384 503 384 384 384 384 384 384 384 384 384 384 384 503 637 574 384 384 384 +0 2 4 6 8 392 384 384 384 384 384 384 553 637 611 460 384 419 637 582 392 384 384 384 384 384 384 384 384 417 637 637 384 384 384 +6 8 10 12 253 253 0 0 0 0 0 0 0 10 52 221 253 253 253 253 253 253 253 253 253 253 202 177 177 79 0 0 0 0 0 +0 2 4 6 0 384 384 384 384 384 384 384 448 639 639 639 575 384 384 384 384 384 384 384 384 384 384 384 384 512 639 639 384 384 384 +0 2 4 6 186 570 384 384 384 384 384 384 384 485 637 637 637 637 637 637 570 404 384 384 384 384 384 384 517 637 637 549 384 384 384 +0 2 4 6 252 636 384 384 384 384 384 384 384 384 552 632 636 637 636 636 636 416 384 384 384 384 384 384 384 568 636 636 384 384 384 +0 2 4 6 102 486 384 384 384 384 384 384 384 467 589 637 599 407 384 425 486 407 384 384 384 384 384 384 392 589 613 407 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 480 635 635 635 635 637 524 384 384 384 384 384 384 384 384 480 635 635 572 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 384 384 639 639 639 384 384 384 384 384 384 512 639 639 512 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 416 613 637 610 384 384 384 384 384 384 384 384 384 384 547 638 637 440 384 384 384 +5 7 9 11 169 178 9 9 9 9 9 9 9 9 9 60 206 191 83 83 178 262 262 242 48 9 9 9 9 9 9 9 9 9 9 +1 3 5 7 251 356 105 105 105 105 105 105 105 105 105 105 105 105 146 331 356 356 358 212 105 105 105 105 105 105 105 105 105 105 105 +0 2 4 6 0 384 384 384 384 384 384 384 384 431 637 637 625 464 384 384 384 384 384 384 560 637 637 637 522 384 384 384 384 384 384 +7 9 11 13 0 -15 -15 -15 -15 -15 -15 -15 -15 -15 -15 -15 -15 -15 -15 -15 -15 -15 105 237 237 237 49 -15 -15 -15 -15 -15 -15 -15 -15 +0 2 4 6 0 384 384 384 384 384 384 384 384 601 636 636 487 384 384 384 384 384 384 384 384 384 441 636 637 584 405 384 384 384 384 +4 6 8 10 1 1 29 10:130 11:254 12:239 13:123 14:1 16:23 17:230 18:254 19:192 +0 2 4 6 138 522 384 384 384 384 384 384 384 384 385 616 636 636 636 637 522 384 384 384 601 636 636 637 615 455 384 384 384 384 384 +0 2 4 6 38 422 384 384 384 384 384 384 384 384 384 384 384 422 487 393 422 384 384 384 384 384 384 384 600 580 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 639 639 639 639 639 448 384 384 384 384 384 384 448 575 639 639 639 639 639 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 395 539 636 636 563 399 384 384 384 384 384 384 416 621 637 615 435 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 384 427 611 636 636 538 384 384 384 384 384 384 584 636 533 384 384 384 384 384 384 +0 2 4 6 11 395 384 384 384 384 384 384 384 384 384 413 527 637 637 571 395 384 384 384 384 384 384 384 540 637 494 384 384 384 384 +0 2 4 6 120 504 384 384 384 384 384 384 384 384 384 504 637 637 637 637 504 384 384 384 384 456 625 637 637 547 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 395 590 636 546 384 384 384 384 384 384 384 384 384 384 384 384 384 406 636 636 384 384 384 +6 8 10 12 31 13:166 14:253 15:170 18:25 19:43 20:139 21:174 22:122 +0 2 4 6 253 637 384 384 384 384 384 384 384 384 384 385 616 636 636 636 637 419 384 384 493 636 636 636 528 384 384 384 384 384 384 +0 2 4 6 17 401 384 384 384 384 384 384 384 384 384 384 384 585 637 637 401 384 384 384 408 595 637 437 384 384 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 384 384 585 637 637 539 384 384 384 384 384 422 609 637 637 547 384 384 384 384 384 +1 3 5 7 237 342 105 105 105 105 105 105 105 105 105 105 105 105 105 147 342 359 359 154 105 105 105 105 105 105 105 105 105 105 105 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 491 636 637 636 502 384 384 384 384 384 384 384 384 609 636 636 496 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 389 471 638 638 638 638 637 512 413 384 384 384 384 387 522 638 638 638 638 611 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 476 637 637 637 638 637 637 574 384 384 384 384 384 384 384 384 638 637 637 637 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 493 613 637 637 637 637 632 492 384 384 384 384 387 521 637 637 637 637 610 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 497 636 636 636 636 447 384 384 384 384 384 384 384 384 524 637 636 636 636 636 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 609 636 636 557 384 384 384 384 384 384 384 384 384 384 384 384 581 636 636 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 410 590 637 637 637 548 397 384 384 384 384 384 384 384 384 498 632 413 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 405 565 636 636 522 384 384 384 384 384 384 384 384 384 384 384 601 636 636 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 393 516 630 637 521 388 384 384 384 384 384 384 384 384 420 607 636 443 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 403 600 636 636 636 606 384 384 384 384 384 384 384 384 459 636 636 636 591 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 397 553 637 612 393 384 384 384 384 384 384 384 450 637 637 519 384 384 384 384 384 +0 2 4 6 0 384 384 384 384 384 384 384 384 384 501 638 638 606 439 384 384 384 384 384 384 602 638 638 402 384 384 384 384 384 384 diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-Schema.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-Schema.txt new file mode 100644 index 0000000000..243005ef4f --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-Schema.txt @@ -0,0 +1,35 @@ +---- BoundLoader ---- +7 columns: + A: Int32 + B: Int32 + C: Int32 + D: Int32 + M: Int32 + N: Int32 + VR: Vector +---- RowToRowMapperTransform ---- +10 columns: + A: Int32 + B: Int32 + B: Int32 + C: Int32 + C: Int32 + D: Int32 + D: Int32 + M: Int32 + N: Int32 + VR: Vector +---- RowToRowMapperTransform ---- +12 columns: + A: Int32 + B: Int32 + B: Int32 + C: Int32 + C: Int32 + D: Int32 + D: Int32 + M: Int32 + N: Int32 + N: Int32 + VR: Vector + VR: Vector diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-b-Schema.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-b-Schema.txt new file mode 100644 index 0000000000..243005ef4f --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-b-Schema.txt @@ -0,0 +1,35 @@ +---- BoundLoader ---- +7 columns: + A: Int32 + B: Int32 + C: Int32 + D: Int32 + M: Int32 + N: Int32 + VR: Vector +---- RowToRowMapperTransform ---- +10 columns: + A: Int32 + B: Int32 + B: Int32 + C: Int32 + C: Int32 + D: Int32 + D: Int32 + M: Int32 + N: Int32 + VR: Vector +---- RowToRowMapperTransform ---- +12 columns: + A: Int32 + B: Int32 + B: Int32 + C: Int32 + C: Int32 + D: Int32 + D: Int32 + M: Int32 + N: Int32 + N: Int32 + VR: Vector + VR: Vector diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-c-Schema.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-c-Schema.txt new file mode 100644 index 0000000000..243005ef4f --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-c-Schema.txt @@ -0,0 +1,35 @@ +---- BoundLoader ---- +7 columns: + A: Int32 + B: Int32 + C: Int32 + D: Int32 + M: Int32 + N: Int32 + VR: Vector +---- RowToRowMapperTransform ---- +10 columns: + A: Int32 + B: Int32 + B: Int32 + C: Int32 + C: Int32 + D: Int32 + D: Int32 + M: Int32 + N: Int32 + VR: Vector +---- RowToRowMapperTransform ---- +12 columns: + A: Int32 + B: Int32 + B: Int32 + C: Int32 + C: Int32 + D: Int32 + D: Int32 + M: Int32 + N: Int32 + N: Int32 + VR: Vector + VR: Vector diff --git a/test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-d-Schema.txt b/test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-d-Schema.txt new file mode 100644 index 0000000000..243005ef4f --- /dev/null +++ b/test/BaselineOutput/Common/SavePipe/SavePipeExprVec2-d-Schema.txt @@ -0,0 +1,35 @@ +---- BoundLoader ---- +7 columns: + A: Int32 + B: Int32 + C: Int32 + D: Int32 + M: Int32 + N: Int32 + VR: Vector +---- RowToRowMapperTransform ---- +10 columns: + A: Int32 + B: Int32 + B: Int32 + C: Int32 + C: Int32 + D: Int32 + D: Int32 + M: Int32 + N: Int32 + VR: Vector +---- RowToRowMapperTransform ---- +12 columns: + A: Int32 + B: Int32 + B: Int32 + C: Int32 + C: Int32 + D: Int32 + D: Int32 + M: Int32 + N: Int32 + N: Int32 + VR: Vector + VR: Vector diff --git a/test/Microsoft.ML.TestFramework/DataPipe/TestDataPipe.cs b/test/Microsoft.ML.TestFramework/DataPipe/TestDataPipe.cs index a1eb0bce7f..a6e10e2f61 100644 --- a/test/Microsoft.ML.TestFramework/DataPipe/TestDataPipe.cs +++ b/test/Microsoft.ML.TestFramework/DataPipe/TestDataPipe.cs @@ -1299,6 +1299,128 @@ public void ArrayDataViewBuilderNoCols() Done(); } + + [Fact] + public void SavePipeExpr() + { + TestCore(null, false, + new[] { + "loader=Text{col=A:BL:0 col=B:BL:0 col=C:I4:1 col=D:I4:5}", + "xf=Expr{col=C col=D expr={x=>x-1}}", + "xf=Expr{col={name=M1 src=A src=B expr={(a,b)=>!a && b}} col={name=N1 src=A src=B expr={(a,b)=>!a || b}}}", + "xf=Expr{col={name=M2 src=A src=B expr={(a,b)=>a && !b}} col={name=N2 src=A src=B expr={(a,b)=>a || !b}}}", + "xf=Expr{col=U:C,D expr={(c,d):10*c+d}}", + "xf=Expr{col=V:C expr={(c):log(c + 1)}}", + "xf=Expr{col=W:C,D expr={(c,d):log(abs(c-d) + 1, 2)}}", + "xf=Expr{col=X1:C col=Y1:D expr={c=>(c+1)/10}}", + "xf=Expr{col=X2:C col=Y2:D expr={c=>(c+1)/10.0}}", + "xf=Expr{col=Z:M1,C,D expr={(m,c,d)=>m ? c + 10 : d + 100}}", + }, logCurs: true); + + TestCore(null, false, + new[] { + "loader=Text{col=A:BL:0 col=B:BL:0 col=C:I4:5 col=D:Num:6}", + "xf=Expr{col=ID:D expr={x:isna(x)}}", + "xf=Expr{col=JD:D expr={x:x ?? -1}}", + "xf=Expr{col=KA:A col=KB:B col=KC:C col=KD:D expr={x:float(x) / 2}}", + "xf=Expr{col=LA:A,B,KA,KB col=LC:C,D,KC,KD expr={(a,b,x,y): isna(x) && isna(y) && isna(float(a)) == isna(x)}}", + }, + null, "-Extra", forceDense: true); + + // Handle all supported non-vector types, with NA. + TestCore(null, false, + new[] { + "loader=Text{col=I4:I4:5 col=I8:I8:5 col=R4:R4:4 col=R8:R8:4 col=BL:BL:0 col=T1:TX:6}", + "xf=Expr{col=I4:I4 col=I8:I8 col=R4:R4 col=R8:R8 col=BL:BL col=T1:T1 expr={x => x}}", // Identity lambda. + "xf=Expr{col=IR4:R4 col=IR8:R8 expr={x => -int(isna(x)) - 2 * int(isna(int(x)))}}", // NA testing and conversion. + "xf=Expr{col=JR4:R4 col=JR8:R8 expr={x => x ?? -1}}", // Coalesce. + "xf=Expr{col=KI4:I4 col=KI8:I8 col=KR4:R4 col=KR8:R8 col=KBL:BL col=KT1:T1 expr={x => single(x) ?? -1}}", // Convert and coalesce. + }, + null, "-All", forceDense: true); + + // These two should produce the same output. + string pathData = GetDataPath("MNIST.Test.tiny.txt"); + + // Text vector spare preservation when mapping to text. + TestCore(pathData, false, + new[] { + "loader=Text{sparse+ rows=100 col=A:I4:0 col=N:I4:378 col=VI:I4:364-392 col=VR:Num:364-392}", + "xf=Expr{col=N col=VI col=VR expr={x => x == default(x) ? \"\" : text(x)}}", + }, + null, "TextDef"); + TestCore(pathData, false, + new[] { + "loader=Text{sparse+ rows=100 col=A:I4:0 col=N:TX:378 col=VI:TX:364-392 col=VR:TX:364-392}", + }, + null, "TextDef-b", "TextDef"); + + // Text vector non-spare preservation when mapping to text. + // These two should produce the same output. + TestCore(pathData, false, + new[] { + "loader=Text{sparse+ rows=100 col=A:I4:0 col=N:I4:378 col=VI:I4:364-392 col=VR:Num:364-392}", + "xf=Expr{col=N col=VI col=VR expr={x => text(x)}}", + }, + null, "TextFull", "TextFull"); + TestCore(pathData, false, + new[] { + "loader=Text{sparse+ rows=100 col=A:I4:0 col=N:TX:378 col=VI:TX:364-392 col=VR:TX:364-392}", + "xf=Expr{col=N col=VI col=VR expr={x => x == \"\" ? text(0) : x}}", + }, + null, "TextFull-b", "TextFull"); + + // These two should produce the same output. + TestCore(pathData, false, + new[] { + "loader=Text{sparse+ rows=100 col=A:I4:0 col=M:I4:378 col=N:I4:378 col=VI:I4:364-392 col=VR:Num:364-392}", + "xf=Expr{col=N col=VI col=VR expr={x=>x / 10}}", + "xf=Expr{col=N col=VI expr={x=>x + 1}}", + }, + null, "Vec1", "Vec1"); + + TestCore(pathData, false, + new[] { + "loader=Text{sparse+ rows=100 col=A:I4:0 col=M:I4:378 col=N:I4:378 col=VI:I4:364-392 col=VR:Num:364-392}", + "xf=Expr{col={name=N expr={x=>int(floor(x / 10.0)) + 1}} col={name=VR expr={x=>x / 10}}}", + "xf=Expr{col=VI:VR expr={(x)=>int(floor(x)) + 1}}", + }, + null, "Vec1-b", "Vec1"); + + // These should have the same output. The only line that varies is the third one. + // The primary purpose of this is for code coverage of ExprTransform. + // Make A, B, C, D be a linear progression with step size 2. + const string line0 = "loader=Text{sparse+ rows=100 col=A:I4:0 col=B:I4:0 col=C:I4:0 col=D:I4:0 col=M:I4:378 col=N:I4:378 col=VR:Num:364-392}"; + const string line1 = "xf=Expr{col={name=B expr={x:x+2}} col={name=C expr={x:x+4}} col={name=D expr={x:x+6}}}"; + TestCore(pathData, false, + new[] { + line0, line1, + "xf=Expr{col=N:A,N col=VR:A,VR expr={(a,x)=>x+(a-8)*(a-6)*(a-4)*(a-2)}}", + }, + null, "Vec2", "Vec2"); + + TestCore(pathData, false, + new[] { + line0, line1, + "xf=Expr{col=N:A,N,B col=VR:A,VR,B expr={(a,x,b)=>x+(a-8)*(b-8)*(a-4)*(b-4)}}", + }, + null, "Vec2-b", "Vec2"); + + TestCore(pathData, false, + new[] { + line0, line1, + "xf=Expr{col=N:N,B,C,A col=VR:VR,B,C,A expr={(x,b,c,a)=>x+(a-8)*(b-8)*(c-8)*(b-4)}}", + }, + null, "Vec2-c", "Vec2"); + + TestCore(pathData, false, + new[] { + line0, line1, + "xf=Expr{col=N:D,A,C,B,N col=VR:D,A,C,B,VR expr={(d,a,c,b,x)=>x+(a-8)*(b-8)*(c-8)*(d-8)}}", + }, + null, "Vec2-d", "Vec2"); + + Done(); + } } /// /// A class for non-baseline data pipe tests. diff --git a/test/Microsoft.ML.Tests/ExpressionLanguageTests/ExpressionLanguageTests.cs b/test/Microsoft.ML.Tests/ExpressionLanguageTests/ExpressionLanguageTests.cs new file mode 100644 index 0000000000..a05b4fa419 --- /dev/null +++ b/test/Microsoft.ML.Tests/ExpressionLanguageTests/ExpressionLanguageTests.cs @@ -0,0 +1,683 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma warning disable 420 // volatile with Interlocked.CompareExchange + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using Microsoft.ML; +using Microsoft.ML.Data; +using Microsoft.ML.Data.IO; +using Microsoft.ML.Data.Conversion; +using Microsoft.ML.Internal.Utilities; +using Microsoft.ML.Runtime; +using Microsoft.ML.Transforms; +using Microsoft.ML.RunTests; +using Microsoft.ML.Tests; +using Microsoft.ML.TestFramework.Attributes; +using Xunit; +using Xunit.Abstractions; + +[assembly: LoadableClass(typeof(TestFuncs1), null, typeof(SignatureFunctionProvider), "Test Functions 1", "__test1")] + +[assembly: LoadableClass(typeof(TestFuncs2), null, typeof(SignatureFunctionProvider), "Test Functions 2", "__test2")] + +namespace Microsoft.ML.Tests +{ + using BL = System.Boolean; + using I4 = System.Int32; + using I8 = System.Int64; + using R4 = Single; + using R8 = Double; + using TX = ReadOnlyMemory; + + public sealed partial class ExprLanguageTests : BaseTestBaseline + { + private const string ResourcePrefix = "Microsoft.ML.Tests.ExpressionLanguageTests.TestData."; + private object _sync = new object(); + + public ExprLanguageTests(ITestOutputHelper output) + : base(output) + { + Env.ComponentCatalog.RegisterAssembly(typeof(TestFuncs1).Assembly); + } + + [Fact, TestCategory("Expr Language")] + public void ExprParse() + { + // Code coverage test for the parser. + Run("ExprParse"); + } + +#if !NETFRAMEWORK + // Bug in sin(x) in .Net Framework: sin(1e+30) returns 1e+30. + [X64Fact("sin(1e+30) gives different value on x86."), TestCategory("Expr Language")] + public void ExprBind() + { + // Code coverage test for the binder. + Run("ExprBind"); + } +#endif + + [Fact, TestCategory("Expr Language")] + public void ExprBindEx() + { + // Addition code coverage test for the binder. + Run("ExprBindEx"); + } + + [Fact, TestCategory("Expr Language")] + public void ExprCodeGen() + { + // Code coverage test for code gen. + Run("ExprCodeGen"); + } + + [Fact, TestCategory("Expr Language")] + public void ExprEval() + { + // Code coverage test evaluation. Note that VS can't help us measure this one :-(. + Run("ExprEval"); + } + + private string InResName(string name) + { + return ResourcePrefix + name + "Input.txt"; + } + + private string GetResText(string resName) + { + var stream = typeof(ExprLanguageTests).Assembly.GetManifestResourceStream(resName); + if (stream == null) + return string.Format("", resName); + + using (var reader = new StreamReader(stream)) + { + return reader.ReadToEnd(); + } + } + + private void Run(string name) + { + string outDir = "ExprParser"; + + string text = GetResText(InResName(name)); + string inName = name + "Input.txt"; + string outName = name + "Output.txt"; + string outNameAssem = name + "Output.Assem.txt"; + string outPath = DeleteOutputPath(outDir, outName); + string outPathAssem = DeleteOutputPath(outDir, outNameAssem); + + using (var wr = OpenWriter(outPath)) + { + var wrt = new IndentedTextWriter(wr, " "); + + // Individual scripts are separated by $. + // Inputs start after #. + int count = 0; + int ichLim = 0; + int lineLim = 1; + for (; ichLim < text.Length; ichLim++) + { + int ichMin = ichLim; + int lineMin = lineLim; + + while (ichLim < text.Length && text[ichLim] != '$') + { + if (text[ichLim] == '\n') + lineLim++; + ichLim++; + } + + while (ichMin < ichLim && char.IsWhiteSpace(text[ichMin])) + { + if (text[ichMin] == '\n') + lineMin++; + ichMin++; + } + + if (ichMin >= ichLim) + continue; + + // Process the script. + count++; + string scriptName = string.Format("Script {0}, lines {1} to {2}", count, lineMin, lineLim); + wrt.WriteLine("===== Start {0} =====", scriptName); + var types = ParseTypes(text, ref ichMin, ichLim); + int ichLimChars = text.IndexOf('#', ichMin); + if (ichLimChars < 0 || ichLimChars >= ichLim) + ichLimChars = ichLim; + else + Contracts.Assert(ichMin < ichLimChars && ichLimChars < ichLim); + CharCursor chars = new CharCursor(text, ichMin, ichLimChars); + Delegate del = null; + lock (_sync) + { + try + { + LambdaNode node; + List errors; + List lineMap; + var perm = Utils.GetIdentityPermutation(types.Length); + using (wrt.Nest()) + { + node = LambdaParser.Parse(out errors, out lineMap, chars, perm, types); + } + Check(node != null, "Null LambdaNode"); + if (Utils.Size(errors) > 0) + { + DumpErrors(wrt, lineMap, lineMin, inName, "Parsing", errors); + goto LDone; + } + + LambdaBinder.Run(Env, ref errors, node, msg => wr.WriteLine(msg)); + if (Utils.Size(errors) > 0) + { + DumpErrors(wrt, lineMap, lineMin, inName, "Binding", errors); + goto LDone; + } + wrt.WriteLine("Binding succeeded. Output type: {0}", node.ResultType); + + del = LambdaCompiler.Compile(out errors, node); + Contracts.Assert(TestFuncs1.Writer == null); + TestFuncs1.Writer = wr; + if (Utils.Size(errors) > 0) + { + DumpErrors(wrt, lineMap, lineMin, inName, "Compiling", errors); + goto LDone; + } + + wrt.WriteLine("Compiling succeeded."); + if (ichLimChars < ichLim) + Evaluate(wrt, del, node.ResultType, types, text, ichLimChars + 1, ichLim); + } + catch (Exception ex) + { + if (!ex.IsMarked()) + wrt.WriteLine("Unknown Exception: {0}!", del != null ? del.GetMethodInfo().DeclaringType : (object)""); + wrt.WriteLine("Exception: {0}", ex.Message); + } + finally + { + TestFuncs1.Writer = null; + } + + LDone: + wrt.WriteLine("===== End {0} =====", scriptName); + } + } + } + + CheckEquality(outDir, outName, digitsOfPrecision: 6); + + Done(); + } + + private DataViewType[] ParseTypes(string text, ref int ichMin, int ichLim) + { + int ichCol = text.IndexOf(':', ichMin); + Contracts.Assert(ichMin < ichCol && ichCol < ichLim); + string[] toks = text.Substring(ichMin, ichCol - ichMin).Split(','); + var res = new DataViewType[toks.Length]; + for (int i = 0; i < toks.Length; i++) + { + InternalDataKind kind; + bool tmp = Enum.TryParse(toks[i], out kind); + Contracts.Assert(tmp); + res[i] = ColumnTypeExtensions.PrimitiveTypeFromKind(kind); + } + ichMin = ichCol + 1; + return res; + } + + private void Evaluate(IndentedTextWriter wrt, Delegate del, DataViewType typeRes, DataViewType[] types, + string text, int ichMin, int ichLim) + { + Contracts.AssertValue(del); + Contracts.AssertNonEmpty(types); + var args = new object[types.Length]; + var getters = new Func, bool>[types.Length]; + for (int i = 0; i < getters.Length; i++) + getters[i] = GetGetter(i, types[i], args); + + StringBuilder sb = new StringBuilder(); + Action printer = GetPrinter(typeRes, sb); + + ReadOnlyMemory chars = text.AsMemory().Slice(ichMin, ichLim - ichMin); + for (bool more = true; more;) + { + ReadOnlyMemory line; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + more = ReadOnlyMemoryUtils.SplitOne(chars, '\x0D', out line, out chars); + else + more = ReadOnlyMemoryUtils.SplitOne(chars, '\x0A', out line, out chars); + line = ReadOnlyMemoryUtils.TrimWhiteSpace(line); + if (line.IsEmpty) + continue; + + // Note this "hack" to map _ to empty. It's easier than fully handling quoting and is sufficient + // for these tests. + var vals = ReadOnlyMemoryUtils.Split(line, new char[] { ',' }) + .Select(x => ReadOnlyMemoryUtils.TrimWhiteSpace(x)) + .Select(x => ReadOnlyMemoryUtils.EqualsStr("_", x) ? ReadOnlyMemory.Empty : x) + .ToArray(); + + Contracts.Assert(vals.Length == getters.Length); + for (int i = 0; i < getters.Length; i++) + { + if (!getters[i](vals[i])) + wrt.Write("*** Parsing {0} Failed *** ", vals[i]); + } + var res = del.DynamicInvoke(args); + printer(res); + wrt.WriteLine(sb); + } + } + + private Func, bool> GetGetter(int i, DataViewType dst, object[] args) + { + switch (dst.GetRawKind()) + { + case InternalDataKind.BL: + return + src => + { + bool v; + bool tmp = Conversions.Instance.TryParse(in src, out v); + args[i] = v; + return tmp; + }; + case InternalDataKind.I4: + return + src => + { + int v; + bool tmp = Conversions.Instance.TryParse(in src, out v); + args[i] = v; + return tmp; + }; + case InternalDataKind.I8: + return + src => + { + long v; + bool tmp = Conversions.Instance.TryParse(in src, out v); + args[i] = v; + return tmp; + }; + case InternalDataKind.R4: + return + src => + { + float v; + bool tmp = Conversions.Instance.TryParse(in src, out v); + args[i] = v; + return tmp; + }; + case InternalDataKind.R8: + return + src => + { + double v; + bool tmp = Conversions.Instance.TryParse(in src, out v); + args[i] = v; + return tmp; + }; + case InternalDataKind.TX: + return + src => + { + args[i] = src; + return true; + }; + } + + Contracts.Assert(false); + return null; + } + + private Action GetPrinter(DataViewType dst, StringBuilder sb) + { + switch (dst.GetRawKind()) + { + case InternalDataKind.BL: + return + src => + { + var v = (bool)src; + Conversions.Instance.Convert(in v, ref sb); + }; + case InternalDataKind.I4: + return + src => + { + var v = (int)src; + Conversions.Instance.Convert(in v, ref sb); + }; + case InternalDataKind.I8: + return + src => + { + var v = (long)src; + Conversions.Instance.Convert(in v, ref sb); + }; + case InternalDataKind.R4: + return + src => + { + var v = (Single)src; + Conversions.Instance.Convert(in v, ref sb); + }; + case InternalDataKind.R8: + return + src => + { + var v = (Double)src; + Conversions.Instance.Convert(in v, ref sb); + }; + case InternalDataKind.TX: + return + src => + { + var v = (ReadOnlyMemory)src; + TextSaverUtils.MapText(v.Span, ref sb, '\t'); + }; + } + + Contracts.Assert(false); + return null; + } + + private void DumpErrors(IndentedTextWriter wrt, List lineMap, int lineMin, + string fileName, string phase, List errors) + { + Contracts.AssertValue(wrt); + Contracts.AssertValue(lineMap); + Contracts.AssertNonEmpty(phase); + Contracts.AssertNonEmpty(errors); + + using (wrt.Nest()) + { + foreach (var err in errors) + { + var tok = err.Token; + Contracts.AssertValue(tok); + var pos = new LambdaParser.SourcePos(lineMap, tok.Span, lineMin); + wrt.Write("{0}({1},{2})-({3},{4}): ", + fileName, pos.LineMin, pos.ColumnMin, pos.LineLim, pos.ColumnLim); + wrt.Write("error: "); + wrt.WriteLine(err.GetMessage()); + } + } + } + } + + public sealed class TestFuncs1 : IFunctionProvider + { + // REVIEW: This is a temporary hack to baseline test the _dump functions. + // Should probably figure out a proper way to do this. + internal static TextWriter Writer; + + private volatile static TestFuncs1 _instance; + + public static TestFuncs1 Instance + { + get + { + if (_instance == null) + Interlocked.CompareExchange(ref _instance, new TestFuncs1(), null); + return _instance; + } + } + + private static TextWriter OutWriter { get { return Writer ?? Console.Out; } } + + public string NameSpace { get { return "__test1"; } } + + public MethodInfo[] Lookup(string name) + { + switch (name) + { + // This one should be ambigous when invoked on an I4. + case "_aa": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(A), + FunctionProviderUtils.Fn(A)); + case "_ab": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(A)); + case "_ac": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(A)); + case "_ad": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(A)); + + case "_var": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Var)); + + case "_ba": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(B), + FunctionProviderUtils.Fn(B), + FunctionProviderUtils.Fn(B)); + + case "_bad": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(X), + FunctionProviderUtils.Fn(X), + FunctionProviderUtils.Fn(X), + ((Func)(X)).GetMethodInfo(), + FunctionProviderUtils.Fn(X)); + + case "_fa": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(F)); + + case "_dump": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(Dump), + FunctionProviderUtils.Fn(Dump), + FunctionProviderUtils.Fn(Dump), + FunctionProviderUtils.Fn(Dump), + FunctionProviderUtils.Fn(Dump), + FunctionProviderUtils.Fn(Dump), + FunctionProviderUtils.Fn(Dump), + FunctionProviderUtils.Fn(Dump), + FunctionProviderUtils.Fn(Dump), + FunctionProviderUtils.Fn(Dump), + FunctionProviderUtils.Fn(Dump), + FunctionProviderUtils.Fn(Dump)); + + case "_chars": + return FunctionProviderUtils.Ret(FunctionProviderUtils.Fn(DumpChars)); + } + + return null; + } + + public object ResolveToConstant(string name, MethodInfo meth, object[] values) + { + switch (name) + { + case "_bad": + // Note this is intentionally wrong (should return an I4, not int), to test + // handling of buggy implementations of IExprFunctions. + return 3; + } + + return null; + } + + public static I8 A(I8 a) + { + return a * 2; + } + + public static R4 A(R4 a) + { + return -a; + } + + /// + /// For testing variable-arg functions. This selects the element in c indicated by a. + /// If b is true, it negates the result. + /// + public static R4 Var(I4 a, BL b, R4[] c) + { + if (a < 0 || a >= c.Length) + return R4.NaN; + R4 res = c[a]; + if (b) + res = -res; + return res; + } + + public static I4 B() + { + return 1; + } + + public static I4 B(I4 a) + { + return 2; + } + + public static I4 B(I4 a, I4 b) + { + return 3; + } + + public static object X() + { + return null; + } + + public static I4 X(string a) + { + return 41; + } + + public static I4 X(I4 a) + { + return a; + } + + public I8 X(I8 a) + { + return a; + } + + internal static R4 X(R4 a) + { + return a; + } + + public static BL F(BL a) + { + return a; + } + + public static T Dump(T a) + { + OutWriter.WriteLine("ExprDump: {0}", a); + return a; + } + + public static T Dump(TX fmt, T a) + { + OutWriter.WriteLine(fmt.ToString(), a); + return a; + } + + public static TX DumpChars(TX a) + { + var sb = new StringBuilder(); + for (int ich = 0; ich < a.Length; ich++) + sb.AppendFormat("{0:X4} ", (short)a.Span[ich]); + OutWriter.WriteLine("ExprDumpChars: {0}", sb); + return a; + } + } + + public sealed class TestFuncs2 : IFunctionProvider + { + private volatile static TestFuncs2 _instance; + public static TestFuncs2 Instance + { + get + { + if (_instance == null) + Interlocked.CompareExchange(ref _instance, new TestFuncs2(), null); + return _instance; + } + } + + public string NameSpace { get { return "__test2"; } } + + private TestFuncs2() + { + } + + private MethodInfo[] R(params Delegate[] funcs) + { + Contracts.AssertValue(funcs); + var meths = new MethodInfo[funcs.Length]; + for (int i = 0; i < funcs.Length; i++) + { + Contracts.Assert(funcs[i] != null); + Contracts.Assert(funcs[i].Target == null); + Contracts.Assert(funcs[i].GetMethodInfo() != null); + meths[i] = funcs[i].GetMethodInfo(); + } + return meths; + } + + public MethodInfo[] Lookup(string name) + { + switch (name) + { + case "_ab": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(A)); + case "_ac": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(A)); + case "_ad": + return FunctionProviderUtils.Ret( + FunctionProviderUtils.Fn(A)); + } + + return null; + } + + public object ResolveToConstant(string name, MethodInfo meth, object[] values) + { + return null; + } + + public static I4 A(I4 a) + { + return a * 3 * 10; + } + + public static I8 A(I8 a) + { + return a * 2 * 10; + } + + public static R4 A(R4 a) + { + return -a * 10; + } + } +} diff --git a/test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprBindExInput.txt b/test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprBindExInput.txt new file mode 100644 index 0000000000..af21c274b7 --- /dev/null +++ b/test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprBindExInput.txt @@ -0,0 +1,613 @@ +R4: x => with(n = na(x) ; isna(log(x, n)) && isna(log(n, x)) && isna(log(n, n)) && !isna(log(x^2, x))) +# + 3 +$ +R8: x => with(n = na(x) ; isna(log(x, n)) && isna(log(n, x)) && isna(log(n, n)) && !isna(log(x^2, x))) +# + 3 +$ +I4: x => sign(x) +# + -3 + 0 + 17 + ? +$ +I8: x => sign(x) +# + -3 + 0 + 17 + ? +$ +R4: x => sign(x) +# + -3 + 0 + -0 + 17 + ? +$ +R8: x => sign(x) +# + -3 + 0 + -0 + 17 + ? +$ +I4: x => sign(-x) +# + -3 + 0 + 17 + ? +$ +I8: x => sign(-x) +# + -3 + 0 + 17 + ? +$ +R4: x => sign(-x) +# + -3 + 0 + -0 + 17 + ? +$ +R8: x => sign(-x) +# + -3 + 0 + -0 + 17 + ? +$ +R4: x => sign(1/x) +# + -3 + 0 + -0 + 17 + ? +$ +R8: x => sign(1/x) +# + -3 + 0 + -0 + 17 + ? +$ +I4: x => sign(-3) +# + ? +$ +I8: x => sign(17L) +# + ? +$ +R4: x => sign(0F) +# + ? +$ +R8: x => sign(-0D) +# + ? +$ +R4: x => sign(1 / 0F) +# + ? +$ +R8: x => sign(1 / -0D) +# + ? +$ +R4: x => sign(na(x)) +# + ? +$ +TX: x => min(x, "hey") + max(x, "hey") +$ +BL,I4: (s,x) => !s ? min(x, 2) : max(x, 2) +# + 0,-3 + 1,-3 + 0,17 + 1,17 + 0,0 + 1,0 + 0,? + 1,? +$ +BL,I4: (s,x) => !s ? min(15, x) : max(15, x) +# + 0,-3 + 1,-3 + 0,12 + 1,12 + 0,17 + 1,17 + 0,0 + 1,0 + 0,? + 1,? +$ +I4: x => min(x) + min(-1, x, 3) + min(x, true) + min("hi", x) + max(x) + max(-1, x, 3) + max(x, true) + max("hi", x) +$ +BL,I4: (s,x) => !s ? 10 * min(3, 6) + min(7, 5) : 10 * max(3, 6) + max(7, 5) +# + 0,? + 1,? +$ +I4: x => with(n = na(x) ; isna(min(n, x)) && isna(min(x, n)) && isna(min(n, n)) && isna(max(n, x)) && isna(max(x, n)) && isna(max(n, n))) +# + 17 +$ +BL,I8: (s,x) => !s ? min(x, 2) : max(x, 2) +# + 0,-3 + 1,-3 + 0,17 + 1,17 + 0,0 + 1,0 + 0,? + 1,? +$ +BL,I8: (s,x) => !s ? min(15, x) : max(15, x) +# + 0,-3 + 1,-3 + 0,12 + 1,12 + 0,17 + 1,17 + 0,0 + 1,0 + 0,? + 1,? +$ +I8: x => min(x) + min(-1, x, 3) + min(x, true) + min("hi", x) + max(x) + max(-1, x, 3) + max(x, true) + max("hi", x) +$ +BL,I8: (s,x) => !s ? 10 * min(3L, 6L) + min(7L, 5) : 10 * max(3, 6L) + max(7L, 5) +# + 0,? + 1,? +$ +I8: x => with(n = na(x) ; isna(min(n, x)) && isna(min(x, n)) && isna(min(n, n)) && isna(max(n, x)) && isna(max(x, n)) && isna(max(n, n))) +# + 17 +$ +BL,R4: (s,x) => !s ? min(x, 2) : max(x, 2) +# + 0,-3 + 1,-3 + 0,17 + 1,17 + 0,0 + 1,0 + 0,? + 1,? +$ +BL,R4: (s,x) => !s ? min(15, x) : max(15, x) +# + 0,-3 + 1,-3 + 0,12 + 1,12 + 0,17 + 1,17 + 0,0 + 1,0 + 0,? + 1,? +$ +R4: x => min(x) + min(-1, x, 3) + min(x, true) + min("hi", x) + max(x) + max(-1, x, 3) + max(x, true) + max("hi", x) +$ +BL,R4: (s,x) => !s ? 10 * min(3f, 6f) + min(7f, 5) : 10 * max(3, 6f) + max(7f, 5) +# + 0,? + 1,? +$ +R4: x => with(n = na(x) ; isna(min(n, x)) && isna(min(x, n)) && isna(min(n, n)) && isna(max(n, x)) && isna(max(x, n)) && isna(max(n, n))) +# + 17 +$ +BL,R8: (s,x) => !s ? min(x, 2) : max(x, 2) +# + 0,-3 + 1,-3 + 0,17 + 1,17 + 0,0 + 1,0 + 0,? + 1,? +$ +BL,R8: (s,x) => !s ? min(15, x) : max(15, x) +# + 0,-3 + 1,-3 + 0,12 + 1,12 + 0,17 + 1,17 + 0,0 + 1,0 + 0,? + 1,? +$ +R8: x => min(x) + min(-1, x, 3) + min(x, true) + min("hi", x) + max(x) + max(-1, x, 3) + max(x, true) + max("hi", x) +$ +BL,R8: (s,x) => !s ? 10 * min(3d, 6f) + min(7d, 5) : 10 * max(3, 6d) + max(7d, 5) +# + 0,? + 1,? +$ +R8: x => with(n = na(x) ; isna(min(n, x)) && isna(min(x, n)) && isna(min(n, n)) && isna(max(n, x)) && isna(max(x, n)) && isna(max(n, n))) +# + 17 +$ +R4,R4: (x,y) => atan2(x) + atan2(y, x, y) + atanyx(y, x == y) + atanyx("hi", x) +$ +R8,R8: (x,y) => atan2(x) + atan2(y, x, y) + atanyx(y, x == y) + atanyx("hi", x) +$ +R4,R4: (x,y) => deg(atan2(y,x)) +# + 0, 0 + -0, 0 + -0,-0 + 0,-0 + 1, 0 + 1, 1 + 0, 1 + -1, 1 + -1, 0 + -1,-1 + 0,-1 + 1,-1 + 1, 0 + ?, 1 + 1, ? + ?, ? + Infinity, 1 + 1, Infinity + -1, Infinity + -Infinity, 1 + -Infinity,-1 + -1,-Infinity + 1,-Infinity + Infinity,-1 + Infinity, Infinity + -Infinity, Infinity + -Infinity,-Infinity + Infinity,-Infinity +$ +R8,R8: (x,y) => degrees(atanyx(y,x)) +# + 0, 0 + -0, 0 + -0,-0 + 0,-0 + 1, 0 + 1, 1 + 0, 1 + -1, 1 + -1, 0 + -1,-1 + 0,-1 + 1,-1 + 1, 0 + ?, 1 + 1, ? + ?, ? + Infinity, 1 + 1, Infinity + -1, Infinity + -Infinity, 1 + -Infinity,-1 + -1,-Infinity + 1,-Infinity + Infinity,-1 + Infinity, Infinity + -Infinity, Infinity + -Infinity,-Infinity + Infinity,-Infinity +$ +I4: s => with(c = float(180 / pi()), nf = na(0f) ; + s == 0 ? c * atan2( 0f, 1f) : + s == 1 ? c * atan2( 1f, 1f) : + s == 2 ? c * atan2( 1f, 0f) : + s == 3 ? c * atan2( 1f,-1f) : + s == 4 ? c * atan2( 0f,-1f) : + s == 5 ? c * atan2(-1f,-1f) : + s == 6 ? c * atan2(-1f, 0f) : + s == 7 ? c * atan2( nf, 0f) : + s == 8 ? c * atan2( 0f, nf) : + s == 9 ? c * atan2( nf, nf) : + 1234567f) +# + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + -1 +$ +R4: x => with(n = na(x) ; isna(atan2(n, x)) && isna(atan2(x, n)) && isna(atan2(n, n))) +# + 1 +$ +I4: s => with(c = double(180 / pi()), nd = na(0d) ; + s == 0 ? c * atan2( 0d, 1d) : + s == 1 ? c * atan2( 1d, 1d) : + s == 2 ? c * atan2( 1d, 0d) : + s == 3 ? c * atan2( 1d,-1d) : + s == 4 ? c * atan2( 0d,-1d) : + s == 5 ? c * atan2(-1d,-1d) : + s == 6 ? c * atan2(-1d, 0d) : + s == 7 ? c * atan2( nd, 0f) : + s == 8 ? c * atan2( 0d, nd) : + s == 9 ? c * atan2( nd, nd) : + 1234567d) +# + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + -1 +$ +R8: x => with(n = na(x) ; isna(atan2(n, x)) && isna(atan2(x, n)) && isna(atan2(n, n))) +# + 1 +$ +R4: x => deg() + deg(x,x) + rad() + rad(x,3) + rad(text(x)) +$ +I4: s => + s == 0 ? deg(0f) : + s == 1 ? deg(float(pi() / 2)) : + s == 2 ? degrees(float(pi() / 6)) : + s == 3 ? degrees(float(-pi() / 4)) : + s == 4 ? deg(na(0f)) : + -1 +# + 0 + 1 + 2 + 3 + 4 +$ +I4: s => + s == 0 ? deg(0d) : + s == 1 ? deg(pi() / 2) : + s == 2 ? degrees(pi() / 6) : + s == 3 ? degrees(-pi() / 4) : + s == 4 ? deg(na(0d)) : + -1 +# + 0 + 1 + 2 + 3 + 4 +$ +I4: s => + s == 0 ? rad(0f) : + s == 1 ? rad(90f) : + s == 2 ? radians(30f) : + s == 3 ? radians(-45f) : + s == 4 ? rad(na(0f)) : + -1 +# + 0 + 1 + 2 + 3 + 4 +$ +I4: s => + s == 0 ? rad(0d) : + s == 1 ? rad(90d) : + s == 2 ? radians(30d) : + s == 3 ? radians(-45d) : + s == 4 ? rad(na(0d)) : + -1 +# + 0 + 1 + 2 + 3 + 4 +$ +R4: x => deg(float(pi() / 180) * x) +# + 0 + 30 + 45 + -60 + 90 + ? +$ +R8: x => deg(pi() / 180 * x) +# + 0 + 30 + 45 + -60 + 90 + ? +$ +R4: x => deg(rad(x)) - x +# + 0 + 30 + 45 + -60 + 90 + ? +$ +R8: x => with(c = pi() / 180 ; radians(x) - x * c) +# + 0 + 30 + 45 + -60 + 90 + ? +$ +R4: x => + trunc() + trunc(x,x) + trunc(true) + + ceil () + ceil (x,x) + ceil (true) + + floor() + floor(x,x) + floor(true) + + round() + round(x,x) + round(true); +$ +R4: x => + trunc() + trunc(x,x) + trunc(true) + + ceil () + ceil (x,x) + ceil (true) + + floor() + floor(x,x) + floor(true) + + round() + round(x,x) + round(true) +$ +R4: x => truncate(x) +# + -1.2 + -1.9 + 3.2 + 3.7 + Infinity + -Infinity + ? +$ +R4: x => floor(x) +# + -1.2 + -1.9 + 3.2 + 3.7 + Infinity + -Infinity + ? +$ +R4: x => ceil(x) +# + -1.2 + -1.9 + 3.2 + 3.7 + Infinity + -Infinity + ? +$ +R4: x => round(x) +# + -1.2 + -1.5 + -1.9 + -2.5 + -3.5 + 3.2 + 3.7 + 3.5 + 2.5 + 1.5 + Infinity + -Infinity + ? +$ +I4: x => _aa(x) +$ +I4: x => _aa(long(x)) +# + 17 + -12 + ? +$ +I4: x => _aa(float(x)) +# + 17 + -12 + ? +$ +I4: x => _ab(x) +$ +I4: x => _ab(long(x)) +# + 17 + -12 + ? +$ +I4: x => _ab(float(x)) +# + 17 + -12 + ? +$ +I4: x => _ac(x) +$ +I4: x => __test1._ac(x) +# + 17 + -12 + ? +$ +I4: x => _ad(x) +# + 17 + -12 + ? +$ +I8: x => _ad(x) +# + 17 + -12 + ? +$ +I4,BL: +(a,b) => _var(a, b, 1, 2, 3, 4) +# + 0,0 + 0,1 + 1,0 + 2,1 + 3,0 + -1,0 + 4,1 + 2,? + ?,0 + ?,? +$ +I4: +x => _ba() + 10 * _ba(x) + 100 * _ba(x, x) +# + 17 + ? +$ +I4: +x => _ba(x, x, x) +$ +I4: +x => _bad(x) +# + -1 + 1 + 17 + ? +$ +BL: x => _fa(blah(x)) +# + 1 +$ diff --git a/test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprBindInput.txt b/test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprBindInput.txt new file mode 100644 index 0000000000..9f6595c963 --- /dev/null +++ b/test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprBindInput.txt @@ -0,0 +1,1560 @@ +I4: x => "hello" // StrLit +# 0 +$ +I4: x => 3 +# + 0 + 5 +$ +I4: x => x ^ 2 * x +# + -1 + 0 + 2 + 3 + 1024 +$ +I4: x : x ^ 2 ^ 3 +# + 2 + 12 + -8 +$ +I4,I8: // Promotion +(x,y) => x+y +# + 3,5 + 2147483647,5 + 3,9223372036854775807 + 3,9223372036854775804 + -3,9223372036854775807 +$ +I4,R4: // Promotion +(x,y) => x+y +# + 3,5 + 2147483647,5 + 3,9223372036854775807 + 3,1e30 +$ +I4,R8: // Promotion +(x,y) => x+y +# + 3,5 + 2147483647,5 + 3,9223372036854775807 + 3,1e30 +$ +I4: // Unresolved identifier +x => y +$ +BL: // Bad number with minus +x => -x +$ +I4: // Bad bool with not +x => !x +$ +I4: // Not on constant bool +x => !(5 < 3 < x) +# + 17 +$ +R4: // Constant fold minus +x => -(0.0/0) ?? -3 + -x +# + 0 + ? + 3 +$ +R8: // Constant fold minus +x => -(0.0/0L) ?? -3L + -x +# + 0 + ? + 3 +$ +R4: // Constant fold minus +x => -(0f/0f) ?? -3f + -x +# + 0 + ? + 3 +$ +R8: // Constant fold minus +x => -(0d/0d) ?? -3d + -x +# + 0 + ? + 3 +$ +I4,BL: +(x,y) => x < y +$ +R4,BL: +(x,y) => x < y +$ +I4: +x => "hello" == x +$ +I4,BL: +(x,y) => (y ?? x) + (x ?? y) + ("hello" ?? x) +$ +BL: +x => (x ?? "hello") || ("hello" ?? x) +$ +I4: x => "whatever" ?? "hello" +# 0 +$ +BL: +x => 1000 * (int(true || x) + int(x || true)) + + 100 * (int(true) + int(true)) + + 10 * (int(not(false && x)) + int(not(x && false))) + + 1 * (int(true) + int(true)) +# + true + false + ? +$ +BL: +x => 100 * (int(0.0/0 == 1 ? x : false) + 1 == 1 ? 2 : 3) + 10 * (int(!(false ? x : false)) + 1 == 1 ? 2 : 3) + 1 * (int(true ? false : x) + 1 > 0 ? 3 : 1) +# + true + false + ? +$ +BL: +x => x + "hello" +$ +BL,I4,I8,R4,R8: +(a,b,c,d,e) => + isna(a + b) || isna(b + a) || + isna(a + c) || isna(c + a) || + isna(a + d) || isna(d + a) || + isna(a + e) || isna(e + a) +$ +BL,I4,I8,R4,R8: +(a,b,c,d,e) => + 10000 * int(!isna(true ?? a)) + + 1000 * int(!isna(1 ?? b)) + + 100 * int(!isna(1 ?? c)) + + 10 * int(!isna(1 ?? d)) + + 1 * int(!isna(1 ?? e)) +# + ?,?,?,?,? + true,3,3,3,3 +$ +I4: x => x + (17 - 31) +# + 1 + 2147483647 + -2147483633 + -2147483634 + ? +$ +I4: s => // Constant folding I4 + s == 0 ? 37 % 5 : + s == 1 ? 37 % -5 : + s == 2 ? -37 % -5 : + s == 3 ? -37 % 5 : + 0 +# + 0 + 1 + 2 + 3 +$ +I4: s => // Constant folding I8 + s == 10 ? 45L + -53 : + s == 11 ? 9223372036854775807L + 1 : + s == 12 ? 9223372036854775807L + -1 : + s == 13 ? -9223372036854775807L + 1 : + s == 14 ? -9223372036854775807L + -1 : + + s == 20 ? 45L - -53 : + s == 21 ? 9223372036854775807L - 1 : + s == 22 ? 9223372036854775807L - -1 : + s == 23 ? -9223372036854775807L - 1 : + s == 24 ? -9223372036854775807L - -1 : + + s == 30 ? 45L * -53 : + s == 31 ? 9000000000000000000L * 2 : + s == 32 ? 9000000000000000000L * -1 : + + s == 40 ? 37L % 5 : + s == 41 ? 37L % -5 : + s == 42 ? -37L % -5 : + s == 43 ? -37L % 5 : + + s == 50 ? 2L^3 : + s == 51 ? (-2L)^5 : + + 0 +# + 10 + 11 + 12 + 13 + 14 + 15 + 16 + + 20 + 21 + 22 + 23 + 24 + 25 + 26 + + 30 + 31 + 32 + 33 + 34 + + 40 + 41 + 42 + 43 + + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 +$ +I4: s => // Constant folding R4 + s == 10 ? 3f + 5 : + s == 11 ? 0f/0 + 5 : + s == 12 ? 5 + 0f/0 : + + s == 20 ? 3f - 5 : + s == 21 ? 0f/0 - 5 : + s == 22 ? 5 - 0f/0 : + + s == 30 ? 3f * 5 : + s == 31 ? (0f/0) * 5 : + s == 32 ? 5 * (0f/0) : + + s == 40 ? 3f / 5 : + s == 41 ? (0f/0) / 5 : + s == 42 ? 5 / (0f/0) : + + s == 50 ? 37f % 5 : + s == 51 ? 37f % -5 : + s == 52 ? -37f % -5 : + s == 53 ? -37f % 5 : + s == 54 ? (0f/0) % 5 : + s == 55 ? 35 % (0f/0) : + + s == 60 ? 2f ^ 3 : + s == 61 ? 2 ^ 3.5f : + s == 62 ? (0f/0) ^ 3 : + s == 63 ? 2f ^ (0f/0) : + + 0 +# + 10 + 11 + 12 + + 20 + 21 + 22 + + 30 + 31 + 32 + + 40 + 41 + 42 + + 50 + 51 + 52 + 53 + 54 + 55 + + 60 + 61 + 62 + 63 +$ +I4: s => // Constant folding R8 + s == 10 ? 3d + 5 : + s == 11 ? 0d/0 + 5 : + s == 12 ? 5 + 0d/0 : + + s == 20 ? 3d - 5 : + s == 21 ? 0d/0 - 5 : + s == 22 ? 5 - 0d/0 : + + s == 30 ? 3d * 5 : + s == 31 ? (0d/0) * 5 : + s == 32 ? 5 * (0d/0) : + + s == 40 ? 3d / 5 : + s == 41 ? (0d/0) / 5 : + s == 42 ? 5 / (0d/0) : + + s == 50 ? 37d % 5 : + s == 51 ? 37d % -5 : + s == 52 ? -37d % -5 : + s == 53 ? -37d % 5 : + s == 54 ? (0d/0) % 5 : + s == 55 ? 35 % (0d/0) : + + s == 60 ? 2d ^ 3 : + s == 61 ? 2 ^ 3.5d : + s == 62 ? (0d/0) ^ 3 : + s == 63 ? 2d ^ (0d/0) : + + 0 +# + 10 + 11 + 12 + + 20 + 21 + 22 + + 30 + 31 + 32 + + 40 + 41 + 42 + + 50 + 51 + 52 + 53 + 54 + 55 + + 60 + 61 + 62 + 63 +$ +I4: +x => 17 >= 12 > x +# + 3 + 11 + 12 + 121 + ? +$ +I4,I4,I4: +(s,x,y) => + s == 0 ? 3 != 5 != 3 != x != y : + s == 1 ? 3 != 3 != 5 != x != y : + s == 2 ? 3 != 5 != -2 != x != y : + na(0.0) == 1 +# + 0,1,2 + 0,?,2 + 1,1,2 + 1,1,? + 2,1,2 + 2,1,3 + 2,-2,1 + 2,?,1 + 2,1,? +$ +I4,I4: +(s,x) => + s == 0 ? int(3 < 5 <= 5 <= 6) : + s == 1 ? int(3 < 5 <= na(0.0) <= 6 <= x) : + -1 +# + 0,-12 + 1,-12 +$ +BL,BL: +(x,y) => x <= y +$ +BL: x => abs(x) +$ +I4: s => + s == 2 ? abs(-3L) : + s == 3 ? abs(-9223372036854775807) : + -1 +# + 0 + 1 + 2 + 3 +$ +I4: s => // R4 + s == 10 ? abs(0f/0) : + s == 11 ? abs(-3.5f) : + s == 12 ? abs(-1f/0) : + + s == 20 ? log(0f/0) : + s == 21 ? log(0f) : + s == 22 ? log(1f) : + s == 23 ? ln(2f) : + s == 24 ? log(-3.5f) : + s == 25 ? log(1f/0) : + + s == 30 ? log(0f/0, 2) : + s == 31 ? log(0f, 2) : + s == 32 ? log(1f, 2) : + s == 33 ? log(2f, 2) : + s == 34 ? log(-3.5f, 2) : + s == 35 ? log(1f/0, 2) : + s == 36 ? log(9f, 3) : + + -1 +# + 10 + 11 + 12 + + 20 + 21 + 22 + 23 + 24 + 25 + + 30 + 31 + 32 + 33 + 34 + 35 + 36 +$ +I4: s => // R8 + s == 10 ? abs(0d/0) : + s == 11 ? abs(-3.5d) : + s == 12 ? abs(-1d/0) : + + s == 20 ? log(0d/0) : + s == 21 ? log(0d) : + s == 22 ? log(1d) : + s == 23 ? ln(2d) : + s == 24 ? log(-3.5d) : + s == 25 ? log(1d/0) : + + s == 30 ? log(0d/0, 2) : + s == 31 ? log(0d, 2) : + s == 32 ? log(1d, 2) : + s == 33 ? log(2d, 2) : + s == 34 ? log(-3.5d, 2) : + s == 35 ? log(1d/0, 2) : + s == 36 ? log(9d, 3) : + + -1 +# + 10 + 11 + 12 + + 20 + 21 + 22 + 23 + 24 + 25 + + 30 + 31 + 32 + 33 + 34 + 35 + 36 +$ +I4: x => isna(x, 3) +$ +R4: x => log() + log(x,x,x) + log(x,true) + log(true,x) +$ +I4,R4: +(s,x) => + s == 0 ? exp(x) : + s == 1 ? sin(x) : + s == 2 ? cos(x) : + s == 3 ? tan(x) : + s == 4 ? sind(x) : + s == 5 ? cosd(x) : + s == 6 ? tand(x) : + s == 7 ? sinh(x) : + s == 8 ? cosh(x) : + s == 9 ? tanh(x) : + s == 10 ? asin(x) : + s == 11 ? acos(x) : + s == 12 ? atan(x) : + s == 13 ? sqrt(x) : + -100 +# + 0,0 + 0,-1 + 0,1 + 0,1000000 + 0,? + 1,0 + 1,0.52359877559829887307710723054658 + 1,1.0471975511965977461542144610932 + 1,-0.52359877559829887307710723054658 + 1,1e30 + 1,1e1000 + 1,? + 2,0 + 2,0.52359877559829887307710723054658 + 2,1.0471975511965977461542144610932 + 2,-0.52359877559829887307710723054658 + 2,1e30 + 2,1e1000 + 2,? + 3,0 + 3,0.52359877559829887307710723054658 + 3,1.0471975511965977461542144610932 + 3,-0.52359877559829887307710723054658 + 3,1e30 + 3,1e1000 + 3,? + 4,0 + 4,30 + 4,60 + 4,-30 + 4,1e30 + 4,1e1000 + 4,? + 5,0 + 5,30 + 5,60 + 5,-30 + 5,1e30 + 5,1e1000 + 5,? + 6,0 + 6,30 + 6,60 + 6,-30 + 6,1e30 + 6,1e1000 + 6,? + 7,0 + 7,1 + 7,-1 + 7,-1e30 + 7,1e1000 + 7,? + 8,0 + 8,1 + 8,-1 + 8,-1e30 + 8,1e1000 + 8,? + 9,0 + 9,1 + 9,-1 + 9,-1e30 + 9,1e1000 + 9,? + 10,0 + 10,0.5 + 10,-0.5 + 10,1 + 10,-2 + 10,? + 11,0 + 11,0.5 + 11,-0.5 + 11,1 + 11,-2 + 11,? + 12,0 + 12,1 + 12,-1 + 12,-1e1000 + 12,1e1000 + 12,? + 13,0 + 13,1 + 13,2 + 13,25 + 13,1e1000 + 13,-1 + 13,? +$ +I4,R8: +(s,x) => + s == 0 ? exp(x) : + s == 1 ? sin(x) : + s == 2 ? cos(x) : + s == 3 ? tan(x) : + s == 4 ? sind(x) : + s == 5 ? cosd(x) : + s == 6 ? tand(x) : + s == 7 ? sinh(x) : + s == 8 ? cosh(x) : + s == 9 ? tanh(x) : + s == 10 ? asin(x) : + s == 11 ? acos(x) : + s == 12 ? atan(x) : + s == 13 ? sqrt(x) : + -100 +# + 0,0 + 0,-1 + 0,1 + 0,1000000 + 0,? + 1,0 + 1,0.52359877559829887307710723054658 + 1,1.0471975511965977461542144610932 + 1,-0.52359877559829887307710723054658 + 1,1e30 + 1,1e1000 + 1,? + 2,0 + 2,0.52359877559829887307710723054658 + 2,1.0471975511965977461542144610932 + 2,-0.52359877559829887307710723054658 + 2,1e30 + 2,1e1000 + 2,? + 3,0 + 3,0.52359877559829887307710723054658 + 3,1.0471975511965977461542144610932 + 3,-0.52359877559829887307710723054658 + 3,1e30 + 3,1e1000 + 3,? + 4,0 + 4,30 + 4,60 + 4,-30 + 4,1e30 + 4,1e1000 + 4,? + 5,0 + 5,30 + 5,60 + 5,-30 + 5,1e30 + 5,1e1000 + 5,? + 6,0 + 6,30 + 6,60 + 6,-30 + 6,1e30 + 6,1e1000 + 6,? + 7,0 + 7,1 + 7,-1 + 7,-1e30 + 7,1e1000 + 7,? + 8,0 + 8,1 + 8,-1 + 8,-1e30 + 8,1e1000 + 8,? + 9,0 + 9,1 + 9,-1 + 9,-1e30 + 9,1e1000 + 9,? + 10,0 + 10,0.5 + 10,-0.5 + 10,1 + 10,-2 + 10,? + 11,0 + 11,0.5 + 11,-0.5 + 11,1 + 11,-2 + 11,? + 12,0 + 12,1 + 12,-1 + 12,-1e1000 + 12,1e1000 + 12,? + 13,0 + 13,1 + 13,2 + 13,25 + 13,1e1000 + 13,-1 + 13,? +$ +R4: x => sin(x,x) + sin(x == x) +$ +R4: x => sind(30f) + cosd(60d) + tand(45) + cos(0) +# + 0 +$ +BL: x => int(x,x) + long(x,x) + single(x,x) + float(x,x) + double(x,x) +$ +BL: x => int(x) + long(x) + single(x) + float(x) + double(x) +# + false + true + ? +$ +I4: +x => + 100000 * int(3) + + 10000 * int(7L) + + 1000 * int(3.5f) + + 100 * int(3.5d) + + 10 * int(false) + + 1 * int(isna(float(10000000000)) && isna(float(-10000000000))) +# + 0 +$ +I4: +x => + 100000 * long(3) + + 10000 * long(7L) + + 1000 * long(3.5f) + + 100 * long(3.5d) + + 10 * long(false) + + 1 * long(isna(float(1e100d)) && isna(float(-1e100d)) && isna(na(0.0)) && isna(float(na(0.0) == 1))) +# + 0 +$ +I4: +x => + 100000 * single(3) + + 10000 * single(7L) + + 1000 * single(3f) + + 100 * single(3.00000000001d) + + 10 * single(false) + + 1 * single(isna(single(0.0)) && isna(single(na(0.0))) && isna(single(na(0.0) == 1))) +# + 0 +$ +I4: +x => + 100000 * double(3) + + 10000 * double(7L) + + 1000 * double(3f) + + 100 * double(3.00000000001d) + + 10 * double(false) + + 1 * double(isna(double(0.0/0)) && isna(double(0.0/0)) && isna(double(0.0/0 == 1))) +# + 0 +$ +I4,R4: +(x,y) => 100 + 10 * int(x == y) + 1 * int(single(x) == y) +# + 1,1 + 123456789,123456789 + 123456792,123456789 +$ +BL: +x => + (x ? x : 3) + (x ? 3 : x) + + (x ? x : 3L) + (x ? 3L : x) + + (x ? x : 3f) + (x ? 3f : x) + + (x ? x : 3d) + (x ? 3d : x) + + (x ? x : "hi") + (x ? "hi" : x) + + (x ? -"hi" : x) + (x ? -"hi" : -"bye") +$ +I4: s => + 1000000000 + + 100000000 * (float(true ? false : true) ?? 2) + + 10000000 * (float(false ? false : true) ?? 2) + + 1000000 * (float(0.0/0 == 1 ? false : true) ?? 2) + + 100000 * (float(true ? 0 : 1) ?? 2) + + 10000 * (float(false ? 0 : 1) ?? 2) + + 1000 * (float(0.0/0 == 1 ? 0 : 1) ?? 2) + + 100 * (float(true ? 0L : 1L) ?? 2) + + 10 * (float(false ? 0L : 1L) ?? 2) + + 1 * (float(0.0/0 == 1 ? 0L : 1L) ?? 2) +# + 0 +$ +I4: s => + 1000000 + + 100000 * (float(true ? 0f : 1f) ?? 2) + + 10000 * (float(false ? 0f : 1f) ?? 2) + + 1000 * (float(0.0/0 == 1 ? 0f : 1f) ?? 2) + + 100 * (float(true ? 0d : 1d) ?? 2) + + 10 * (float(false ? 0d : 1d) ?? 2) + + 1 * (float(0.0/0 == 1 ? 0d : 1d) ?? 2) +# + 0 +$ +I4: +x => foo(x) +$ +I4: +x => -"hi" < 3 <= x +$ +I4: s => + (false == false) && + !(false == true ) && + !(false != false) && + (false != true ) && + ( 3 == 3 ) && + ( 3L == 3L) && + ( 3F == 3F) && + ( 3D == 3D) && + ("3" == "3") && + !( 3 == 4 ) && + !( 3L == 4L) && + !( 3F == 4F) && + !( 3D == 4D) && + !("3" == "4") && + !( 3 != 3 ) && + !( 3L != 3L) && + !( 3F != 3F) && + !( 3D != 3D) && + !("3" != "3") && + ( 3 != 4 ) && + ( 3L != 4L) && + ( 3F != 4F) && + ( 3D != 4D) && + ("3" != "4") && + true +# + 0 +$ +I4: s => + !( 3 < 3 ) && + !( 3L < 3L) && + !( 3F < 3F) && + !( 3D < 3D) && + ( 3 < 4 ) && + ( 3L < 4L) && + ( 3F < 4F) && + ( 3D < 4D) && + ( 3 <= 3 ) && + ( 3L <= 3L) && + ( 3F <= 3F) && + ( 3D <= 3D) && + ( 3 <= 4 ) && + ( 3L <= 4L) && + ( 3F <= 4F) && + ( 3D <= 4D) && + !( 3 <= 2 ) && + !( 3L <= 2L) && + !( 3F <= 2F) && + !( 3D <= 2D) && + true +# + 0 +$ +I4: s => + !( 3 > 3 ) && + !( 3L > 3L) && + !( 3F > 3F) && + !( 3D > 3D) && + ( 3 > 2 ) && + ( 3L > 2L) && + ( 3F > 2F) && + ( 3D > 2D) && + ( 3 >= 3 ) && + ( 3L >= 3L) && + ( 3F >= 3F) && + ( 3D >= 3D) && + !( 3 >= 4 ) && + !( 3L >= 4L) && + !( 3F >= 4F) && + !( 3D >= 4D) && + ( 3 >= 2 ) && + ( 3L >= 2L) && + ( 3F >= 2F) && + ( 3D >= 2D) && + true +# + 0 +$ +TX: x => x +# + hello + goodbye +$ +BL: x => x ? "a" : "b" +# + false + true + ? +$ +BL: x => 0 == 1 ? "a" : "b" +# + 0 +$ +BL: x => 0.0/0 == 1 ? "a" : "b" +# + 0 +$ +BL: x => (x ? "a" : "b") == "a" +# + 0 + 1 + ? +$ +BL,TX: (s,x) => lower(s ? x : x) +# + 1,Hello + 1,hElLo + 0,BlaH + 0, + ?,Whatever +$ +BL,TX: (s,x) => upper(s ? x : x) +# + 1,Hello + 1,hElLo + 0,BlaH + 0, + ?,Whatever +$ +I4: s => + s == 0 ? lower("hElLo") : + s == 1 ? lower("") : + s == 2 ? lower(0.0/0 == 1 ? "a" : "b") : + "BAD" +# + 0 + 1 + 2 +$ +I4: s => + s == 0 ? upper("hElLo") : + s == 1 ? upper("") : + s == 2 ? upper(0.0/0 == 1 ? "a" : "b") : + "bad" +# + 0 + 1 + 2 +$ +I4: s => + s == 0 ? concat("Hello", " There", " Tom") : + s == 1 ? concat("Howdy ", "Nizar") : + s == 2 ? concat("Hola", " NA!", 0.0/0 == 1 ? "x" : "y") : + s == 3 ? concat() : + s == 4 ? concat("Hola", "\t", "Whoever") : + "bad" +# + 0 + 1 + 2 + 3 + 4 +$ +TX,TX,TX: +(a,b,c) => concat(concat(a), "|", b, concat("|", c)) +# + Mary,Joe,Tom + Cat,Dog,Zebra + Cat,,Zebra + Cat,_,Zebra +$ +TX,I4: +(x,y) => concat(x,y) +$ +I4: x => pi() +# + 0 +$ +R8: x => asin(x) * 180 / pi() +# + 0 + 0.5 + 1 + -0.5 + -1 + ? +$ +R8: x => asin(sqrt(x) / 2) * 180 / pi() +# + 0 + 1 + 2 + 3 + 4 + ? +$ +R8: x => lower(x) + upper(x, x) +$ +I4,TX: +(x,y) => y ?? "hello" +# + 0,Joe + 0, + 0,_ +$ +I4,TX: +(x,y) => float(y) +# + 0,0 + 0,1 + 0,1.5 + 0,-1 + 0,? + 0,Joe + 0, + 0,_ +$ +I4,BL,TX: +(a,b,c) => (blah(a) ?? a) + (blah(b) ?? b) + (blah(c) ?? c) + (blah(a) ?? blah(b)) +$ +I4: +a => (0.0/0 == 0.0/0 ? "a" : "b") == "b" ? "b" : "c" +# + 0 +$ +BL: +x => x ? blah(3) : "hello" +$ +BL: +x => x || true ? "a" : "b" +# + 0 +$ +BL: +x => int(blah(x)) + long(blah(x)) + single(blah(x)) + double(blah(x)) +$ +TX: +x => isna(x) || isna("hello") || !isna(0.0/0 == 1 ? "a" : "b") +# + x + y + _ +$ +R4: +x => pi(x) +$ +BL: x => na(x) +# + 0 +$ +I4: x => na(x) +# + 0 +$ +I8: x => na(x) +# + 0 +$ +R4: x => na(x) +# + 0 +$ +R8: x => na(x) +# + 0 +$ +TX: x => na(x) +# + 0 +$ +BL: x => na(blah(x)) +# + 0 +$ +BL: x => default(x) +# + 0 +$ +I4: x => default(x) +# + 0 +$ +I8: x => default(x) +# + 0 +$ +R4: x => default(x) +# + 0 +$ +R8: x => default(x) +# + 0 +$ +TX: x => default(x) +# + 0 +$ +BL: x => default(blah(x)) +# + 0 +$ +BL: x => bool() && bool(x, x) && bool(int(x)) && bool(3) +$ +BL: x => bool(x) +# + 0 + 1 + ? +$ +TX: x => bool(x) +# + false + yes + ? +$ +BL: x => x ? bool(true) : bool(false) +# + F + Y + NA +$ +BL: x => x ? bool("true") : bool("false") +# + 0 + 1 + ? +$ +BL: x => concat(text(), text(x, x), text(blah(x))) +$ +BL: x => concat(text(true), "|", text(-3), "|", text(17L), "|", text(2.5f), "|", text(-3.25d), "|", text("end")) +# + 0 +$ +I4: x => _dump(x) +# + 17 + ? +$ +I4: x => _dump("Hello from _dump: {0}", x) +# + 17 + ? +$ +I4: x => _dump() +$ +I4: x => _dump("a", 1, 2) +$ +TX,I4: (x,y) => _dump(x, y) +$ +I4,I4: (x,y) => _dump(x, y) +$ +I4: y => _dump(1, y) +$ +I4: y => with(x = 1; _dump(x, y)) +$ +I4: y => with(x = "Hello from _dump: {0}"; _dump(x, y)) +# + -17 + ? +$ +I4: x => with(y = _dump(" Eval[y]: {0}", x + 1), z = _dump(" Eval[z]: {0}", y + 1); z) +# + 0 + 17 + -2 + ? +$ +I4: +a => with(b = _dump(a + 1); b * b) +# + 0 + -1 + 1 + 2 + ? +$ +I4: +a => with( + b = _dump(" Eval[b]: {0}", a * a), + c = b * b, + d = c * c, + q = "?" + ; + concat(text(a) ?? q, "|", text(b) ?? q, "|", text(c) ?? q, "|", text(d) ?? q) +) +# + 0 + 1 + 2 + -2 + 10 + 14 + 15 + 1000 + ? +$ +I4: +x => concat(text(with(x = x * x, x = x * x, x = x * x ; x))??"?", "|", text(with(x = x + x, y = x + x, x = y + y ; x))??"?") +# + 0 + 1 + 2 + 3 + 10 + 14 + 15 + 100 + 1000 + ? +$ +TX: x => len("yo") +# + hello +$ +TX: x => len(na("")) ?? -12345 +# + hello +$ +TX,I8: (x,y) => len(x) +# + hello,1 + _,2 + ,3 +$ +I4: x => concat(right("hello", 2), "|", left("hello", -3), "|", mid("hello", -4, 3)) +# + 0 +$ +I4: x => concat(right("hello", x), "|", left("hello", x), "|", mid("hello", x, 3)) +# + 1 + ? + -2 +$ +I4: x => concat(right(na(""), x) ?? "?", "|", left(na(""), x) ?? "?", "|", mid(na(""), x, 3) ?? "?") +# + 1 +$ +TX: x => concat(right(x, na(0)) ?? "?", "|", left(x, na(0)) ?? "?", "|", mid(x, na(0), 3) ?? "?", "|", mid(x, 1, na(0)) ?? "?") +# + hello +$ +TX, I4: (t,i) => len()==0 && len(i)==0 && len(t,i)==0 +$ +TX, I4: (t,i) => concat(right(), right(t), right(i,t), right(t,t), right(t,i,i)) +$ +TX, I4: (t,i) => concat(left(), left(t), left(i,t), left(t,t), left(t,i,i)) +$ +TX, I4: (t,i) => concat(mid(), mid(t), mid(i,t,i), mid(t,t,i), mid(t,i,t), mid(t,i), mid(t,i,i,i)) +$ +BL: x => false || x +# + 0 + 1 + ? +$ +BL: x => true && x +# + 0 + 1 + ? +$ +BL: x => x && true +# + 0 + 1 + ? +$ +BL: x => float(0.0/0 == 1) ?? float(0 == 1) +# + 0 + 1 + ? +$ +BL: x => float(0.0/0 == 1) ?? float(x) +# + 0 + 1 + ? +$ +TX: x => isna(float("hello")) ? "hello" : x +# + hi + bye + _ +$ +TX: x => x ?? na("hello") +# + hi + bye + _ +$ +I4: x => na(x) + x +# + 2 + -2 + ? +$ +I4: x => x + na(x) +# + 2 + -2 + ? +$ +I4: x => 1/3 + x +# + 2 + -2 + ? +$ +I4: x => x + 1/3 +# + 2 + -2 + ? +$ +I4: x => na(x) * x +# + 2 + -2 + ? +$ +I4: x => x * na(x) +# + 2 + -2 + ? +$ +I4: x => (3 / 2) * x * (3 / 2) +# + 2 + -2 + ? +$ +I4: x => na(x) % x +# + 2 + -2 + ? +$ +I4: x => x / na(x) +# + 2 + -2 + ? +$ +R4: x => x ?? na(x) +# + 2 + -2 + ? +$ +I8: x => na(x) + x +# + 2 + -2 + ? +$ +I8: x => x + na(x) +# + 2 + -2 + ? +$ +I8: x => 1/3 + x +# + 2 + -2 + ? +$ +I8: x => x + 1/3 +# + 2 + -2 + ? +$ +I8: x => na(x) * x +# + 2 + -2 + ? +$ +I8: x => x * na(x) +# + 2 + -2 + ? +$ +I8: x => (3 / 2) * x * (3 / 2) +# + 2 + -2 + ? +$ +I8: x => na(x) % x +# + 2 + -2 + ? +$ +I8: x => x / na(x) +# + 2 + -2 + ? +$ +R8: x => x ?? na(x) +# + 2 + -2 + ? +$ +R4: x => na(x) + x +# + 2 + -2 + ? +$ +R4: x => x + na(x) +# + 2 + -2 + ? +$ +R4: x => 1/3 + x +# + 2 + -2 + ? +$ +R4: x => x + 1/3 +# + 2 + -2 + ? +$ +R4: x => na(x) * x +# + 2 + -2 + ? +$ +R4: x => x * na(x) +# + 2 + -2 + ? +$ +R4: x => (3 / 2) * x * (3 / 2) +# + 2 + -2 + ? +$ +R4: x => na(x) % x +# + 2 + -2 + ? +$ +R4: x => x / na(x) +# + 2 + -2 + ? +$ +R4: x => x ?? na(x) +# + 2 + -2 + ? +$ +R8: x => na(x) + x +# + 2 + -2 + ? +$ +R8: x => x + na(x) +# + 2 + -2 + ? +$ +R8: x => 1/3 + x +# + 2 + -2 + ? +$ +R8: x => x + 1/3 +# + 2 + -2 + ? +$ +R8: x => na(x) * x +# + 2 + -2 + ? +$ +R8: x => x * na(x) +# + 2 + -2 + ? +$ +R8: x => (3 / 2) * x * (3 / 2) +# + 2 + -2 + ? +$ +R8: x => na(x) % x +# + 2 + -2 + ? +$ +R8: x => x / na(x) +# + 2 + -2 + ? +$ +R8: x => x ?? na(x) +# + 2 + -2 + ? +$ +I8: x => 1L ?? 2L +# + ? +$ +I8: x => na(1L) ?? 2L +# + ? +$ +R4: x => 1f ?? 2f +# + ? +$ +R4: x => na(1f) ?? 2f +# + ? +$ +R8: x => 1d ?? 2d +# + ? +$ +R8: x => na(1d) ?? 2d +# + ? +$ +I4: x => x < na(x) < 3 +# + 1 +$ +I4: x => na(x, x) +$ diff --git a/test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprCodeGenInput.txt b/test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprCodeGenInput.txt new file mode 100644 index 0000000000..6fc34bf2c4 --- /dev/null +++ b/test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprCodeGenInput.txt @@ -0,0 +1,719 @@ +BL: +x => x ? false : true +# + false + true + ? +$ +I4,I4,I4: +(s,x,y) => + s == 0 ? x * y : + s == 1 ? x / y : + s == 2 ? x % y : + s == 3 ? x ^ y : + -1 +# + 0,-1,-1 + 0,?,1 + 0,1,? + 0,40000,40000 + 0,-40000,40000 + 0,40000,50000 + 0,40000,-50000 + + 1,?,1 + 1,1,1 + + 2,?,3 + 2,37,5 + 2,37,-5 + 2,-37,-5 + 2,-37,5 + + 3,?,5 + 3,5,? + 3,1,2000000000 + 3,1,-2000000000 + 3,-1,2000000000 + 3,-1,-2000000000 + 3,-1,2000000001 + 3,-1,-2000000001 + 3,2000000000,0 + 3,-2000000000,1 + 3,2000000000,? + 3,2,29 + 3,-2,29 + 3,2,30 + 3,-2,30 + 3,1290,3 +$ +I4,I8,I8: +(s,x,y) => + s == 0 ? x + y : + s == 1 ? x - y : + s == 2 ? x * y : + s == 3 ? x / y : + s == 4 ? x % y : + s == 5 ? x ^ y : + -1 +# + 0,9223372036854775807,1 + 0,9223372036854775807,-1 + 0,-9223372036854775807,1 + 0,-9223372036854775807,-1 + 0,?,1 + 0,1,? + + 1,9223372036854775807,1 + 1,9223372036854775807,-1 + 1,-9223372036854775807,1 + 1,-9223372036854775807,-1 + 1,?,1 + 1,1,? + + 2,0,9223372036854775807 + 2,1,9223372036854775807 + 2,0,? + 2,9223372036854775807,0 + 2,9223372036854775807,1 + 2,?,0 + 2,-1,9223372036854775807 + 2,3000000000,4000000000 + 2,8000000000,2000000000 + 2,4294967296,4294967296 + 2,2000000000,8000000000 + 2,4294967296,2147483647 + 2,4294967296,2147483648 + 2,2147483647,4294967296 + 2,-2147483647,4294967296 + 2,2147483647,-4294967296 + 2,-2147483647,-4294967296 + 2,2147483648,4294967296 + + 3,?,3 + 3,9223372036854775807,4294967296 + 3,-9223372036854775807,4294967296 + 3,9223372036854775807,-4294967296 + 3,-9223372036854775807,-4294967296 + + 4,?,3 + 4,37,5 + 4,37,-5 + 4,-37,-5 + 4,-37,5 + + 5,?,5 + 5,5,? + 5,1,2000000000 + 5,1,-2000000000 + 5,-1,2000000000 + 5,-1,-2000000000 + 5,-1,2000000001 + 5,-1,-2000000001 + 5,2000000000,0 + 5,-2000000000,1 + 5,2000000000,? + 5,2,29 + 5,-2,29 + 5,2,30 + 5,-2,30 + 5,2,31 + 5,-2,31 + 5,2,61 + 5,-2,61 + 5,2,62 + 5,-2,62 + 5,2097151,3 +$ +I4,R4,R4: +(s,x,y) => + s == 0 ? x + y : + s == 1 ? x - y : + s == 2 ? x * y : + s == 3 ? x / y : + s == 4 ? x % y : + s == 5 ? x ^ y : + -1 +# + 0,1,2 + 1,5,3 + 2,-12,5 + 3,-12,5 + 4,37,5 + 4,-37,5 + 4,-37,-5 + 4,37,-5 + 5,10,100 +$ +I4,R8,R8: +(s,x,y) => + s == 0 ? x + y : + s == 1 ? x - y : + s == 2 ? x * y : + s == 3 ? x / y : + s == 4 ? x % y : + s == 5 ? x ^ y : + -1 +# + 0,1,2 + 1,5,3 + 2,-12,5 + 3,-12,5 + 4,37,5 + 4,-37,5 + 4,-37,-5 + 4,37,-5 + 5,10,100 + 5,10,1000 +$ +I4: x => true ? x : x - 1 +# + 3 +$ +I4: x => false ? x : x - 1 +# + 3 +$ +I4: x => 0.0/0 == 1 ? x : x - 1 +# + 3 +$ +BL,BL: (x,y) => x == y +# + true,true + true,false + true,? + ?,false +$ +BL,BL: (x,y) => x != y +# + true,true + true,false + true,? + ?,false +$ +I4,I4: (x,y) => x <= y +# + 0,0 + 0,1 + 1,0 + 0,? + ?,1 +$ +R4,R4: (x,y) => x != y != 3 +# + 0,0 + 0,1 + 1,0 + 3,0 + 0,3 + 0,? + ?,1 +$ +R4,R4: (x,y) => x <= y < 3 +# + 0,0 + 0,1 + 1,0 + 3,0 + 0,3 + 0,? + ?,1 +$ +R8,R4: (x,y) => 3 >= x > y +# + 0,0 + 0,1 + 1,0 + 3,0 + 0,3 + 4,0 + 0,? + ?,1 +$ +R4: x => log(x) +# + 1 + 2 + 0 + 1e100 + ? +$ +R8: x => log(x) +# + 1 + 2 + 0 + 1e100 + 1e1000 + ? +$ +R4,R4: (x,y) => log(x, y) +# + 1,2 + 2,2 + 0,2 + 1024,2 + 1024,0.5 + 1e100,2 + ?,2 + 1024,? +$ +R8,R8: (x,y) => log(x, y) +# + 1,2 + 2,2 + 0,2 + 1024,2 + 1024,0.5 + 1e100,2 + 1e1000,2 + ?,2 + 1024,? +$ +I4,I8,R4,R8: +(a,b,c,d) => abs(a) + abs(b) + abs(c) + abs(d) +# + 1,0,0,0 + -1,0,0,0 + ?,0,0,0 + 0, 2,0,0 + 0,-2,0,0 + 0, ?,0,0 + 0,0, 3,0 + 0,0,-3,0 + 0,0, ?,0 + 0,0,0, 4 + 0,0,0,-4 + 0,0,0, ? +$ +BL,I4,I8,R4,R8: +(a,b,c,d,e) => int(a) + int(b) + int(c) + int(d) + int(e) +# + 0,0,0,0,0 + 1,0,0,0,0 + ?,0,0,0,0 + 0, 2,0,0,0 + 0,-2,0,0,0 + 0, ?,0,0,0 + 0,0, 3,0,0 + 0,0,-3,0,0 + 0,0, ?,0,0 + 0,0,2147483647,0,0 + 0,0,-2147483647,0,0 + 0,0,0, 4,0 + 0,0,0,-4,0 + 0,0,0,2147483520,0 + 0,0,0,-2147483520,0 + 0,0,0,0, 5 + 0,0,0,0,-5 + 0,0,0,0,2147483647 + 0,0,0,0,-2147483647 +$ +BL,I4,I8,R4,R8: +(a,b,c,d,e) => long(a) + long(b) + long(c) + long(d) + long(e) +# + 0,0,0,0,0 + 1,0,0,0,0 + ?,0,0,0,0 + 0, 2,0,0,0 + 0,-2,0,0,0 + 0, ?,0,0,0 + 0,0, 3,0,0 + 0,0,-3,0,0 + 0,0, ?,0,0 + 0,0,9223372036854775807,0,0 + 0,0,-9223372036854775807,0,0 + 0,0,0, 4,0 + 0,0,0,-4,0 + 0,0,0,9223371487098961920,0 + 0,0,0,-9223371487098961920,0 + 0,0,0,0, 5 + 0,0,0,0,-5 + 0,0,0,0,9223372036854774784 + 0,0,0,0,-9223372036854774784 +$ +BL,I4,I8,R4,R8: +(a,b,c,d,e) => single(a) + single(b) + single(c) + single(d) + single(e) +# + 0,0,0,0,0 + 1,0,0,0,0 + ?,0,0,0,0 + 0, 2,0,0,0 + 0,-2,0,0,0 + 0, ?,0,0,0 + 0,0, 3,0,0 + 0,0,-3,0,0 + 0,0, ?,0,0 + 0,0,9223372036854775807,0,0 + 0,0,-9223372036854775807,0,0 + 0,0,0, 4,0 + 0,0,0,-4,0 + 0,0,0, ?,0 + 0,0,0,9223371487098961920,0 + 0,0,0,9223371761976868864,0 + 0,0,0,1e100,0 + 0,0,0,-9223371487098961920,0 + 0,0,0,-9223371761976868864,0 + 0,0,0,-1e100,0 + 0,0,0,0, 5 + 0,0,0,0,-5 + 0,0,0,0, ? + 0,0,0,0,9223372036854774784 + 0,0,0,0,9223372036854775296 + 0,0,0,0,1e100 + 0,0,0,0,1e1000 + 0,0,0,0,-9223372036854774784 + 0,0,0,0,-9223372036854775296 + 0,0,0,0,-1e100 + 0,0,0,0,-1e1000 +$ +BL,I4,I8,R4,R8: +(a,b,c,d,e) => double(a) + double(b) + double(c) + double(d) + double(e) +# + 0,0,0,0,0 + 1,0,0,0,0 + ?,0,0,0,0 + 0, 2,0,0,0 + 0,-2,0,0,0 + 0, ?,0,0,0 + 0,0, 3,0,0 + 0,0,-3,0,0 + 0,0, ?,0,0 + 0,0,9223372036854775807,0,0 + 0,0,-9223372036854775807,0,0 + 0,0,0, 4,0 + 0,0,0,-4,0 + 0,0,0, ?,0 + 0,0,0,9223371487098961920,0 + 0,0,0,9223371761976868864,0 + 0,0,0,1e100,0 + 0,0,0,-9223371487098961920,0 + 0,0,0,-9223371761976868864,0 + 0,0,0,-1e100,0 + 0,0,0,0, 5 + 0,0,0,0,-5 + 0,0,0,0, ? + 0,0,0,0,9223372036854774784 + 0,0,0,0,9223372036854775296 + 0,0,0,0,1e100 + 0,0,0,0,1e1000 + 0,0,0,0,-9223372036854774784 + 0,0,0,0,-9223372036854775296 + 0,0,0,0,-1e100 + 0,0,0,0,-1e1000 +$ +BL: x => isna(x) +# + false + true + ? +$ +I8,I8: (x,y) => x <= y < 3 +# + 0,0 + 0,1 + 1,0 + 3,0 + 0,3 + 0,? + ?,1 +$ +BL,BL,BL: (a,b,c) => a == b == c +# + 0,0,0 + 0,0,1 + 0,1,0 + 0,1,1 + 1,0,0 + 1,0,1 + 1,1,0 + 1,1,1 + 0,0,? + 0,?,0 + ?,0,0 +$ +BL,BL,BL: (a,b,c) => a != b != c +# + 0,0,0 + 0,0,1 + 0,1,0 + 0,1,1 + 1,0,0 + 1,0,1 + 1,1,0 + 1,1,1 + 0,0,? + 0,?,0 + ?,0,0 +$ +TX,TX: +(x,y) => + ((x == y) ?? false) ? "EQ" : + ((x != y) ?? false) ? "NE" : + "NA" +# + A,A + A,B + A,_ + _,B + _,_ +$ +I4,I8,R4,R8,BL,TX: +(a,b,c,d,e,f) => + 1000000 + + 100000 * int(isna(a)) + + 10000 * int(isna(b)) + + 1000 * int(isna(c)) + + 100 * int(isna(d)) + + 10 * int(isna(e)) + + 1 * int(isna(f)) +# + 1,2,3,4,1,X + 1,?,3,?,1,_ + ?,2,?,4,?,X + ?,?,?,?,?,_ +$ +I4,I4: +(x,y) => _dump("X", x) ?? _dump("Y", y) +# + 1,2 + 1,? + ?,2 + ?,? +$ +I4,I4: +(x,y) => with(z = _dump(" Eval[z]: {0}", x * y); x > 0 ? z : -z) +# + 3, 5 + -3, 5 + 3,-5 + -3,-5 + ?, 5 + ?,-5 + 3, ? + -3, ? + ?, ? +$ +I4,I4: +(s,x) => + with( + y = _dump(" Eval[y]: {0}", 2 * x), + z = _dump(" Eval[z]: {0}", 3 * x); + s == 0 ? x * x : + s == 1 ? y * y : + z * z + ) +# + 0,5 + 1,5 + 2,5 + ?,5 +$ +I4,I4: +(s,x) => + with( + y = _dump(" Eval[y]: {0}", 2 * x), + z = _dump(" Eval[z]: {0}", 3 * y); + s == 0 ? x * x : + s == 1 ? y * y : + z * z + ) +# + 0,5 + 1,5 + 2,5 + ?,5 +$ +I4: +a => with(b=_dump("B", a+a), + c=b+b, d=c+c, e=d+d, f=e+e, g=f+f, h=g+g, i=h+h, j=i+i, k=j+j, l=k+k, m=l+l, n=m+m, + o=n+n, p=o+o, q=p+p, r=q+q, s=r+r, t=s+s, u=t+t, v=u+u, w=v+v, x=w+w, y=x+x, z=y+y; + z) +# + 0 + 1 + -2 + 3 + ? +$ +I4: +a => with(b=_dump("B", a+a); + b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+ + b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+ + b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+ + b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+ + b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b) +# + 0 + 1 + -2 + 3 + ? +$ +TX,I4,I4: +(t,i,j) => + concat(left(t,i) ?? "?", "|", + mid(t,i,j) ?? "?", "|", + right(t,j) ?? "?") +# + hello,1,3 + hello,1,10 + hello,1,-10 + hello,-4,-1 + hello,-4000,-1 + _,1,3 + hello,?,3 + hello,1,? + ,1,3 + ,-3,-1 + ,-4000,1 +$ +R4: x => x < 3 <= 5 +# + -1 + 3 + ? +$ +R4: x => 3f <= x < 5f +# + -1 + 3 + ? +$ +TX: x => "hi" == x == "bye" +# + hi + bye + _ +$ +TX: x => "hi" != x != "bye" +# + hi + bye + hola + _ +$ +R4: x => 3f <= x < na(x) +# + -1 + 3 + ? +$ +TX: x => "hi" != x != na(x) +# + hi + bye + ? +$ +BL: x => x == true +# + 0 + 1 + ? +$ +I8: x => x ?? 17 +# + -1 + 3 + ? +$ +R8: x => x ?? 17 +# + -1 + 3 + ? +$ +R8: x => x != 17 +# + -1 + 17 + ? +$ +R8: x => x < 17 +# + -1 + 17 + 18 + ? +$ +R8: x => x <= 17 +# + -1 + 17 + 18 + ? +$ +R8: x => x >= 17 +# + -1 + 17 + 18 + ? +$ +R8: x => x > 17 +# + -1 + 17 + 18 + ? +$ +I8,I8: (x,y) => x == y == 17 +# + 1,17 + 17,1 + 17,17 + ?,17 + 17,? + ?,? +$ +R8,R8: (x,y) => x == y == 17 +# + 1,17 + 17,1 + 17,17 + ?,17 + 17,? + ?,? +$ +TX: x => long(x) +# + 3 + -12 + _ +$ +TX: x => single(x) +# + 3 + -12.5 + xyz + _ +$ +TX: x => double(x) +# + 3 + -12.5 + xyz + _ +$ +R8: x => x < 3 < 5 < x + 17 < na(x) < 4 * x < x^1000 +# + 1 + -13 + 4 + ? +$ +I4: x => x >= 17 +# + -1 + 17 + 18 + ? +$ +I4: x => x > 17 +# + -1 + 17 + 18 + ? +$ diff --git a/test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprEvalInput.txt b/test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprEvalInput.txt new file mode 100644 index 0000000000..46835e058a --- /dev/null +++ b/test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprEvalInput.txt @@ -0,0 +1,485 @@ +BL,BL: +(x,y) => x or y +# + 0,0 + 0,1 + 1,0 + 1,1 + ?,0 + ?,1 + 0,? + 1,? + ?,? +$ +I4: s => + 9000000000 + + 100000000 * (float(false or false ) ?? 2) + + 10000000 * (float(false or true ) ?? 2) + + 1000000 * (float(true or false ) ?? 2) + + 100000 * (float(true or true ) ?? 2) + + 10000 * (float((0.0/0==1) or false ) ?? 2) + + 1000 * (float((0.0/0==1) or true ) ?? 2) + + 100 * (float(false or (0.0/0==1)) ?? 2) + + 10 * (float(true or (0.0/0==1)) ?? 2) + + 1 * (float((0.0/0==1) or (0.0/0==1)) ?? 2) + + 0 +# + 0 +$ +BL,BL: +(x,y) => x and y +# + 0,0 + 0,1 + 1,0 + 1,1 + ?,0 + ?,1 + 0,? + 1,? + ?,? +$ +I4: s => + 9000000000 + + 100000000 * (float(false and false ) ?? 2) + + 10000000 * (float(false and true ) ?? 2) + + 1000000 * (float(true and false ) ?? 2) + + 100000 * (float(true and true ) ?? 2) + + 10000 * (float((0.0/0==1) and false ) ?? 2) + + 1000 * (float((0.0/0==1) and true ) ?? 2) + + 100 * (float(false and (0.0/0==1)) ?? 2) + + 10 * (float(true and (0.0/0==1)) ?? 2) + + 1 * (float((0.0/0==1) and (0.0/0==1)) ?? 2) + + 0 +# + 0 +$ +BL,BL: +(x,y) => x == y +# + 0,0 + 0,1 + 1,0 + 1,1 + ?,0 + ?,1 + 0,? + 1,? + ?,? +$ +I4: s => + 9000000000 + + 100000000 * (float(false == false ) ?? 2) + + 10000000 * (float(false == true ) ?? 2) + + 1000000 * (float(true == false ) ?? 2) + + 100000 * (float(true == true ) ?? 2) + + 10000 * (float((0.0/0==1) == false ) ?? 2) + + 1000 * (float((0.0/0==1) == true ) ?? 2) + + 100 * (float(false == (0.0/0==1)) ?? 2) + + 10 * (float(true == (0.0/0==1)) ?? 2) + + 1 * (float((0.0/0==1) == (0.0/0==1)) ?? 2) + + 0 +# + 0 +$ +BL,BL: +(x,y) => x != y +# + 0,0 + 0,1 + 1,0 + 1,1 + ?,0 + ?,1 + 0,? + 1,? + ?,? +$ +I4: s => + 9000000000 + + 100000000 * (float(false != false ) ?? 2) + + 10000000 * (float(false != true ) ?? 2) + + 1000000 * (float(true != false ) ?? 2) + + 100000 * (float(true != true ) ?? 2) + + 10000 * (float((0.0/0==1) != false ) ?? 2) + + 1000 * (float((0.0/0==1) != true ) ?? 2) + + 100 * (float(false != (0.0/0==1)) ?? 2) + + 10 * (float(true != (0.0/0==1)) ?? 2) + + 1 * (float((0.0/0==1) != (0.0/0==1)) ?? 2) + + 0 +# + 0 +$ + +I4: s => + 9000000000 + + 100000000 * (float(0 == 0 ) ?? 2) + + 10000000 * (float(0 == 1 ) ?? 2) + + 1000000 * (float(1 == 0 ) ?? 2) + + 100000 * (float(1 == 1 ) ?? 2) + + 10000 * (float(0.0/0 == 0 ) ?? 2) + + 1000 * (float(0.0/0 == 1 ) ?? 2) + + 100 * (float(0 == 0.0/0) ?? 2) + + 10 * (float(1 == 0.0/0) ?? 2) + + 1 * (float(0.0/0 == 0.0/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0 != 0 ) ?? 2) + + 10000000 * (float(0 != 1 ) ?? 2) + + 1000000 * (float(1 != 0 ) ?? 2) + + 100000 * (float(1 != 1 ) ?? 2) + + 10000 * (float(0.0/0 != 0 ) ?? 2) + + 1000 * (float(0.0/0 != 1 ) ?? 2) + + 100 * (float(0 != 0.0/0) ?? 2) + + 10 * (float(1 != 0.0/0) ?? 2) + + 1 * (float(0.0/0 != 0.0/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0 < 0 ) ?? 2) + + 10000000 * (float(0 < 1 ) ?? 2) + + 1000000 * (float(1 < 0 ) ?? 2) + + 100000 * (float(1 < 1 ) ?? 2) + + 10000 * (float(0.0/0 < 0 ) ?? 2) + + 1000 * (float(0.0/0 < 1 ) ?? 2) + + 100 * (float(0 < 0.0/0) ?? 2) + + 10 * (float(1 < 0.0/0) ?? 2) + + 1 * (float(0.0/0 < 0.0/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0 <= 0 ) ?? 2) + + 10000000 * (float(0 <= 1 ) ?? 2) + + 1000000 * (float(1 <= 0 ) ?? 2) + + 100000 * (float(1 <= 1 ) ?? 2) + + 10000 * (float(0.0/0 <= 0 ) ?? 2) + + 1000 * (float(0.0/0 <= 1 ) ?? 2) + + 100 * (float(0 <= 0.0/0) ?? 2) + + 10 * (float(1 <= 0.0/0) ?? 2) + + 1 * (float(0.0/0 <= 0.0/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0 >= 0 ) ?? 2) + + 10000000 * (float(0 >= 1 ) ?? 2) + + 1000000 * (float(1 >= 0 ) ?? 2) + + 100000 * (float(1 >= 1 ) ?? 2) + + 10000 * (float(0.0/0 >= 0 ) ?? 2) + + 1000 * (float(0.0/0 >= 1 ) ?? 2) + + 100 * (float(0 >= 0.0/0) ?? 2) + + 10 * (float(1 >= 0.0/0) ?? 2) + + 1 * (float(0.0/0 >= 0.0/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0 > 0 ) ?? 2) + + 10000000 * (float(0 > 1 ) ?? 2) + + 1000000 * (float(1 > 0 ) ?? 2) + + 100000 * (float(1 > 1 ) ?? 2) + + 10000 * (float(0.0/0 > 0 ) ?? 2) + + 1000 * (float(0.0/0 > 1 ) ?? 2) + + 100 * (float(0 > 0.0/0) ?? 2) + + 10 * (float(1 > 0.0/0) ?? 2) + + 1 * (float(0.0/0 > 0.0/0) ?? 2) + + 0 +# + 0 +$ + +I4: s => + 9000000000 + + 100000000 * (float(0L == 0L ) ?? 2) + + 10000000 * (float(0L == 1L ) ?? 2) + + 1000000 * (float(1L == 0L ) ?? 2) + + 100000 * (float(1L == 1L ) ?? 2) + + 10000 * (float(0.0/0 == 0L ) ?? 2) + + 1000 * (float(0.0/0 == 1L ) ?? 2) + + 100 * (float(0L == 0.0/0) ?? 2) + + 10 * (float(1L == 0.0/0) ?? 2) + + 1 * (float(0.0/0 == 0.0/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0L != 0L ) ?? 2) + + 10000000 * (float(0L != 1L ) ?? 2) + + 1000000 * (float(1L != 0L ) ?? 2) + + 100000 * (float(1L != 1L ) ?? 2) + + 10000 * (float(0.0/0 != 0L ) ?? 2) + + 1000 * (float(0.0/0 != 1L ) ?? 2) + + 100 * (float(0L != 0.0/0) ?? 2) + + 10 * (float(1L != 0.0/0) ?? 2) + + 1 * (float(0.0/0 != 0.0/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0L < 0L ) ?? 2) + + 10000000 * (float(0L < 1L ) ?? 2) + + 1000000 * (float(1L < 0L ) ?? 2) + + 100000 * (float(1L < 1L ) ?? 2) + + 10000 * (float(0.0/0 < 0L ) ?? 2) + + 1000 * (float(0.0/0 < 1L ) ?? 2) + + 100 * (float(0L < 0.0/0) ?? 2) + + 10 * (float(1L < 0.0/0) ?? 2) + + 1 * (float(0.0/0 < 0.0/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0L <= 0L ) ?? 2) + + 10000000 * (float(0L <= 1L ) ?? 2) + + 1000000 * (float(1L <= 0L ) ?? 2) + + 100000 * (float(1L <= 1L ) ?? 2) + + 10000 * (float(0.0/0 <= 0L ) ?? 2) + + 1000 * (float(0.0/0 <= 1L ) ?? 2) + + 100 * (float(0L <= 0.0/0) ?? 2) + + 10 * (float(1L <= 0.0/0) ?? 2) + + 1 * (float(0.0/0 <= 0.0/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0L >= 0L ) ?? 2) + + 10000000 * (float(0L >= 1L ) ?? 2) + + 1000000 * (float(1L >= 0L ) ?? 2) + + 100000 * (float(1L >= 1L ) ?? 2) + + 10000 * (float(0.0/0 >= 0L ) ?? 2) + + 1000 * (float(0.0/0 >= 1L ) ?? 2) + + 100 * (float(0L >= 0.0/0) ?? 2) + + 10 * (float(1L >= 0.0/0) ?? 2) + + 1 * (float(0.0/0 >= 0.0/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0L > 0L ) ?? 2) + + 10000000 * (float(0L > 1L ) ?? 2) + + 1000000 * (float(1L > 0L ) ?? 2) + + 100000 * (float(1L > 1L ) ?? 2) + + 10000 * (float(0.0/0 > 0L ) ?? 2) + + 1000 * (float(0.0/0 > 1L ) ?? 2) + + 100 * (float(0L > 0.0/0) ?? 2) + + 10 * (float(1L > 0.0/0) ?? 2) + + 1 * (float(0.0/0 > 0.0/0) ?? 2) + + 0 +# + 0 +$ + +I4: s => + 9000000000 + + 100000000 * (float(0F == 0F ) ?? 2) + + 10000000 * (float(0F == 1F ) ?? 2) + + 1000000 * (float(1F == 0F ) ?? 2) + + 100000 * (float(1F == 1F ) ?? 2) + + 10000 * (float(0F/0 == 0F ) ?? 2) + + 1000 * (float(0F/0 == 1F ) ?? 2) + + 100 * (float(0F == 0F/0) ?? 2) + + 10 * (float(1F == 0F/0) ?? 2) + + 1 * (float(0F/0 == 0F/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0F != 0F ) ?? 2) + + 10000000 * (float(0F != 1F ) ?? 2) + + 1000000 * (float(1F != 0F ) ?? 2) + + 100000 * (float(1F != 1F ) ?? 2) + + 10000 * (float(0F/0 != 0F ) ?? 2) + + 1000 * (float(0F/0 != 1F ) ?? 2) + + 100 * (float(0F != 0F/0) ?? 2) + + 10 * (float(1F != 0F/0) ?? 2) + + 1 * (float(0F/0 != 0F/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0F < 0F ) ?? 2) + + 10000000 * (float(0F < 1F ) ?? 2) + + 1000000 * (float(1F < 0F ) ?? 2) + + 100000 * (float(1F < 1F ) ?? 2) + + 10000 * (float(0F/0 < 0F ) ?? 2) + + 1000 * (float(0F/0 < 1F ) ?? 2) + + 100 * (float(0F < 0F/0) ?? 2) + + 10 * (float(1F < 0F/0) ?? 2) + + 1 * (float(0F/0 < 0F/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0F <= 0F ) ?? 2) + + 10000000 * (float(0F <= 1F ) ?? 2) + + 1000000 * (float(1F <= 0F ) ?? 2) + + 100000 * (float(1F <= 1F ) ?? 2) + + 10000 * (float(0F/0 <= 0F ) ?? 2) + + 1000 * (float(0F/0 <= 1F ) ?? 2) + + 100 * (float(0F <= 0F/0) ?? 2) + + 10 * (float(1F <= 0F/0) ?? 2) + + 1 * (float(0F/0 <= 0F/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0F >= 0F ) ?? 2) + + 10000000 * (float(0F >= 1F ) ?? 2) + + 1000000 * (float(1F >= 0F ) ?? 2) + + 100000 * (float(1F >= 1F ) ?? 2) + + 10000 * (float(0F/0 >= 0F ) ?? 2) + + 1000 * (float(0F/0 >= 1F ) ?? 2) + + 100 * (float(0F >= 0F/0) ?? 2) + + 10 * (float(1F >= 0F/0) ?? 2) + + 1 * (float(0F/0 >= 0F/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0F > 0F ) ?? 2) + + 10000000 * (float(0F > 1F ) ?? 2) + + 1000000 * (float(1F > 0F ) ?? 2) + + 100000 * (float(1F > 1F ) ?? 2) + + 10000 * (float(0F/0 > 0F ) ?? 2) + + 1000 * (float(0F/0 > 1F ) ?? 2) + + 100 * (float(0F > 0F/0) ?? 2) + + 10 * (float(1F > 0F/0) ?? 2) + + 1 * (float(0F/0 > 0F/0) ?? 2) + + 0 +# + 0 +$ + +I4: s => + 9000000000 + + 100000000 * (float(0D == 0D ) ?? 2) + + 10000000 * (float(0D == 1D ) ?? 2) + + 1000000 * (float(1D == 0D ) ?? 2) + + 100000 * (float(1D == 1D ) ?? 2) + + 10000 * (float(0D/0 == 0D ) ?? 2) + + 1000 * (float(0D/0 == 1D ) ?? 2) + + 100 * (float(0D == 0D/0) ?? 2) + + 10 * (float(1D == 0D/0) ?? 2) + + 1 * (float(0D/0 == 0D/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0D != 0D ) ?? 2) + + 10000000 * (float(0D != 1D ) ?? 2) + + 1000000 * (float(1D != 0D ) ?? 2) + + 100000 * (float(1D != 1D ) ?? 2) + + 10000 * (float(0D/0 != 0D ) ?? 2) + + 1000 * (float(0D/0 != 1D ) ?? 2) + + 100 * (float(0D != 0D/0) ?? 2) + + 10 * (float(1D != 0D/0) ?? 2) + + 1 * (float(0D/0 != 0D/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0D < 0D ) ?? 2) + + 10000000 * (float(0D < 1D ) ?? 2) + + 1000000 * (float(1D < 0D ) ?? 2) + + 100000 * (float(1D < 1D ) ?? 2) + + 10000 * (float(0D/0 < 0D ) ?? 2) + + 1000 * (float(0D/0 < 1D ) ?? 2) + + 100 * (float(0D < 0D/0) ?? 2) + + 10 * (float(1D < 0D/0) ?? 2) + + 1 * (float(0D/0 < 0D/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0D <= 0D ) ?? 2) + + 10000000 * (float(0D <= 1D ) ?? 2) + + 1000000 * (float(1D <= 0D ) ?? 2) + + 100000 * (float(1D <= 1D ) ?? 2) + + 10000 * (float(0D/0 <= 0D ) ?? 2) + + 1000 * (float(0D/0 <= 1D ) ?? 2) + + 100 * (float(0D <= 0D/0) ?? 2) + + 10 * (float(1D <= 0D/0) ?? 2) + + 1 * (float(0D/0 <= 0D/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0D >= 0D ) ?? 2) + + 10000000 * (float(0D >= 1D ) ?? 2) + + 1000000 * (float(1D >= 0D ) ?? 2) + + 100000 * (float(1D >= 1D ) ?? 2) + + 10000 * (float(0D/0 >= 0D ) ?? 2) + + 1000 * (float(0D/0 >= 1D ) ?? 2) + + 100 * (float(0D >= 0D/0) ?? 2) + + 10 * (float(1D >= 0D/0) ?? 2) + + 1 * (float(0D/0 >= 0D/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000000000 + + 100000000 * (float(0D > 0D ) ?? 2) + + 10000000 * (float(0D > 1D ) ?? 2) + + 1000000 * (float(1D > 0D ) ?? 2) + + 100000 * (float(1D > 1D ) ?? 2) + + 10000 * (float(0D/0 > 0D ) ?? 2) + + 1000 * (float(0D/0 > 1D ) ?? 2) + + 100 * (float(0D > 0D/0) ?? 2) + + 10 * (float(1D > 0D/0) ?? 2) + + 1 * (float(0D/0 > 0D/0) ?? 2) + + 0 +# + 0 +$ +I4: s => + 9000 + + 100 * (float(!false ) ?? 2) + + 10 * (float(!true ) ?? 2) + + 1 * (float(!(0.0/0==1)) ?? 2) + + 0 +# + 0 +$ diff --git a/test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprParseInput.txt b/test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprParseInput.txt new file mode 100644 index 0000000000..16edd864c5 --- /dev/null +++ b/test/Microsoft.ML.Tests/ExpressionLanguageTests/TestData/ExprParseInput.txt @@ -0,0 +1,240 @@ +I4: // Basic +x => x + 1 +# + 3 + 5 + -2 + ? + 2147483647 + -2147483647 +$ +I8: // Basic +x => x + 1 +# + 3 + 5 + -2 + ? + 9223372036854775807 + -9223372036854775807 +$ +R4: // Basic +x => x + 1 +# + 3 + 5.25 + -2.5 + ? + 1e30 +$ +R8: // Basic +x => x + 1 +# + 3 + 5.25 + -2.5 + ? + 1e30 +$ +R4: +x => 10 ^ x +# + 2 + 0.5 + ? + 30 +$ +R8: +x => 10 ^ x +# + 2 + 0.5 + ? + 30 +$ +I4: // Expected EOF +x => x + 1 foo +$ +I4: // A bogus token +x => "hello +$ +I4: x => 3 /* Unterminated comment +$ +I4: // Operator expected +x => 3 x +$ +I4: x => 1 < x >= -7 +$ +I4: // TokEat +x : abs(-x +$ +I4: // ParseParam +( ) => 123 +$ +I4: x 123 +$ +I4: (x) 123 +$ +I4: x => 5 * (x + 2 +$ +I8: // Overflow +x => 9223372036854775808 +$ +I4: // Missing primary +x : 3 * + x +$ +I4: // Empty list +x => abs() + + // Multiple list items + abs(-3, true) +$ +I4: // Peek past comment +x => abs /*comment*/ ( /*comment*/ -x /*comment*/ ) +# + 3 + -3 + ? +$ +I4: // Peek past newline +x => abs +( +-12 +) +# + 3 + ? +$ +I4: // Operator expected +x => 0 true +$ +I4: // Stringize ident +x => x > 0 ? 3 xyz +$ +I4,I4: // Multiple args +(x,y) => x + y +# + 3,5 + 5,3 + ?,5 + 3,? + 2000000000,147483647 + 2000000000,147483648 + 147483648,2000000000 + -2000000000,-147483647 + -2000000000,-147483648 + -147483648,-2000000000 +$ +I4,I4: // Too many params +(x,y,z) => x + y + z +$ +I4,I4,I4: // Too few params +(x,y) => x + y +$ +I4,I4,I4,I4: +(a,b,c,d) => a + b * c / d +# + -1,3,4,2 + -1,3,4,5 +$ +I4,I4,I4,I4: +(a,b,c,d) => a + b ^ c * d +# + -1,3,4,2 + -1,3,4,5 +$ +I4,I4,I4,I4: +(a,b,c,d) => a + b ^ c % d +# + -1,3,4,13 + -1,3,4,7 +$ +I4,I4,I4,I4: +(a,b,c,d) => a + b ^ c - d +# + -1,3,4,2 + -1,3,4,5 +$ +I4,I4,I4,I4: +(a,b,c,d) => a + 2 == b || b + 2 != c && c - 2 < d +# + -1,3,4,2 + -1,3,4,5 +$ +I4: // NA +x => single(x - 5) ?? 3 +# + ? + 2 + NA +$ +I4: // not +x => not (x == 3) +# + ? + 7 + 3 +$ +I4: // CharLit - error +x => x == 'x' +$ +I4: x => with(y = x; y) +# + 0 + 17 + -2 + ? +$ +I4: x => with y = x; y) +$ +I4: x => with( = x; y) +$ +I4: x => with(y x; y) +$ +I4: x => with(y = ; y) +$ +I4: x => with(y = x y) +$ +I4: x => with(y = x; ) +$ +I4: x => with(y = x; y +$ +I4: x => with(y = x + 1, z = y + 1; z) +# + 0 + 17 + -2 + ? +$ +I4: +x => with(y = x, z = x + 1; concat(text(x)??"?", "|", text(y)??"?", "|", text(z)??"?")) +# + 0 + 17 + -2 + ? +$ +BL: x => false || x; +$ +I4: +x => global.sign(x) +# + -17 + 0 + 12 + ? +$ +I4: +x => global.x +$ +TX: x => left(_chars(concat(x, "A\nB", x)), 2) +# + X +$ +TX: x => right(_chars(concat(x, "A\rB", x)), -2) +# + X +$ +TX: x => left(_chars(concat(x, "A\r\nB", x)), 2) +# + X +$ diff --git a/test/Microsoft.ML.Tests/Microsoft.ML.Tests.csproj b/test/Microsoft.ML.Tests/Microsoft.ML.Tests.csproj index 1c28480f50..cd61ad45ed 100644 --- a/test/Microsoft.ML.Tests/Microsoft.ML.Tests.csproj +++ b/test/Microsoft.ML.Tests/Microsoft.ML.Tests.csproj @@ -50,4 +50,12 @@ + + + + + + + + diff --git a/test/Microsoft.ML.Tests/Transformers/ExpressionTransformerTests.cs b/test/Microsoft.ML.Tests/Transformers/ExpressionTransformerTests.cs new file mode 100644 index 0000000000..b6792c0089 --- /dev/null +++ b/test/Microsoft.ML.Tests/Transformers/ExpressionTransformerTests.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.ML.Data; +using Microsoft.ML.RunTests; +using Microsoft.ML.Transforms; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.ML.Tests.Transformers +{ + public sealed class ExpressionTransformerTests : TestDataPipeBase + { + public ExpressionTransformerTests(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void TestExpressionTransformer() + { + string dataPath = GetDataPath("adult.tiny.with-schema.txt"); + + var loader = new TextLoader(ML, new TextLoader.Options + { + Columns = new[]{ + new TextLoader.Column("Float", DataKind.Single, 9), + new TextLoader.Column("FloatVector", DataKind.Single, 9, 14), + new TextLoader.Column("Double", DataKind.Double, 9), + new TextLoader.Column("DoubleVector", DataKind.Double, 9, 14), + new TextLoader.Column("Int", DataKind.Int32, 9), + new TextLoader.Column("IntVector", DataKind.Int32, 9, 14), + new TextLoader.Column("Text", DataKind.String, 1), + new TextLoader.Column("TextVector", DataKind.String, 2, 8), + }, + Separator = "\t", + HasHeader = true + }, new MultiFileSource(dataPath)); + + var expr = ML.Transforms.Expression("Expr1", "x=>x/2", "Double"). + Append(ML.Transforms.Expression("Expr2", "(x,y)=>(x+y)/3", "Float", "FloatVector")). + Append(ML.Transforms.Expression("Expr3", "(x,y)=>x*y", "Float", "Int")). + Append(ML.Transforms.Expression("Expr4", "(x,y,z)=>abs(x-y)*z", "Float", "FloatVector", "Double")). + Append(ML.Transforms.Expression("Expr5", "x=>len(concat(upper(x),lower(x)))", "Text")). + Append(ML.Transforms.Expression("Expr6", "(x,y)=>right(x,y)", "TextVector", "Int")); + + TestEstimatorCore(expr, loader.Load(dataPath)); + + var transformed = expr.Fit(loader.Load(dataPath)).Transform(loader.Load(dataPath)); + Assert.True(transformed.Schema["Expr1"].Type == NumberDataViewType.Double); + Assert.Equal(6, transformed.Schema["Expr2"].Type.GetValueCount()); + Assert.True(transformed.Schema["Expr2"].Type.GetItemType() == NumberDataViewType.Single); + Assert.True(transformed.Schema["Expr3"].Type == NumberDataViewType.Single); + Assert.True(transformed.Schema["Expr4"].Type.GetItemType() == NumberDataViewType.Double); + Assert.Equal(6, transformed.Schema["Expr4"].Type.GetValueCount()); + Assert.True(transformed.Schema["Expr5"].Type == NumberDataViewType.Int32); + Assert.True(transformed.Schema["Expr6"].Type.GetItemType() == TextDataViewType.Instance); + Assert.Equal(7, transformed.Schema["Expr6"].Type.GetValueCount()); + } + } +}