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 e421a95c4..734a54a91 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 @@ -55,6 +55,7 @@ import { SdsBlock, SdsBlockLambda, SdsCall, + SdsClassMember, SdsDeclaration, SdsExpression, SdsModule, @@ -1018,6 +1019,10 @@ export class SafeDsPythonGenerator { Parameter.isOptional(this.nodeMapper.argumentToParameter(arg)), ); const fullyQualifiedTargetName = this.generateFullyQualifiedFunctionName(expression); + if (!containsOptionalArgs && isSdsMemberAccess(expression.receiver)) { + const referenceImport = this.createImportDataForReference(expression.receiver.member!); + frame.addImport(referenceImport); + } return expandTracedToNode(expression)`${RUNNER_PACKAGE}.memoized_call("${fullyQualifiedTargetName}", ${ containsOptionalArgs ? 'lambda *_ : ' : '' }${ @@ -1028,7 +1033,9 @@ export class SafeDsPythonGenerator { expression.receiver.receiver.receiver, frame, )}.${this.generateExpression(expression.receiver.member!, frame)}` - : this.generateExpression(expression.receiver, frame) + : isSdsMemberAccess(expression.receiver) + ? this.getClassQualifiedNameForMember(callable) + : this.generateExpression(expression.receiver, frame) }, [${generateThisParam ? thisParam : ''}${ generateThisParam && memoizedArgs.length > 0 ? ', ' : '' }${joinTracedToNode(expression.argumentList, 'arguments')( @@ -1083,6 +1090,16 @@ export class SafeDsPythonGenerator { throw new Error('Callable of provided call does not exist or is not a declaration.'); } + private getClassQualifiedNameForMember(node: SdsClassMember): string { + const classMemberPath = []; + let enclosingClass: SdsDeclaration | undefined = node; + while (enclosingClass) { + classMemberPath.unshift(this.getPythonNameOrDefault(enclosingClass)); + enclosingClass = AstUtils.getContainerOfType(enclosingClass.$container, isSdsClass); + } + return classMemberPath.join('.'); + } + private getArgumentsMap( argumentList: SdsArgument[], frame: GenerationInfoFrame, diff --git a/packages/safe-ds-lang/tests/resources/generation/python/runner integration/expressions/member access/generated/tests/generator/memberAccessWithRunnerIntegration/gen_input.py b/packages/safe-ds-lang/tests/resources/generation/python/runner integration/expressions/member access/generated/tests/generator/memberAccessWithRunnerIntegration/gen_input.py index 9eccb036d..153481ae6 100644 --- a/packages/safe-ds-lang/tests/resources/generation/python/runner integration/expressions/member access/generated/tests/generator/memberAccessWithRunnerIntegration/gen_input.py +++ b/packages/safe-ds-lang/tests/resources/generation/python/runner integration/expressions/member access/generated/tests/generator/memberAccessWithRunnerIntegration/gen_input.py @@ -1,7 +1,8 @@ # Imports ---------------------------------------------------------------------- import safeds_runner -from tests.generator.memberAccessWithRunnerIntegration import C, f, factory, g, h +from safeds.data.tabular.containers import Table +from tests.generator.memberAccessWithRunnerIntegration import C, f, factory, factoryNested, g, h, Outer from typing import Any, TypeVar # Type variables --------------------------------------------------------------- @@ -27,3 +28,14 @@ def test(): f(safeds_runner.memoized_call("tests.generator.memberAccessWithRunnerIntegration.C.j", C.j, [safeds_runner.memoized_call("tests.generator.memberAccessWithRunnerIntegration.C", C, [], []), 123], [])) f(safeds_runner.memoized_call("tests.generator.memberAccessWithRunnerIntegration.C.k2", C.k2, [safeds_runner.memoized_call("tests.generator.memberAccessWithRunnerIntegration.C", C, [], []), 'abc'], [])) f(safeds_runner.memoized_call("tests.generator.memberAccessWithRunnerIntegration.C.from_csv_file", C.from_csv_file, ['abc.csv'], [safeds_runner.file_mtime('abc.csv')])) + a = safeds_runner.memoized_call("safeds.data.tabular.containers.Table.from_csv_file", Table.from_csv_file, ['abc.csv'], [safeds_runner.file_mtime('abc.csv')]) + safeds_runner.save_placeholder('a', a) + v = safeds_runner.memoized_call("safeds.data.tabular.containers.Table.get_column", Table.get_column, [a, 'b'], []) + safeds_runner.save_placeholder('v', v) + f(v) + f(safeds_runner.memoized_call("tests.generator.memberAccessWithRunnerIntegration.Outer.Nested.f", Outer.Nested.f, [], [])) + nestedInstance = safeds_runner.memoized_call("tests.generator.memberAccessWithRunnerIntegration.factoryNested", factoryNested, [], []) + safeds_runner.save_placeholder('nestedInstance', nestedInstance) + nestedResult = safeds_runner.memoized_call("tests.generator.memberAccessWithRunnerIntegration.Outer.Nested.g", Outer.Nested.g, [nestedInstance], []) + safeds_runner.save_placeholder('nestedResult', nestedResult) + f(nestedResult) diff --git a/packages/safe-ds-lang/tests/resources/generation/python/runner integration/expressions/member access/generated/tests/generator/memberAccessWithRunnerIntegration/gen_input.py.map b/packages/safe-ds-lang/tests/resources/generation/python/runner integration/expressions/member access/generated/tests/generator/memberAccessWithRunnerIntegration/gen_input.py.map index 41430fb2d..5ed84ea1e 100644 --- a/packages/safe-ds-lang/tests/resources/generation/python/runner integration/expressions/member access/generated/tests/generator/memberAccessWithRunnerIntegration/gen_input.py.map +++ b/packages/safe-ds-lang/tests/resources/generation/python/runner integration/expressions/member access/generated/tests/generator/memberAccessWithRunnerIntegration/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,mFAAAC,CAAC;IACHD,CAAC,CAAC,mFAAAE,CAAC,UAAGC,CAAO;IACbH,CAAC,CAAC,mFAAAE,CAAC,UAAGE,CAAO;IACbJ,CAAC,CAAC,mFAAAK,CAAC,UAAGC,CAAC;IACPN,CAAC,CAAC,mFAAAK,CAAC,UAAGE,CAAC;IACPP,CAAC,CAAU,6BAAC,CAAV,yFAAAQ,OAAO,YAAIF,CAAC;IACdN,CAAC,CAAU,6BAAC,CAAV,yFAAAQ,OAAO,YAAID,CAAC;IACdP,CAAC,CAAC,iGAAM,CAAC,GAAP,mFAAAK,CAAC,aAAK,CAAC;IACTL,CAAC,CAAC,qFAAAK,CAAC,CAAGI,CAAC,GAAL,mFAAAJ,CAAC,WAAK,GAAG;IACXL,CAAC,CAAC,sFAAAK,CAAC,CAAGK,EAAC,GAAL,mFAAAL,CAAC,WAAK,KAAK;IACbL,CAAC,CAAC,iGAAAK,CAAC,CAACM,aAAa,GAAC,SAAS,IAAT,yBAAA,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","v","factorynested","nestedinstance","nestedresult"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;AAwCA,IAASA,IAAI;IACTC,CAAC,CAAC,mFAAAC,CAAC;IACHD,CAAC,CAAC,mFAAAE,CAAC,UAAGC,CAAO;IACbH,CAAC,CAAC,mFAAAE,CAAC,UAAGE,CAAO;IACbJ,CAAC,CAAC,mFAAAK,CAAC,UAAGC,CAAC;IACPN,CAAC,CAAC,mFAAAK,CAAC,UAAGE,CAAC;IACPP,CAAC,CAAU,6BAAC,CAAV,yFAAAQ,OAAO,YAAIF,CAAC;IACdN,CAAC,CAAU,6BAAC,CAAV,yFAAAQ,OAAO,YAAID,CAAC;IACdP,CAAC,CAAC,iGAAM,CAAC,GAAP,mFAAAK,CAAC,aAAK,CAAC;IACTL,CAAC,CAAC,qFAAAK,CAAC,CAAGI,CAAC,GAAL,mFAAAJ,CAAC,WAAK,GAAG;IACXL,CAAC,CAAC,sFAAAK,CAAC,CAAGK,EAAC,GAAL,mFAAAL,CAAC,WAAK,KAAK;IACbL,CAAC,CAAC,mHAAgB,SAAS,IAAT,yBAAA,SAAS;IAC3B,IAAQ,wGAAkB,SAAS,IAAT,yBAAA,SAAS;IAAnC;IACA,IAAQ,kGAAAM,CAAC,EAAW,GAAG;IAAvB;IACAN,CAAC,CAACW,CAAC;IACHX,CAAC,CAAC;IACF,iBAAqB,+FAAAY,aAAa;IAAlC;IACA,eAAmB,iHAAAC,cAAc;IAAjC;IACAb,CAAC,CAACc,YAAY","file":"gen_input.py"} \ No newline at end of file diff --git a/packages/safe-ds-lang/tests/resources/generation/python/runner integration/expressions/member access/input.sdstest b/packages/safe-ds-lang/tests/resources/generation/python/runner integration/expressions/member access/input.sdstest index 27404f554..8e18adbec 100644 --- a/packages/safe-ds-lang/tests/resources/generation/python/runner integration/expressions/member access/input.sdstest +++ b/packages/safe-ds-lang/tests/resources/generation/python/runner integration/expressions/member access/input.sdstest @@ -24,8 +24,20 @@ class C() { static fun from_csv_file(name: String) -> c: C } +class Outer() { + class Nested() { + @Pure + static fun f() -> result: Boolean + + @Pure + fun g() -> result: Boolean + } +} + @Pure fun factory() -> instance: C? +@Pure fun factoryNested() -> instance: Outer.Nested + pipeline test { f(g().result); f(h().result1); @@ -38,4 +50,11 @@ pipeline test { f(C().j(123)); f(C().k("abc")); f(C.from_csv_file("abc.csv")); + val a = Table.fromCsvFile("abc.csv"); + val v = a.getColumn("b"); + f(v); + f(Outer.Nested.f()); + val nestedInstance = factoryNested(); + val nestedResult = nestedInstance.g(); + f(nestedResult); }