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:
gingerBill
2021-02-23 14:37:05 +00:00
parent 28ed310f31
commit 908a403d78
3 changed files with 198 additions and 172 deletions
+60 -52
View File
@@ -1050,23 +1050,7 @@ parse_foreign_decl :: proc(p: ^Parser) -> ^ast.Decl {
} }
parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { parse_unrolled_for_loop :: proc(p: ^Parser, inline_tok: tokenizer.Token) -> ^ast.Stmt {
#partial switch p.curr_tok.kind {
// Operands
case .Context, // Also allows for 'context = '
.Proc,
.Inline, .No_Inline,
.Asm, // Inline assembly
.Ident,
.Integer, .Float, .Imag,
.Rune, .String,
.Open_Paren,
.Pointer,
// Unary Expressions
.Add, .Sub, .Xor, .Not, .And:
if peek_token_kind(p, .For) {
inline_tok := expect_token(p, .Inline);
for_tok := expect_token(p, .For); for_tok := expect_token(p, .For);
val0, val1: ^ast.Expr; val0, val1: ^ast.Expr;
in_tok: tokenizer.Token; in_tok: tokenizer.Token;
@@ -1119,8 +1103,29 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
range_stmt.expr = expr; range_stmt.expr = expr;
range_stmt.body = body; range_stmt.body = body;
return range_stmt; return range_stmt;
} }
parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
#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
case .Context, // Also allows for 'context = '
.Proc,
.No_Inline,
.Asm, // Inline assembly
.Ident,
.Integer, .Float, .Imag,
.Rune, .String,
.Open_Paren,
.Pointer,
// Unary Expressions
.Add, .Sub, .Xor, .Not, .And:
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);
@@ -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);
-2
View File
@@ -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",
+57 -37
View File
@@ -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,14 +4296,7 @@ Ast *parse_attribute(AstFile *f, Token token, TokenKind open_kind, TokenKind clo
} }
Ast *parse_stmt(AstFile *f) { Ast *parse_unrolled_for_loop(AstFile *f, Token inline_token) {
Ast *s = nullptr;
Token token = f->curr_token;
switch (token.kind) {
// Operands
case Token_inline:
if (peek_token_kind(f, Token_for)) {
Token inline_token = expect_token(f, Token_inline);
Token for_token = expect_token(f, Token_for); Token for_token = expect_token(f, Token_for);
Ast *val0 = nullptr; Ast *val0 = nullptr;
Ast *val1 = nullptr; Ast *val1 = nullptr;
@@ -4339,6 +4346,17 @@ Ast *parse_stmt(AstFile *f) {
return ast_bad_stmt(f, inline_token, f->curr_token); 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); return ast_inline_range_stmt(f, inline_token, for_token, val0, val1, in_token, expr, body);
}
Ast *parse_stmt(AstFile *f) {
Ast *s = nullptr;
Token token = f->curr_token;
switch (token.kind) {
// Operands
case Token_inline:
if (peek_token_kind(f, Token_for)) {
Token inline_token = expect_token(f, Token_inline);
return parse_unrolled_for_loop(f, inline_token);
} }
/* 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);