1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

[Tolk] AST-based semantic analysis, get rid of Expr

This is a huge refactoring focusing on untangling compiler internals
(previously forked from FunC).
The goal is to convert AST directly to Op (a kind of IR representation),
doing all code analysis at AST level.

Noteable changes:
- AST-based semantic kernel includes: registering global symbols,
  scope handling and resolving local/global identifiers,
  lvalue/rvalue calc and check, implicit return detection,
  mutability analysis, pure/impure validity checks,
  simple constant folding
- values of `const` variables are calculated NOT based on CodeBlob,
  but via a newly-introduced AST-based constant evaluator
- AST vertices are now inherited from expression/statement/other;
  expression vertices have common properties (TypeExpr, lvalue/rvalue)
- symbol table is rewritten completely, SymDef/SymVal no longer exist,
  lexer now doesn't need to register identifiers
- AST vertices have references to symbols, filled at different
  stages of pipeline
- the remaining "FunC legacy part" is almost unchanged besides Expr
  which was fully dropped; AST is converted to Ops (IR) directly
This commit is contained in:
tolk-vm 2024-12-16 21:19:45 +03:00
parent ea0dc16163
commit 3540424aa1
No known key found for this signature in database
GPG key ID: 7905DD7FE0324B12
71 changed files with 4270 additions and 3060 deletions

View file

