Skip to content

Commit

Permalink
feat: add assign float to int casting
Browse files Browse the repository at this point in the history
  • Loading branch information
Mati365 committed Jan 18, 2024
1 parent 3dd2ad9 commit c54630e
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 4 deletions.
1 change: 1 addition & 0 deletions packages/compiler-lexer/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './extractNestableTokensList';
export * from './isEOFToken';
export * from './isFloatMathOpToken';
export * from './isLineTerminatorToken';
export * from './isLogicOpToken';
export * from './isMathOpToken';
Expand Down
20 changes: 20 additions & 0 deletions packages/compiler-lexer/src/utils/isFloatMathOpToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { TokenType } from '../shared/TokenTypes';
import { isMathOpToken } from './isMathOpToken';

/**
* Checks if token can perform numeric expression
*/
export function isFloatMathOpToken(type: TokenType): boolean {
switch (type) {
case TokenType.BIT_SHIFT_LEFT:
case TokenType.BIT_SHIFT_RIGHT:
case TokenType.BIT_OR:
case TokenType.BIT_AND:
case TokenType.POW:
case TokenType.NOT:
return false;

default:
return isMathOpToken(type);
}
}
2 changes: 1 addition & 1 deletion packages/compiler-pico-c/src/constants/lang.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export enum CAssignOperator {
RIGHT_ASSIGN = '>>=',
AND_ASSIGN = '&=',
XOR_ASSIGN = '^=',
OR_ASSIGN = '||=',
OR_ASSIGN = '|=',
}

