diff --git a/packages/safe-ds-lang/src/language/builtins/safe-ds-classes.ts b/packages/safe-ds-lang/src/language/builtins/safe-ds-classes.ts index c02869b88..2ca1f3ba0 100644 --- a/packages/safe-ds-lang/src/language/builtins/safe-ds-classes.ts +++ b/packages/safe-ds-lang/src/language/builtins/safe-ds-classes.ts @@ -3,6 +3,7 @@ import { SafeDsModuleMembers } from './safe-ds-module-members.js'; import { resourceNameToUri } from '../../helpers/resources.js'; import { URI } from 'langium'; +const CELL_URI = resourceNameToUri('builtins/safeds/data/tabular/containers/Cell.sdsstub'); const CORE_CLASSES_URI = resourceNameToUri('builtins/safeds/lang/coreClasses.sdsstub'); const IMAGE_URI = resourceNameToUri('builtins/safeds/data/image/containers/Image.sdsstub'); const TABLE_URI = resourceNameToUri('builtins/safeds/data/tabular/containers/Table.sdsstub'); @@ -16,6 +17,10 @@ export class SafeDsClasses extends SafeDsModuleMembers { return this.getClass('Boolean'); } + get Cell(): SdsClass | undefined { + return this.getClass('Cell', CELL_URI); + } + get Float(): SdsClass | undefined { return this.getClass('Float'); } diff --git a/packages/safe-ds-lang/src/language/generation/python/safe-ds-python-generator.ts b/packages/safe-ds-lang/src/language/generation/python/safe-ds-python-generator.ts index 0ab5a540d..7b76fb0f1 100644 --- a/packages/safe-ds-lang/src/language/generation/python/safe-ds-python-generator.ts +++ b/packages/safe-ds-lang/src/language/generation/python/safe-ds-python-generator.ts @@ -114,6 +114,8 @@ import { } from './utilityFunctions.js'; import { CODEGEN_PREFIX } from './constants.js'; import { SafeDsSlicer } from '../../flow/safe-ds-slicer.js'; +import { SafeDsTypeChecker } from '../../typing/safe-ds-type-checker.js'; +import { SafeDsCoreTypes } from '../../typing/safe-ds-core-types.js'; const LAMBDA_PREFIX = `${CODEGEN_PREFIX}lambda_`; const BLOCK_LAMBDA_RESULT_PREFIX = `${CODEGEN_PREFIX}block_lambda_result_`; @@ -130,18 +132,22 @@ const SPACING = new CompositeGeneratorNode(NL, NL); export class SafeDsPythonGenerator { private readonly builtinAnnotations: SafeDsAnnotations; + private readonly coreTypes: SafeDsCoreTypes; private readonly nodeMapper: SafeDsNodeMapper; private readonly partialEvaluator: SafeDsPartialEvaluator; private readonly purityComputer: SafeDsPurityComputer; private readonly slicer: SafeDsSlicer; + private readonly typeChecker: SafeDsTypeChecker; private readonly typeComputer: SafeDsTypeComputer; constructor(services: SafeDsServices) { this.builtinAnnotations = services.builtins.Annotations; + this.coreTypes = services.typing.CoreTypes; this.nodeMapper = services.helpers.NodeMapper; this.partialEvaluator = services.evaluation.PartialEvaluator; this.purityComputer = services.purity.PurityComputer; this.slicer = services.flow.Slicer; + this.typeChecker = services.typing.TypeChecker; this.typeComputer = services.typing.TypeComputer; } @@ -722,19 +728,43 @@ export class SafeDsPythonGenerator { } else if (isSdsInfixOperation(expression)) { const leftOperand = this.generateExpression(expression.leftOperand, frame); const rightOperand = this.generateExpression(expression.rightOperand, frame); + + const leftOperandType = this.typeComputer.computeType(expression.leftOperand); + const rightOperandType = this.typeComputer.computeType(expression.rightOperand); + switch (expression.operator) { case 'or': - frame.addUtility(eagerOr); - return expandTracedToNode(expression)`${traceToNode( - expression, - 'operator', - )(eagerOr.name)}(${leftOperand}, ${rightOperand})`; + if ( + this.typeChecker.isSubtypeOf(leftOperandType, this.coreTypes.Boolean) && + this.typeChecker.isSubtypeOf(rightOperandType, this.coreTypes.Boolean) + ) { + frame.addUtility(eagerOr); + return expandTracedToNode(expression)`${traceToNode( + expression, + 'operator', + )(eagerOr.name)}(${leftOperand}, ${rightOperand})`; + } else { + return expandTracedToNode(expression)`(${leftOperand}) ${traceToNode( + expression, + 'operator', + )('|')} (${rightOperand})`; + } case 'and': - frame.addUtility(eagerAnd); - return expandTracedToNode(expression)`${traceToNode( - expression, - 'operator', - )(eagerAnd.name)}(${leftOperand}, ${rightOperand})`; + if ( + this.typeChecker.isSubtypeOf(leftOperandType, this.coreTypes.Boolean) && + this.typeChecker.isSubtypeOf(rightOperandType, this.coreTypes.Boolean) + ) { + frame.addUtility(eagerAnd); + return expandTracedToNode(expression)`${traceToNode( + expression, + 'operator', + )(eagerAnd.name)}(${leftOperand}, ${rightOperand})`; + } else { + return expandTracedToNode(expression)`(${leftOperand}) ${traceToNode( + expression, + 'operator', + )('&')} (${rightOperand})`; + } case '?:': frame.addUtility(eagerElvis); return expandTracedToNode(expression)`${traceToNode( @@ -807,7 +837,14 @@ export class SafeDsPythonGenerator { const operand = this.generateExpression(expression.operand, frame); switch (expression.operator) { case 'not': - return expandTracedToNode(expression)`${traceToNode(expression, 'operator')('not')} (${operand})`; + const operandType = this.typeComputer.computeType(expression.operand); + if (this.typeChecker.isSubtypeOf(operandType, this.coreTypes.Boolean)) { + return expandTracedToNode( + expression, + )`${traceToNode(expression, 'operator')('not')} (${operand})`; + } else { + return expandTracedToNode(expression)`${traceToNode(expression, 'operator')('~')}(${operand})`; + } case '-': return expandTracedToNode(expression)`${traceToNode(expression, 'operator')('-')}(${operand})`; } 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 5bda923ec..19893dea7 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 @@ -77,16 +77,22 @@ import { substitutionsAreEqual, UnknownEvaluatedNode, } from './model.js'; +import type { SafeDsTypeComputer } from '../typing/safe-ds-type-computer.js'; +import { SafeDsCoreTypes } from '../typing/safe-ds-core-types.js'; export class SafeDsPartialEvaluator { private readonly astNodeLocator: AstNodeLocator; + private readonly coreTypes: SafeDsCoreTypes; private readonly nodeMapper: SafeDsNodeMapper; + private readonly typeComputer: () => SafeDsTypeComputer; private readonly cache: WorkspaceCache; constructor(services: SafeDsServices) { this.astNodeLocator = services.workspace.AstNodeLocator; + this.coreTypes = services.typing.CoreTypes; this.nodeMapper = services.helpers.NodeMapper; + this.typeComputer = () => services.typing.TypeComputer; this.cache = new WorkspaceCache(services.shared); } @@ -357,7 +363,10 @@ export class SafeDsPartialEvaluator { ): EvaluatedNode { // Short-circuit if (evaluatedLeft.equals(trueConstant)) { - return trueConstant; + const rightType = this.typeComputer().computeType(rightOperand); + if (rightType.equals(this.coreTypes.Boolean)) { + return trueConstant; + } } // Compute the result if both operands are constant booleans @@ -377,7 +386,10 @@ export class SafeDsPartialEvaluator { ): EvaluatedNode { // Short-circuit if (evaluatedLeft.equals(falseConstant)) { - return falseConstant; + const rightType = this.typeComputer().computeType(rightOperand); + if (rightType.equals(this.coreTypes.Boolean)) { + return falseConstant; + } } // Compute the result if both operands are constant booleans diff --git a/packages/safe-ds-lang/src/language/typing/safe-ds-core-types.ts b/packages/safe-ds-lang/src/language/typing/safe-ds-core-types.ts index 810c00338..4be035de4 100644 --- a/packages/safe-ds-lang/src/language/typing/safe-ds-core-types.ts +++ b/packages/safe-ds-lang/src/language/typing/safe-ds-core-types.ts @@ -26,6 +26,19 @@ export class SafeDsCoreTypes { return this.createCoreType(this.builtinClasses.Boolean); } + Cell(wrappedType: Type = this.AnyOrNull): Type { + const cell = this.builtinClasses.Cell; + const wrappedTypeParameter = getTypeParameters(cell)[0]; + + if (!cell || !wrappedTypeParameter) { + /* c8 ignore next 2 */ + return UnknownType; + } + + let substitutions = new Map([[wrappedTypeParameter, wrappedType]]); + return new ClassType(cell, substitutions, false); + } + get Float(): Type { return this.createCoreType(this.builtinClasses.Float); } 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 d57c60021..c1495eab0 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 @@ -371,24 +371,23 @@ export class SafeDsTypeComputer { return this.computeTypeOfIndexedAccess(node); } else if (isSdsInfixOperation(node)) { switch (node.operator) { - // Boolean operators - case 'or': - case 'and': - return this.coreTypes.Boolean; - // Equality operators - case '==': - case '!=': case '===': case '!==': return this.coreTypes.Boolean; + case '==': + case '!=': + + // Logical operators + case 'or': + case 'and': // Comparison operators case '<': case '<=': case '>=': case '>': - return this.coreTypes.Boolean; + return this.computeTypeOfBooleanOperation(node); // Arithmetic operators case '+': @@ -429,7 +428,7 @@ export class SafeDsTypeComputer { } else if (isSdsPrefixOperation(node)) { switch (node.operator) { case 'not': - return this.coreTypes.Boolean; + return this.computeTypeOfBooleanPrefixOperation(node); case '-': return this.computeTypeOfArithmeticPrefixOperation(node); @@ -509,11 +508,32 @@ export class SafeDsTypeComputer { return UnknownType; } + private computeTypeOfBooleanOperation(node: SdsInfixOperation): Type { + const leftOperandType = this.computeType(node.leftOperand); + const rightOperandType = this.computeType(node.rightOperand); + const cellType = this.coreTypes.Cell(); + + if ( + this.typeChecker.isSubtypeOf(leftOperandType, cellType) || + this.typeChecker.isSubtypeOf(rightOperandType, cellType) + ) { + return this.coreTypes.Cell(this.coreTypes.Boolean); + } else { + return this.coreTypes.Boolean; + } + } + private computeTypeOfArithmeticInfixOperation(node: SdsInfixOperation): Type { const leftOperandType = this.computeType(node.leftOperand); const rightOperandType = this.computeType(node.rightOperand); + const cellType = this.coreTypes.Cell(); if ( + this.typeChecker.isSubtypeOf(leftOperandType, cellType) || + this.typeChecker.isSubtypeOf(rightOperandType, cellType) + ) { + return this.coreTypes.Cell(this.coreTypes.Number); + } else if ( this.typeChecker.isSubtypeOf(leftOperandType, this.coreTypes.Int) && this.typeChecker.isSubtypeOf(rightOperandType, this.coreTypes.Int) ) { @@ -596,10 +616,24 @@ export class SafeDsTypeComputer { ); } + private computeTypeOfBooleanPrefixOperation(node: SdsPrefixOperation): Type { + const operandType = this.computeType(node.operand); + const cellType = this.coreTypes.Cell(); + + if (this.typeChecker.isSubtypeOf(operandType, cellType)) { + return this.coreTypes.Cell(this.coreTypes.Boolean); + } else { + return this.coreTypes.Boolean; + } + } + private computeTypeOfArithmeticPrefixOperation(node: SdsPrefixOperation): Type { const operandType = this.computeType(node.operand); + const cellType = this.coreTypes.Cell(); - if (this.typeChecker.isSubtypeOf(operandType, this.coreTypes.Int)) { + if (this.typeChecker.isSubtypeOf(operandType, cellType)) { + return this.coreTypes.Cell(this.coreTypes.Number); + } else if (this.typeChecker.isSubtypeOf(operandType, this.coreTypes.Int)) { return this.coreTypes.Int; } else { return this.coreTypes.Float; diff --git a/packages/safe-ds-lang/src/language/validation/types.ts b/packages/safe-ds-lang/src/language/validation/types.ts index 84b9dbd40..e9db69dca 100644 --- a/packages/safe-ds-lang/src/language/validation/types.ts +++ b/packages/safe-ds-lang/src/language/validation/types.ts @@ -161,17 +161,27 @@ export const infixOperationOperandsMustHaveCorrectType = (services: SafeDsServic return (node: SdsInfixOperation, accept: ValidationAcceptor): void => { const leftType = typeComputer.computeType(node.leftOperand); const rightType = typeComputer.computeType(node.rightOperand); + const cellType = coreTypes.Cell(); + switch (node.operator) { case 'or': case 'and': - if (node.leftOperand && !typeChecker.isSubtypeOf(leftType, coreTypes.Boolean)) { - accept('error', `Expected type '${coreTypes.Boolean}' but got '${leftType}'.`, { + if ( + node.leftOperand && + !typeChecker.isSubtypeOf(leftType, coreTypes.Boolean) && + !typeChecker.isSubtypeOf(leftType, cellType) + ) { + accept('error', `This operator is not defined for type '${leftType}'.`, { node: node.leftOperand, code: CODE_TYPE_MISMATCH, }); } - if (node.rightOperand && !typeChecker.isSubtypeOf(rightType, coreTypes.Boolean)) { - accept('error', `Expected type '${coreTypes.Boolean}' but got '${rightType}'.`, { + if ( + node.rightOperand && + !typeChecker.isSubtypeOf(rightType, coreTypes.Boolean) && + !typeChecker.isSubtypeOf(rightType, cellType) + ) { + accept('error', `This operator is not defined for type '${rightType}'.`, { node: node.rightOperand, code: CODE_TYPE_MISMATCH, }); @@ -202,9 +212,10 @@ export const infixOperationOperandsMustHaveCorrectType = (services: SafeDsServic if ( node.leftOperand && !typeChecker.isSubtypeOf(leftType, coreTypes.Float) && - !typeChecker.isSubtypeOf(leftType, coreTypes.Int) + !typeChecker.isSubtypeOf(leftType, coreTypes.Int) && + !typeChecker.isSubtypeOf(leftType, cellType) ) { - accept('error', `Expected type '${coreTypes.Float}' or '${coreTypes.Int}' but got '${leftType}'.`, { + accept('error', `This operator is not defined for type '${leftType}'.`, { node: node.leftOperand, code: CODE_TYPE_MISMATCH, }); @@ -212,16 +223,13 @@ export const infixOperationOperandsMustHaveCorrectType = (services: SafeDsServic if ( node.rightOperand && !typeChecker.isSubtypeOf(rightType, coreTypes.Float) && - !typeChecker.isSubtypeOf(rightType, coreTypes.Int) + !typeChecker.isSubtypeOf(rightType, coreTypes.Int) && + !typeChecker.isSubtypeOf(rightType, cellType) ) { - accept( - 'error', - `Expected type '${coreTypes.Float}' or '${coreTypes.Int}' but got '${rightType}'.`, - { - node: node.rightOperand, - code: CODE_TYPE_MISMATCH, - }, - ); + accept('error', `This operator is not defined for type '${rightType}'.`, { + node: node.rightOperand, + code: CODE_TYPE_MISMATCH, + }); } return; } @@ -338,10 +346,15 @@ export const prefixOperationOperandMustHaveCorrectType = (services: SafeDsServic return (node: SdsPrefixOperation, accept: ValidationAcceptor): void => { const operandType = typeComputer.computeType(node.operand); + const cellType = coreTypes.Cell(coreTypes.AnyOrNull); + switch (node.operator) { case 'not': - if (!typeChecker.isSubtypeOf(operandType, coreTypes.Boolean)) { - accept('error', `Expected type '${coreTypes.Boolean}' but got '${operandType}'.`, { + if ( + !typeChecker.isSubtypeOf(operandType, coreTypes.Boolean) && + !typeChecker.isSubtypeOf(operandType, cellType) + ) { + accept('error', `This operator is not defined for type '${operandType}'.`, { node, property: 'operand', code: CODE_TYPE_MISMATCH, @@ -351,17 +364,14 @@ export const prefixOperationOperandMustHaveCorrectType = (services: SafeDsServic case '-': if ( !typeChecker.isSubtypeOf(operandType, coreTypes.Float) && - !typeChecker.isSubtypeOf(operandType, coreTypes.Int) + !typeChecker.isSubtypeOf(operandType, coreTypes.Int) && + !typeChecker.isSubtypeOf(operandType, cellType) ) { - accept( - 'error', - `Expected type '${coreTypes.Float}' or '${coreTypes.Int}' but got '${operandType}'.`, - { - node, - property: 'operand', - code: CODE_TYPE_MISMATCH, - }, - ); + accept('error', `This operator is not defined for type '${operandType}'.`, { + node, + property: 'operand', + code: CODE_TYPE_MISMATCH, + }); } return; } 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 d48f75ef1..3fb2e7172 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 @@ -26,12 +26,12 @@ class Cell { */ @Pure @PythonName("first_not_none") - static fun firstNotNone( - cells: List> - ) -> cell: Cell + static fun firstNotNone( + cells: List> + ) -> cell: Cell /** - * Negate a boolean. This WILL LATER BE equivalent to the ^not operator. + * Negate a boolean. This is equivalent to the `not` operator. * * @example * pipeline example { @@ -39,13 +39,20 @@ class Cell { * val result = column.transform((cell) -> cell.^not()); * // Column("example", [false, true]) * } + * + * @example + * pipeline example { + * val column = Column("example", [true, false]); + * val result = column.transform((cell) -> not cell); + * // Column("example", [false, true]) + * } */ @Pure @PythonName("not_") fun ^not() -> result: Cell /** - * Perform a boolean AND operation. This WILL LATER BE equivalent to the ^and operator. + * Perform a boolean AND operation. This is equivalent to the `and` operator. * * @example * pipeline example { @@ -53,15 +60,22 @@ class Cell { * val result = column.transform((cell) -> cell.^and(false)); * // Column("example", [false, false]) * } + * + * @example + * pipeline example { + * val column = Column("example", [true, false]); + * val result = column.transform((cell) -> cell and false); + * // Column("example", [false, false]) + * } */ @Pure @PythonName("and_") fun ^and( - other: union> + other: union // TODO, once cell types can be inferred: union> ) -> result: Cell /** - * Perform a boolean OR operation. This WILL LATER BE equivalent to the ^or operator. + * Perform a boolean OR operation. This is equivalent to the `or` operator. * * @example * pipeline example { @@ -69,11 +83,18 @@ class Cell { * val result = column.transform((cell) -> cell.^or(true)); * // Column("example", [true, true]) * } + * + * @example + * pipeline example { + * val column = Column("example", [true, false]); + * val result = column.transform((cell) -> cell or true); + * // Column("example", [true, true]) + * } */ @Pure @PythonName("or_") fun ^or( - other: union> + other: union // TODO, once cell types can be inferred: union> ) -> result: Cell /** @@ -88,7 +109,7 @@ class Cell { */ @Pure fun xor( - other: union> + other: union // TODO, once cell types can be inferred: union> ) -> result: Cell /** @@ -102,7 +123,7 @@ class Cell { * } */ @Pure - fun abs() -> result: Cell + fun abs() -> result: Cell /** * Round up to the nearest integer. @@ -115,7 +136,7 @@ class Cell { * } */ @Pure - fun ceil() -> result: Cell + fun ceil() -> result: Cell /** * Round down to the nearest integer. @@ -128,10 +149,10 @@ class Cell { * } */ @Pure - fun floor() -> result: Cell + fun floor() -> result: Cell /** - * Negate the value. + * Negate the value. This is equivalent to the unary `-` operator. * * @example * pipeline example { @@ -139,12 +160,19 @@ class Cell { * val result = column.transform((cell) -> cell.neg()); * // Column("example", [-1, 2]) * } + * + * @example + * pipeline example { + * val column = Column("example", [1, -2]); + * val result = column.transform((cell) -> -cell); + * // Column("example", [-1, 2]) + * } */ @Pure - fun neg() -> result: Cell + fun neg() -> result: Cell /** - * Add a value. This WILL LATER BE equivalent to the `+` operator. + * Add a value. This is equivalent to the `+` operator. * * @example * pipeline example { @@ -152,14 +180,21 @@ class Cell { * val result = column.transform((cell) -> cell.add(3)); * // Column("example", [4, 5]) * } + * + * @example + * pipeline example { + * val column = Column("example", [1, 2]); + * val result = column.transform((cell) -> cell + 3); + * // Column("example", [4, 5]) + * } */ @Pure fun add( - other: Any - ) -> result: Cell + other: union // TODO, once cell types can be inferred: union> + ) -> result: Cell /** - * Divide by a value. This WILL LATER BE equivalent to the `/` operator. + * Divide by a value. This is equivalent to the `/` operator. * * @example * pipeline example { @@ -167,11 +202,18 @@ class Cell { * val result = column.transform((cell) -> cell.div(2)); * // Column("example", [3, 4]) * } + * + * @example + * pipeline example { + * val column = Column("example", [6, 8]); + * val result = column.transform((cell) -> cell / 2); + * // Column("example", [3, 4]) + * } */ @Pure fun div( - other: Any - ) -> result: Cell + other: union // TODO, once cell types can be inferred: union> + ) -> result: Cell /** * Perform a modulo operation. @@ -185,11 +227,11 @@ class Cell { */ @Pure fun mod( - other: Any - ) -> result: Cell + other: union // TODO, once cell types can be inferred: union> + ) -> result: Cell /** - * Multiply by a value. This WILL LATER BE equivalent to the `*` operator. + * Multiply by a value. This is equivalent to the `*` operator. * * @example * pipeline example { @@ -197,11 +239,18 @@ class Cell { * val result = column.transform((cell) -> cell.mul(4)); * // Column("example", [8, 12]) * } + * + * @example + * pipeline example { + * val column = Column("example", [2, 3]); + * val result = column.transform((cell) -> cell * 4); + * // Column("example", [8, 12]) + * } */ @Pure fun mul( - other: Any - ) -> result: Cell + other: union // TODO, once cell types can be inferred: union> + ) -> result: Cell /** * Raise to a power. @@ -215,11 +264,11 @@ class Cell { */ @Pure fun pow( - other: union - ) -> result: Cell + other: union // TODO, once cell types can be inferred: union> + ) -> result: Cell /** - * Subtract a value. This WILL LATER BE equivalent to the `-` operator. + * Subtract a value. This is equivalent to the binary `-` operator. * * @example * pipeline example { @@ -227,14 +276,21 @@ class Cell { * val result = column.transform((cell) -> cell.^sub(3)); * // Column("example", [2, 3]) * } + * + * @example + * pipeline example { + * val column = Column("example", [5, 6]); + * val result = column.transform((cell) -> cell - 3); + * // Column("example", [2, 3]) + * } */ @Pure fun ^sub( - other: Any - ) -> result: Cell + other: union // TODO, once cell types can be inferred: union> + ) -> result: Cell /** - * Check if equal to a value. This WILL LATER BE equivalent to the `==` operator. + * Check if equal to a value. This is equivalent to the `==` operator. * * @example * pipeline example { @@ -242,14 +298,43 @@ class Cell { * val result = column.transform((cell) -> cell.eq(2)); * // Column("example", [false, true]) * } + * + * @example + * pipeline example { + * val column = Column("example", [1, 2]); + * val result = column.transform((cell) -> cell == 2); + * // Column("example", [false, true]) + * } */ @Pure fun eq( - other: Any + other: Any? + ) -> result: Cell + + /** + * Check if not equal to a value. This is equivalent to the `!=` operator. + * + * @example + * pipeline example { + * val column = Column("example", [1, 2]); + * val result = column.transform((cell) -> cell.neq(2)); + * // Column("example", [true, false]) + * } + * + * @example + * pipeline example { + * val column = Column("example", [1, 2]); + * val result = column.transform((cell) -> cell != 2); + * // Column("example", [true, false]) + * } + */ + @Pure + fun neq( + other: Any? ) -> result: Cell /** - * Check if greater than or equal to a value. This WILL LATER BE equivalent to the `>=` operator. + * Check if greater than or equal to a value. This is equivalent to the `>=` operator. * * @example * pipeline example { @@ -257,14 +342,21 @@ class Cell { * val result = column.transform((cell) -> cell.ge(2)); * // Column("example", [false, true]) * } + * + * @example + * pipeline example { + * val column = Column("example", [1, 2]); + * val result = column.transform((cell) -> cell >= 2); + * // Column("example", [false, true]) + * } */ @Pure fun ge( - other: Any + other: union // TODO, once cell types can be inferred: union> ) -> result: Cell /** - * Check if greater than a value. This WILL LATER BE equivalent to the `>` operator. + * Check if greater than a value. This is equivalent to the `>` operator. * * @example * pipeline example { @@ -272,14 +364,21 @@ class Cell { * val result = column.transform((cell) -> cell.gt(2)); * // Column("example", [false, false]) * } + * + * @example + * pipeline example { + * val column = Column("example", [1, 2]); + * val result = column.transform((cell) -> cell > 2); + * // Column("example", [false, false]) + * } */ @Pure fun gt( - other: Any + other: union // TODO, once cell types can be inferred: union> ) -> result: Cell /** - * Check if less than or equal to a value. This WILL LATER BE equivalent to the `<=` operator. + * Check if less than or equal to a value. This is equivalent to the `<=` operator. * * @example * pipeline example { @@ -287,14 +386,21 @@ class Cell { * val result = column.transform((cell) -> cell.le(2)); * // Column("example", [true, true]) * } + * + * @example + * pipeline example { + * val column = Column("example", [1, 2]); + * val result = column.transform((cell) -> cell <= 2); + * // Column("example", [true, true]) + * } */ @Pure fun le( - other: Any + other: union // TODO, once cell types can be inferred: union> ) -> result: Cell /** - * Check if less than a value. This WILL LATER BE equivalent to the `<` operator. + * Check if less than a value. This is equivalent to the `<` operator. * * @example * pipeline example { @@ -302,9 +408,16 @@ class Cell { * val result = column.transform((cell) -> cell.lt(2)); * // Column("example", [true, false]) * } + * + * @example + * pipeline example { + * val column = Column("example", [1, 2]); + * val result = column.transform((cell) -> cell < 2); + * // Column("example", [true, false]) + * } */ @Pure fun lt( - other: Any + other: union // TODO, once cell types can be inferred: union> ) -> result: Cell } 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 9efeea59a..d69bb37f9 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 @@ -1,6 +1,6 @@ # Imports ---------------------------------------------------------------------- -from tests.generator.infixOperation import f, g, h, i +from tests.generator.infixOperation import cell, f, g, h, i from typing import TypeVar # Type variables --------------------------------------------------------------- @@ -22,17 +22,53 @@ def __gen_eager_elvis(left_operand: __gen_T, right_operand: __gen_T) -> __gen_T: def test(): f(__gen_eager_or(g(), g())) + f((cell()) | (g())) + f((g()) | (cell())) + f((cell()) | (cell())) f(__gen_eager_and(g(), g())) + f((cell()) & (g())) + f((g()) & (cell())) + f((cell()) & (cell())) f((h()) == (h())) + f((cell()) == (h())) + f((h()) == (cell())) + f((cell()) == (cell())) f((h()) != (h())) + f((cell()) != (h())) + f((h()) != (cell())) + f((cell()) != (cell())) f((h()) is (h())) f((h()) is not (h())) f((h()) < (h())) + f((cell()) < (h())) + f((h()) < (cell())) + f((cell()) < (cell())) f((h()) <= (h())) + f((cell()) <= (h())) + f((h()) <= (cell())) + f((cell()) <= (cell())) f((h()) >= (h())) + f((cell()) >= (h())) + f((h()) >= (cell())) + f((cell()) >= (cell())) f((h()) > (h())) + f((cell()) > (h())) + f((h()) > (cell())) + f((cell()) > (cell())) f((h()) + (h())) + f((cell()) + (h())) + f((h()) + (cell())) + f((cell()) + (cell())) f((h()) - (h())) + f((cell()) - (h())) + f((h()) - (cell())) + f((cell()) - (cell())) f((h()) * (h())) + 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 0b40662cf..51dc8c94d 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","and","h","i"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;AAUA,IAASA,IAAI;IACTC,CAAC,CAAKC,cAAE,CAANC,CAAC,IAAMA,CAAC;IACVF,CAAC,CAAKG,eAAG,CAAPD,CAAC,IAAOA,CAAC;IAEXF,CAAC,CAAC,CAAAI,CAAC,IAAG,EAAE,EAACA,CAAC;IACVJ,CAAC,CAAC,CAAAI,CAAC,IAAG,EAAE,EAACA,CAAC;IACVJ,CAAC,CAAC,CAAAI,CAAC,IAAG,EAAG,EAACA,CAAC;IACXJ,CAAC,CAAC,CAAAI,CAAC,IAAG,QAAIA,CAAC;IAEXJ,CAAC,CAAC,CAAAI,CAAC,IAAG,CAAC,EAACA,CAAC;IACTJ,CAAC,CAAC,CAAAI,CAAC,IAAG,EAAE,EAACA,CAAC;IACVJ,CAAC,CAAC,CAAAI,CAAC,IAAG,EAAE,EAACA,CAAC;IACVJ,CAAC,CAAC,CAAAI,CAAC,IAAG,CAAC,EAACA,CAAC;IAETJ,CAAC,CAAC,CAAAI,CAAC,IAAG,CAAC,EAACA,CAAC;IACTJ,CAAC,CAAC,CAAAI,CAAC,IAAG,CAAC,EAACA,CAAC;IACTJ,CAAC,CAAC,CAAAI,CAAC,IAAG,CAAC,EAACA,CAAC;IACTJ,CAAC,CAAC,CAAAI,CAAC,IAAG,CAAC,EAACA,CAAC;IAETJ,CAAC,CAAK,iBAAE,CAANK,CAAC,IAAMA,CAAC","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;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 cd554cc93..b0aa3dedb 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 @@ -8,24 +8,75 @@ package tests.generator.infixOperation @Pure fun i() -> result: Int? +@Pure fun cell() -> result: Cell + pipeline test { f(g() or g()); + f(cell() or g()); + f(g() or cell()); + f(cell() or cell()); + f(g() and g()); + f(cell() and g()); + f(g() and cell()); + f(cell() and cell()); + f(h() == h()); + f(cell() == h()); + f(h() == cell()); + f(cell() == cell()); + f(h() != h()); + f(cell() != h()); + f(h() != cell()); + f(cell() != cell()); + f(h() === h()); f(h() !== h()); + f(h() < h()); + f(cell() < h()); + f(h() < cell()); + f(cell() < cell()); + f(h() <= h()); + f(cell() <= h()); + f(h() <= cell()); + f(cell() <= cell()); + f(h() >= h()); + f(cell() >= h()); + f(h() >= cell()); + f(cell() >= cell()); + f(h() > h()); + f(cell() > h()); + f(h() > cell()); + f(cell() > cell()); + f(h() + h()); + f(cell() + h()); + f(h() + cell()); + f(cell() + cell()); + f(h() - h()); + f(cell() - h()); + f(h() - cell()); + f(cell() - cell()); + f(h() * h()); + f(cell() * h()); + 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/generation/python/expressions/prefix operation/generated/tests/generator/prefixOperation/gen_input.py b/packages/safe-ds-lang/tests/resources/generation/python/expressions/prefix operation/generated/tests/generator/prefixOperation/gen_input.py index b2b657444..baf270061 100644 --- a/packages/safe-ds-lang/tests/resources/generation/python/expressions/prefix operation/generated/tests/generator/prefixOperation/gen_input.py +++ b/packages/safe-ds-lang/tests/resources/generation/python/expressions/prefix operation/generated/tests/generator/prefixOperation/gen_input.py @@ -1,9 +1,11 @@ # Imports ---------------------------------------------------------------------- -from tests.generator.prefixOperation import f, g, h +from tests.generator.prefixOperation import cell, f, g, h # Pipelines -------------------------------------------------------------------- def test(): f(not (g())) + f(~(cell())) f(-(h())) + f(-(cell())) diff --git a/packages/safe-ds-lang/tests/resources/generation/python/expressions/prefix operation/generated/tests/generator/prefixOperation/gen_input.py.map b/packages/safe-ds-lang/tests/resources/generation/python/expressions/prefix operation/generated/tests/generator/prefixOperation/gen_input.py.map index bf42dbf74..be95cb413 100644 --- a/packages/safe-ds-lang/tests/resources/generation/python/expressions/prefix operation/generated/tests/generator/prefixOperation/gen_input.py.map +++ b/packages/safe-ds-lang/tests/resources/generation/python/expressions/prefix operation/generated/tests/generator/prefixOperation/gen_input.py.map @@ -1 +1 @@ -{"version":3,"sources":["input.sdsdev"],"names":["test","f","not","g","h"],"mappings":"AAAA;;;;;;AAQA,IAASA,IAAI;IACTC,CAAC,CAACC,GAAG,EAACC,CAAC;IACPF,CAAC,CAAC,CAAC,CAAAG,CAAC","file":"gen_input.py"} \ No newline at end of file +{"version":3,"sources":["input.sdsdev"],"names":["test","f","not","g","cell","h"],"mappings":"AAAA;;;;;;AAUA,IAASA,IAAI;IACTC,CAAC,CAACC,GAAG,EAACC,CAAC;IACPF,CAAC,CAACC,CAAG,CAACE,IAAI;IAEVH,CAAC,CAAC,CAAC,CAAAI,CAAC;IACJJ,CAAC,CAAC,CAAC,CAAAG,IAAI","file":"gen_input.py"} \ No newline at end of file diff --git a/packages/safe-ds-lang/tests/resources/generation/python/expressions/prefix operation/input.sdsdev b/packages/safe-ds-lang/tests/resources/generation/python/expressions/prefix operation/input.sdsdev index ff38d2a73..7e06fc8f6 100644 --- a/packages/safe-ds-lang/tests/resources/generation/python/expressions/prefix operation/input.sdsdev +++ b/packages/safe-ds-lang/tests/resources/generation/python/expressions/prefix operation/input.sdsdev @@ -6,7 +6,12 @@ package tests.generator.prefixOperation @Pure fun h() -> result: Int +@Pure fun cell() -> result: Cell + pipeline test { f(not g()); + f(not cell()); + f(-h()); + f(-cell()); } 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 57046ac4a..056e2c89f 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 @@ -1,7 +1,9 @@ package tests.typing.operations.arithmetic -fun anyInt() -> r: Int -fun anyFloat() -> r: Float +@Pure fun anyInt() -> r: Int +@Pure fun anyFloat() -> r: Float + +@Pure fun cell() -> r: Cell pipeline constantOperands { // $TEST$ serialization literal<2> @@ -141,6 +143,74 @@ pipeline mixedOperands { val divisionFloatFloat = »1.5 / anyFloat()«; } +pipeline cellOperands { + // $TEST$ serialization Cell + val additionIntCell = »10 + cell()«; + // $TEST$ serialization Cell + val subtractionIntCell = »10 - cell()«; + // $TEST$ serialization Cell + val multiplicationIntCell = »10 * cell()«; + // $TEST$ serialization Cell + val divisionIntCell = »10 / cell()«; + + // $TEST$ serialization Cell + val additionFloatCell = »1.5 + cell()«; + // $TEST$ serialization Cell + val subtractionFloatCell = »1.5 - cell()«; + // $TEST$ serialization Cell + val multiplicationFloatCell = »1.5 * cell()«; + // $TEST$ serialization Cell + val divisionFloatCell = »1.5 / cell()«; + + // $TEST$ serialization Cell + val additionInvalidCell = »true + cell()«; + // $TEST$ serialization Cell + val subtractionInvalidCell = »true - cell()«; + // $TEST$ serialization Cell + val multiplicationInvalidCell = »true * cell()«; + // $TEST$ serialization Cell + val divisionInvalidCell = »true / cell()«; + + // $TEST$ serialization Cell + val additionCellInt = »cell() + 10«; + // $TEST$ serialization Cell + val subtractionCellInt = »cell() - 10«; + // $TEST$ serialization Cell + val multiplicationCellInt = »cell() * 10«; + // $TEST$ serialization Cell + val divisionCellInt = »cell() / 10«; + + // $TEST$ serialization Cell + val additionCellFloat = »cell() + 1.5«; + // $TEST$ serialization Cell + val subtractionCellFloat = »cell() - 1.5«; + // $TEST$ serialization Cell + val multiplicationCellFloat = »cell() * 1.5«; + // $TEST$ serialization Cell + val divisionCellFloat = »cell() / 1.5«; + + // $TEST$ serialization Cell + val additionCellInvalid = »cell() + true«; + // $TEST$ serialization Cell + val subtractionCellInvalid = »cell() - true«; + // $TEST$ serialization Cell + val multiplicationCellInvalid = »cell() * true«; + // $TEST$ serialization Cell + val divisionCellInvalid = »cell() / true«; + + // $TEST$ serialization Cell + val additionCellCell = »cell() + cell()«; + // $TEST$ serialization Cell + val subtractionCellCell = »cell() - cell()«; + // $TEST$ serialization Cell + val multiplicationCellCell = »cell() * cell()«; + // $TEST$ serialization Cell + val divisionCellCell = »cell() / cell()«; + + // $TEST$ serialization Cell + val negationCell = »-cell()«; +} + // Strict checking of type parameter types class MyClass( p1: T, diff --git a/packages/safe-ds-lang/tests/resources/typing/expressions/operations/comparison/main.sdsdev b/packages/safe-ds-lang/tests/resources/typing/expressions/operations/comparison/main.sdsdev index 1aa39738e..6f3dbc76a 100644 --- a/packages/safe-ds-lang/tests/resources/typing/expressions/operations/comparison/main.sdsdev +++ b/packages/safe-ds-lang/tests/resources/typing/expressions/operations/comparison/main.sdsdev @@ -1,6 +1,8 @@ package tests.typing.operations.comparison -pipeline myPipeline { +@Pure fun cell() -> r: Cell + +pipeline constantOperands { // $TEST$ serialization literal val lessThan = »1 < 1«; // $TEST$ serialization literal @@ -9,7 +11,9 @@ pipeline myPipeline { val greaterThanOrEquals = »1 >= 1«; // $TEST$ serialization literal val greaterThan = »1 > 1«; +} +pipeline invalidOperands { // $TEST$ serialization Boolean val lessThanInvalid = »true < true«; // $TEST$ serialization Boolean @@ -19,3 +23,50 @@ pipeline myPipeline { // $TEST$ serialization Boolean val greaterThanInvalid = »true > true«; } + +pipeline cellOperands { + // $TEST$ serialization Cell + val lessThanNumberCell = »10 < cell()«; + // $TEST$ serialization Cell + val lessThanOrEqualsNumberCell = »10 <= cell()«; + // $TEST$ serialization Cell + val greaterThanOrEqualsNumberCell = »10 >= cell()«; + // $TEST$ serialization Cell + val greaterThanNumberCell = »10 > cell()«; + + // $TEST$ serialization Cell + val lessThanInvalidCell = »true < cell()«; + // $TEST$ serialization Cell + val lessThanOrEqualsInvalidCell = »true <= cell()«; + // $TEST$ serialization Cell + val greaterThanOrEqualsInvalidCell = »true >= cell()«; + // $TEST$ serialization Cell + val greaterThanInvalidCell = »true > cell()«; + + // $TEST$ serialization Cell + val lessThanCellNumber = »cell() < 10«; + // $TEST$ serialization Cell + val lessThanOrEqualsCellNumber = »cell() <= 10«; + // $TEST$ serialization Cell + val greaterThanOrEqualsCellNumber = »cell() >= 10«; + // $TEST$ serialization Cell + val greaterThanCellNumber = »cell() > 10«; + + // $TEST$ serialization Cell + val lessThanCellInvalid = »cell() < true«; + // $TEST$ serialization Cell + val lessThanOrEqualsCellInvalid = »cell() <= true«; + // $TEST$ serialization Cell + val greaterThanOrEqualsCellInvalid = »cell() >= true«; + // $TEST$ serialization Cell + val greaterThanCellInvalid = »cell() > true«; + + // $TEST$ serialization Cell + val lessThanCellCell = »cell() < cell()«; + // $TEST$ serialization Cell + val lessThanOrEqualsCellCell = »cell() <= cell()«; + // $TEST$ serialization Cell + val greaterThanOrEqualsCellCell = »cell() >= cell()«; + // $TEST$ serialization Cell + val greaterThanCellCell = »cell() > cell()«; +} diff --git a/packages/safe-ds-lang/tests/resources/typing/expressions/operations/equality/main.sdsdev b/packages/safe-ds-lang/tests/resources/typing/expressions/operations/equality/main.sdsdev index 6d7ffa536..2811ba4ba 100644 --- a/packages/safe-ds-lang/tests/resources/typing/expressions/operations/equality/main.sdsdev +++ b/packages/safe-ds-lang/tests/resources/typing/expressions/operations/equality/main.sdsdev @@ -1,6 +1,8 @@ package tests.typing.operations.equality -pipeline myPipeline { +@Pure fun cell() -> r: Cell + +pipeline basicOperands { // $TEST$ serialization literal val equals = (»1 == 1«); // $TEST$ serialization literal @@ -20,3 +22,20 @@ pipeline myPipeline { // $TEST$ serialization Boolean val nonConstantNotIdenticalTo = (»1 !== unresolved«); } + +pipeline cellOperands { + // $TEST$ serialization Cell + val equalsAnyCell = (»1 == cell()«); + // $TEST$ serialization Cell + val notEqualsAnyCell = (»1 != cell()«); + + // $TEST$ serialization Cell + val equalsCellAny = (»cell() == 1«); + // $TEST$ serialization Cell + val notEqualsCellAny = (»cell() != 1«); + + // $TEST$ serialization Cell + val equalsCellCell = (»cell() == cell()«); + // $TEST$ serialization Cell + val notEqualsCellCell = (»cell() != cell()«); +} diff --git a/packages/safe-ds-lang/tests/resources/typing/expressions/operations/logical/main.sdsdev b/packages/safe-ds-lang/tests/resources/typing/expressions/operations/logical/main.sdsdev index 2428e6b44..723740a77 100644 --- a/packages/safe-ds-lang/tests/resources/typing/expressions/operations/logical/main.sdsdev +++ b/packages/safe-ds-lang/tests/resources/typing/expressions/operations/logical/main.sdsdev @@ -1,13 +1,17 @@ package tests.typing.operations.logical -pipeline myPipeline { +@Pure fun cell() -> r: Cell + +pipeline constantOperands { // $TEST$ serialization literal val conjunction = »true and true«; // $TEST$ serialization literal val disjunction = »true or true«; // $TEST$ serialization literal val negation = »not true«; +} +pipeline invalidOperands { // $TEST$ serialization Boolean val conjunctionInvalid = »1 and 1«; // $TEST$ serialization Boolean @@ -15,3 +19,23 @@ pipeline myPipeline { // $TEST$ serialization Boolean val negationInvalid = »not "true"«; } + +pipeline cellOperands { + // $TEST$ serialization Cell + val conjunctionBooleanCell = »true and cell()«; + // $TEST$ serialization Cell + val disjunctionBooleanCell = »true or cell()«; + + // $TEST$ serialization Cell + val conjunctionCellBoolean = »cell() and true«; + // $TEST$ serialization Cell + val disjunctionCellBoolean = »cell() or true«; + + // $TEST$ serialization Cell + val conjunctionCellCell = »cell() and cell()«; + // $TEST$ serialization Cell + val disjunctionCellCell = »cell() or cell()«; + + // $TEST$ serialization Cell + val negationCell = »not 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 bf8587f87..4bb281ee8 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 @@ -1,131 +1,163 @@ package tests.validation.types.checking.infixOperations +@Pure fun cell() -> cell: Cell + pipeline myPipeline { - // $TEST$ no error r"Expected type 'Boolean' but got .*\." - // $TEST$ no error r"Expected type 'Boolean' but got .*\." + // $TEST$ no error r"This operator is not defined for type .*\." + // $TEST$ no error r"This operator is not defined for type .*\." »true« or »true« ; - // $TEST$ error "Expected type 'Boolean' but got 'literal<0>'." - // $TEST$ error "Expected type 'Boolean' but got 'literal<0>'." + // $TEST$ no error r"This operator is not defined for type .*\." + // $TEST$ no error r"This operator is not defined for type .*\." + »cell()« or »cell()«; + // $TEST$ error "This operator is not defined for type 'literal<0>'." + // $TEST$ error "This operator is not defined for type 'literal<0>'." »0« or »0«; - // $TEST$ error "Expected type 'Boolean' but got 'unknown'." - // $TEST$ error "Expected type 'Boolean' but got 'unknown'." + // $TEST$ error "This operator is not defined for type 'unknown'." + // $TEST$ error "This operator is not defined for type 'unknown'." »unresolved« or »unresolved«; - // $TEST$ no error r"Expected type 'Boolean' but got .*\." - // $TEST$ no error r"Expected type 'Boolean' but got .*\." + // $TEST$ no error r"This operator is not defined for type .*\." + // $TEST$ no error r"This operator is not defined for type .*\." »true« and »true«; - // $TEST$ error "Expected type 'Boolean' but got 'literal<0>'." - // $TEST$ error "Expected type 'Boolean' but got 'literal<0>'." + // $TEST$ no error r"This operator is not defined for type .*\." + // $TEST$ no error r"This operator is not defined for type .*\." + »cell()« and »cell()«; + // $TEST$ error "This operator is not defined for type 'literal<0>'." + // $TEST$ error "This operator is not defined for type 'literal<0>'." »0« and »0«; - // $TEST$ error "Expected type 'Boolean' but got 'unknown'." - // $TEST$ error "Expected type 'Boolean' but got 'unknown'." + // $TEST$ error "This operator is not defined for type 'unknown'." + // $TEST$ error "This operator is not defined for type 'unknown'." »unresolved« and »unresolved«; - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." + // $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"Expected type 'Float' or 'Int' but got .*\." - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." + // $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$ error "Expected type 'Float' or 'Int' but got 'literal'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'literal'." + // $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'." »true« + »false«; - // $TEST$ error "Expected type 'Float' or 'Int' but got 'unknown'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'unknown'." + // $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"Expected type 'Float' or 'Int' but got .*\." - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." + // $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"Expected type 'Float' or 'Int' but got .*\." - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." + // $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$ error "Expected type 'Float' or 'Int' but got 'literal<"">'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'literal<"">'." + // $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 "Expected type 'Float' or 'Int' but got 'unknown'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'unknown'." + // $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"Expected type 'Float' or 'Int' but got .*\." - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." + // $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"Expected type 'Float' or 'Int' but got .*\." - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." + // $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$ error "Expected type 'Float' or 'Int' but got 'literal<"">'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'literal<"">'." + // $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 "Expected type 'Float' or 'Int' but got 'unknown'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'unknown'." + // $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"Expected type 'Float' or 'Int' but got .*\." - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." + // $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"Expected type 'Float' or 'Int' but got .*\." - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." + // $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$ error "Expected type 'Float' or 'Int' but got 'literal<"">'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'literal<"">'." + // $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 "Expected type 'Float' or 'Int' but got 'unknown'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'unknown'." + // $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"Expected type 'Float' or 'Int' but got .*\." - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." + // $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"Expected type 'Float' or 'Int' but got .*\." - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." + // $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$ error "Expected type 'Float' or 'Int' but got 'literal<"">'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'literal<"">'." + // $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 "Expected type 'Float' or 'Int' but got 'unknown'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'unknown'." + // $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"Expected type 'Float' or 'Int' but got .*\." - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." + // $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"Expected type 'Float' or 'Int' but got .*\." - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." + // $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$ error "Expected type 'Float' or 'Int' but got 'literal<"">'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'literal<"">'." + // $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 "Expected type 'Float' or 'Int' but got 'unknown'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'unknown'." + // $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"Expected type 'Float' or 'Int' but got .*\." - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." + // $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"Expected type 'Float' or 'Int' but got .*\." - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." + // $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$ error "Expected type 'Float' or 'Int' but got 'literal<"">'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'literal<"">'." + // $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 "Expected type 'Float' or 'Int' but got 'unknown'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'unknown'." + // $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"Expected type 'Float' or 'Int' but got .*\." - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." + // $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"Expected type 'Float' or 'Int' but got .*\." - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." + // $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$ error "Expected type 'Float' or 'Int' but got 'literal<"">'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'literal<"">'." + // $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 "Expected type 'Float' or 'Int' but got 'unknown'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'unknown'." + // $TEST$ error "This operator is not defined for type 'unknown'." + // $TEST$ error "This operator is not defined for type 'unknown'." »unresolved« > »unresolved«; } @@ -133,37 +165,37 @@ pipeline myPipeline { class MyClass( p1: T, - // $TEST$ error "Expected type 'Boolean' but got 'T'." - // $TEST$ error "Expected type 'Boolean' but got 'T'." + // $TEST$ error "This operator is not defined for type 'T'." + // $TEST$ error "This operator is not defined for type 'T'." a1: Any? = »p1« or »p1«, - // $TEST$ error "Expected type 'Boolean' but got 'T'." - // $TEST$ error "Expected type 'Boolean' but got 'T'." + // $TEST$ error "This operator is not defined for type 'T'." + // $TEST$ error "This operator is not defined for type 'T'." a2: Any? = »p1« and »p1«, - // $TEST$ error "Expected type 'Float' or 'Int' but got 'T'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'T'." + // $TEST$ error "This operator is not defined for type 'T'." + // $TEST$ error "This operator is not defined for type 'T'." b1: Any? = »p1« + »p1«, - // $TEST$ error "Expected type 'Float' or 'Int' but got 'T'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'T'." + // $TEST$ error "This operator is not defined for type 'T'." + // $TEST$ error "This operator is not defined for type 'T'." b2: Any? = »p1« - »p1«, - // $TEST$ error "Expected type 'Float' or 'Int' but got 'T'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'T'." + // $TEST$ error "This operator is not defined for type 'T'." + // $TEST$ error "This operator is not defined for type 'T'." b3: Any? = »p1« * »p1«, - // $TEST$ error "Expected type 'Float' or 'Int' but got 'T'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'T'." + // $TEST$ error "This operator is not defined for type 'T'." + // $TEST$ error "This operator is not defined for type 'T'." b4: Any? = »p1« / »p1«, - // $TEST$ error "Expected type 'Float' or 'Int' but got 'T'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'T'." + // $TEST$ error "This operator is not defined for type 'T'." + // $TEST$ error "This operator is not defined for type 'T'." c1: Any? = »p1« < »p1«, - // $TEST$ error "Expected type 'Float' or 'Int' but got 'T'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'T'." + // $TEST$ error "This operator is not defined for type 'T'." + // $TEST$ error "This operator is not defined for type 'T'." c2: Any? = »p1« <= »p1«, - // $TEST$ error "Expected type 'Float' or 'Int' but got 'T'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'T'." + // $TEST$ error "This operator is not defined for type 'T'." + // $TEST$ error "This operator is not defined for type 'T'." c3: Any? = »p1« >= »p1«, - // $TEST$ error "Expected type 'Float' or 'Int' but got 'T'." - // $TEST$ error "Expected type 'Float' or 'Int' but got 'T'." + // $TEST$ error "This operator is not defined for type 'T'." + // $TEST$ error "This operator is not defined for type 'T'." c4: Any? = »p1« > »p1«, ) diff --git a/packages/safe-ds-lang/tests/resources/validation/types/checking/prefix operations/main.sdsdev b/packages/safe-ds-lang/tests/resources/validation/types/checking/prefix operations/main.sdsdev index 9daaccdcb..7d029ac9a 100644 --- a/packages/safe-ds-lang/tests/resources/validation/types/checking/prefix operations/main.sdsdev +++ b/packages/safe-ds-lang/tests/resources/validation/types/checking/prefix operations/main.sdsdev @@ -1,21 +1,27 @@ package tests.validation.types.checking.prefixOperations +@Pure fun cell() -> cell: Cell + segment mySegment() { - // $TEST$ no error r"Expected type 'Boolean' but got .*\." + // $TEST$ no error r"This operator is not defined for type .*\." not »true«; - // $TEST$ error "Expected type 'Boolean' but got 'literal<0>'." + // $TEST$ no error r"This operator is not defined for type .*\." + not »cell()«; + // $TEST$ error "This operator is not defined for type 'literal<0>'." not »0«; - // $TEST$ error "Expected type 'Boolean' but got 'unknown'." + // $TEST$ error "This operator is not defined for type 'unknown'." not »unresolved«; - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." + // $TEST$ no error r"This operator is not defined for type .*\." -»0.0«; - // $TEST$ no error r"Expected type 'Float' or 'Int' but got .*\." + // $TEST$ no error r"This operator is not defined for type .*\." -»0«; - // $TEST$ error "Expected type 'Float' or 'Int' but got 'literal<"">'." + // $TEST$ no error r"This operator is not defined for type .*\." + -»cell()«; + // $TEST$ error "This operator is not defined for type 'literal<"">'." -»""«; - // $TEST$ error "Expected type 'Float' or 'Int' but got 'unknown'." + // $TEST$ error "This operator is not defined for type 'unknown'." -»unresolved«; } @@ -23,9 +29,9 @@ segment mySegment() { class MyClass( p1: T, - // $TEST$ error "Expected type 'Boolean' but got 'T'." + // $TEST$ error "This operator is not defined for type 'T'." a: Any? = not »p1«, - // $TEST$ error "Expected type 'Float' or 'Int' but got 'T'." + // $TEST$ error "This operator is not defined for type 'T'." b: Any? = -»p1«, ) diff --git a/packages/safe-ds-vscode/src/extension/mainClient.ts b/packages/safe-ds-vscode/src/extension/mainClient.ts index ecd1ce35d..c389db6bc 100644 --- a/packages/safe-ds-vscode/src/extension/mainClient.ts +++ b/packages/safe-ds-vscode/src/extension/mainClient.ts @@ -319,25 +319,29 @@ export const getPipelineDocument = async function ( (document) => !( ast.isSdsModule(document.parseResult.value) && - (document.parseResult.value).name === 'safeds.lang' + (document.parseResult.value).name.startsWith('safeds') ), ) .forEach((oldDocument) => { services.shared.workspace.LangiumDocuments.deleteDocument(oldDocument.uri); }); - const workspaceSdsFiles = await vscode.workspace.findFiles('**/*.{sds,sdsstub,sdsdev}'); - // Load all documents - const unvalidatedSdsDocuments = await Promise.all( - workspaceSdsFiles.map((newDocumentUri) => - services.shared.workspace.LangiumDocuments.getOrCreateDocument(newDocumentUri), - ), - ); - // Validate them - const validationErrorMessage = await validateDocuments(services, unvalidatedSdsDocuments); - if (validationErrorMessage) { - vscode.window.showErrorMessage(validationErrorMessage); - return; - } + + // TODO: Needs a more robust way for validation. Only files that are used by the main file should be validated. + // For now, we are better off disabling this check, since users cannot run pipelines if any file in their workspace + // has an error. + // const workspaceSdsFiles = await vscode.workspace.findFiles('**/*.{sds,sdsstub,sdsdev}'); + // // Load all documents + // const unvalidatedSdsDocuments = await Promise.all( + // workspaceSdsFiles.map((newDocumentUri) => + // services.shared.workspace.LangiumDocuments.getOrCreateDocument(newDocumentUri), + // ), + // ); + // // Validate them + // const validationErrorMessage = await validateDocuments(services, unvalidatedSdsDocuments); + // if (validationErrorMessage) { + // vscode.window.showErrorMessage(validationErrorMessage); + // return; + // } let mainDocument; if (!services.shared.workspace.LangiumDocuments.hasDocument(pipelinePath)) {