diff --git a/docs/development/generation-testing.md b/docs/development/generation-testing.md index 37d470d53..2a023ee1d 100644 --- a/docs/development/generation-testing.md +++ b/docs/development/generation-testing.md @@ -12,6 +12,10 @@ generation test. If you want to skip a test, add the prefix `skip-` to the folder name. + !!! tip "Tests without runner integration" + + If you want to create a test without runner integration (memoization and placeholder saving), put it in the `eject` folder or use `eject` as a prefix for a new top level folder. + 2. Add files with the extension `.sdstest`, `.sdspipe`, or `.sdsstub` **directly inside the folder**. All files in a folder will be loaded into the same workspace, so they can reference each other. Files in different folders are loaded into different workspaces, so they cannot reference each other. Generation will be triggered for all files in diff --git a/packages/safe-ds-cli/src/cli/generate.ts b/packages/safe-ds-cli/src/cli/generate.ts index 60460161b..a4f752262 100644 --- a/packages/safe-ds-cli/src/cli/generate.ts +++ b/packages/safe-ds-cli/src/cli/generate.ts @@ -23,6 +23,7 @@ export const generate = async (fsPaths: string[], options: GenerateOptions): Pro destination: URI.file(path.resolve(options.out)), createSourceMaps: options.sourcemaps, targetPlaceholder: undefined, + disableRunnerIntegration: false, }); for (const file of generatedFiles) { diff --git a/packages/safe-ds-lang/src/language/generation/safe-ds-python-generator.ts b/packages/safe-ds-lang/src/language/generation/safe-ds-python-generator.ts index b5fefc820..584cbac0e 100644 --- a/packages/safe-ds-lang/src/language/generation/safe-ds-python-generator.ts +++ b/packages/safe-ds-lang/src/language/generation/safe-ds-python-generator.ts @@ -105,12 +105,60 @@ const BLOCK_LAMBDA_PREFIX = `${CODEGEN_PREFIX}block_lambda_`; const BLOCK_LAMBDA_RESULT_PREFIX = `${CODEGEN_PREFIX}block_lambda_result_`; const YIELD_PREFIX = `${CODEGEN_PREFIX}yield_`; -const RUNNER_CODEGEN_PACKAGE = 'safeds_runner.codegen'; const RUNNER_SERVER_PIPELINE_MANAGER_PACKAGE = 'safeds_runner.server.pipeline_manager'; const PYTHON_INDENT = ' '; const NLNL = new CompositeGeneratorNode(NL, NL); +const UTILITY_EAGER_OR: UtilityFunction = { + code: expandToNode`def ${CODEGEN_PREFIX}eager_or(left_operand: bool, right_operand: bool) -> bool:` + .appendNewLine() + .indent({ indentedChildren: ['return left_operand or right_operand'], indentation: PYTHON_INDENT }), + name: `${CODEGEN_PREFIX}eager_or`, + imports: [], +}; + +const UTILITY_EAGER_AND: UtilityFunction = { + code: expandToNode`def ${CODEGEN_PREFIX}eager_and(left_operand: bool, right_operand: bool) -> bool:` + .appendNewLine() + .indent({ indentedChildren: ['return left_operand and right_operand'], indentation: PYTHON_INDENT }), + name: `${CODEGEN_PREFIX}eager_and`, + imports: [], +}; + +const UTILITY_EAGER_ELVIS: UtilityFunction = { + code: expandToNode`${CODEGEN_PREFIX}T = TypeVar("${CODEGEN_PREFIX}T")` + .appendNewLine() + .appendNewLine() + .append( + `def ${CODEGEN_PREFIX}eager_elvis(left_operand: ${CODEGEN_PREFIX}T, right_operand: ${CODEGEN_PREFIX}T) -> ${CODEGEN_PREFIX}T:`, + ) + .appendNewLine() + .indent({ + indentedChildren: ['return left_operand if left_operand is not None else right_operand'], + indentation: PYTHON_INDENT, + }), + name: `${CODEGEN_PREFIX}eager_elvis`, + imports: [{ importPath: 'typing', declarationName: 'TypeVar' }], +}; + +const UTILITY_SAFE_ACCESS: UtilityFunction = { + code: expandToNode`${CODEGEN_PREFIX}S = TypeVar("${CODEGEN_PREFIX}S")` + .appendNewLine() + .appendNewLine() + .append(`def ${CODEGEN_PREFIX}safe_access(receiver: Any, member_name: str) -> ${CODEGEN_PREFIX}S | None:`) + .appendNewLine() + .indent({ + indentedChildren: ['return getattr(receiver, member_name) if receiver is not None else None'], + indentation: PYTHON_INDENT, + }), + name: `${CODEGEN_PREFIX}safe_access`, + imports: [ + { importPath: 'typing', declarationName: 'TypeVar' }, + { importPath: 'typing', declarationName: 'Any' }, + ], +}; + export class SafeDsPythonGenerator { private readonly builtinAnnotations: SafeDsAnnotations; private readonly nodeMapper: SafeDsNodeMapper; @@ -138,7 +186,7 @@ export class SafeDsPythonGenerator { const parentDirectoryPath = path.join(generateOptions.destination!.fsPath, ...packagePath); const generatedFiles = new Map(); - const generatedModule = this.generateModule(node, generateOptions.targetPlaceholder); + const generatedModule = this.generateModule(node, generateOptions); const { text, trace } = toStringAndTrace(generatedModule); const pythonOutputPath = `${path.join(parentDirectoryPath, this.formatGeneratedFileName(name))}.py`; if (generateOptions.createSourceMaps) { @@ -261,14 +309,15 @@ export class SafeDsPythonGenerator { return moduleName.replaceAll('%2520', '_').replaceAll(/[ .-]/gu, '_').replaceAll(/\\W/gu, ''); } - private generateModule(module: SdsModule, targetPlaceholder: string | undefined): CompositeGeneratorNode { + private generateModule(module: SdsModule, generateOptions: GenerateOptions): CompositeGeneratorNode { const importSet = new Map(); + const utilitySet = new Set(); const segments = getModuleMembers(module) .filter(isSdsSegment) - .map((segment) => this.generateSegment(segment, importSet)); + .map((segment) => this.generateSegment(segment, importSet, utilitySet, generateOptions)); const pipelines = getModuleMembers(module) .filter(isSdsPipeline) - .map((pipeline) => this.generatePipeline(pipeline, importSet, targetPlaceholder)); + .map((pipeline) => this.generatePipeline(pipeline, importSet, utilitySet, generateOptions)); const imports = this.generateImports(Array.from(importSet.values())); const output = new CompositeGeneratorNode(); output.trace(module); @@ -279,8 +328,16 @@ export class SafeDsPythonGenerator { output.append(joinToNode(imports, (importDecl) => importDecl, { separator: NL })); output.appendNewLine(); } - if (segments.length > 0) { + if (utilitySet.size > 0) { output.appendNewLineIf(imports.length > 0); + output.append('# Utils ------------------------------------------------------------------------'); + output.appendNewLine(); + output.appendNewLine(); + output.append(joinToNode(utilitySet, (importDecl) => importDecl.code, { separator: NLNL })); + output.appendNewLine(); + } + if (segments.length > 0) { + output.appendNewLineIf(imports.length > 0 || utilitySet.size > 0); output.append('# Segments ---------------------------------------------------------------------'); output.appendNewLine(); output.appendNewLine(); @@ -288,7 +345,7 @@ export class SafeDsPythonGenerator { output.appendNewLine(); } if (pipelines.length > 0) { - output.appendNewLineIf(imports.length > 0 || segments.length > 0); + output.appendNewLineIf(imports.length > 0 || utilitySet.size > 0 || segments.length > 0); output.append('# Pipelines --------------------------------------------------------------------'); output.appendNewLine(); output.appendNewLine(); @@ -298,8 +355,19 @@ export class SafeDsPythonGenerator { return output; } - private generateSegment(segment: SdsSegment, importSet: Map): CompositeGeneratorNode { - const infoFrame = new GenerationInfoFrame(importSet); + private generateSegment( + segment: SdsSegment, + importSet: Map, + utilitySet: Set, + generateOptions: GenerateOptions, + ): CompositeGeneratorNode { + const infoFrame = new GenerationInfoFrame( + importSet, + utilitySet, + false, + undefined, + generateOptions.disableRunnerIntegration, + ); const segmentResult = segment.resultList?.results || []; const segmentBlock = this.generateBlock(segment.body, infoFrame); if (segmentResult.length !== 0) { @@ -350,9 +418,16 @@ export class SafeDsPythonGenerator { private generatePipeline( pipeline: SdsPipeline, importSet: Map, - targetPlaceholder: string | undefined, + utilitySet: Set, + generateOptions: GenerateOptions, ): CompositeGeneratorNode { - const infoFrame = new GenerationInfoFrame(importSet, true, targetPlaceholder); + const infoFrame = new GenerationInfoFrame( + importSet, + utilitySet, + true, + generateOptions.targetPlaceholder, + generateOptions.disableRunnerIntegration, + ); return expandTracedToNode(pipeline)`def ${traceToNode( pipeline, 'name', @@ -538,7 +613,7 @@ export class SafeDsPythonGenerator { )} = ${this.generateExpression(assignment.expression!, frame)}`, ); } - if (frame.isInsidePipeline && !generateLambda) { + if (frame.isInsidePipeline && !generateLambda && !frame.disableRunnerIntegration) { for (const savableAssignment of assignees.filter(isSdsPlaceholder)) { // should always be SdsPlaceholder frame.addImport({ importPath: RUNNER_SERVER_PIPELINE_MANAGER_PACKAGE }); @@ -675,7 +750,7 @@ export class SafeDsPythonGenerator { return this.generatePythonCall(expression, pythonCall, argumentsMap, frame, thisParam); } } - if (this.isMemoizableCall(expression)) { + if (this.isMemoizableCall(expression) && !frame.disableRunnerIntegration) { let thisParam: CompositeGeneratorNode | undefined = undefined; if (isSdsMemberAccess(expression.receiver)) { thisParam = this.generateExpression(expression.receiver.receiver, frame); @@ -694,23 +769,23 @@ export class SafeDsPythonGenerator { const rightOperand = this.generateExpression(expression.rightOperand, frame); switch (expression.operator) { case 'or': - frame.addImport({ importPath: RUNNER_CODEGEN_PACKAGE }); + frame.addUtility(UTILITY_EAGER_OR); return expandTracedToNode(expression)`${traceToNode( expression, 'operator', - )(`${RUNNER_CODEGEN_PACKAGE}.eager_or`)}(${leftOperand}, ${rightOperand})`; + )(UTILITY_EAGER_OR.name)}(${leftOperand}, ${rightOperand})`; case 'and': - frame.addImport({ importPath: RUNNER_CODEGEN_PACKAGE }); + frame.addUtility(UTILITY_EAGER_AND); return expandTracedToNode(expression)`${traceToNode( expression, 'operator', - )(`${RUNNER_CODEGEN_PACKAGE}.eager_and`)}(${leftOperand}, ${rightOperand})`; + )(UTILITY_EAGER_AND.name)}(${leftOperand}, ${rightOperand})`; case '?:': - frame.addImport({ importPath: RUNNER_CODEGEN_PACKAGE }); + frame.addUtility(UTILITY_EAGER_ELVIS); return expandTracedToNode(expression)`${traceToNode( expression, 'operator', - )(`${RUNNER_CODEGEN_PACKAGE}.eager_elvis`)}(${leftOperand}, ${rightOperand})`; + )(UTILITY_EAGER_ELVIS.name)}(${leftOperand}, ${rightOperand})`; case '===': return expandTracedToNode(expression)`(${leftOperand}) ${traceToNode( expression, @@ -751,11 +826,11 @@ export class SafeDsPythonGenerator { } else { const memberExpression = this.generateExpression(expression.member!, frame); if (expression.isNullSafe) { - frame.addImport({ importPath: RUNNER_CODEGEN_PACKAGE }); + frame.addUtility(UTILITY_SAFE_ACCESS); return expandTracedToNode(expression)`${traceToNode( expression, 'isNullSafe', - )(`${RUNNER_CODEGEN_PACKAGE}.safe_access`)}(${receiver}, '${memberExpression}')`; + )(UTILITY_SAFE_ACCESS.name)}(${receiver}, '${memberExpression}')`; } else { return expandTracedToNode(expression)`${receiver}.${memberExpression}`; } @@ -817,7 +892,7 @@ export class SafeDsPythonGenerator { { separator: '' }, )!; // Non-memoizable calls can be directly generated - if (!this.isMemoizableCall(expression)) { + if (!this.isMemoizableCall(expression) || frame.disableRunnerIntegration) { return generatedPythonCall; } frame.addImport({ importPath: RUNNER_SERVER_PIPELINE_MANAGER_PACKAGE }); @@ -1040,6 +1115,12 @@ export class SafeDsPythonGenerator { } } +interface UtilityFunction { + readonly code: CompositeGeneratorNode; + readonly name: string; + readonly imports: ImportData[]; +} + interface ImportData { readonly importPath: string; readonly declarationName?: string; @@ -1049,18 +1130,24 @@ interface ImportData { class GenerationInfoFrame { private readonly blockLambdaManager: IdManager; private readonly importSet: Map; + private readonly utilitySet: Set; public readonly isInsidePipeline: boolean; public readonly targetPlaceholder: string | undefined; + public readonly disableRunnerIntegration: boolean; constructor( importSet: Map = new Map(), + utilitySet: Set = new Set(), insidePipeline: boolean = false, targetPlaceholder: string | undefined = undefined, + disableRunnerIntegration: boolean = false, ) { this.blockLambdaManager = new IdManager(); this.importSet = importSet; + this.utilitySet = utilitySet; this.isInsidePipeline = insidePipeline; this.targetPlaceholder = targetPlaceholder; + this.disableRunnerIntegration = disableRunnerIntegration; } addImport(importData: ImportData | undefined) { @@ -1072,6 +1159,13 @@ class GenerationInfoFrame { } } + addUtility(utilityFunction: UtilityFunction) { + this.utilitySet.add(utilityFunction); + for (const importData of utilityFunction.imports) { + this.addImport(importData); + } + } + getUniqueLambdaBlockName(lambda: SdsBlockLambda): string { return `${BLOCK_LAMBDA_PREFIX}${this.blockLambdaManager.assignId(lambda)}`; } @@ -1081,4 +1175,5 @@ export interface GenerateOptions { destination: URI; createSourceMaps: boolean; targetPlaceholder: string | undefined; + disableRunnerIntegration: boolean; } diff --git a/packages/safe-ds-lang/tests/language/generation/creator.ts b/packages/safe-ds-lang/tests/language/generation/creator.ts index cec13c10d..94a11d70f 100644 --- a/packages/safe-ds-lang/tests/language/generation/creator.ts +++ b/packages/safe-ds-lang/tests/language/generation/creator.ts @@ -82,6 +82,7 @@ const createGenerationTest = async (parentDirectory: URI, inputUris: URI[]): Pro actualOutputRoot, expectedOutputFiles, runUntil, + disableRunnerIntegration: shortenedResourceName.startsWith('eject'), // Tests in the "eject" top level folder are tested with disabled runner integration }; }; @@ -115,6 +116,7 @@ const invalidTest = (level: 'FILE' | 'SUITE', error: TestDescriptionError): Gene actualOutputRoot: URI.file(''), expectedOutputFiles: [], error, + disableRunnerIntegration: false, }; }; @@ -141,6 +143,11 @@ interface GenerationTest extends TestDescription { * Location after which execution should be stopped. */ runUntil?: Location; + + /** + * Whether the test should run with runner integration (memoization & placeholder saving) disabled + */ + disableRunnerIntegration: boolean; } /** diff --git a/packages/safe-ds-lang/tests/language/generation/safe-ds-python-generator.test.ts b/packages/safe-ds-lang/tests/language/generation/safe-ds-python-generator.test.ts index 75aa9be22..8d86d0d68 100644 --- a/packages/safe-ds-lang/tests/language/generation/safe-ds-python-generator.test.ts +++ b/packages/safe-ds-lang/tests/language/generation/safe-ds-python-generator.test.ts @@ -36,6 +36,7 @@ describe('generation', async () => { destination: test.actualOutputRoot, createSourceMaps: true, targetPlaceholder: runUntilPlaceholderName, + disableRunnerIntegration: test.disableRunnerIntegration, }), ) .map((textDocument) => [textDocument.uri, textDocument.getText()]) diff --git a/packages/safe-ds-lang/tests/resources/generation/eject/input.sdstest b/packages/safe-ds-lang/tests/resources/generation/eject/input.sdstest new file mode 100644 index 000000000..a75130d75 --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/generation/eject/input.sdstest @@ -0,0 +1,24 @@ +package tests.generator.eject + +@Impure([ImpurityReason.Other]) fun f(param: Any?) + +@Pure fun g() -> result: Boolean + +@Pure fun i() -> result: Int? + +@Pure fun factory() -> instance: C? + +class C() { + attr a: Int + @PythonName("c") attr b: Int +} + +pipeline test { + f(g() or g()); + f(g() and g()); + + f(factory()?.a); + f(factory()?.b); + + f(i() ?: i()); +} diff --git a/packages/safe-ds-lang/tests/resources/generation/eject/output/tests/generator/eject/gen_input.py b/packages/safe-ds-lang/tests/resources/generation/eject/output/tests/generator/eject/gen_input.py new file mode 100644 index 000000000..aa2750540 --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/generation/eject/output/tests/generator/eject/gen_input.py @@ -0,0 +1,30 @@ +# Imports ---------------------------------------------------------------------- + +from typing import Any, TypeVar + +# Utils ------------------------------------------------------------------------ + +def __gen_eager_or(left_operand: bool, right_operand: bool) -> bool: + return left_operand or right_operand + +def __gen_eager_and(left_operand: bool, right_operand: bool) -> bool: + return left_operand and right_operand + +__gen_S = TypeVar("__gen_S") + +def __gen_safe_access(receiver: Any, member_name: str) -> __gen_S | None: + return getattr(receiver, member_name) if receiver is not None else None + +__gen_T = TypeVar("__gen_T") + +def __gen_eager_elvis(left_operand: __gen_T, right_operand: __gen_T) -> __gen_T: + return left_operand if left_operand is not None else right_operand + +# Pipelines -------------------------------------------------------------------- + +def test(): + f(__gen_eager_or(g(), g())) + f(__gen_eager_and(g(), g())) + f(__gen_safe_access(factory(), 'a')) + f(__gen_safe_access(factory(), 'c')) + f(__gen_eager_elvis(i(), i())) diff --git a/packages/safe-ds-lang/tests/resources/generation/eject/output/tests/generator/eject/gen_input.py.map b/packages/safe-ds-lang/tests/resources/generation/eject/output/tests/generator/eject/gen_input.py.map new file mode 100644 index 000000000..9ef834fd9 --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/generation/eject/output/tests/generator/eject/gen_input.py.map @@ -0,0 +1 @@ +{"version":3,"sources":["input.sdstest"],"names":["test","f","or","g","and","factory","a","b","i"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;AAeA,IAASA,IAAI;IACTC,CAAC,CAAKC,cAAE,CAANC,CAAC,IAAMA,CAAC;IACVF,CAAC,CAAKG,eAAG,CAAPD,CAAC,IAAOA,CAAC;IAEXF,CAAC,CAAU,iBAAC,CAAVI,OAAO,KAAIC,CAAC;IACdL,CAAC,CAAU,iBAAC,CAAVI,OAAO,KAAIE,CAAC;IAEdN,CAAC,CAAK,iBAAE,CAANO,CAAC,IAAMA,CAAC","file":"gen_input.py"} \ No newline at end of file diff --git a/packages/safe-ds-lang/tests/resources/generation/eject/output/tests/generator/eject/gen_input_test.py b/packages/safe-ds-lang/tests/resources/generation/eject/output/tests/generator/eject/gen_input_test.py new file mode 100644 index 000000000..824f70b1f --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/generation/eject/output/tests/generator/eject/gen_input_test.py @@ -0,0 +1,4 @@ +from .gen_input import test + +if __name__ == '__main__': + test() diff --git a/packages/safe-ds-lang/tests/resources/generation/expressions/infix operation/output/tests/generator/infixOperation/gen_input.py b/packages/safe-ds-lang/tests/resources/generation/expressions/infix operation/output/tests/generator/infixOperation/gen_input.py index 192da8512..9f2529504 100644 --- a/packages/safe-ds-lang/tests/resources/generation/expressions/infix operation/output/tests/generator/infixOperation/gen_input.py +++ b/packages/safe-ds-lang/tests/resources/generation/expressions/infix operation/output/tests/generator/infixOperation/gen_input.py @@ -1,13 +1,26 @@ # Imports ---------------------------------------------------------------------- -import safeds_runner.codegen import safeds_runner.server.pipeline_manager +from typing import TypeVar + +# Utils ------------------------------------------------------------------------ + +def __gen_eager_or(left_operand: bool, right_operand: bool) -> bool: + return left_operand or right_operand + +def __gen_eager_and(left_operand: bool, right_operand: bool) -> bool: + return left_operand and right_operand + +__gen_T = TypeVar("__gen_T") + +def __gen_eager_elvis(left_operand: __gen_T, right_operand: __gen_T) -> __gen_T: + return left_operand if left_operand is not None else right_operand # Pipelines -------------------------------------------------------------------- def test(): - f(safeds_runner.codegen.eager_or(safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.g", g, [], []), safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.g", g, [], []))) - f(safeds_runner.codegen.eager_and(safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.g", g, [], []), safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.g", g, [], []))) + f(__gen_eager_or(safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.g", g, [], []), safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.g", g, [], []))) + f(__gen_eager_and(safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.g", g, [], []), safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.g", g, [], []))) f((safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.h", h, [], [])) == (safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.h", h, [], []))) f((safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.h", h, [], [])) != (safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.h", h, [], []))) f((safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.h", h, [], [])) is (safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.h", h, [], []))) @@ -20,4 +33,4 @@ def test(): f((safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.h", h, [], [])) - (safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.h", h, [], []))) f((safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.h", h, [], [])) * (safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.h", h, [], []))) f((safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.h", h, [], [])) / (safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.h", h, [], []))) - f(safeds_runner.codegen.eager_elvis(safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.i", i, [], []), safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.i", i, [], []))) + f(__gen_eager_elvis(safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.i", i, [], []), safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.infixOperation.i", i, [], []))) diff --git a/packages/safe-ds-lang/tests/resources/generation/expressions/infix operation/output/tests/generator/infixOperation/gen_input.py.map b/packages/safe-ds-lang/tests/resources/generation/expressions/infix operation/output/tests/generator/infixOperation/gen_input.py.map index d1e853d11..36bb9ecd6 100644 --- a/packages/safe-ds-lang/tests/resources/generation/expressions/infix operation/output/tests/generator/infixOperation/gen_input.py.map +++ b/packages/safe-ds-lang/tests/resources/generation/expressions/infix operation/output/tests/generator/infixOperation/gen_input.py.map @@ -1 +1 @@ -{"version":3,"sources":["input.sdstest"],"names":["test","f","or","g","and","h","i"],"mappings":"AAAA;;;;;;;AAUA,IAASA,IAAI;IACTC,CAAC,CAAKC,8BAAE,CAAN,wGAAAC,CAAC,WAAM,wGAAAA,CAAC;IACVF,CAAC,CAAKG,+BAAG,CAAP,wGAAAD,CAAC,WAAO,wGAAAA,CAAC;IAEXF,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,EAAE,EAAC,wGAAAA,CAAC;IACVJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,EAAE,EAAC,wGAAAA,CAAC;IACVJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,EAAG,EAAC,wGAAAA,CAAC;IACXJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,QAAI,wGAAAA,CAAC;IAEXJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,CAAC,EAAC,wGAAAA,CAAC;IACTJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,EAAE,EAAC,wGAAAA,CAAC;IACVJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,EAAE,EAAC,wGAAAA,CAAC;IACVJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,CAAC,EAAC,wGAAAA,CAAC;IAETJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,CAAC,EAAC,wGAAAA,CAAC;IACTJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,CAAC,EAAC,wGAAAA,CAAC;IACTJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,CAAC,EAAC,wGAAAA,CAAC;IACTJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,CAAC,EAAC,wGAAAA,CAAC;IAETJ,CAAC,CAAK,iCAAE,CAAN,wGAAAK,CAAC,WAAM,wGAAAA,CAAC","file":"gen_input.py"} \ No newline at end of file +{"version":3,"sources":["input.sdstest"],"names":["test","f","or","g","and","h","i"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;AAUA,IAASA,IAAI;IACTC,CAAC,CAAKC,cAAE,CAAN,wGAAAC,CAAC,WAAM,wGAAAA,CAAC;IACVF,CAAC,CAAKG,eAAG,CAAP,wGAAAD,CAAC,WAAO,wGAAAA,CAAC;IAEXF,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,EAAE,EAAC,wGAAAA,CAAC;IACVJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,EAAE,EAAC,wGAAAA,CAAC;IACVJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,EAAG,EAAC,wGAAAA,CAAC;IACXJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,QAAI,wGAAAA,CAAC;IAEXJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,CAAC,EAAC,wGAAAA,CAAC;IACTJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,EAAE,EAAC,wGAAAA,CAAC;IACVJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,EAAE,EAAC,wGAAAA,CAAC;IACVJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,CAAC,EAAC,wGAAAA,CAAC;IAETJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,CAAC,EAAC,wGAAAA,CAAC;IACTJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,CAAC,EAAC,wGAAAA,CAAC;IACTJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,CAAC,EAAC,wGAAAA,CAAC;IACTJ,CAAC,CAAC,CAAA,wGAAAI,CAAC,WAAG,CAAC,EAAC,wGAAAA,CAAC;IAETJ,CAAC,CAAK,iBAAE,CAAN,wGAAAK,CAAC,WAAM,wGAAAA,CAAC","file":"gen_input.py"} \ No newline at end of file diff --git a/packages/safe-ds-lang/tests/resources/generation/expressions/member access/output/tests/generator/memberAccess/gen_input.py b/packages/safe-ds-lang/tests/resources/generation/expressions/member access/output/tests/generator/memberAccess/gen_input.py index 984201abb..899aed991 100644 --- a/packages/safe-ds-lang/tests/resources/generation/expressions/member access/output/tests/generator/memberAccess/gen_input.py +++ b/packages/safe-ds-lang/tests/resources/generation/expressions/member access/output/tests/generator/memberAccess/gen_input.py @@ -1,7 +1,14 @@ # Imports ---------------------------------------------------------------------- -import safeds_runner.codegen import safeds_runner.server.pipeline_manager +from typing import Any, TypeVar + +# Utils ------------------------------------------------------------------------ + +__gen_S = TypeVar("__gen_S") + +def __gen_safe_access(receiver: Any, member_name: str) -> __gen_S | None: + return getattr(receiver, member_name) if receiver is not None else None # Pipelines -------------------------------------------------------------------- @@ -11,8 +18,8 @@ def test(): f(safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.memberAccess.h", h, [], [])[1]) f(safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.memberAccess.C", C, [], []).a) f(safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.memberAccess.C", C, [], []).c) - f(safeds_runner.codegen.safe_access(safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.memberAccess.factory", factory, [], []), 'a')) - f(safeds_runner.codegen.safe_access(safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.memberAccess.factory", factory, [], []), 'c')) + f(__gen_safe_access(safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.memberAccess.factory", factory, [], []), 'a')) + f(__gen_safe_access(safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.memberAccess.factory", factory, [], []), 'c')) f(safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.memberAccess.C.i", lambda *_ : 1.i(safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.memberAccess.C", C, [], [])), [1], [])) f(safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.memberAccess.C.j", C.j, [safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.memberAccess.C", C, [], []), 123], [])) f(safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.memberAccess.C.k2", C.k2, [safeds_runner.server.pipeline_manager.runner_memoized_function_call("tests.generator.memberAccess.C", C, [], []), 'abc'], [])) diff --git a/packages/safe-ds-lang/tests/resources/generation/expressions/member access/output/tests/generator/memberAccess/gen_input.py.map b/packages/safe-ds-lang/tests/resources/generation/expressions/member access/output/tests/generator/memberAccess/gen_input.py.map index a487e4f3d..eb804acfa 100644 --- a/packages/safe-ds-lang/tests/resources/generation/expressions/member access/output/tests/generator/memberAccess/gen_input.py.map +++ b/packages/safe-ds-lang/tests/resources/generation/expressions/member access/output/tests/generator/memberAccess/gen_input.py.map @@ -1 +1 @@ -{"version":3,"sources":["input.sdstest"],"names":["test","f","g","h","result1","result2","c","a","b","factory","j","k","from_csv_file"],"mappings":"AAAA;;;;;;;AA4BA,IAASA,IAAI;IACTC,CAAC,CAAC,sGAAAC,CAAC;IACHD,CAAC,CAAC,sGAAAE,CAAC,UAAGC,CAAO;IACbH,CAAC,CAAC,sGAAAE,CAAC,UAAGE,CAAO;IACbJ,CAAC,CAAC,sGAAAK,CAAC,UAAGC,CAAC;IACPN,CAAC,CAAC,sGAAAK,CAAC,UAAGE,CAAC;IACPP,CAAC,CAAU,iCAAC,CAAV,4GAAAQ,OAAO,YAAIF,CAAC;IACdN,CAAC,CAAU,iCAAC,CAAV,4GAAAQ,OAAO,YAAID,CAAC;IACdP,CAAC,CAAC,oHAAM,CAAC,GAAP,sGAAAK,CAAC,aAAK,CAAC;IACTL,CAAC,CAAC,wGAAAK,CAAC,CAAGI,CAAC,GAAL,sGAAAJ,CAAC,WAAK,GAAG;IACXL,CAAC,CAAC,yGAAAK,CAAC,CAAGK,EAAC,GAAL,sGAAAL,CAAC,WAAK,KAAK;IACbL,CAAC,CAAC,oHAAAK,CAAC,CAACM,aAAa,GAAC,SAAS,IAAT,uDAAA,SAAS","file":"gen_input.py"} \ No newline at end of file +{"version":3,"sources":["input.sdstest"],"names":["test","f","g","h","result1","result2","c","a","b","factory","j","k","from_csv_file"],"mappings":"AAAA;;;;;;;;;;;;;;AA4BA,IAASA,IAAI;IACTC,CAAC,CAAC,sGAAAC,CAAC;IACHD,CAAC,CAAC,sGAAAE,CAAC,UAAGC,CAAO;IACbH,CAAC,CAAC,sGAAAE,CAAC,UAAGE,CAAO;IACbJ,CAAC,CAAC,sGAAAK,CAAC,UAAGC,CAAC;IACPN,CAAC,CAAC,sGAAAK,CAAC,UAAGE,CAAC;IACPP,CAAC,CAAU,iBAAC,CAAV,4GAAAQ,OAAO,YAAIF,CAAC;IACdN,CAAC,CAAU,iBAAC,CAAV,4GAAAQ,OAAO,YAAID,CAAC;IACdP,CAAC,CAAC,oHAAM,CAAC,GAAP,sGAAAK,CAAC,aAAK,CAAC;IACTL,CAAC,CAAC,wGAAAK,CAAC,CAAGI,CAAC,GAAL,sGAAAJ,CAAC,WAAK,GAAG;IACXL,CAAC,CAAC,yGAAAK,CAAC,CAAGK,EAAC,GAAL,sGAAAL,CAAC,WAAK,KAAK;IACbL,CAAC,CAAC,oHAAAK,CAAC,CAACM,aAAa,GAAC,SAAS,IAAT,uDAAA,SAAS","file":"gen_input.py"} \ No newline at end of file diff --git a/packages/safe-ds-vscode/src/extension/pythonServer.ts b/packages/safe-ds-vscode/src/extension/pythonServer.ts index c66560216..ae6947ffb 100644 --- a/packages/safe-ds-vscode/src/extension/pythonServer.ts +++ b/packages/safe-ds-vscode/src/extension/pythonServer.ts @@ -286,6 +286,7 @@ const generateCodeForRunner = function ( destination: URI.file(rootGenerationDir), // actual directory of main module file createSourceMaps: true, targetPlaceholder, + disableRunnerIntegration: false, }); const lastGeneratedSources = new Map(); let codeMap: ProgramCodeMap = {};