export type CMathOperator =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { isFloatMathOpToken, isMathOpToken } from '@ts-c-compiler/lexer';
import {
ASTCCompilerKind,
ASTCAssignmentExpression,
Expand All @@ -10,6 +11,8 @@ import {
} from '../../../errors/CTypeCheckError';

import { ASTCTypeCreator } from './ASTCTypeCreator';
import { isPrimitiveLikeType } from 'frontend/analyze/types';
import { CCOMPILER_ASSIGN_MATH_OPERATORS } from '#constants';

export class ASTCAssignmentExpressionTypeCreator extends ASTCTypeCreator<ASTCAssignmentExpression> {
kind = ASTCCompilerKind.AssignmentExpression;
Expand All @@ -20,7 +23,8 @@ export class ASTCAssignmentExpressionTypeCreator extends ASTCTypeCreator<ASTCAss
}

if (node.isOperatorExpression()) {
const { unaryExpression: left, expression: right } = node;
const { unaryExpression: left, expression: right, operator: op } = node;
const mathToken = CCOMPILER_ASSIGN_MATH_OPERATORS[op];

if (left?.type?.isConst()) {
throw new CTypeCheckError(
Expand All @@ -34,6 +38,28 @@ export class ASTCAssignmentExpressionTypeCreator extends ASTCTypeCreator<ASTCAss
);
}

if (
mathToken &&
isMathOpToken(mathToken) &&
!isFloatMathOpToken(mathToken) &&
isPrimitiveLikeType(left?.type, true) &&
isPrimitiveLikeType(right?.type, true) &&
left.type.isFloating() !== right.type.isFloating()
) {
throw new CTypeCheckError(
CTypeCheckErrorCode.MATH_EXPRESSION_MUST_BE_INTEGRAL_TYPE,
node.loc.start,
{
left:
left?.type?.getShortestDisplayName() ??
'<unknown-left-expr-type>',
right:
right?.type?.getShortestDisplayName() ??
'<unknown-right-expr-type>',
},
);
}

if (!checkLeftTypeOverlapping(left?.type, right?.type)) {
throw new CTypeCheckError(
CTypeCheckErrorCode.ASSIGNMENT_EXPRESSION_TYPES_MISMATCH,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { ASTCCompilerKind, ASTCBinaryOpNode } from 'frontend/parser/ast';
import { TokenType } from '@ts-c-compiler/lexer';
import {
TokenType,
isFloatMathOpToken,
isMathOpToken,
} from '@ts-c-compiler/lexer';

import { ASTCTypeCreator } from './ASTCTypeCreator';
import {
Expand All @@ -11,8 +15,9 @@ import {
checkLeftTypeOverlapping,
isPointerArithmeticOperator,
} from '../../../checker';

import { tryCastToPointer } from '../../../casts';
import { isPointerLikeType } from '../../../types';
import { isPointerLikeType, isPrimitiveLikeType } from '../../../types';

export class ASTCBinaryOpTypeCreator extends ASTCTypeCreator<ASTCBinaryOpNode> {
kind = ASTCCompilerKind.BinaryOperator;
Expand All @@ -26,6 +31,26 @@ export class ASTCBinaryOpTypeCreator extends ASTCTypeCreator<ASTCBinaryOpNode> {
const leftType = tryCastToPointer(left.type);
const rightType = tryCastToPointer(right.type);

if (
isMathOpToken(op) &&
!isFloatMathOpToken(op) &&
isPrimitiveLikeType(leftType, true) &&
isPrimitiveLikeType(rightType, true) &&
leftType.isFloating() !== rightType.isFloating()
) {
throw new CTypeCheckError(
CTypeCheckErrorCode.MATH_EXPRESSION_MUST_BE_INTEGRAL_TYPE,
node.loc.start,
{
left:
left?.type?.getShortestDisplayName() ?? '<unknown-left-expr-type>',
right:
right?.type?.getShortestDisplayName() ??
'<unknown-right-expr-type>',
},
);
}

if (!checkLeftTypeOverlapping(leftType, rightType)) {
throw new CTypeCheckError(
CTypeCheckErrorCode.OPERATOR_SIDES_TYPES_MISMATCH,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export enum CTypeCheckErrorCode {
INCORRECT_POINTER_SIDES_TYPES,
PROVIDED_TYPE_MUST_BE_POINTER,
UNABLE_EVAL_CONST_EXPRESSION,
MATH_EXPRESSION_MUST_BE_INTEGRAL_TYPE,
}

export const C_TYPE_CHECK_ERROR_TRANSLATIONS: Record<
Expand Down Expand Up @@ -144,6 +145,9 @@ export const C_TYPE_CHECK_ERROR_TRANSLATIONS: Record<
'Assignment to read-only type "%{left}"!',
[CTypeCheckErrorCode.OPERATOR_SIDES_TYPES_MISMATCH]:
'Operator types mismatch! Left side type "%{left}" mismatch with right side "%{right}"!',
[CTypeCheckErrorCode.MATH_EXPRESSION_MUST_BE_INTEGRAL_TYPE]:
// eslint-disable-next-line max-len
'Expression must be integral type! Left side type "%{left}" mismatch with right side "%{right}"! Try casting variable.',
[CTypeCheckErrorCode.REDEFINITION_OF_COMPILE_CONSTANT]:
'Redefinition of compile type constant "%{name}"!',
[CTypeCheckErrorCode.UNKNOWN_INITIALIZER_VALUE_TYPE]:
Expand Down
35 changes: 35 additions & 0 deletions packages/compiler-pico-c/tests/analyze/floats.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { CTypeCheckErrorCode } from './utils';

const BIT_OPERATORS = ['<<', '>>', '^', '|', '&'];

describe('Float typechecks', () => {
test.each(BIT_OPERATORS)(
'non math %s operator not work with floats in math expression',
operator => {
expect(/* cpp */ `
int main() {
float b = 4;
float a = b ${operator} 3;
}
`).toHaveCompilerError(
CTypeCheckErrorCode.MATH_EXPRESSION_MUST_BE_INTEGRAL_TYPE,
);
},
);

test.each(BIT_OPERATORS)(
'non math %s operator not work with floats in math assign expression',
operator => {
expect(/* cpp */ `
int main() {
float b = 4;
float a = 4;
a ${operator}= 3;
}
`).toHaveCompilerError(
CTypeCheckErrorCode.MATH_EXPRESSION_MUST_BE_INTEGRAL_TYPE,
);
},
);
});

0 comments on commit c54630e

Please sign in to comment.