Skip to content

Commit

Permalink
fix: generate code for receivers outside of block lambdas (#1246)
Browse files Browse the repository at this point in the history
### Summary of Changes

The code that was generated for the following example was wrong: 

```
rawData.removeRows((row) {
    yield result = row.getValue("age").eq(22).^not();
});
```

The code that was created for `rawData` was inside the body of the
function created for the block lambda. Later references to `rawData`
were, thus, unresolved.
lars-reimann authored Oct 31, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 28f81bd commit 0d27e33
Showing 39 changed files with 228 additions and 139 deletions.
Original file line number Diff line number Diff line change
@@ -117,6 +117,7 @@ import { SafeDsSlicer } from '../../flow/safe-ds-slicer.js';

const LAMBDA_PREFIX = `${CODEGEN_PREFIX}lambda_`;
const BLOCK_LAMBDA_RESULT_PREFIX = `${CODEGEN_PREFIX}block_lambda_result_`;
const PLACEHOLDER_PREFIX = `${CODEGEN_PREFIX}placeholder_`;
const RECEIVER_PREFIX = `${CODEGEN_PREFIX}receiver_`;
const YIELD_PREFIX = `${CODEGEN_PREFIX}yield_`;

@@ -538,7 +539,7 @@ export class SafeDsPythonGenerator {
assignmentStatements.push(
expandTracedToNode(
savableAssignment,
)`${RUNNER_PACKAGE}.save_placeholder('${savableAssignment.name}', ${CODEGEN_PREFIX}${savableAssignment.name})`,
)`${RUNNER_PACKAGE}.save_placeholder('${savableAssignment.name}', ${PLACEHOLDER_PREFIX}${savableAssignment.name})`,
);
}
}
@@ -557,7 +558,7 @@ export class SafeDsPythonGenerator {
'name',
)(assignee.name)}`;
} else if (isSdsPlaceholder(assignee)) {
return expandTracedToNode(assignee)`${CODEGEN_PREFIX}${assignee.name}`;
return expandTracedToNode(assignee)`${PLACEHOLDER_PREFIX}${assignee.name}`;
} else if (isSdsWildcard(assignee)) {
return traceToNode(assignee)('_');
} else if (isSdsYield(assignee)) {
@@ -572,7 +573,8 @@ export class SafeDsPythonGenerator {

private generateBlockLambda(blockLambda: SdsBlockLambda, frame: GenerationInfoFrame): Generated {
const results = streamBlockLambdaResults(blockLambda).toArray();
const lambdaBlock = this.generateBlock(blockLambda.body, frame, true);
const lambdaFrame = frame.newScope();
const lambdaBlock = this.generateBlock(blockLambda.body, lambdaFrame, true);
if (results.length !== 0) {
lambdaBlock.appendNewLine();
lambdaBlock.append(
@@ -815,7 +817,7 @@ export class SafeDsPythonGenerator {
frame.addImport(referenceImport);

if (isSdsPlaceholder(declaration)) {
return traceToNode(expression)(`${CODEGEN_PREFIX}${declaration.name}`);
return traceToNode(expression)(`${PLACEHOLDER_PREFIX}${declaration.name}`);
} else {
return traceToNode(expression)(referenceImport?.alias ?? this.getPythonNameOrDefault(declaration));
}
Original file line number Diff line number Diff line change
@@ -23,5 +23,5 @@ def __gen_lambda_3(a, b=2):
def __gen_lambda_4(a, b=2):
__gen_block_lambda_result_d = g()
return __gen_block_lambda_result_d
__gen_c = f3(__gen_lambda_4)
g2(__gen_c)
__gen_placeholder_c = f3(__gen_lambda_4)
g2(__gen_placeholder_c)

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Segments ---------------------------------------------------------------------

def mySegment(p):
__gen_a = p
__gen_placeholder_a = p

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -5,4 +5,4 @@
# Pipelines --------------------------------------------------------------------

def test():
__gen_a = Table()
__gen_placeholder_a = Table()

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -2,6 +2,6 @@

def myPipeline():
__gen_receiver_0 = 'Hello, world!'
__gen_toBoolean = (bool((__gen_receiver_0)))
__gen_placeholder_toBoolean = (bool((__gen_receiver_0)))
__gen_receiver_1 = 'Hello, world!'
__gen_toString = (str((__gen_receiver_1)))
__gen_placeholder_toString = (str((__gen_receiver_1)))

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -2,38 +2,38 @@

def myPipeline():
__gen_receiver_0 = 'Hello, world!'
__gen_contains = (('world') in (__gen_receiver_0))
__gen_placeholder_contains = (('world') in (__gen_receiver_0))
__gen_receiver_1 = 'Hello, world!'
__gen_endsWith = ((__gen_receiver_1).endswith(('world!')))
__gen_placeholder_endsWith = ((__gen_receiver_1).endswith(('world!')))
__gen_receiver_2 = 'Hello, world!'
__gen_indexOf = ((__gen_receiver_2).find(('o')))
__gen_placeholder_indexOf = ((__gen_receiver_2).find(('o')))
__gen_receiver_3 = 'Hello, world!'
__gen_lastIndexOf = ((__gen_receiver_3).rfind(('o')))
__gen_placeholder_lastIndexOf = ((__gen_receiver_3).rfind(('o')))
__gen_receiver_4 = 'Hello, world!'
__gen_length = (len((__gen_receiver_4)))
__gen_placeholder_length = (len((__gen_receiver_4)))
__gen_receiver_5 = 'Hello, world!'
__gen_repeat = ((__gen_receiver_5) * (2))
__gen_placeholder_repeat = ((__gen_receiver_5) * (2))
__gen_receiver_6 = 'Hello, world!'
__gen_replace = ((__gen_receiver_6).replace(('world'), ('planet')))
__gen_placeholder_replace = ((__gen_receiver_6).replace(('world'), ('planet')))
__gen_receiver_7 = 'Hello, world!'
__gen_split = ((__gen_receiver_7).split((', ')))
__gen_placeholder_split = ((__gen_receiver_7).split((', ')))
__gen_receiver_8 = 'Hello, world!'
__gen_startsWith = ((__gen_receiver_8).startswith(('Hello')))
__gen_placeholder_startsWith = ((__gen_receiver_8).startswith(('Hello')))
__gen_receiver_9 = 'Hello, world!'
__gen_substring = ((__gen_receiver_9)[(7):()])
__gen_placeholder_substring = ((__gen_receiver_9)[(7):()])
__gen_receiver_10 = 'Hello, world!'
__gen_casefolded = ((__gen_receiver_10).casefold())
__gen_placeholder_casefolded = ((__gen_receiver_10).casefold())
__gen_receiver_11 = '3.14'
__gen_float = (float((__gen_receiver_11)))
__gen_placeholder_float = (float((__gen_receiver_11)))
__gen_receiver_12 = '42'
__gen_int = (int((__gen_receiver_12), ()))
__gen_placeholder_int = (int((__gen_receiver_12), ()))
__gen_receiver_13 = 'Hello, world!'
__gen_lowercase = ((__gen_receiver_13).lower())
__gen_placeholder_lowercase = ((__gen_receiver_13).lower())
__gen_receiver_14 = 'Hello, world!'
__gen_uppercase = ((__gen_receiver_14).upper())
__gen_placeholder_uppercase = ((__gen_receiver_14).upper())
__gen_receiver_15 = ' Hello, world! '
__gen_trimmed = ((__gen_receiver_15).strip())
__gen_placeholder_trimmed = ((__gen_receiver_15).strip())
__gen_receiver_16 = ' Hello, world! '
__gen_trimmedEnd = ((__gen_receiver_16).rstrip())
__gen_placeholder_trimmedEnd = ((__gen_receiver_16).rstrip())
__gen_receiver_17 = ' Hello, world! '
__gen_trimmedStart = ((__gen_receiver_17).lstrip())
__gen_placeholder_trimmedStart = ((__gen_receiver_17).lstrip())

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -5,10 +5,10 @@
# Pipelines --------------------------------------------------------------------

def testPipeline():
__gen_impureFileWrite = iFileWriteA()
__gen_impureFileWrite2 = iFileWriteA()
__gen_impureFileReadAgain = iFileReadA()
__gen_impureFileWriteB = iFileWriteB()
__gen_impureFileWrite2B = iFileWriteB()
__gen_impureFileReadAgainB = iFileReadB()
__gen_result = (__gen_impureFileReadAgain) + (__gen_impureFileReadAgainB)
__gen_placeholder_impureFileWrite = iFileWriteA()
__gen_placeholder_impureFileWrite2 = iFileWriteA()
__gen_placeholder_impureFileReadAgain = iFileReadA()
__gen_placeholder_impureFileWriteB = iFileWriteB()
__gen_placeholder_impureFileWrite2B = iFileWriteB()
__gen_placeholder_impureFileReadAgainB = iFileReadB()
__gen_placeholder_result = (__gen_placeholder_impureFileReadAgain) + (__gen_placeholder_impureFileReadAgainB)

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@
# Pipelines --------------------------------------------------------------------

def testPipeline():
__gen_impureFileWrite = iFileWrite('b.txt')
__gen_impureFileWrite2 = iFileWrite('c.txt')
__gen_impureFileReadAgain = iFileRead('d.txt')
__gen_result = (__gen_impureFileReadAgain) + (2)
__gen_placeholder_impureFileWrite = iFileWrite('b.txt')
__gen_placeholder_impureFileWrite2 = iFileWrite('c.txt')
__gen_placeholder_impureFileReadAgain = iFileRead('d.txt')
__gen_placeholder_result = (__gen_placeholder_impureFileReadAgain) + (2)

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -6,17 +6,17 @@

def testPipeline():
i1(1)
__gen_impureFileWrite = iFileWrite()
__gen_impureFileWrite2 = iFileWrite()
__gen_pureValueForImpure2 = noPartialEvalInt(2)
__gen_pureValueForImpure3 = 3
__gen_placeholder_impureFileWrite = iFileWrite()
__gen_placeholder_impureFileWrite2 = iFileWrite()
__gen_placeholder_pureValueForImpure2 = noPartialEvalInt(2)
__gen_placeholder_pureValueForImpure3 = 3
def __gen_lambda_0():
i1(1)
__gen_block_lambda_result_r = 1
return __gen_block_lambda_result_r
fp(__gen_lambda_0)
i1(1)
__gen_impureA1 = i1(__gen_pureValueForImpure2)
__gen_impureA2 = i1(noPartialEvalInt(3))
__gen_placeholder_impureA1 = i1(__gen_placeholder_pureValueForImpure2)
__gen_placeholder_impureA2 = i1(noPartialEvalInt(3))
i1(4)
__gen_result = i1(__gen_impureA2)
__gen_placeholder_result = i1(__gen_placeholder_impureA2)

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -5,30 +5,30 @@
# Pipelines --------------------------------------------------------------------

def testPipeline():
__gen_lFalse = False
__gen_lDouble = -1.0
__gen_lInt = 1
__gen_lNull = None
__gen_lStrMulti = 'multi\nline'
__gen_boolean1 = True
__gen_value1 = g(True, -1.0, 1, None, 'multi\nline')
__gen_placeholder_lFalse = False
__gen_placeholder_lDouble = -1.0
__gen_placeholder_lInt = 1
__gen_placeholder_lNull = None
__gen_placeholder_lStrMulti = 'multi\nline'
__gen_placeholder_boolean1 = True
__gen_placeholder_value1 = g(True, -1.0, 1, None, 'multi\nline')
def __gen_lambda_0():
__gen_i = 1
__gen_i2 = 3
__gen_j = 6
__gen_j2 = 4
__gen_placeholder_i = 1
__gen_placeholder_i2 = 3
__gen_placeholder_j = 6
__gen_placeholder_j2 = 4
__gen_block_lambda_result_z = 7
return __gen_block_lambda_result_z
def __gen_lambda_1():
return 2
__gen_o = (f(__gen_lambda_0)) + (f(__gen_lambda_1))
__gen_mapKey = 'key'
__gen_mapValue = 'value'
__gen_mapResult = g2({'key': 'value'})
__gen_listV1 = 1
__gen_listV3 = noPartialEvalInt(1)
__gen_list = [1]
__gen_list3 = [__gen_listV3]
__gen_listValue = __gen_list3[0]
__gen_listResult = g3(__gen_list)
__gen_result = (((-(__gen_o)) + (1)) + (__gen_value1)) + (((__gen_mapResult) * (__gen_listResult)) / (g4(__gen_listValue)))
__gen_placeholder_o = (f(__gen_lambda_0)) + (f(__gen_lambda_1))
__gen_placeholder_mapKey = 'key'
__gen_placeholder_mapValue = 'value'
__gen_placeholder_mapResult = g2({'key': 'value'})
__gen_placeholder_listV1 = 1
__gen_placeholder_listV3 = noPartialEvalInt(1)
__gen_placeholder_list = [1]
__gen_placeholder_list3 = [__gen_placeholder_listV3]
__gen_placeholder_listValue = __gen_placeholder_list3[0]
__gen_placeholder_listResult = g3(__gen_placeholder_list)
__gen_placeholder_result = (((-(__gen_placeholder_o)) + (1)) + (__gen_placeholder_value1)) + (((__gen_placeholder_mapResult) * (__gen_placeholder_listResult)) / (g4(__gen_placeholder_listValue)))

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -5,5 +5,5 @@
# Pipelines --------------------------------------------------------------------

def testPipeline():
__gen_pureValue = noPartialEvalInt(2)
__gen_result = (__gen_pureValue) - (1)
__gen_placeholder_pureValue = noPartialEvalInt(2)
__gen_placeholder_result = (__gen_placeholder_pureValue) - (1)
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Imports ----------------------------------------------------------------------

import safeds_runner
from tests.generation.python.runnerIntegration.blockLambdas import f
from tests.generation.python.runnerIntegration.blockLambdas import C, f

# Pipelines --------------------------------------------------------------------

@@ -16,11 +16,45 @@ def __gen_lambda_1(p):
[]
)
return __gen_block_lambda_result_r
__gen_result = safeds_runner.memoized_static_call(
__gen_placeholder__result = safeds_runner.memoized_static_call(
"tests.generation.python.runnerIntegration.blockLambdas.f",
f,
[__gen_lambda_1],
{},
[]
)
safeds_runner.save_placeholder('result', __gen_result)
safeds_runner.save_placeholder('_result', __gen_placeholder__result)
__gen_receiver_2 = safeds_runner.memoized_static_call(
"tests.generation.python.runnerIntegration.blockLambdas.C",
C,
[],
{},
[]
)
def __gen_lambda_4(a):
__gen_receiver_3 = a
__gen_block_lambda_result_result = safeds_runner.memoized_dynamic_call(
__gen_receiver_3,
"parent",
[],
{},
[]
)
return __gen_block_lambda_result_result
__gen_placeholder_result2 = safeds_runner.memoized_dynamic_call(
__gen_receiver_2,
"f1",
[__gen_lambda_4],
{},
[]
)
safeds_runner.save_placeholder('result2', __gen_placeholder_result2)
__gen_receiver_5 = __gen_placeholder_result2
__gen_placeholder_result3 = safeds_runner.memoized_dynamic_call(
__gen_receiver_5,
"parent",
[],
{},
[]
)
safeds_runner.save_placeholder('result3', __gen_placeholder_result3)
Original file line number Diff line number Diff line change
@@ -12,10 +12,21 @@ fun f(
callback: (p: MyClass) -> (r: Int)
) -> result: Any

class C() {
@Pure fun parent() -> parent: C

@Pure fun f1(param: (a: C) -> ()) -> parent: C
}

pipeline myPipeline {
val result = f(
val _result = f(
(p) {
yield r = p.g();
}
);

val result2 = C().f1((a) {
yield result = a.parent();
});
val result3 = result2.parent();
}
Original file line number Diff line number Diff line change
@@ -6,11 +6,11 @@
# Pipelines --------------------------------------------------------------------

def test():
__gen_a = safeds_runner.memoized_static_call(
__gen_placeholder_a = safeds_runner.memoized_static_call(
"tests.generator.runnerIntegration.expressions.calls.ofClasses.MyClass",
MyClass,
[0],
{},
[]
)
safeds_runner.save_placeholder('a', __gen_a)
safeds_runner.save_placeholder('a', __gen_placeholder_a)
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Imports ----------------------------------------------------------------------

import safeds_runner
from tests.generation.python.runnerIntegration.expressionLambdas import f
from tests.generation.python.runnerIntegration.expressionLambdas import C, f

# Pipelines --------------------------------------------------------------------

@@ -15,11 +15,44 @@ def __gen_lambda_0(p):
{},
[]
)
__gen_result = safeds_runner.memoized_static_call(
__gen_placeholder__result = safeds_runner.memoized_static_call(
"tests.generation.python.runnerIntegration.expressionLambdas.f",
f,
[__gen_lambda_0],
{},
[]
)
safeds_runner.save_placeholder('result', __gen_result)
safeds_runner.save_placeholder('_result', __gen_placeholder__result)
__gen_receiver_2 = safeds_runner.memoized_static_call(
"tests.generation.python.runnerIntegration.expressionLambdas.C",
C,
[],
{},
[]
)
def __gen_lambda_3(a):
__gen_receiver_4 = a
return safeds_runner.memoized_dynamic_call(
__gen_receiver_4,
"parent",
[],
{},
[]
)
__gen_placeholder_result2 = safeds_runner.memoized_dynamic_call(
__gen_receiver_2,
"f1",
[__gen_lambda_3],
{},
[]
)
safeds_runner.save_placeholder('result2', __gen_placeholder_result2)
__gen_receiver_5 = __gen_placeholder_result2
__gen_placeholder_result3 = safeds_runner.memoized_dynamic_call(
__gen_receiver_5,
"parent",
[],
{},
[]
)
safeds_runner.save_placeholder('result3', __gen_placeholder_result3)
Original file line number Diff line number Diff line change
@@ -12,8 +12,17 @@ fun f(
callback: (p: MyClass) -> (r: Int)
) -> result: Any

class C() {
@Pure fun parent() -> parent: C

@Pure fun f1(param: (a: C) -> ()) -> parent: C
}

pipeline myPipeline {
val result = f(
val _result = f(
(p) -> p.g()
);

val result2 = C().f1((a) -> a.parent());
val result3 = result2.parent();
}
Original file line number Diff line number Diff line change
@@ -13,11 +13,11 @@ def myPipeline():
{},
[]
)
__gen_a = safeds_runner.memoized_dynamic_call(
__gen_placeholder_a = safeds_runner.memoized_dynamic_call(
__gen_receiver_0,
"myFunction",
[],
{"p": __gen_receiver_0},
[]
)
safeds_runner.save_placeholder('a', __gen_a)
safeds_runner.save_placeholder('a', __gen_placeholder_a)
Original file line number Diff line number Diff line change
@@ -7,34 +7,34 @@

def testSegment():
g()
__gen_a, _, __gen_yield_c = g()
__gen_x, _, _ = g()
f1(__gen_a)
f1(__gen_x)
__gen_placeholder_a, _, __gen_yield_c = g()
__gen_placeholder_x, _, _ = g()
f1(__gen_placeholder_a)
f1(__gen_placeholder_x)
return __gen_yield_c

# Pipelines --------------------------------------------------------------------

def testPipeline():
g()
__gen_a, _, _ = g()
safeds_runner.save_placeholder('a', __gen_a)
__gen_x, _, _ = g()
safeds_runner.save_placeholder('x', __gen_x)
f1(__gen_a)
f1(__gen_x)
__gen_l, __gen_m, __gen_n = g()
safeds_runner.save_placeholder('l', __gen_l)
safeds_runner.save_placeholder('m', __gen_m)
safeds_runner.save_placeholder('n', __gen_n)
f1(__gen_l)
f1(__gen_m)
f1(__gen_n)
__gen_placeholder_a, _, _ = g()
safeds_runner.save_placeholder('a', __gen_placeholder_a)
__gen_placeholder_x, _, _ = g()
safeds_runner.save_placeholder('x', __gen_placeholder_x)
f1(__gen_placeholder_a)
f1(__gen_placeholder_x)
__gen_placeholder_l, __gen_placeholder_m, __gen_placeholder_n = g()
safeds_runner.save_placeholder('l', __gen_placeholder_l)
safeds_runner.save_placeholder('m', __gen_placeholder_m)
safeds_runner.save_placeholder('n', __gen_placeholder_n)
f1(__gen_placeholder_l)
f1(__gen_placeholder_m)
f1(__gen_placeholder_n)
def __gen_lambda_0():
g()
__gen_a, _, __gen_block_lambda_result_c = g()
__gen_x, _, _ = g()
f1(__gen_a)
f1(__gen_x)
__gen_placeholder_a, _, __gen_block_lambda_result_c = g()
__gen_placeholder_x, _, _ = g()
f1(__gen_placeholder_a)
f1(__gen_placeholder_x)
return __gen_block_lambda_result_c
f2(__gen_lambda_0)
Original file line number Diff line number Diff line change
@@ -6,29 +6,29 @@

def testSegment():
g()
__gen_a, _, __gen_yield_c = g()
__gen_x, _, _ = g()
f1(__gen_a)
f1(__gen_x)
__gen_placeholder_a, _, __gen_yield_c = g()
__gen_placeholder_x, _, _ = g()
f1(__gen_placeholder_a)
f1(__gen_placeholder_x)
return __gen_yield_c

# Pipelines --------------------------------------------------------------------

def testPipeline():
g()
__gen_a, _, _ = g()
__gen_x, _, _ = g()
f1(__gen_a)
f1(__gen_x)
__gen_l, __gen_m, __gen_n = g()
f1(__gen_l)
f1(__gen_m)
f1(__gen_n)
__gen_placeholder_a, _, _ = g()
__gen_placeholder_x, _, _ = g()
f1(__gen_placeholder_a)
f1(__gen_placeholder_x)
__gen_placeholder_l, __gen_placeholder_m, __gen_placeholder_n = g()
f1(__gen_placeholder_l)
f1(__gen_placeholder_m)
f1(__gen_placeholder_n)
def __gen_lambda_0():
g()
__gen_a, _, __gen_block_lambda_result_c = g()
__gen_x, _, _ = g()
f1(__gen_a)
f1(__gen_x)
__gen_placeholder_a, _, __gen_block_lambda_result_c = g()
__gen_placeholder_x, _, _ = g()
f1(__gen_placeholder_a)
f1(__gen_placeholder_x)
return __gen_block_lambda_result_c
f2(__gen_lambda_0)
Original file line number Diff line number Diff line change
@@ -5,4 +5,4 @@
# Pipelines --------------------------------------------------------------------

def testPipeline():
__gen_a = MyClass1()
__gen_placeholder_a = MyClass1()
Original file line number Diff line number Diff line change
@@ -5,4 +5,4 @@
# Pipelines --------------------------------------------------------------------

def testPipeline():
__gen_a = MyEnum1.MyEnumVariant1(1)
__gen_placeholder_a = MyEnum1.MyEnumVariant1(1)

0 comments on commit 0d27e33

Please sign in to comment.