Skip to content

Commit

Permalink
feat: handle cells in code generator
Browse files Browse the repository at this point in the history
  • Loading branch information
lars-reimann committed Oct 31, 2024
1 parent 60ca2f3 commit 8a7926f
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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_`;
Expand All @@ -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;
}

Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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})`;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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 ---------------------------------------------------------------
Expand All @@ -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()))

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
Expand Up @@ -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());
}
Original file line number Diff line number Diff line change
@@ -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()))

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
Expand Up @@ -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());
}

0 comments on commit 8a7926f

Please sign in to comment.