mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 07:08:48 +00:00
Add #force_inline, #force_no_inline and #unroll for the transition to deprecate and then remove the keywords inline and no_inline
`inline for` will be replaced with `#unroll for`
This commit is contained in:
+100
-92
@@ -1050,12 +1050,74 @@ parse_foreign_decl :: proc(p: ^Parser) -> ^ast.Decl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
parse_unrolled_for_loop :: proc(p: ^Parser, inline_tok: tokenizer.Token) -> ^ast.Stmt {
|
||||||
|
for_tok := expect_token(p, .For);
|
||||||
|
val0, val1: ^ast.Expr;
|
||||||
|
in_tok: tokenizer.Token;
|
||||||
|
expr: ^ast.Expr;
|
||||||
|
body: ^ast.Stmt;
|
||||||
|
|
||||||
|
bad_stmt := false;
|
||||||
|
|
||||||
|
if p.curr_tok.kind != .In {
|
||||||
|
idents := parse_ident_list(p, false);
|
||||||
|
switch len(idents) {
|
||||||
|
case 1:
|
||||||
|
val0 = idents[0];
|
||||||
|
case 2:
|
||||||
|
val0, val1 = idents[0], idents[1];
|
||||||
|
case:
|
||||||
|
error(p, for_tok.pos, "expected either 1 or 2 identifiers");
|
||||||
|
bad_stmt = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
in_tok = expect_token(p, .In);
|
||||||
|
|
||||||
|
prev_allow_range := p.allow_range;
|
||||||
|
prev_level := p.expr_level;
|
||||||
|
p.allow_range = true;
|
||||||
|
p.expr_level = -1;
|
||||||
|
|
||||||
|
expr = parse_expr(p, false);
|
||||||
|
|
||||||
|
p.expr_level = prev_level;
|
||||||
|
p.allow_range = prev_allow_range;
|
||||||
|
|
||||||
|
if allow_token(p, .Do) {
|
||||||
|
body = convert_stmt_to_body(p, parse_stmt(p));
|
||||||
|
} else {
|
||||||
|
body = parse_block_stmt(p, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if bad_stmt {
|
||||||
|
return ast.new(ast.Bad_Stmt, inline_tok.pos, end_pos(p.prev_tok));
|
||||||
|
}
|
||||||
|
|
||||||
|
range_stmt := ast.new(ast.Inline_Range_Stmt, inline_tok.pos, body.end);
|
||||||
|
range_stmt.inline_pos = inline_tok.pos;
|
||||||
|
range_stmt.for_pos = for_tok.pos;
|
||||||
|
range_stmt.val0 = val0;
|
||||||
|
range_stmt.val1 = val1;
|
||||||
|
range_stmt.in_pos = in_tok.pos;
|
||||||
|
range_stmt.expr = expr;
|
||||||
|
range_stmt.body = body;
|
||||||
|
return range_stmt;
|
||||||
|
}
|
||||||
|
|
||||||
parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
||||||
#partial switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
|
|
||||||
|
case .Inline:
|
||||||
|
if peek_token_kind(p, .For) {
|
||||||
|
inline_tok := expect_token(p, .Inline);
|
||||||
|
return parse_unrolled_for_loop(p, inline_tok);
|
||||||
|
}
|
||||||
|
fallthrough;
|
||||||
// Operands
|
// Operands
|
||||||
case .Context, // Also allows for 'context = '
|
case .Context, // Also allows for 'context = '
|
||||||
.Proc,
|
.Proc,
|
||||||
.Inline, .No_Inline,
|
.No_Inline,
|
||||||
.Asm, // Inline assembly
|
.Asm, // Inline assembly
|
||||||
.Ident,
|
.Ident,
|
||||||
.Integer, .Float, .Imag,
|
.Integer, .Float, .Imag,
|
||||||
@@ -1065,63 +1127,6 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
|||||||
// Unary Expressions
|
// Unary Expressions
|
||||||
.Add, .Sub, .Xor, .Not, .And:
|
.Add, .Sub, .Xor, .Not, .And:
|
||||||
|
|
||||||
if peek_token_kind(p, .For) {
|
|
||||||
inline_tok := expect_token(p, .Inline);
|
|
||||||
for_tok := expect_token(p, .For);
|
|
||||||
val0, val1: ^ast.Expr;
|
|
||||||
in_tok: tokenizer.Token;
|
|
||||||
expr: ^ast.Expr;
|
|
||||||
body: ^ast.Stmt;
|
|
||||||
|
|
||||||
bad_stmt := false;
|
|
||||||
|
|
||||||
if p.curr_tok.kind != .In {
|
|
||||||
idents := parse_ident_list(p, false);
|
|
||||||
switch len(idents) {
|
|
||||||
case 1:
|
|
||||||
val0 = idents[0];
|
|
||||||
case 2:
|
|
||||||
val0, val1 = idents[0], idents[1];
|
|
||||||
case:
|
|
||||||
error(p, for_tok.pos, "expected either 1 or 2 identifiers");
|
|
||||||
bad_stmt = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
in_tok = expect_token(p, .In);
|
|
||||||
|
|
||||||
prev_allow_range := p.allow_range;
|
|
||||||
prev_level := p.expr_level;
|
|
||||||
p.allow_range = true;
|
|
||||||
p.expr_level = -1;
|
|
||||||
|
|
||||||
expr = parse_expr(p, false);
|
|
||||||
|
|
||||||
p.expr_level = prev_level;
|
|
||||||
p.allow_range = prev_allow_range;
|
|
||||||
|
|
||||||
if allow_token(p, .Do) {
|
|
||||||
body = convert_stmt_to_body(p, parse_stmt(p));
|
|
||||||
} else {
|
|
||||||
body = parse_block_stmt(p, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if bad_stmt {
|
|
||||||
return ast.new(ast.Bad_Stmt, inline_tok.pos, end_pos(p.prev_tok));
|
|
||||||
}
|
|
||||||
|
|
||||||
range_stmt := ast.new(ast.Inline_Range_Stmt, inline_tok.pos, body.end);
|
|
||||||
range_stmt.inline_pos = inline_tok.pos;
|
|
||||||
range_stmt.for_pos = for_tok.pos;
|
|
||||||
range_stmt.val0 = val0;
|
|
||||||
range_stmt.val1 = val1;
|
|
||||||
range_stmt.in_pos = in_tok.pos;
|
|
||||||
range_stmt.expr = expr;
|
|
||||||
range_stmt.body = body;
|
|
||||||
return range_stmt;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
s := parse_simple_stmt(p, {Stmt_Allow_Flag.Label});
|
s := parse_simple_stmt(p, {Stmt_Allow_Flag.Label});
|
||||||
expect_semicolon(p, s);
|
expect_semicolon(p, s);
|
||||||
return s;
|
return s;
|
||||||
@@ -1261,6 +1266,8 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
|||||||
es := ast.new(ast.Expr_Stmt, ce.pos, ce.end);
|
es := ast.new(ast.Expr_Stmt, ce.pos, ce.end);
|
||||||
es.expr = ce;
|
es.expr = ce;
|
||||||
return es;
|
return es;
|
||||||
|
case "unroll":
|
||||||
|
return parse_unrolled_for_loop(p, tag);
|
||||||
case "include":
|
case "include":
|
||||||
error(p, tag.pos, "#include is not a valid import declaration kind. Did you meant 'import'?");
|
error(p, tag.pos, "#include is not a valid import declaration kind. Did you meant 'import'?");
|
||||||
return ast.new(ast.Bad_Stmt, tok.pos, end_pos(tag));
|
return ast.new(ast.Bad_Stmt, tok.pos, end_pos(tag));
|
||||||
@@ -2004,7 +2011,41 @@ check_poly_params_for_type :: proc(p: ^Parser, poly_params: ^ast.Field_List, tok
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parse_inlining_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^ast.Expr {
|
||||||
|
expr := parse_unary_expr(p, lhs);
|
||||||
|
|
||||||
|
pi := ast.Proc_Inlining.None;
|
||||||
|
#partial switch tok.kind {
|
||||||
|
case .Inline:
|
||||||
|
pi = .Inline;
|
||||||
|
case .No_Inline:
|
||||||
|
pi = .No_Inline;
|
||||||
|
case .Ident:
|
||||||
|
switch tok.text {
|
||||||
|
case "force_inline":
|
||||||
|
pi = .Inline;
|
||||||
|
case "force_no_inline":
|
||||||
|
pi = .No_Inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e in &ast.unparen_expr(expr).derived {
|
||||||
|
case ast.Proc_Lit:
|
||||||
|
if e.inlining != .None && e.inlining != pi {
|
||||||
|
error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure literal");
|
||||||
|
}
|
||||||
|
e.inlining = pi;
|
||||||
|
case ast.Call_Expr:
|
||||||
|
if e.inlining != .None && e.inlining != pi {
|
||||||
|
error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure call");
|
||||||
|
}
|
||||||
|
e.inlining = pi;
|
||||||
|
case:
|
||||||
|
error(p, tok.pos, "'%s' must be followed by a procedure literal or call", tok.text);
|
||||||
|
return ast.new(ast.Bad_Expr, tok.pos, expr.end);
|
||||||
|
}
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||||
#partial switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
@@ -2056,14 +2097,6 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
|||||||
dt.type = type;
|
dt.type = type;
|
||||||
return dt;
|
return dt;
|
||||||
|
|
||||||
case .Opaque:
|
|
||||||
tok := advance_token(p);
|
|
||||||
warn(p, tok.pos, "opaque is deprecated in favour of #opaque");
|
|
||||||
type := parse_type(p);
|
|
||||||
ot := ast.new(ast.Opaque_Type, tok.pos, type.end);
|
|
||||||
ot.type = type;
|
|
||||||
return ot;
|
|
||||||
|
|
||||||
case .Hash:
|
case .Hash:
|
||||||
tok := expect_token(p, .Hash);
|
tok := expect_token(p, .Hash);
|
||||||
name := expect_token(p, .Ident);
|
name := expect_token(p, .Ident);
|
||||||
@@ -2164,32 +2197,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
|||||||
|
|
||||||
case .Inline, .No_Inline:
|
case .Inline, .No_Inline:
|
||||||
tok := advance_token(p);
|
tok := advance_token(p);
|
||||||
expr := parse_unary_expr(p, lhs);
|
return parse_inlining_operand(p, lhs, tok);
|
||||||
|
|
||||||
pi := ast.Proc_Inlining.None;
|
|
||||||
#partial switch tok.kind {
|
|
||||||
case .Inline:
|
|
||||||
pi = ast.Proc_Inlining.Inline;
|
|
||||||
case .No_Inline:
|
|
||||||
pi = ast.Proc_Inlining.No_Inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch e in &ast.unparen_expr(expr).derived {
|
|
||||||
case ast.Proc_Lit:
|
|
||||||
if e.inlining != ast.Proc_Inlining.None && e.inlining != pi {
|
|
||||||
error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure literal");
|
|
||||||
}
|
|
||||||
e.inlining = pi;
|
|
||||||
case ast.Call_Expr:
|
|
||||||
if e.inlining != ast.Proc_Inlining.None && e.inlining != pi {
|
|
||||||
error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure call");
|
|
||||||
}
|
|
||||||
e.inlining = pi;
|
|
||||||
case:
|
|
||||||
error(p, tok.pos, "'%s' must be followed by a procedure literal or call", tok.text);
|
|
||||||
return ast.new(ast.Bad_Expr, tok.pos, expr.end);
|
|
||||||
}
|
|
||||||
return expr;
|
|
||||||
|
|
||||||
case .Proc:
|
case .Proc:
|
||||||
tok := expect_token(p, .Proc);
|
tok := expect_token(p, .Proc);
|
||||||
|
|||||||
@@ -142,7 +142,6 @@ Token_Kind :: enum u32 {
|
|||||||
Cast, // cast
|
Cast, // cast
|
||||||
Transmute, // transmute
|
Transmute, // transmute
|
||||||
Distinct, // distinct
|
Distinct, // distinct
|
||||||
Opaque, // opaque
|
|
||||||
Using, // using
|
Using, // using
|
||||||
Inline, // inline
|
Inline, // inline
|
||||||
No_Inline, // no_inline
|
No_Inline, // no_inline
|
||||||
@@ -270,7 +269,6 @@ tokens := [Token_Kind.COUNT]string {
|
|||||||
"cast",
|
"cast",
|
||||||
"transmute",
|
"transmute",
|
||||||
"distinct",
|
"distinct",
|
||||||
"opaque",
|
|
||||||
"using",
|
"using",
|
||||||
"inline",
|
"inline",
|
||||||
"no_inline",
|
"no_inline",
|
||||||
|
|||||||
+98
-78
@@ -1865,6 +1865,45 @@ bool ast_on_same_line(Ast *x, Ast *y) {
|
|||||||
return ast_on_same_line(ast_token(x), y);
|
return ast_on_same_line(ast_token(x), y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ast *parse_force_inlining_operand(AstFile *f, Token token) {
|
||||||
|
Ast *expr = parse_unary_expr(f, false);
|
||||||
|
Ast *e = unparen_expr(expr);
|
||||||
|
if (e->kind != Ast_ProcLit && e->kind != Ast_CallExpr) {
|
||||||
|
syntax_error(expr, "%.*s must be followed by a procedure literal or call, got %.*s", LIT(token.string), LIT(ast_strings[expr->kind]));
|
||||||
|
return ast_bad_expr(f, token, f->curr_token);
|
||||||
|
}
|
||||||
|
ProcInlining pi = ProcInlining_none;
|
||||||
|
if (token.kind == Token_inline) {
|
||||||
|
pi = ProcInlining_inline;
|
||||||
|
} else if (token.kind == Token_no_inline) {
|
||||||
|
pi = ProcInlining_no_inline;
|
||||||
|
} else if (token.kind == Token_Ident) {
|
||||||
|
if (token.string == "force_inline") {
|
||||||
|
pi = ProcInlining_inline;
|
||||||
|
} else if (token.string == "force_no_inline") {
|
||||||
|
pi = ProcInlining_no_inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pi != ProcInlining_none) {
|
||||||
|
if (e->kind == Ast_ProcLit) {
|
||||||
|
if (expr->ProcLit.inlining != ProcInlining_none &&
|
||||||
|
expr->ProcLit.inlining != pi) {
|
||||||
|
syntax_error(expr, "You cannot apply both 'inline' and 'no_inline' to a procedure literal");
|
||||||
|
}
|
||||||
|
expr->ProcLit.inlining = pi;
|
||||||
|
} else if (e->kind == Ast_CallExpr) {
|
||||||
|
if (expr->CallExpr.inlining != ProcInlining_none &&
|
||||||
|
expr->CallExpr.inlining != pi) {
|
||||||
|
syntax_error(expr, "You cannot apply both 'inline' and 'no_inline' to a procedure call");
|
||||||
|
}
|
||||||
|
expr->CallExpr.inlining = pi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Ast *parse_operand(AstFile *f, bool lhs) {
|
Ast *parse_operand(AstFile *f, bool lhs) {
|
||||||
Ast *operand = nullptr; // Operand
|
Ast *operand = nullptr; // Operand
|
||||||
@@ -1986,6 +2025,9 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
} else if (name.string == "opaque") {
|
} else if (name.string == "opaque") {
|
||||||
Ast *type = parse_type(f);
|
Ast *type = parse_type(f);
|
||||||
return ast_opaque_type(f, token, type);
|
return ast_opaque_type(f, token, type);
|
||||||
|
} else if (name.string == "force_inline" ||
|
||||||
|
name.string == "force_no_inline") {
|
||||||
|
return parse_force_inlining_operand(f, name);
|
||||||
} else {
|
} else {
|
||||||
operand = ast_tag_expr(f, token, name, parse_expr(f, false));
|
operand = ast_tag_expr(f, token, name, parse_expr(f, false));
|
||||||
}
|
}
|
||||||
@@ -1996,35 +2038,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
case Token_no_inline:
|
case Token_no_inline:
|
||||||
{
|
{
|
||||||
Token token = advance_token(f);
|
Token token = advance_token(f);
|
||||||
Ast *expr = parse_unary_expr(f, false);
|
return parse_force_inlining_operand(f, token);
|
||||||
Ast *e = unparen_expr(expr);
|
|
||||||
if (e->kind != Ast_ProcLit && e->kind != Ast_CallExpr) {
|
|
||||||
syntax_error(expr, "%.*s must be followed by a procedure literal or call, got %.*s", LIT(token.string), LIT(ast_strings[expr->kind]));
|
|
||||||
return ast_bad_expr(f, token, f->curr_token);
|
|
||||||
}
|
|
||||||
ProcInlining pi = ProcInlining_none;
|
|
||||||
if (token.kind == Token_inline) {
|
|
||||||
pi = ProcInlining_inline;
|
|
||||||
} else if (token.kind == Token_no_inline) {
|
|
||||||
pi = ProcInlining_no_inline;
|
|
||||||
}
|
|
||||||
if (pi != ProcInlining_none) {
|
|
||||||
if (e->kind == Ast_ProcLit) {
|
|
||||||
if (expr->ProcLit.inlining != ProcInlining_none &&
|
|
||||||
expr->ProcLit.inlining != pi) {
|
|
||||||
syntax_error(expr, "You cannot apply both 'inline' and 'no_inline' to a procedure literal");
|
|
||||||
}
|
|
||||||
expr->ProcLit.inlining = pi;
|
|
||||||
} else if (e->kind == Ast_CallExpr) {
|
|
||||||
if (expr->CallExpr.inlining != ProcInlining_none &&
|
|
||||||
expr->CallExpr.inlining != pi) {
|
|
||||||
syntax_error(expr, "You cannot apply both 'inline' and 'no_inline' to a procedure call");
|
|
||||||
}
|
|
||||||
expr->CallExpr.inlining = pi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return expr;
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
// Parse Procedure Type or Literal or Group
|
// Parse Procedure Type or Literal or Group
|
||||||
@@ -4282,6 +4296,58 @@ Ast *parse_attribute(AstFile *f, Token token, TokenKind open_kind, TokenKind clo
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ast *parse_unrolled_for_loop(AstFile *f, Token inline_token) {
|
||||||
|
Token for_token = expect_token(f, Token_for);
|
||||||
|
Ast *val0 = nullptr;
|
||||||
|
Ast *val1 = nullptr;
|
||||||
|
Token in_token = {};
|
||||||
|
Ast *expr = nullptr;
|
||||||
|
Ast *body = nullptr;
|
||||||
|
|
||||||
|
bool bad_stmt = false;
|
||||||
|
|
||||||
|
if (f->curr_token.kind != Token_in) {
|
||||||
|
Array<Ast *> idents = parse_ident_list(f, false);
|
||||||
|
switch (idents.count) {
|
||||||
|
case 1:
|
||||||
|
val0 = idents[0];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
val0 = idents[0];
|
||||||
|
val1 = idents[1];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
syntax_error(for_token, "Expected either 1 or 2 identifiers");
|
||||||
|
bad_stmt = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
in_token = expect_token(f, Token_in);
|
||||||
|
|
||||||
|
bool prev_allow_range = f->allow_range;
|
||||||
|
isize prev_level = f->expr_level;
|
||||||
|
f->allow_range = true;
|
||||||
|
f->expr_level = -1;
|
||||||
|
expr = parse_expr(f, false);
|
||||||
|
f->expr_level = prev_level;
|
||||||
|
f->allow_range = prev_allow_range;
|
||||||
|
|
||||||
|
if (allow_token(f, Token_do)) {
|
||||||
|
body = convert_stmt_to_body(f, parse_stmt(f));
|
||||||
|
if (build_context.disallow_do) {
|
||||||
|
syntax_error(body, "'do' has been disallowed");
|
||||||
|
} else if (!ast_on_same_line(for_token, body)) {
|
||||||
|
syntax_error(body, "The body of a 'do' be on the same line as the 'for' token");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
body = parse_block_stmt(f, false);
|
||||||
|
}
|
||||||
|
if (bad_stmt) {
|
||||||
|
return ast_bad_stmt(f, inline_token, f->curr_token);
|
||||||
|
}
|
||||||
|
return ast_inline_range_stmt(f, inline_token, for_token, val0, val1, in_token, expr, body);
|
||||||
|
}
|
||||||
|
|
||||||
Ast *parse_stmt(AstFile *f) {
|
Ast *parse_stmt(AstFile *f) {
|
||||||
Ast *s = nullptr;
|
Ast *s = nullptr;
|
||||||
Token token = f->curr_token;
|
Token token = f->curr_token;
|
||||||
@@ -4290,55 +4356,7 @@ Ast *parse_stmt(AstFile *f) {
|
|||||||
case Token_inline:
|
case Token_inline:
|
||||||
if (peek_token_kind(f, Token_for)) {
|
if (peek_token_kind(f, Token_for)) {
|
||||||
Token inline_token = expect_token(f, Token_inline);
|
Token inline_token = expect_token(f, Token_inline);
|
||||||
Token for_token = expect_token(f, Token_for);
|
return parse_unrolled_for_loop(f, inline_token);
|
||||||
Ast *val0 = nullptr;
|
|
||||||
Ast *val1 = nullptr;
|
|
||||||
Token in_token = {};
|
|
||||||
Ast *expr = nullptr;
|
|
||||||
Ast *body = nullptr;
|
|
||||||
|
|
||||||
bool bad_stmt = false;
|
|
||||||
|
|
||||||
if (f->curr_token.kind != Token_in) {
|
|
||||||
Array<Ast *> idents = parse_ident_list(f, false);
|
|
||||||
switch (idents.count) {
|
|
||||||
case 1:
|
|
||||||
val0 = idents[0];
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
val0 = idents[0];
|
|
||||||
val1 = idents[1];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
syntax_error(for_token, "Expected either 1 or 2 identifiers");
|
|
||||||
bad_stmt = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
in_token = expect_token(f, Token_in);
|
|
||||||
|
|
||||||
bool prev_allow_range = f->allow_range;
|
|
||||||
isize prev_level = f->expr_level;
|
|
||||||
f->allow_range = true;
|
|
||||||
f->expr_level = -1;
|
|
||||||
expr = parse_expr(f, false);
|
|
||||||
f->expr_level = prev_level;
|
|
||||||
f->allow_range = prev_allow_range;
|
|
||||||
|
|
||||||
if (allow_token(f, Token_do)) {
|
|
||||||
body = convert_stmt_to_body(f, parse_stmt(f));
|
|
||||||
if (build_context.disallow_do) {
|
|
||||||
syntax_error(body, "'do' has been disallowed");
|
|
||||||
} else if (!ast_on_same_line(for_token, body)) {
|
|
||||||
syntax_error(body, "The body of a 'do' be on the same line as the 'for' token");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
body = parse_block_stmt(f, false);
|
|
||||||
}
|
|
||||||
if (bad_stmt) {
|
|
||||||
return ast_bad_stmt(f, inline_token, f->curr_token);
|
|
||||||
}
|
|
||||||
return ast_inline_range_stmt(f, inline_token, for_token, val0, val1, in_token, expr, body);
|
|
||||||
}
|
}
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case Token_no_inline:
|
case Token_no_inline:
|
||||||
@@ -4484,6 +4502,8 @@ Ast *parse_stmt(AstFile *f) {
|
|||||||
} else if (tag == "panic") {
|
} else if (tag == "panic") {
|
||||||
Ast *t = ast_basic_directive(f, hash_token, tag);
|
Ast *t = ast_basic_directive(f, hash_token, tag);
|
||||||
return ast_expr_stmt(f, parse_call_expr(f, t));
|
return ast_expr_stmt(f, parse_call_expr(f, t));
|
||||||
|
} else if (tag == "unroll" || tag == "force_inline") {
|
||||||
|
return parse_unrolled_for_loop(f, name);
|
||||||
} else if (tag == "include") {
|
} else if (tag == "include") {
|
||||||
syntax_error(token, "#include is not a valid import declaration kind. Did you mean 'import'?");
|
syntax_error(token, "#include is not a valid import declaration kind. Did you mean 'import'?");
|
||||||
s = ast_bad_stmt(f, token, f->curr_token);
|
s = ast_bad_stmt(f, token, f->curr_token);
|
||||||
|
|||||||
Reference in New Issue
Block a user