@ -75,7 +75,7 @@ static void fire_error_mix_and_or_no_parenthesis(SrcLocation loc, std::string_vi
// the only way to suppress this error for the programmer is to use parenthesis
// (how do we detect presence of parenthesis? simple: (0!=1) is ast_parenthesized_expr{ast_binary_operator},
// that's why if rhs->type == ast_binary_operator, it's not surrounded by parenthesis)
static void diagnose_bitwise_precedence(SrcLocation loc, std::string_view operator_name, AnyV lhs, AnyV rhs) {
static void diagnose_bitwise_precedence(SrcLocation loc, std::string_view operator_name, AnyExprV lhs, AnyExprV rhs) {
// handle "flags & 0xFF != 0" (rhs = "0xFF != 0")
if (rhs->type == ast_binary_operator && is_comparison_binary_op(rhs->as<ast_binary_operator>()->tok)) {
fire_error_lower_precedence(loc, operator_name, rhs->as<ast_binary_operator>()->operator_name);
@ -90,7 +90,7 @@ static void diagnose_bitwise_precedence(SrcLocation loc, std::string_view operat
// similar to above, but detect potentially invalid usage of && and ||
// since anyway, using parenthesis when both && and || occur in the same expression,
// && and || have equal operator precedence in Tolk
static void diagnose_and_or_precedence(SrcLocation loc, AnyV lhs, TokenType rhs_tok, std::string_view rhs_operator_name) {
static void diagnose_and_or_precedence(SrcLocation loc, AnyExprV lhs, TokenType rhs_tok, std::string_view rhs_operator_name) {
if (auto lhs_op = lhs->try_as<ast_binary_operator>()) {
// handle "arg1 & arg2 | arg3" (lhs = "arg1 & arg2")
if (is_bitwise_binary_op(lhs_op->tok) && is_bitwise_binary_op(rhs_tok) && lhs_op->tok != rhs_tok) {
@ -105,7 +105,7 @@ static void diagnose_and_or_precedence(SrcLocation loc, AnyV lhs, TokenType rhs_
}
// diagnose "a << 8 + 1" (equivalent to "a << 9", probably unexpected)
static void diagnose_addition_in_bitshift(SrcLocation loc, std::string_view bitshift_operator_name, AnyV rhs) {
static void diagnose_addition_in_bitshift(SrcLocation loc, std::string_view bitshift_operator_name, AnyExprV rhs) {
if (rhs->type == ast_binary_operator && is_add_or_sub_binary_op(rhs->as<ast_binary_operator>()->tok)) {
fire_error_lower_precedence(loc, bitshift_operator_name, rhs->as<ast_binary_operator>()->operator_name);
}
@ -122,7 +122,7 @@ static void fire_error_FunC_style_var_declaration(Lexer& lex) {
}
// replace (a == null) and similar to isNull(a) (call of a built-in function)
static AnyV maybe_replace_eq_null_with_isNull_call(V<ast_binary_operator> v) {
static AnyExprV maybe_replace_eq_null_with_isNull_call(V<ast_binary_operator> v) {
bool has_null = v->get_lhs()->type == ast_null_keyword || v->get_rhs()->type == ast_null_keyword;
bool replace = has_null && (v->tok == tok_eq || v->tok == tok_neq);
if (!replace) {
@ -130,9 +130,9 @@ static AnyV maybe_replace_eq_null_with_isNull_call(V<ast_binary_operator> v) {
}
auto v_ident = createV<ast_identifier>(v->loc, "__isNull"); // built-in function
AnyV v_null = v->get_lhs()->type == ast_null_keyword ? v->get_rhs() : v->get_lhs();
AnyV v_arg = createV<ast_argument>(v->loc, v_null, false);
AnyV v_isNull = createV<ast_function_call>(v->loc, v_ident, createV<ast_argument_list>(v->loc, {v_arg}));
AnyExprV v_null = v->get_lhs()->type == ast_null_keyword ? v->get_rhs() : v->get_lhs();
AnyExprV v_arg = createV<ast_argument>(v->loc, v_null, false);
AnyExprV v_isNull = createV<ast_function_call>(v->loc, v_ident, createV<ast_argument_list>(v->loc, {v_arg}));
if (v->tok == tok_neq) {
v_isNull = createV<ast_unary_operator>(v->loc, "!", tok_logical_not, v_isNull);
}
@ -230,7 +230,7 @@ static TypeExpr* parse_type(Lexer& lex, V<ast_genericsT_list> genericsT_list) {
return res;
}
AnyV parse_expr(Lexer& lex);
AnyExprV parse_expr(Lexer& lex);
static AnyV parse_parameter(Lexer& lex, V<ast_genericsT_list> genericsT_list, bool is_first) {
SrcLocation loc = lex.cur_location();
@ -256,7 +256,6 @@ static AnyV parse_parameter(Lexer& lex, V<ast_genericsT_list> genericsT_list, bo
} else if (lex.tok() != tok_underscore) {
lex.unexpected("parameter name");
}
auto v_ident = createV<ast_identifier>(lex.cur_location(), param_name);
lex.next();
// parameter type after colon, also mandatory (even explicit ":auto")
@ -269,7 +268,7 @@ static AnyV parse_parameter(Lexer& lex, V<ast_genericsT_list> genericsT_list, bo
throw ParseError(loc, "`self` parameter must be strictly typed");
}
return createV<ast_parameter>(loc, v_ident, param_type, declared_as_mutate);
return createV<ast_parameter>(loc, param_name, param_type, declared_as_mutate);
}
static AnyV parse_global_var_declaration(Lexer& lex, const std::vector<V<ast_annotation>>& annotations) {
@ -316,7 +315,7 @@ static AnyV parse_constant_declaration(Lexer& lex, const std::vector<V<ast_annot
}
}
lex.expect(tok_assign, "`=`");
AnyV init_value = parse_expr(lex);
AnyExprV init_value = parse_expr(lex);
if (lex.tok() == tok_comma) {
lex.error("multiple declarations are not allowed, split constants on separate lines");
}
@ -341,7 +340,7 @@ static V<ast_parameter_list> parse_parameter_list(Lexer& lex, V<ast_genericsT_li
}
// "arguments" are at function call: `f(arg1, mutate arg2)`
static AnyV parse_argument(Lexer& lex) {
static AnyExprV parse_argument(Lexer& lex) {
SrcLocation loc = lex.cur_location();
// keyword `mutate` is necessary when a parameter is declared `mutate` (to make mutation obvious for the reader)
@ -351,13 +350,13 @@ static AnyV parse_argument(Lexer& lex) {
passed_as_mutate = true;
}
AnyV expr = parse_expr(lex);
AnyExprV expr = parse_expr(lex);
return createV<ast_argument>(loc, expr, passed_as_mutate);
}
static V<ast_argument_list> parse_argument_list(Lexer& lex) {
SrcLocation loc = lex.cur_location();
std::vector<AnyV> args;
std::vector<AnyExprV> args;
lex.expect(tok_oppar, "`(`");
if (lex.tok() != tok_clpar) {
args.push_back(parse_argument(lex));
@ -371,7 +370,7 @@ static V<ast_argument_list> parse_argument_list(Lexer& lex) {
}
// parse (expr) / [expr] / identifier / number
static AnyV parse_expr100(Lexer& lex) {
static AnyExprV parse_expr100(Lexer& lex) {
SrcLocation loc = lex.cur_location();
switch (lex.tok()) {
case tok_oppar: {
@ -380,12 +379,12 @@ static AnyV parse_expr100(Lexer& lex) {
lex.next();
return createV<ast_tensor>(loc, {});
}
AnyV first = parse_expr(lex);
AnyExprV first = parse_expr(lex);
if (lex.tok() == tok_clpar) {
lex.next();
return createV<ast_parenthesized_expr>(loc, first);
return createV<ast_parenthesized_expression>(loc, first);
}
std::vector<AnyV> items(1, first);
std::vector<AnyExprV> items(1, first);
while (lex.tok() == tok_comma) {
lex.next();
items.emplace_back(parse_expr(lex));
@ -399,7 +398,7 @@ static AnyV parse_expr100(Lexer& lex) {
lex.next();
return createV<ast_tensor_square>(loc, {});
}
std::vector<AnyV> items(1, parse_expr(lex));
std::vector<AnyExprV> items(1, parse_expr(lex));
while (lex.tok() == tok_comma) {
lex.next();
items.emplace_back(parse_expr(lex));
@ -408,9 +407,13 @@ static AnyV parse_expr100(Lexer& lex) {
return createV<ast_tensor_square>(loc, std::move(items));
}
case tok_int_const: {
std::string_view int_val = lex.cur_str();
std::string_view orig_str = lex.cur_str();
td::RefInt256 intval = td::string_to_int256(static_cast<std::string>(orig_str));
if (intval.is_null() || !intval->signed_fits_bits(257)) {
lex.error("invalid integer constant");
}
lex.next();
return createV<ast_int_const>(loc, int_val);
return createV<ast_int_const>(loc, std::move(intval), orig_str);
}
case tok_string_const: {
std::string_view str_val = lex.cur_str();
@ -459,8 +462,8 @@ static AnyV parse_expr100(Lexer& lex) {
}
// parse E(args)
static AnyV parse_expr90(Lexer& lex) {
AnyV res = parse_expr100(lex);
static AnyExprV parse_expr90(Lexer& lex) {
AnyExprV res = parse_expr100(lex);
if (lex.tok() == tok_oppar) {
return createV<ast_function_call>(res->loc, res, parse_argument_list(lex));
}
@ -468,8 +471,8 @@ static AnyV parse_expr90(Lexer& lex) {
}
// parse E.method(...) (left-to-right)
static AnyV parse_expr80(Lexer& lex) {
AnyV lhs = parse_expr90(lex);
static AnyExprV parse_expr80(Lexer& lex) {
AnyExprV lhs = parse_expr90(lex);
while (lex.tok() == tok_dot) {
SrcLocation loc = lex.cur_location();
lex.next();
@ -482,27 +485,27 @@ static AnyV parse_expr80(Lexer& lex) {
}
// parse ! ~ - + E (unary)
static AnyV parse_expr75(Lexer& lex) {
static AnyExprV parse_expr75(Lexer& lex) {
TokenType t = lex.tok();
if (t == tok_logical_not || t == tok_bitwise_not || t == tok_minus || t == tok_plus) {
SrcLocation loc = lex.cur_location();
std::string_view operator_name = lex.cur_str();
lex.next();
AnyV rhs = parse_expr75(lex);
AnyExprV rhs = parse_expr75(lex);
return createV<ast_unary_operator>(loc, operator_name, t, rhs);
}
return parse_expr80(lex);
}
// parse E * / % ^/ ~/ E (left-to-right)
static AnyV parse_expr30(Lexer& lex) {
AnyV lhs = parse_expr75(lex);
static AnyExprV parse_expr30(Lexer& lex) {
AnyExprV lhs = parse_expr75(lex);
TokenType t = lex.tok();
while (t == tok_mul || t == tok_div || t == tok_mod || t == tok_divC || t == tok_divR) {
SrcLocation loc = lex.cur_location();
std::string_view operator_name = lex.cur_str();
lex.next();
AnyV rhs = parse_expr75(lex);
AnyExprV rhs = parse_expr75(lex);
lhs = createV<ast_binary_operator>(loc, operator_name, t, lhs, rhs);
t = lex.tok();
}
@ -510,14 +513,14 @@ static AnyV parse_expr30(Lexer& lex) {
}
// parse E + - E (left-to-right)
static AnyV parse_expr20(Lexer& lex) {
AnyV lhs = parse_expr30(lex);
static AnyExprV parse_expr20(Lexer& lex) {
AnyExprV lhs = parse_expr30(lex);
TokenType t = lex.tok();
while (t == tok_minus || t == tok_plus) {
SrcLocation loc = lex.cur_location();
std::string_view operator_name = lex.cur_str();
lex.next();
AnyV rhs = parse_expr30(lex);
AnyExprV rhs = parse_expr30(lex);
lhs = createV<ast_binary_operator>(loc, operator_name, t, lhs, rhs);
t = lex.tok();
}
@ -525,14 +528,14 @@ static AnyV parse_expr20(Lexer& lex) {
}
// parse E << >> ~>> ^>> E (left-to-right)
static AnyV parse_expr17(Lexer& lex) {
AnyV lhs = parse_expr20(lex);
static AnyExprV parse_expr17(Lexer& lex) {
AnyExprV lhs = parse_expr20(lex);
TokenType t = lex.tok();
while (t == tok_lshift || t == tok_rshift || t == tok_rshiftC || t == tok_rshiftR) {
SrcLocation loc = lex.cur_location();
std::string_view operator_name = lex.cur_str();
lex.next();
AnyV rhs = parse_expr20(lex);
AnyExprV rhs = parse_expr20(lex);
diagnose_addition_in_bitshift(loc, operator_name, rhs);
lhs = createV<ast_binary_operator>(loc, operator_name, t, lhs, rhs);
t = lex.tok();
@ -541,14 +544,14 @@ static AnyV parse_expr17(Lexer& lex) {
}
// parse E == < > <= >= != <=> E (left-to-right)
static AnyV parse_expr15(Lexer& lex) {
AnyV lhs = parse_expr17(lex);
static AnyExprV parse_expr15(Lexer& lex) {
AnyExprV lhs = parse_expr17(lex);
TokenType t = lex.tok();
if (t == tok_eq || t == tok_lt || t == tok_gt || t == tok_leq || t == tok_geq || t == tok_neq || t == tok_spaceship) {
SrcLocation loc = lex.cur_location();
std::string_view operator_name = lex.cur_str();
lex.next();
AnyV rhs = parse_expr17(lex);
AnyExprV rhs = parse_expr17(lex);
lhs = createV<ast_binary_operator>(loc, operator_name, t, lhs, rhs);
if (t == tok_eq || t == tok_neq) {
lhs = maybe_replace_eq_null_with_isNull_call(lhs->as<ast_binary_operator>());
@ -558,14 +561,14 @@ static AnyV parse_expr15(Lexer& lex) {
}
// parse E & | ^ E (left-to-right)
static AnyV parse_expr14(Lexer& lex) {
AnyV lhs = parse_expr15(lex);
static AnyExprV parse_expr14(Lexer& lex) {
AnyExprV lhs = parse_expr15(lex);
TokenType t = lex.tok();
while (t == tok_bitwise_and || t == tok_bitwise_or || t == tok_bitwise_xor) {
SrcLocation loc = lex.cur_location();
std::string_view operator_name = lex.cur_str();
lex.next();
AnyV rhs = parse_expr15(lex);
AnyExprV rhs = parse_expr15(lex);
diagnose_bitwise_precedence(loc, operator_name, lhs, rhs);
diagnose_and_or_precedence(loc, lhs, t, operator_name);
lhs = createV<ast_binary_operator>(loc, operator_name, t, lhs, rhs);
@ -575,14 +578,14 @@ static AnyV parse_expr14(Lexer& lex) {
}
// parse E && || E (left-to-right)
static AnyV parse_expr13(Lexer& lex) {
AnyV lhs = parse_expr14(lex);
static AnyExprV parse_expr13(Lexer& lex) {
AnyExprV lhs = parse_expr14(lex);
TokenType t = lex.tok();
while (t == tok_logical_and || t == tok_logical_or) {
SrcLocation loc = lex.cur_location();
std::string_view operator_name = lex.cur_str();
lex.next();
AnyV rhs = parse_expr14(lex);
AnyExprV rhs = parse_expr14(lex);
diagnose_and_or_precedence(loc, lhs, t, operator_name);
lhs = createV<ast_binary_operator>(loc, operator_name, t, lhs, rhs);
t = lex.tok();
@ -591,8 +594,8 @@ static AnyV parse_expr13(Lexer& lex) {
}
// parse E = += -= E and E ? E : E (right-to-left)
static AnyV parse_expr10(Lexer& lex) {
AnyV lhs = parse_expr13(lex);
static AnyExprV parse_expr10(Lexer& lex) {
AnyExprV lhs = parse_expr13(lex);
TokenType t = lex.tok();
if (t == tok_set_plus || t == tok_set_minus || t == tok_set_mul || t == tok_set_div ||
t == tok_set_mod || t == tok_set_lshift || t == tok_set_rshift ||
@ -601,36 +604,36 @@ static AnyV parse_expr10(Lexer& lex) {
SrcLocation loc = lex.cur_location();
std::string_view operator_name = lex.cur_str();
lex.next();
AnyV rhs = parse_expr10(lex);
AnyExprV rhs = parse_expr10(lex);
return createV<ast_binary_operator>(loc, operator_name, t, lhs, rhs);
}
if (t == tok_question) {
SrcLocation loc = lex.cur_location();
lex.next();
AnyV when_true = parse_expr10(lex);
AnyExprV when_true = parse_expr10(lex);
lex.expect(tok_colon, "`:`");
AnyV when_false = parse_expr10(lex);
AnyExprV when_false = parse_expr10(lex);
return createV<ast_ternary_operator>(loc, lhs, when_true, when_false);
}
return lhs;
}
AnyV parse_expr(Lexer& lex) {
AnyExprV parse_expr(Lexer& lex) {
return parse_expr10(lex);
}
AnyV parse_statement(Lexer& lex);
static AnyV parse_var_declaration_lhs(Lexer& lex, bool is_immutable) {
static AnyExprV parse_var_declaration_lhs(Lexer& lex, bool is_immutable) {
SrcLocation loc = lex.cur_location();
if (lex.tok() == tok_oppar) {
lex.next();
AnyV first = parse_var_declaration_lhs(lex, is_immutable);
AnyExprV first = parse_var_declaration_lhs(lex, is_immutable);
if (lex.tok() == tok_clpar) {
lex.next();
return createV<ast_parenthesized_expr>(loc, first);
return createV<ast_parenthesized_expression>(loc, first);
}
std::vector<AnyV> args(1, first);
std::vector<AnyExprV> args(1, first);
while (lex.tok() == tok_comma) {
lex.next();
args.push_back(parse_var_declaration_lhs(lex, is_immutable));
@ -640,7 +643,7 @@ static AnyV parse_var_declaration_lhs(Lexer& lex, bool is_immutable) {
}
if (lex.tok() == tok_opbracket) {
lex.next();
std::vector<AnyV> args(1, parse_var_declaration_lhs(lex, is_immutable));
std::vector<AnyExprV> args(1, parse_var_declaration_lhs(lex, is_immutable));
while (lex.tok() == tok_comma) {
lex.next();
args.push_back(parse_var_declaration_lhs(lex, is_immutable));
@ -679,12 +682,12 @@ static AnyV parse_local_vars_declaration(Lexer& lex) {
bool is_immutable = lex.tok() == tok_val;
lex.next();
AnyV lhs = parse_var_declaration_lhs(lex, is_immutable);
AnyExprV lhs = parse_var_declaration_lhs(lex, is_immutable);
if (lex.tok() != tok_assign) {
lex.error("variables declaration must be followed by assignment: `var xxx = ...`");
}
lex.next();
AnyV assigned_val = parse_expr(lex);
AnyExprV assigned_val = parse_expr(lex);
if (lex.tok() == tok_comma) {
lex.error("multiple declarations are not allowed, split variables on separate lines");
@ -708,7 +711,7 @@ static V<ast_sequence> parse_sequence(Lexer& lex) {
static AnyV parse_return_statement(Lexer& lex) {
SrcLocation loc = lex.cur_location();
lex.expect(tok_return, "`return`");
AnyV child = lex.tok() == tok_semicolon // `return;` actually means `return ();` (which is void)
AnyExprV child = lex.tok() == tok_semicolon // `return;` actually means `return ();` (which is void)
? createV<ast_tensor>(lex.cur_location(), {})
: parse_expr(lex);
lex.expect(tok_semicolon, "`;`");
@ -720,7 +723,7 @@ static AnyV parse_if_statement(Lexer& lex, bool is_ifnot) {
lex.expect(tok_if, "`if`");
lex.expect(tok_oppar, "`(`");
AnyV cond = parse_expr(lex);
AnyExprV cond = parse_expr(lex);
lex.expect(tok_clpar, "`)`");
// replace if(!expr) with ifnot(expr) (this should be done later, but for now, let this be right at parsing time)
if (auto v_not = cond->try_as<ast_unary_operator>(); v_not && v_not->tok == tok_logical_not) {
@ -748,7 +751,7 @@ static AnyV parse_repeat_statement(Lexer& lex) {
SrcLocation loc = lex.cur_location();
lex.expect(tok_repeat, "`repeat`");
lex.expect(tok_oppar, "`(`");
AnyV cond = parse_expr(lex);
AnyExprV cond = parse_expr(lex);
lex.expect(tok_clpar, "`)`");
V<ast_sequence> body = parse_sequence(lex);
return createV<ast_repeat_statement>(loc, cond, body);
@ -758,7 +761,7 @@ static AnyV parse_while_statement(Lexer& lex) {
SrcLocation loc = lex.cur_location();
lex.expect(tok_while, "`while`");
lex.expect(tok_oppar, "`(`");
AnyV cond = parse_expr(lex);
AnyExprV cond = parse_expr(lex);
lex.expect(tok_clpar, "`)`");
V<ast_sequence> body = parse_sequence(lex);
return createV<ast_while_statement>(loc, cond, body);
@ -770,13 +773,13 @@ static AnyV parse_do_while_statement(Lexer& lex) {
V<ast_sequence> body = parse_sequence(lex);
lex.expect(tok_while, "`while`");
lex.expect(tok_oppar, "`(`");
AnyV cond = parse_expr(lex);
AnyExprV cond = parse_expr(lex);
lex.expect(tok_clpar, "`)`");
lex.expect(tok_semicolon, "`;`");
return createV<ast_do_while_statement>(loc, body, cond);
}
static AnyV parse_catch_variable(Lexer& lex) {
static AnyExprV parse_catch_variable(Lexer& lex) {
SrcLocation loc = lex.cur_location();
if (lex.tok() == tok_identifier) {
std::string_view var_name = lex.cur_str();
@ -794,7 +797,7 @@ static AnyV parse_throw_statement(Lexer& lex) {
SrcLocation loc = lex.cur_location();
lex.expect(tok_throw, "`throw`");
AnyV thrown_code, thrown_arg;
AnyExprV thrown_code, thrown_arg;
if (lex.tok() == tok_oppar) { // throw (code) or throw (code, arg)
lex.next();
thrown_code = parse_expr(lex);
@ -802,12 +805,12 @@ static AnyV parse_throw_statement(Lexer& lex) {
lex.next();
thrown_arg = parse_expr(lex);
} else {
thrown_arg = createV<ast_empty>(loc);
thrown_arg = createV<ast_empty_expression>(loc);
}
lex.expect(tok_clpar, "`)`");
} else { // throw code
thrown_code = parse_expr(lex);
thrown_arg = createV<ast_empty>(loc);
thrown_arg = createV<ast_empty_expression>(loc);
}
lex.expect(tok_semicolon, "`;`");
@ -819,8 +822,8 @@ static AnyV parse_assert_statement(Lexer& lex) {
lex.expect(tok_assert, "`assert`");
lex.expect(tok_oppar, "`(`");
AnyV cond = parse_expr(lex);
AnyV thrown_code;
AnyExprV cond = parse_expr(lex);
AnyExprV thrown_code;
if (lex.tok() == tok_comma) { // assert(cond, code)
lex.next();
thrown_code = parse_expr(lex);
@ -840,7 +843,7 @@ static AnyV parse_try_catch_statement(Lexer& lex) {
lex.expect(tok_try, "`try`");
V<ast_sequence> try_body = parse_sequence(lex);
std::vector<AnyV> catch_args;
std::vector<AnyExprV> catch_args;
lex.expect(tok_catch, "`catch`");
SrcLocation catch_loc = lex.cur_location();
if (lex.tok() == tok_oppar) {
@ -889,13 +892,13 @@ AnyV parse_statement(Lexer& lex) {
case tok_semicolon: {
SrcLocation loc = lex.cur_location();
lex.next();
return createV<ast_empty>(loc);
return createV<ast_empty_statement>(loc);
}
case tok_break:
case tok_continue:
lex.error("break/continue from loops are not supported yet");
default: {
AnyV expr = parse_expr(lex);
AnyExprV expr = parse_expr(lex);
lex.expect(tok_semicolon, "`;`");
return expr;
}
@ -976,7 +979,7 @@ static V<ast_annotation> parse_annotation(Lexer& lex) {
if (lex.tok() == tok_oppar) {
SrcLocation loc_args = lex.cur_location();
lex.next();
std::vector<AnyV> args;
std::vector<AnyExprV> args;
args.push_back(parse_expr(lex));
while (lex.tok() == tok_comma) {
lex.next();
@ -1038,7 +1041,7 @@ static AnyV parse_function_declaration(Lexer& lex, const std::vector<V<ast_annot
}
V<ast_parameter_list> v_param_list = parse_parameter_list(lex, genericsT_list)->as<ast_parameter_list>();
bool accepts_self = !v_param_list->empty() && v_param_list->get_param(0)->get_identifier()->name == "self";
bool accepts_self = !v_param_list->empty() && v_param_list->get_param(0)->param_name == "self";
int n_mutate_params = v_param_list->get_mutate_params_count();
TypeExpr* ret_type = nullptr;
@ -1069,7 +1072,7 @@ static AnyV parse_function_declaration(Lexer& lex, const std::vector<V<ast_annot
ret_tensor_items.reserve(1 + n_mutate_params);
for (AnyV v_param : v_param_list->get_params()) {
if (v_param->as<ast_parameter>()->declared_as_mutate) {
ret_tensor_items.emplace_back(v_param->as<ast_parameter>()->param_type);
ret_tensor_items.emplace_back(v_param->as<ast_parameter>()->declared_type);
}
}
ret_tensor_items.emplace_back(ret_type ? ret_type : TypeExpr::new_hole());
@ -1079,7 +1082,7 @@ static AnyV parse_function_declaration(Lexer& lex, const std::vector<V<ast_annot
AnyV v_body = nullptr;
if (lex.tok() == tok_builtin) {
v_body = createV<ast_empty>(lex.cur_location());
v_body = createV<ast_empty_statement>(lex.cur_location());
lex.next();
lex.expect(tok_semicolon, "`;`");
} else if (lex.tok() == tok_opbrace) {
@ -1098,7 +1101,7 @@ static AnyV parse_function_declaration(Lexer& lex, const std::vector<V<ast_annot
f_declaration->is_entrypoint = is_entrypoint;
f_declaration->genericsT_list = genericsT_list;
f_declaration->marked_as_get_method = is_get_method;
f_declaration->marked_as_builtin = v_body->type == ast_empty;
f_declaration->marked_as_builtin = v_body->type == ast_empty_statement;
f_declaration->accepts_self = accepts_self;
f_declaration->returns_self = returns_self;
@ -1142,7 +1145,7 @@ static AnyV parse_tolk_required_version(Lexer& lex) {
loc.show_warning("the contract is written in Tolk v" + semver + ", but you use Tolk compiler v" + TOLK_VERSION + "; probably, it will lead to compilation errors or hash changes");
}
return createV<ast_tolk_required_version>(loc, tok_eq, semver); // semicolon is not necessary
return createV<ast_tolk_required_version>(loc, semver); // semicolon is not necessary
}
static AnyV parse_import_statement(Lexer& lex) {