Skip to content

Commit 989629a

Browse files
committed
[Tolk] Compiler built-in __expect_type() for testing purposes
Currently, tolk-tester can test various "output" of the compiler: pass input and check output, validate fif codegen, etc. But it can not test compiler internals and AST representation. I've added an ability to have special functions to check/expose internal compiler state. The first (and the only now) is: > __expect_type(some_expr, "<type>"); Such a call has special treatment in a compilation process. Compilation fails if this expression doesn't have requested type. It's intended to be used in tests only. Not present in stdlib.
1 parent c720204 commit 989629a

File tree

9 files changed

+147
-7
lines changed

9 files changed

+147
-7
lines changed

tolk-tester/tests/a6.tolk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
fun f(a: int, b: int, c: int, d: int, e: int, f: int): (int, int) {
22
// solve a 2x2 linear equation
33
var D: int = a*d - b*c;;;; var Dx: int = e*d-b*f ;;;; var Dy: int = a * f - e * c;
4+
__expect_type(D, "int");
5+
__expect_type(D*D, "int");
6+
__expect_type(calc_phi, "() -> int");
47
return (Dx/D,Dy/D);
58
};;;;
69

tolk-tester/tests/generics-1.tolk

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,12 @@ fun manyEq<T1, T2, T3>(a: T1, b: T2, c: T3): [T1, T2, T3] {
4141

4242
@method_id(104)
4343
fun test104(f: int) {
44-
return (
44+
var result = (
4545
manyEq(1 ? 1 : 1, f ? 0 : null, !f ? getTwo() as int : null),
4646
manyEq((f ? null as int : eq2(2), beginCell().storeBool(true).endCell().beginParse().loadBool()), 0, eq4(f))
4747
);
48+
__expect_type(result, "([int, int, int], [(int, bool), int, int])");
49+
return result;
4850
}
4951

5052
fun calcSum<X>(x: X, y: X) { return x + y; }
@@ -68,6 +70,7 @@ fun abstractTransform<X, Y, R>(xToY: (X) -> Y, yToR: (((Y))) -> R, initialX: X):
6870
@method_id(106)
6971
fun test106() {
7072
var c = beginCell().storeInt(106, 32).endCell();
73+
__expect_type(calcYPlus1<int>, "(int) -> int");
7174
return [
7275
abstractTransform(cellToSlice, calcLoad32, c),
7376
abstractTransform(calcYPlus1<int>, calcYPlus1<int>, 0),
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// the goal of this file is not only to @testcase results —
2+
// but to check that this file compiles
3+
4+
fun eq<X>(value: X): X { return value; }
5+
6+
fun test1(x: int, y: int) {
7+
__expect_type(0, "int");
8+
__expect_type("0"c, "int");
9+
__expect_type(x, "int");
10+
__expect_type(x + y, "int");
11+
__expect_type(x * y, "int");
12+
__expect_type(x & y, "int");
13+
__expect_type(x << y, "int");
14+
__expect_type((((x))), "int");
15+
__expect_type(x = x, "int");
16+
__expect_type(x += x, "int");
17+
__expect_type(x &= x, "int");
18+
__expect_type(random() ? x : y, "int");
19+
__expect_type(eq(x), "int");
20+
__expect_type(eq<int>(x), "int");
21+
__expect_type(eq<int>(null), "int");
22+
__expect_type(x as int, "int");
23+
__expect_type(+x, "int");
24+
__expect_type(~x, "int");
25+
{
26+
var x: slice = beginCell().endCell().beginParse();
27+
__expect_type(x, "slice");
28+
__expect_type(beginCell(), "builder");
29+
__expect_type(beginCell().endCell(), "cell");
30+
}
31+
}
32+
33+
fun test2(x: int, y: bool) {
34+
__expect_type(!x, "bool");
35+
__expect_type(x != x, "bool");
36+
__expect_type(x <= x, "bool");
37+
__expect_type(x <=> x, "bool");
38+
__expect_type(x <=> x, "bool");
39+
__expect_type(!random(), "bool");
40+
__expect_type(!!(x != null), "bool");
41+
__expect_type(x ? x != null : null == x, "bool");
42+
__expect_type(y & true, "bool");
43+
__expect_type(y ^= false, "bool");
44+
__expect_type(x && y, "bool");
45+
__expect_type(true && false && true, "bool");
46+
__expect_type(x || x, "bool");
47+
__expect_type(x || !x || (true & false), "bool");
48+
}
49+
50+
fun test3() {
51+
__expect_type(true as int, "int");
52+
__expect_type(!random() as int, "int");
53+
}
54+
55+
fun test4(x: int) {
56+
__expect_type((), "()");
57+
__expect_type((x, x), "(int, int)");
58+
__expect_type((x, (x, x), x), "(int, (int, int), int)");
59+
}
60+
61+
fun test5(x: int) {
62+
__expect_type([], "[]");
63+
__expect_type([x], "[int]");
64+
__expect_type([x, x >= 1], "[int, bool]");
65+
__expect_type([x, x >= 1, null as slice], "[int, bool, slice]");
66+
__expect_type((x, [x], [[x], x]), "(int, [int], [[int], int])");
67+
__expect_type(getMyOriginalBalanceWithExtraCurrencies(), "[int, cell]");
68+
}
69+
70+
fun test6() {
71+
var t = createEmptyTuple();
72+
__expect_type(t, "tuple");
73+
t.tuplePush(1);
74+
__expect_type(t, "tuple");
75+
}
76+
77+
fun test7() {
78+
__expect_type(test3(), "void");
79+
__expect_type(test3, "() -> void");
80+
var cb = test1;
81+
__expect_type(cb, "(int, int) -> void");
82+
var t = createEmptyTuple();
83+
__expect_type(beginCell().endCell, "(builder) -> cell");
84+
// __expect_type(eq<(int, slice)>, "(int, slice) -> (int, slice)");
85+
}
86+
87+
88+
fun main() {
89+
return 0;
90+
}
91+
92+
/**
93+
@testcase | 0 | | 0
94+
*/

tolk/builtins.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,6 +1255,13 @@ void define_builtins() {
12551255
define_builtin_func("debugDumpStack", {}, Unit, nullptr,
12561256
AsmOp::Custom("DUMPSTK", 0, 0),
12571257
0);
1258+
1259+
// functions not presented in stdlib at all
1260+
// used in tolk-tester to check/expose internal compiler state
1261+
// each of them is handled in a special way, search by its name
1262+
define_builtin_func("__expect_type", {TypeDataUnknown::create(), Slice}, Unit, nullptr,
1263+
AsmOp::Nop(),
1264+
FunctionData::flagMarkedAsPure);
12581265
}
12591266

12601267
} // namespace tolk

tolk/lexer.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,15 @@ Lexer::Lexer(const SrcFile* file)
555555
next();
556556
}
557557

558+
Lexer::Lexer(std::string_view text)
559+
: file(nullptr)
560+
, p_start(text.data())
561+
, p_end(p_start + text.size())
562+
, p_next(p_start)
563+
, location() {
564+
next();
565+
}
566+
558567
void Lexer::next() {
559568
while (cur_token_idx == last_token_idx && !is_eof()) {
560569
update_location();
@@ -563,7 +572,7 @@ void Lexer::next() {
563572
}
564573
}
565574
if (is_eof()) {
566-
add_token(tok_eof, file->text);
575+
add_token(tok_eof, "");
567576
}
568577
cur_token = tokens_circularbuf[++cur_token_idx & 7];
569578
}

tolk/lexer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ class Lexer {
173173
};
174174

175175
explicit Lexer(const SrcFile* file);
176+
explicit Lexer(std::string_view text);
176177
Lexer(const Lexer&) = delete;
177178
Lexer &operator=(const Lexer&) = delete;
178179

tolk/pipe-infer-types-and-calls.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,24 @@ class TypeInferringUnifyStrategy {
240240
TypePtr get_result() const { return unified_result; }
241241
};
242242

243+
// handle __expect_type(expr, "type") call
244+
// this is used in compiler tests
245+
GNU_ATTRIBUTE_NOINLINE GNU_ATTRIBUTE_COLD
246+
static void handle_possible_compiler_internal_call(const FunctionData* current_function, V<ast_function_call> v) {
247+
const FunctionData* fun_ref = v->fun_maybe;
248+
tolk_assert(fun_ref && fun_ref->is_builtin_function());
249+
static_cast<void>(current_function);
250+
251+
if (fun_ref->name == "__expect_type") {
252+
tolk_assert(v->get_num_args() == 2);
253+
TypePtr expected_type = parse_type_from_string(v->get_arg(1)->get_expr()->as<ast_string_const>()->str_val);
254+
TypePtr expr_type = v->get_arg(0)->inferred_type;
255+
if (expected_type != expr_type) {
256+
v->error("__expect_type failed: expected " + to_string(expected_type) + ", got " + to_string(expr_type));
257+
}
258+
}
259+
}
260+
243261
/*
244262
* This class handles all types of AST vertices and traverses them, filling all AnyExprV::inferred_type.
245263
* Note, that it isn't derived from ASTVisitor, it has manual `switch` over all existing vertex types.
@@ -974,6 +992,9 @@ class InferCheckTypesAndCallsAndFieldsVisitor final {
974992
TypePtr inferred_type = dot_obj && fun_ref->does_return_self() ? dot_obj->inferred_type : fun_ref->inferred_return_type;
975993
assign_inferred_type(v, inferred_type);
976994
assign_inferred_type(callee, fun_ref->inferred_full_type);
995+
if (fun_ref->is_builtin_function() && fun_ref->name[0] == '_') {
996+
handle_possible_compiler_internal_call(current_function, v);
997+
}
977998
// note, that mutate params don't affect typing, they are handled when converting to IR
978999
}
9791000

tolk/type-system.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -651,11 +651,6 @@ static TypePtr parse_simple_type(Lexer& lex) {
651651
std::vector<TypePtr> items = parse_nested_type_list(lex, tok_opbracket, "`[`", tok_clbracket, "`]` or `,`");
652652
return TypeDataTypedTuple::create(std::move(items));
653653
}
654-
case tok_fun: {
655-
lex.next();
656-
std::vector<TypePtr> params_types = parse_nested_type_list_in_parenthesis(lex);
657-
lex.expect(tok_arrow, "`->`");
658-
}
659654
default:
660655
lex.unexpected("<type>");
661656
}
@@ -695,6 +690,12 @@ TypePtr parse_type_from_tokens(Lexer& lex) {
695690
return parse_type_expression(lex);
696691
}
697692

693+
// for internal usage only
694+
TypePtr parse_type_from_string(std::string_view text) {
695+
Lexer lex(text);
696+
return parse_type_expression(lex);
697+
}
698+
698699
std::ostream& operator<<(std::ostream& os, TypePtr type_data) {
699700
return os << (type_data ? type_data->as_human_readable() : "(nullptr-type)");
700701
}

tolk/type-system.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,7 @@ class TypeDataVoid final : public TypeData {
417417

418418
class Lexer;
419419
TypePtr parse_type_from_tokens(Lexer& lex);
420+
TypePtr parse_type_from_string(std::string_view text);
420421

421422
void type_system_init();
422423

0 commit comments

Comments
 (0)