diff --git a/src/types/resolveConstantValue.ts b/src/types/resolveConstantValue.ts index 5482c0799..873a7f08d 100644 --- a/src/types/resolveConstantValue.ts +++ b/src/types/resolveConstantValue.ts @@ -1,9 +1,10 @@ -import { Address, Cell, toNano } from "@ton/core"; +import { Address, Cell, Slice, toNano } from "@ton/core"; import { enabledMasterchain } from "../config/features"; import { CompilerContext } from "../context"; import { ASTExpression, throwError } from "../grammar/ast"; import { printTypeRef, TypeRef } from "./types"; import { sha256_sync } from "@ton/crypto"; +import { getExpType } from "./resolveExpression"; function reduceInt(ast: ASTExpression): bigint { if (ast.kind === 'number') { @@ -59,22 +60,51 @@ function reduceInt(ast: ASTExpression): bigint { throwError('Cannot reduce expression to a constant integer', ast.ref); } -function reduceBool(ast: ASTExpression): boolean { +function reduceBool(ast: ASTExpression, ctx: CompilerContext): boolean { if (ast.kind === 'boolean') { return ast.value; } if (ast.kind === 'op_unary') { if (ast.op === '!') { - return !reduceBool(ast.right); + return !reduceBool(ast.right, ctx); } } if (ast.kind === 'op_binary') { if (ast.op === '&&') { - return reduceBool(ast.left) && reduceBool(ast.right); + return reduceBool(ast.left, ctx) && reduceBool(ast.right, ctx); } else if (ast.op === '||') { - return reduceBool(ast.left) || reduceBool(ast.right); + return reduceBool(ast.left, ctx) || reduceBool(ast.right, ctx); + } else { + const leftType = getExpType(ctx, ast.left); + const rightType = getExpType(ctx, ast.right); + if (ast.op === '>') { + return reduceInt(ast.left) > reduceInt(ast.right); + } else if (ast.op === '<') { + return reduceInt(ast.left) < reduceInt(ast.right); + } else if (ast.op === '>=') { + return reduceInt(ast.left) >= reduceInt(ast.right); + } else if (ast.op === '<=') { + return reduceInt(ast.left) <= reduceInt(ast.right); + } else if (ast.op === '==') { + if (leftType.kind === 'ref' && rightType.kind === 'ref') { + if (leftType.name === 'Address' && rightType.name === 'Address') { + return reduceAddress(ast.left, ctx).equals(reduceAddress(ast.right, ctx)); + } else if (leftType.name === 'Cell' && rightType.name === 'Cell') { + return reduceCell(ast.left).equals(reduceCell(ast.right)); + } else if (leftType.name === 'String' && rightType.name === 'String') { + return reduceString(ast.left) === reduceString(ast.right); + } else if (leftType.name === 'Int' && rightType.name === 'Int') { + return reduceInt(ast.left) === reduceInt(ast.right); + } else if (leftType.name === 'Bool' && rightType.name === 'Bool') { + return reduceBool(ast.left, ctx) === reduceBool(ast.right, ctx); + } else if (leftType.name === 'Slice' && rightType.name === 'Slice') { + return reduceSlice(ast.left).asCell().equals(reduceSlice(ast.right).asCell()); + } + } else if (leftType.kind === 'null' && rightType.kind === 'null') { + return true; + } + } } - // TODO: More cases } throwError('Cannot reduce expression to a constant boolean', ast.ref); @@ -126,6 +156,24 @@ function reduceCell(ast: ASTExpression): Cell { throwError('Cannot reduce expression to a constant Cell', ast.ref); } +function reduceSlice(ast: ASTExpression): Slice { + if (ast.kind === 'op_static_call') { + if (ast.name === 'slice') { + if (ast.args.length === 1) { + const str = reduceString(ast.args[0]); + let c: Cell; + try { + c = Cell.fromBase64(str); + } catch (e) { + throwError(`Invalid cell ${str}`, ast.ref); + } + return c.asSlice(); + } + } + } + throwError('Cannot reduce expression to a constant Slice', ast.ref); +} + export function resolveConstantValue(type: TypeRef, ast: ASTExpression | null, ctx: CompilerContext) { if (ast === null) { return undefined; @@ -149,7 +197,7 @@ export function resolveConstantValue(type: TypeRef, ast: ASTExpression | null, c // Handle bool if (type.name === 'Bool') { - return reduceBool(ast); + return reduceBool(ast, ctx); } // Handle string