diff --git a/docs/api/safeds/data/tabular/containers/Cell.md b/docs/api/safeds/data/tabular/containers/Cell.md index 76a8764b4..2c5534454 100644 --- a/docs/api/safeds/data/tabular/containers/Cell.md +++ b/docs/api/safeds/data/tabular/containers/Cell.md @@ -226,7 +226,7 @@ This class cannot be instantiated directly. It is only used for arguments of cal ) -> result: Cell /** - * Perform a modulo operation. + * Perform a modulo operation. This is equivalent to the `%` operator. * * @example * pipeline example { @@ -234,6 +234,13 @@ This class cannot be instantiated directly. It is only used for arguments of cal * val result = column.transform((cell) -> cell.mod(3)); * // Column("example", [2, 0]) * } + * + * @example + * pipeline example { + * val column = Column("example", [5, 6]); + * val result = column.transform((cell) -> cell % 3); + * // Column("example", [2, 0]) + * } */ @Pure fun mod( @@ -661,7 +668,7 @@ pipeline example { ??? quote "Stub code in `Cell.sdsstub`" - ```sds linenums="309" + ```sds linenums="316" @Pure fun eq( other: Any? @@ -730,7 +737,7 @@ pipeline example { ??? quote "Stub code in `Cell.sdsstub`" - ```sds linenums="353" + ```sds linenums="360" @Pure fun ge( other: union // TODO, once cell types can be inferred: union> @@ -772,7 +779,7 @@ pipeline example { ??? quote "Stub code in `Cell.sdsstub`" - ```sds linenums="375" + ```sds linenums="382" @Pure fun gt( other: union // TODO, once cell types can be inferred: union> @@ -814,7 +821,7 @@ pipeline example { ??? quote "Stub code in `Cell.sdsstub`" - ```sds linenums="397" + ```sds linenums="404" @Pure fun le( other: union // TODO, once cell types can be inferred: union> @@ -856,7 +863,7 @@ pipeline example { ??? quote "Stub code in `Cell.sdsstub`" - ```sds linenums="419" + ```sds linenums="426" @Pure fun lt( other: union // TODO, once cell types can be inferred: union> @@ -865,7 +872,7 @@ pipeline example { ## `mod` {#safeds.data.tabular.containers.Cell.mod data-toc-label='[function] mod'} -Perform a modulo operation. +Perform a modulo operation. This is equivalent to the `%` operator. **Parameters:** @@ -888,10 +895,17 @@ pipeline example { // Column("example", [2, 0]) } ``` +```sds +pipeline example { + val column = Column("example", [5, 6]); + val result = column.transform((cell) -> cell % 3); + // Column("example", [2, 0]) +} +``` ??? quote "Stub code in `Cell.sdsstub`" - ```sds linenums="228" + ```sds linenums="235" @Pure fun mod( other: union // TODO, once cell types can be inferred: union> @@ -933,7 +947,7 @@ pipeline example { ??? quote "Stub code in `Cell.sdsstub`" - ```sds linenums="250" + ```sds linenums="257" @Pure fun mul( other: union // TODO, once cell types can be inferred: union> @@ -1009,7 +1023,7 @@ pipeline example { ??? quote "Stub code in `Cell.sdsstub`" - ```sds linenums="331" + ```sds linenums="338" @Pure fun neq( other: Any? @@ -1122,7 +1136,7 @@ pipeline example { ??? quote "Stub code in `Cell.sdsstub`" - ```sds linenums="265" + ```sds linenums="272" @Pure fun pow( other: union // TODO, once cell types can be inferred: union> @@ -1164,7 +1178,7 @@ pipeline example { ??? quote "Stub code in `Cell.sdsstub`" - ```sds linenums="287" + ```sds linenums="294" @Pure fun ^sub( other: union // TODO, once cell types can be inferred: union> diff --git a/docs/pipeline-language/expressions/operations.md b/docs/pipeline-language/expressions/operations.md index 8db31ae45..364163224 100644 --- a/docs/pipeline-language/expressions/operations.md +++ b/docs/pipeline-language/expressions/operations.md @@ -18,6 +18,16 @@ The usual arithmetic operations are also supported for integers, floats and comb - Subtraction: `#!sds 6 - 2.9` (result is a float) - Multiplication: `#!sds 1.1 * 3` (result is a float) - Division: `#!sds 1.0 / 4.2` (result is a float) +- Modulo: `#!sds 5 % 2` (result is an integer) + +The `%` operator is well-known from other programming languages. However, there is no consensus on its result for negative operands. Safe-DS defines `n % d` as $n - \left\lfloor\frac{n}{d}\right\rfloor \cdot d$, where $\left\lfloor\text{ }\right\rfloor$ is the floor function (rounding down). The result always has the same sign as the divisor `d`. The following table shows some examples: + +| `n` | `d` | `n % d` | +|-----|-----|---------| +| 5 | 3 | 2 | +| 5 | -3 | -1 | +| -5 | 3 | 1 | +| -5 | -3 | -2 | Finally, two numbers can be compared, which results in a boolean. The integer `#!sds 3` for example is less than the integer `#!sds 5`. Safe-DS offers operators to do such checks for order: @@ -33,22 +43,22 @@ To work with logic, Safe-DS has the two boolean literals `#!sds false` and `#!sd - (Logical) **negation** (example `#!sds not a`): Output is `#!sds true` if and only if the operand is false: | `#!sds not a` | false | true | -|---------|-------|-------| -|   | true | false | +|---------------|-------|-------| +|   | true | false | - **Conjunction** (example `#!sds a and b`): Output is `#!sds true` if and only if both operands are `#!sds true`. Note that the second operand is always evaluated, even if the first operand is `#!sds false` and, thus, already determines the result of the expression. The operator is not short-circuited: | `#!sds a and b` | false | true | -|-----------|-------|-------| -| **false** | false | false | -| **true** | false | true | +|-----------------|-------|-------| +| **false** | false | false | +| **true** | false | true | - **Disjunction** (example `#!sds a or b`): Output is `#!sds true` if and only if at least one operand is `#!sds true`. Note that the second operand is always evaluated, even if the first operand is `#!sds true` and, thus, already determines the result of the expression. The operator is not short-circuited: -| `#!sds a or b` | false | true | -|-----------|-------|------| -| **false** | false | true | -| **true** | true | true | +| `#!sds a or b` | false | true | +|----------------|-------|------| +| **false** | false | true | +| **true** | true | true | ## Equality Checks diff --git a/docs/pipeline-language/expressions/precedence.md b/docs/pipeline-language/expressions/precedence.md index 1fe2aac7e..8f8bcca4e 100644 --- a/docs/pipeline-language/expressions/precedence.md +++ b/docs/pipeline-language/expressions/precedence.md @@ -9,7 +9,7 @@ We all know that `#!sds 2 + 3 * 7` is `#!sds 23` and not `#!sds 35`. The reason - `#!sds -` (unary, [arithmetic negations][operations-on-numbers]) - `#!sds as` ([type casts][type-casts]) - `#!sds ?:` ([Elvis operators][elvis-operator]) -- `#!sds *`, `#!sds /` ([multiplicative operators][operations-on-numbers]) +- `#!sds *`, `#!sds /`, `#!sds %` ([multiplicative operators][operations-on-numbers]) - `#!sds +`, `#!sds -` (binary, [additive operators][operations-on-numbers]) - `#!sds <`, `#!sds <=`, `#!sds >=`, `#!sds >` ([comparison operators][operations-on-numbers]) - `#!sds ===`, `#!sds ==`, `#!sds !==`, `#!sds !=` ([equality operators][equality-checks]) diff --git a/packages/safe-ds-lang/src/language/grammar/safe-ds.langium b/packages/safe-ds-lang/src/language/grammar/safe-ds.langium index c28cd5e9d..9566341a8 100644 --- a/packages/safe-ds-lang/src/language/grammar/safe-ds.langium +++ b/packages/safe-ds-lang/src/language/grammar/safe-ds.langium @@ -664,7 +664,7 @@ SdsMultiplicativeExpression returns SdsExpression: ; SdsMultiplicativeOperator returns string: - '*' | '/' + '*' | '/' | '%' ; SdsElvisExpression returns SdsExpression: diff --git a/packages/safe-ds-lang/src/language/partialEvaluation/safe-ds-partial-evaluator.ts b/packages/safe-ds-lang/src/language/partialEvaluation/safe-ds-partial-evaluator.ts index 19893dea7..1ec2f93cd 100644 --- a/packages/safe-ds-lang/src/language/partialEvaluation/safe-ds-partial-evaluator.ts +++ b/packages/safe-ds-lang/src/language/partialEvaluation/safe-ds-partial-evaluator.ts @@ -348,6 +348,18 @@ export class SafeDsPartialEvaluator { (leftOperand, rightOperand) => leftOperand / rightOperand, evaluatedRight, ); + case '%': + // Division by zero + if (zeroConstants.some((it) => it.equals(evaluatedRight))) { + return UnknownEvaluatedNode; + } + + return this.evaluateArithmeticOp( + evaluatedLeft, + (leftOperand, rightOperand) => ((leftOperand % rightOperand) + rightOperand) % rightOperand, + (leftOperand, rightOperand) => ((leftOperand % rightOperand) + rightOperand) % rightOperand, + evaluatedRight, + ); /* c8 ignore next 2 */ default: diff --git a/packages/safe-ds-lang/src/language/typing/safe-ds-type-computer.ts b/packages/safe-ds-lang/src/language/typing/safe-ds-type-computer.ts index 6eefcb5cb..2dddb674d 100644 --- a/packages/safe-ds-lang/src/language/typing/safe-ds-type-computer.ts +++ b/packages/safe-ds-lang/src/language/typing/safe-ds-type-computer.ts @@ -394,6 +394,7 @@ export class SafeDsTypeComputer { case '-': case '*': case '/': + case '%': return this.computeTypeOfArithmeticInfixOperation(node); // Elvis operator diff --git a/packages/safe-ds-lang/src/language/validation/types.ts b/packages/safe-ds-lang/src/language/validation/types.ts index 869e99185..df0b8aef1 100644 --- a/packages/safe-ds-lang/src/language/validation/types.ts +++ b/packages/safe-ds-lang/src/language/validation/types.ts @@ -218,6 +218,7 @@ export const infixOperationOperandsMustHaveCorrectType = (services: SafeDsServic case '-': case '*': case '/': + case '%': if ( node.leftOperand && !typeChecker.isSubtypeOf(leftType, coreTypes.Float) && diff --git a/packages/safe-ds-lang/src/resources/builtins/safeds/data/tabular/containers/Cell.sdsstub b/packages/safe-ds-lang/src/resources/builtins/safeds/data/tabular/containers/Cell.sdsstub index 3fb2e7172..86ea8ef33 100644 --- a/packages/safe-ds-lang/src/resources/builtins/safeds/data/tabular/containers/Cell.sdsstub +++ b/packages/safe-ds-lang/src/resources/builtins/safeds/data/tabular/containers/Cell.sdsstub @@ -216,7 +216,7 @@ class Cell { ) -> result: Cell /** - * Perform a modulo operation. + * Perform a modulo operation. This is equivalent to the `%` operator. * * @example * pipeline example { @@ -224,6 +224,13 @@ class Cell { * val result = column.transform((cell) -> cell.mod(3)); * // Column("example", [2, 0]) * } + * + * @example + * pipeline example { + * val column = Column("example", [5, 6]); + * val result = column.transform((cell) -> cell % 3); + * // Column("example", [2, 0]) + * } */ @Pure fun mod( diff --git a/packages/safe-ds-lang/tests/resources/formatting/expressions/arithmetic operators/modulo.sdsdev b/packages/safe-ds-lang/tests/resources/formatting/expressions/arithmetic operators/modulo.sdsdev new file mode 100644 index 000000000..cbb61ef0c --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/formatting/expressions/arithmetic operators/modulo.sdsdev @@ -0,0 +1,9 @@ +pipeline myPipeline { + 1 % 2; +} + +// ----------------------------------------------------------------------------- + +pipeline myPipeline { + 1 % 2; +} diff --git a/packages/safe-ds-lang/tests/resources/generation/python/expressions/infix operation/generated/tests/generator/infixOperation/gen_input.py b/packages/safe-ds-lang/tests/resources/generation/python/expressions/infix operation/generated/tests/generator/infixOperation/gen_input.py index d69bb37f9..b068190fb 100644 --- a/packages/safe-ds-lang/tests/resources/generation/python/expressions/infix operation/generated/tests/generator/infixOperation/gen_input.py +++ b/packages/safe-ds-lang/tests/resources/generation/python/expressions/infix operation/generated/tests/generator/infixOperation/gen_input.py @@ -71,4 +71,8 @@ def test(): f((cell()) / (h())) f((h()) / (cell())) f((cell()) / (cell())) + f((h()) % (h())) + f((cell()) % (h())) + f((h()) % (cell())) + f((cell()) % (cell())) f(__gen_eager_elvis(i(), i())) diff --git a/packages/safe-ds-lang/tests/resources/generation/python/expressions/infix operation/generated/tests/generator/infixOperation/gen_input.py.map b/packages/safe-ds-lang/tests/resources/generation/python/expressions/infix operation/generated/tests/generator/infixOperation/gen_input.py.map index 51dc8c94d..63135cb68 100644 --- a/packages/safe-ds-lang/tests/resources/generation/python/expressions/infix operation/generated/tests/generator/infixOperation/gen_input.py.map +++ b/packages/safe-ds-lang/tests/resources/generation/python/expressions/infix operation/generated/tests/generator/infixOperation/gen_input.py.map @@ -1 +1 @@ -{"version":3,"sources":["input.sdsdev"],"names":["test","f","or","g","cell","and","h","i"],"mappings":"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","file":"gen_input.py"} \ No newline at end of file +{"version":3,"sources":["input.sdsdev"],"names":["test","f","or","g","cell","and","h","i"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;AAYA,IAASA,IAAI;IACTC,CAAC,CAAKC,cAAE,CAANC,CAAC,IAAMA,CAAC;IACVF,CAAC,CAAC,CAAAG,IAAI,IAAGF,CAAE,EAACC,CAAC;IACbF,CAAC,CAAC,CAAAE,CAAC,IAAGD,CAAE,EAACE,IAAI;IACbH,CAAC,CAAC,CAAAG,IAAI,IAAGF,CAAE,EAACE,IAAI;IAEhBH,CAAC,CAAKI,eAAG,CAAPF,CAAC,IAAOA,CAAC;IACXF,CAAC,CAAC,CAAAG,IAAI,IAAGC,CAAG,EAACF,CAAC;IACdF,CAAC,CAAC,CAAAE,CAAC,IAAGE,CAAG,EAACD,IAAI;IACdH,CAAC,CAAC,CAAAG,IAAI,IAAGC,CAAG,EAACD,IAAI;IAGjBH,CAAC,CAAC,CAAAK,CAAC,IAAG,EAAE,EAACA,CAAC;IACVL,CAAC,CAAC,CAAAG,IAAI,IAAG,EAAE,EAACE,CAAC;IACbL,CAAC,CAAC,CAAAK,CAAC,IAAG,EAAE,EAACF,IAAI;IACbH,CAAC,CAAC,CAAAG,IAAI,IAAG,EAAE,EAACA,IAAI;IAEhBH,CAAC,CAAC,CAAAK,CAAC,IAAG,EAAE,EAACA,CAAC;IACVL,CAAC,CAAC,CAAAG,IAAI,IAAG,EAAE,EAACE,CAAC;IACbL,CAAC,CAAC,CAAAK,CAAC,IAAG,EAAE,EAACF,IAAI;IACbH,CAAC,CAAC,CAAAG,IAAI,IAAG,EAAE,EAACA,IAAI;IAEhBH,CAAC,CAAC,CAAAK,CAAC,IAAG,EAAG,EAACA,CAAC;IACXL,CAAC,CAAC,CAAAK,CAAC,IAAG,QAAIA,CAAC;IAGXL,CAAC,CAAC,CAAAK,CAAC,IAAG,CAAC,EAACA,CAAC;IACTL,CAAC,CAAC,CAAAG,IAAI,IAAG,CAAC,EAACE,CAAC;IACZL,CAAC,CAAC,CAAAK,CAAC,IAAG,CAAC,EAACF,IAAI;IACZH,CAAC,CAAC,CAAAG,IAAI,IAAG,CAAC,EAACA,IAAI;IAEfH,CAAC,CAAC,CAAAK,CAAC,IAAG,EAAE,EAACA,CAAC;IACVL,CAAC,CAAC,CAAAG,IAAI,IAAG,EAAE,EAACE,CAAC;IACbL,CAAC,CAAC,CAAAK,CAAC,IAAG,EAAE,EAACF,IAAI;IACbH,CAAC,CAAC,CAAAG,IAAI,IAAG,EAAE,EAACA,IAAI;IAEhBH,CAAC,CAAC,CAAAK,CAAC,IAAG,EAAE,EAACA,CAAC;IACVL,CAAC,CAAC,CAAAG,IAAI,IAAG,EAAE,EAACE,CAAC;IACbL,CAAC,CAAC,CAAAK,CAAC,IAAG,EAAE,EAACF,IAAI;IACbH,CAAC,CAAC,CAAAG,IAAI,IAAG,EAAE,EAACA,IAAI;IAEhBH,CAAC,CAAC,CAAAK,CAAC,IAAG,CAAC,EAACA,CAAC;IACTL,CAAC,CAAC,CAAAG,IAAI,IAAG,CAAC,EAACE,CAAC;IACZL,CAAC,CAAC,CAAAK,CAAC,IAAG,CAAC,EAACF,IAAI;IACZH,CAAC,CAAC,CAAAG,IAAI,IAAG,CAAC,EAACA,IAAI;IAGfH,CAAC,CAAC,CAAAK,CAAC,IAAG,CAAC,EAACA,CAAC;IACTL,CAAC,CAAC,CAAAG,IAAI,IAAG,CAAC,EAACE,CAAC;IACZL,CAAC,CAAC,CAAAK,CAAC,IAAG,CAAC,EAACF,IAAI;IACZH,CAAC,CAAC,CAAAG,IAAI,IAAG,CAAC,EAACA,IAAI;IAEfH,CAAC,CAAC,CAAAK,CAAC,IAAG,CAAC,EAACA,CAAC;IACTL,CAAC,CAAC,CAAAG,IAAI,IAAG,CAAC,EAACE,CAAC;IACZL,CAAC,CAAC,CAAAK,CAAC,IAAG,CAAC,EAACF,IAAI;IACZH,CAAC,CAAC,CAAAG,IAAI,IAAG,CAAC,EAACA,IAAI;IAEfH,CAAC,CAAC,CAAAK,CAAC,IAAG,CAAC,EAACA,CAAC;IACTL,CAAC,CAAC,CAAAG,IAAI,IAAG,CAAC,EAACE,CAAC;IACZL,CAAC,CAAC,CAAAK,CAAC,IAAG,CAAC,EAACF,IAAI;IACZH,CAAC,CAAC,CAAAG,IAAI,IAAG,CAAC,EAACA,IAAI;IAEfH,CAAC,CAAC,CAAAK,CAAC,IAAG,CAAC,EAACA,CAAC;IACTL,CAAC,CAAC,CAAAG,IAAI,IAAG,CAAC,EAACE,CAAC;IACZL,CAAC,CAAC,CAAAK,CAAC,IAAG,CAAC,EAACF,IAAI;IACZH,CAAC,CAAC,CAAAG,IAAI,IAAG,CAAC,EAACA,IAAI;IAEfH,CAAC,CAAC,CAAAK,CAAC,IAAG,CAAC,EAACA,CAAC;IACTL,CAAC,CAAC,CAAAG,IAAI,IAAG,CAAC,EAACE,CAAC;IACZL,CAAC,CAAC,CAAAK,CAAC,IAAG,CAAC,EAACF,IAAI;IACZH,CAAC,CAAC,CAAAG,IAAI,IAAG,CAAC,EAACA,IAAI;IAGfH,CAAC,CAAK,iBAAE,CAANM,CAAC,IAAMA,CAAC","file":"gen_input.py"} \ No newline at end of file diff --git a/packages/safe-ds-lang/tests/resources/generation/python/expressions/infix operation/input.sdsdev b/packages/safe-ds-lang/tests/resources/generation/python/expressions/infix operation/input.sdsdev index b0aa3dedb..ea595d0e0 100644 --- a/packages/safe-ds-lang/tests/resources/generation/python/expressions/infix operation/input.sdsdev +++ b/packages/safe-ds-lang/tests/resources/generation/python/expressions/infix operation/input.sdsdev @@ -77,6 +77,11 @@ pipeline test { f(h() / cell()); f(cell() / cell()); + f(h() % h()); + f(cell() % h()); + f(h() % cell()); + f(cell() % cell()); + f(i() ?: i()); } diff --git a/packages/safe-ds-lang/tests/resources/grammar/expressions/arithmetic operators/bad-modulo without left operator.sdsdev b/packages/safe-ds-lang/tests/resources/grammar/expressions/arithmetic operators/bad-modulo without left operator.sdsdev new file mode 100644 index 000000000..2ddf63555 --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/grammar/expressions/arithmetic operators/bad-modulo without left operator.sdsdev @@ -0,0 +1,5 @@ +// $TEST$ syntax_error + +pipeline myPipeline { + % 2; +} diff --git a/packages/safe-ds-lang/tests/resources/grammar/expressions/arithmetic operators/bad-modulo without right operator.sdsdev b/packages/safe-ds-lang/tests/resources/grammar/expressions/arithmetic operators/bad-modulo without right operator.sdsdev new file mode 100644 index 000000000..efb24a154 --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/grammar/expressions/arithmetic operators/bad-modulo without right operator.sdsdev @@ -0,0 +1,5 @@ +// $TEST$ syntax_error + +pipeline myPipeline { + 1 %; +} diff --git a/packages/safe-ds-lang/tests/resources/grammar/expressions/arithmetic operators/good-modulo.sdsdev b/packages/safe-ds-lang/tests/resources/grammar/expressions/arithmetic operators/good-modulo.sdsdev new file mode 100644 index 000000000..251d6416c --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/grammar/expressions/arithmetic operators/good-modulo.sdsdev @@ -0,0 +1,5 @@ +// $TEST$ no_syntax_error + +pipeline myPipeline { + 1 % 2; +} diff --git a/packages/safe-ds-lang/tests/resources/partial evaluation/recursive cases/infix operations/modulo/main.sdsdev b/packages/safe-ds-lang/tests/resources/partial evaluation/recursive cases/infix operations/modulo/main.sdsdev new file mode 100644 index 000000000..361e58ae4 --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/partial evaluation/recursive cases/infix operations/modulo/main.sdsdev @@ -0,0 +1,47 @@ +package tests.partialValidation.recursiveCases.infixOperations.modulo + +pipeline test { + // $TEST$ serialization 0.25 + »0.25 % 0.5«; + + // $TEST$ serialization 0.5 + »1.5 % 1«; + + // $TEST$ serialization 0.375 + »1 % 0.625«; + + // $TEST$ serialization 0 + »1 % 1«; + + // $TEST$ serialization -1 + »3 % -2«; + + // $TEST$ serialization 1 + »-3 % 2«; + + // $TEST$ serialization -1 + »-3 % -2«; + + + // $TEST$ serialization ? + »1 % 0«; + + // $TEST$ serialization ? + »1 % 0.0«; + + // $TEST$ serialization ? + »1 % -0.0«; + + + // $TEST$ serialization ? + »true % 1«; + + // $TEST$ serialization ? + »1 % true«; + + // $TEST$ serialization ? + »unresolved % 1«; + + // $TEST$ serialization ? + »1 % unresolved«; +} diff --git a/packages/safe-ds-lang/tests/resources/typing/expressions/operations/arithmetic/main.sdsdev b/packages/safe-ds-lang/tests/resources/typing/expressions/operations/arithmetic/main.sdsdev index 056e2c89f..23c418354 100644 --- a/packages/safe-ds-lang/tests/resources/typing/expressions/operations/arithmetic/main.sdsdev +++ b/packages/safe-ds-lang/tests/resources/typing/expressions/operations/arithmetic/main.sdsdev @@ -14,6 +14,8 @@ pipeline constantOperands { val multiplicationIntInt = »1 * 1«; // $TEST$ serialization literal<1> val divisionIntInt = »1 / 1«; + // $TEST$ serialization literal<0> + val moduloIntInt = »1 % 1«; // $TEST$ serialization literal<2.5> val additionIntFloat = »1 + 1.5«; @@ -23,6 +25,8 @@ pipeline constantOperands { val multiplicationIntFloat = »1 * 1.5«; // $TEST$ serialization literal<1.6> val divisionIntFloat = »1 / 0.625«; + // $TEST$ serialization literal<0.375> + val moduloIntFloat = »1 % 0.625«; // $TEST$ serialization literal<2.5> val additionFloatInt = »1.5 + 1«; @@ -32,6 +36,8 @@ pipeline constantOperands { val multiplicationFloatInt = »1.5 * 1«; // $TEST$ serialization literal<1.5> val divisionFloatInt = »1.5 / 1«; + // $TEST$ serialization literal<0.5> + val moduloFloatInt = »1.5 % 1«; // $TEST$ serialization literal<2.75> val additionFloatFloat = »1.5 + 1.25«; @@ -41,6 +47,8 @@ pipeline constantOperands { val multiplicationFloatFloat = »1.5 * 1.25«; // $TEST$ serialization literal<0.6> val divisionFloatFloat = »1.5 / 2.5«; + // $TEST$ serialization literal<1.5> + val moduloFloatFloat = »1.5 % 2.5«; // $TEST$ serialization literal<-1> val negationInt = »-1«; @@ -57,6 +65,8 @@ pipeline invalidOperands { val multiplicationInvalid = »true * true«; // $TEST$ serialization Float val divisionInvalid = »true / true«; + // $TEST$ serialization Float + val moduloInvalid = »true % true«; // $TEST$ serialization Float val negationInvalid = »-true«; @@ -71,6 +81,8 @@ pipeline nonConstantOperands { val multiplicationIntInt = »anyInt() * anyInt()«; // $TEST$ serialization Int val divisionIntInt = »anyInt() / anyInt()«; + // $TEST$ serialization Int + val moduloIntInt = »anyInt() % anyInt()«; // $TEST$ serialization Float val additionIntFloat = »anyInt() + anyFloat()«; @@ -80,6 +92,8 @@ pipeline nonConstantOperands { val multiplicationIntFloat = »anyInt() * anyFloat()«; // $TEST$ serialization Float val divisionIntFloat = »anyInt() / anyFloat()«; + // $TEST$ serialization Float + val moduloIntFloat = »anyInt() % anyFloat()«; // $TEST$ serialization Float val additionFloatInt = »anyFloat() + anyInt()«; @@ -89,6 +103,8 @@ pipeline nonConstantOperands { val multiplicationFloatInt = »anyFloat() * anyInt()«; // $TEST$ serialization Float val divisionFloatInt = »anyFloat() / anyInt()«; + // $TEST$ serialization Float + val moduloFloatInt = »anyFloat() % anyInt()«; // $TEST$ serialization Float val additionFloatFloat = »anyFloat() + anyFloat()«; @@ -98,6 +114,8 @@ pipeline nonConstantOperands { val multiplicationFloatFloat = »anyFloat() * anyFloat()«; // $TEST$ serialization Float val divisionFloatFloat = »anyFloat() / anyFloat()«; + // $TEST$ serialization Float + val moduloFloatFloat = »anyFloat() % anyFloat()«; // $TEST$ serialization Int val negationInt = »-anyInt()«; @@ -114,6 +132,8 @@ pipeline mixedOperands { val multiplicationIntInt = »10 * anyInt()«; // $TEST$ serialization Int val divisionIntInt = »10 / anyInt()«; + // $TEST$ serialization Int + val moduloIntInt = »10 % anyInt()«; // $TEST$ serialization Float val additionIntFloat = »10 + anyFloat()«; @@ -123,6 +143,8 @@ pipeline mixedOperands { val multiplicationIntFloat = »10 * anyFloat()«; // $TEST$ serialization Float val divisionIntFloat = »10 / anyFloat()«; + // $TEST$ serialization Float + val moduloIntFloat = »10 % anyFloat()«; // $TEST$ serialization Float val additionFloatInt = »1.5 + anyInt()«; @@ -132,6 +154,8 @@ pipeline mixedOperands { val multiplicationFloatInt = »1.5 * anyInt()«; // $TEST$ serialization Float val divisionFloatInt = »1.5 / anyInt()«; + // $TEST$ serialization Float + val moduloFloatInt = »1.5 % anyInt()«; // $TEST$ serialization Float val additionFloatFloat = »1.5 + anyFloat()«; @@ -141,6 +165,8 @@ pipeline mixedOperands { val multiplicationFloatFloat = »1.5 * anyFloat()«; // $TEST$ serialization Float val divisionFloatFloat = »1.5 / anyFloat()«; + // $TEST$ serialization Float + val moduloFloatFloat = »1.5 % anyFloat()«; } pipeline cellOperands { @@ -152,6 +178,8 @@ pipeline cellOperands { val multiplicationIntCell = »10 * cell()«; // $TEST$ serialization Cell val divisionIntCell = »10 / cell()«; + // $TEST$ serialization Cell + val moduloIntCell = »10 % cell()«; // $TEST$ serialization Cell val additionFloatCell = »1.5 + cell()«; @@ -161,6 +189,8 @@ pipeline cellOperands { val multiplicationFloatCell = »1.5 * cell()«; // $TEST$ serialization Cell val divisionFloatCell = »1.5 / cell()«; + // $TEST$ serialization Cell + val moduloFloatCell = »1.5 % cell()«; // $TEST$ serialization Cell val additionInvalidCell = »true + cell()«; @@ -170,6 +200,8 @@ pipeline cellOperands { val multiplicationInvalidCell = »true * cell()«; // $TEST$ serialization Cell val divisionInvalidCell = »true / cell()«; + // $TEST$ serialization Cell + val moduloInvalidCell = »true % cell()«; // $TEST$ serialization Cell val additionCellInt = »cell() + 10«; @@ -179,6 +211,8 @@ pipeline cellOperands { val multiplicationCellInt = »cell() * 10«; // $TEST$ serialization Cell val divisionCellInt = »cell() / 10«; + // $TEST$ serialization Cell + val moduloCellInt = »cell() % 10«; // $TEST$ serialization Cell val additionCellFloat = »cell() + 1.5«; @@ -188,6 +222,8 @@ pipeline cellOperands { val multiplicationCellFloat = »cell() * 1.5«; // $TEST$ serialization Cell val divisionCellFloat = »cell() / 1.5«; + // $TEST$ serialization Cell + val moduloCellFloat = »cell() % 1.5«; // $TEST$ serialization Cell val additionCellInvalid = »cell() + true«; @@ -197,6 +233,8 @@ pipeline cellOperands { val multiplicationCellInvalid = »cell() * true«; // $TEST$ serialization Cell val divisionCellInvalid = »cell() / true«; + // $TEST$ serialization Cell + val moduloCellInvalid = »cell() % true«; // $TEST$ serialization Cell val additionCellCell = »cell() + cell()«; @@ -206,6 +244,8 @@ pipeline cellOperands { val multiplicationCellCell = »cell() * cell()«; // $TEST$ serialization Cell val divisionCellCell = »cell() / cell()«; + // $TEST$ serialization Cell + val moduloCellCell = »cell() % cell()«; // $TEST$ serialization Cell val negationCell = »-cell()«; diff --git a/packages/safe-ds-lang/tests/resources/validation/types/checking/infix operations/main.sdsdev b/packages/safe-ds-lang/tests/resources/validation/types/checking/infix operations/main.sdsdev index 4bb281ee8..d1cbc0b25 100644 --- a/packages/safe-ds-lang/tests/resources/validation/types/checking/infix operations/main.sdsdev +++ b/packages/safe-ds-lang/tests/resources/validation/types/checking/infix operations/main.sdsdev @@ -95,6 +95,22 @@ pipeline myPipeline { // $TEST$ error "This operator is not defined for type 'unknown'." »unresolved« / »unresolved«; + // $TEST$ no error r"This operator is not defined for type .*\." + // $TEST$ no error r"This operator is not defined for type .*\." + »0.0« % »0.0«; + // $TEST$ no error r"This operator is not defined for type .*\." + // $TEST$ no error r"This operator is not defined for type .*\." + »0« % »0«; + // $TEST$ no error r"This operator is not defined for type .*\." + // $TEST$ no error r"This operator is not defined for type .*\." + »cell()« % »cell()«; + // $TEST$ error "This operator is not defined for type 'literal<"">'." + // $TEST$ error "This operator is not defined for type 'literal<"">'." + »""« % »""«; + // $TEST$ error "This operator is not defined for type 'unknown'." + // $TEST$ error "This operator is not defined for type 'unknown'." + »unresolved« % »unresolved«; + // $TEST$ no error r"This operator is not defined for type .*\." // $TEST$ no error r"This operator is not defined for type .*\."