rename intrinsics
This commit is contained in:
@@ -120,6 +120,7 @@ Expr :: struct {
|
||||
body: []Stmt_Id,
|
||||
diagnostic: source.Diagnostic_Id,
|
||||
parenthesized: bool,
|
||||
intrinsic: bool,
|
||||
kind: Expr_Kind,
|
||||
}
|
||||
|
||||
|
||||
@@ -401,10 +401,11 @@ type_label :: proc(checker: ^Checker, value: types.Type) -> string {
|
||||
return strings.to_string(builder)
|
||||
}
|
||||
|
||||
is_ptr_cast_call :: proc(checker: ^Checker, expr: ast.Expr) -> bool {
|
||||
return expr.left == ast.INVALID_EXPR &&
|
||||
is_ptrcast_call :: proc(checker: ^Checker, expr: ast.Expr) -> bool {
|
||||
return expr.intrinsic &&
|
||||
expr.left == ast.INVALID_EXPR &&
|
||||
!symbol.is_valid(expr.qualifier) &&
|
||||
symbol_text(checker, expr.name) == "ptr_cast"
|
||||
symbol_text(checker, expr.name) == "ptrcast"
|
||||
}
|
||||
|
||||
Type_Builtin :: enum u8 {
|
||||
@@ -426,14 +427,14 @@ Division_Builtin :: enum u8 {
|
||||
}
|
||||
|
||||
division_builtin_call :: proc(checker: ^Checker, expr: ast.Expr) -> Division_Builtin {
|
||||
if expr.kind != .Call || expr.left != ast.INVALID_EXPR || symbol.is_valid(expr.qualifier) {
|
||||
if !expr.intrinsic || expr.kind != .Call || expr.left != ast.INVALID_EXPR || symbol.is_valid(expr.qualifier) {
|
||||
return .None
|
||||
}
|
||||
switch symbol_text(checker, expr.name) {
|
||||
case "div_trunc": return .Trunc
|
||||
case "div_floor": return .Floor
|
||||
case "div_exact": return .Exact
|
||||
case "div_ceil": return .Ceil
|
||||
case "divtrunc": return .Trunc
|
||||
case "divfloor": return .Floor
|
||||
case "divexact": return .Exact
|
||||
case "divceil": return .Ceil
|
||||
case "rem": return .Rem
|
||||
case "mod": return .Mod
|
||||
}
|
||||
@@ -441,26 +442,26 @@ division_builtin_call :: proc(checker: ^Checker, expr: ast.Expr) -> Division_Bui
|
||||
}
|
||||
|
||||
type_builtin_call :: proc(checker: ^Checker, expr: ast.Expr) -> Type_Builtin {
|
||||
if expr.kind != .Call || expr.left != ast.INVALID_EXPR || symbol.is_valid(expr.qualifier) {
|
||||
if !expr.intrinsic || expr.kind != .Call || expr.left != ast.INVALID_EXPR || symbol.is_valid(expr.qualifier) {
|
||||
return .None
|
||||
}
|
||||
name := symbol_text(checker, expr.name)
|
||||
if name == "size_of" {
|
||||
if name == "sizeof" {
|
||||
return .Size_Of
|
||||
}
|
||||
if name == "align_of" {
|
||||
if name == "alignof" {
|
||||
return .Align_Of
|
||||
}
|
||||
if name == "min_value" {
|
||||
if name == "minval" {
|
||||
return .Min_Value
|
||||
}
|
||||
if name == "max_value" {
|
||||
if name == "maxval" {
|
||||
return .Max_Value
|
||||
}
|
||||
return .None
|
||||
}
|
||||
|
||||
valid_ptr_cast_child :: proc(checker: ^Checker, value: types.Type) -> bool {
|
||||
valid_ptrcast_child :: proc(checker: ^Checker, value: types.Type) -> bool {
|
||||
return types.is_valid(value) &&
|
||||
!types.is_void(value) &&
|
||||
!types.is_anyopaque(value) &&
|
||||
@@ -501,7 +502,7 @@ build_type_builtin :: proc(
|
||||
file: ast.File_Id,
|
||||
) -> hir.Expr_Id {
|
||||
if len(expr.args) != 1 {
|
||||
id := source.addf(checker.diagnostics, expr.span, "%s expects 1 argument, got %d", symbol_text(checker, expr.name), len(expr.args))
|
||||
id := source.addf(checker.diagnostics, expr.span, "%s! expects 1 argument, got %d", symbol_text(checker, expr.name), len(expr.args))
|
||||
return invalid_hir_expr(checker, expr.span, id, types.USIZE)
|
||||
}
|
||||
target, target_ok := resolve_type_argument(checker, expr.args[0], pkg, file)
|
||||
@@ -640,7 +641,7 @@ type_from_syntax :: proc(
|
||||
}
|
||||
} else {
|
||||
if constant.kind == .Integer_Division {
|
||||
source.add(checker.diagnostics, span, "integer '/' is not allowed; use div_trunc, div_floor, div_exact, or div_ceil")
|
||||
source.add(checker.diagnostics, span, "integer '/' is not allowed; use divtrunc!, divfloor!, divexact!, or divceil!")
|
||||
return types.INVALID
|
||||
}
|
||||
source.add(checker.diagnostics, span, "array count must be a compile-time integer expression")
|
||||
@@ -3365,7 +3366,7 @@ infer_expr :: proc(
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
if is_ptr_cast_call(checker, expr) {
|
||||
if is_ptrcast_call(checker, expr) {
|
||||
if len(expr.args) != 2 {
|
||||
last = types.INVALID
|
||||
_ = pop(&stack)
|
||||
@@ -3374,13 +3375,18 @@ infer_expr :: proc(
|
||||
child, child_ok := resolve_type_argument(checker, expr.args[0], pkg, file)
|
||||
operand := infer_nested_expr(checker, expr.args[1], locals, pkg, file, demanded, local_types)
|
||||
result := types.INVALID
|
||||
if child_ok && valid_ptr_cast_child(checker, child) {
|
||||
if child_ok && valid_ptrcast_child(checker, child) {
|
||||
result, _ = types.replace_pointer_child(&checker.module.types, operand, child)
|
||||
}
|
||||
last = result
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
if expr.intrinsic {
|
||||
last = types.INVALID
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
if callee_type, handled := infer_qualified_value_field_type(checker, expr, locals, pkg, file); handled {
|
||||
_, function_item, function_type, ok := types.function_pointer(callee_type, &checker.module.types)
|
||||
if !ok {
|
||||
@@ -4957,7 +4963,7 @@ build_constant_expr :: proc(
|
||||
return invalid_hir_expr(checker, expr.span, id, recovery_type)
|
||||
}
|
||||
if constant.kind == .Integer_Division {
|
||||
id := source.add(checker.diagnostics, expr.span, "integer '/' is not allowed; use div_trunc, div_floor, div_exact, or div_ceil")
|
||||
id := source.add(checker.diagnostics, expr.span, "integer '/' is not allowed; use divtrunc!, divfloor!, divexact!, or divceil!")
|
||||
return invalid_hir_expr(checker, expr.span, id, recovery_type)
|
||||
}
|
||||
if constant.kind == .Overflow ||
|
||||
@@ -5447,7 +5453,7 @@ build_division_builtin :: proc(
|
||||
) -> hir.Expr_Id {
|
||||
if len(expr.args) != 2 {
|
||||
id := source.addf(
|
||||
checker.diagnostics, expr.span, "%s expects 2 arguments, got %d",
|
||||
checker.diagnostics, expr.span, "%s! expects 2 arguments, got %d",
|
||||
symbol_text(checker, expr.name), len(expr.args),
|
||||
)
|
||||
return invalid_hir_expr(checker, expr.span, id)
|
||||
@@ -6223,7 +6229,7 @@ build_binary_arith :: proc(
|
||||
if op == .Div && !types.is_float(result, checker.target) {
|
||||
id := source.add(
|
||||
checker.diagnostics, span,
|
||||
"integer '/' is not allowed; use div_trunc, div_floor, div_exact, or div_ceil",
|
||||
"integer '/' is not allowed; use divtrunc!, divfloor!, divexact!, or divceil!",
|
||||
)
|
||||
return invalid_hir_expr(checker, span, id, result)
|
||||
}
|
||||
@@ -6463,22 +6469,22 @@ build_expr :: proc(
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
if is_ptr_cast_call(checker, expr) {
|
||||
if is_ptrcast_call(checker, expr) {
|
||||
if len(expr.args) != 2 {
|
||||
id := source.addf(checker.diagnostics, expr.span, "ptr_cast expects 2 arguments, got %d", len(expr.args))
|
||||
id := source.addf(checker.diagnostics, expr.span, "ptrcast! expects 2 arguments, got %d", len(expr.args))
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
target, target_ok := resolve_type_argument(checker, expr.args[0], pkg, file)
|
||||
if !target_ok {
|
||||
id := source.add(checker.diagnostics, checker.ast_module.exprs[expr.args[0]].span, "ptr_cast target must be a type")
|
||||
id := source.add(checker.diagnostics, checker.ast_module.exprs[expr.args[0]].span, "ptrcast! target must be a type")
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
if !valid_ptr_cast_child(checker, target) {
|
||||
id := source.addf(checker.diagnostics, checker.ast_module.exprs[expr.args[0]].span, "ptr_cast target must be a sized runtime object type, got %s", type_label(checker, target))
|
||||
if !valid_ptrcast_child(checker, target) {
|
||||
id := source.addf(checker.diagnostics, checker.ast_module.exprs[expr.args[0]].span, "ptrcast! target must be a sized runtime object type, got %s", type_label(checker, target))
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
@@ -6488,6 +6494,17 @@ build_expr :: proc(
|
||||
append(&stack, Build_Expr_Frame{expr=expr.args[1], expected=types.INVALID, template=ast.INVALID_FUNCTION})
|
||||
continue
|
||||
}
|
||||
if expr.intrinsic {
|
||||
id := source.INVALID_DIAGNOSTIC
|
||||
if symbol.is_valid(expr.qualifier) {
|
||||
id = source.add(checker.diagnostics, expr.span, "intrinsic calls must be unqualified")
|
||||
} else {
|
||||
id = source.addf(checker.diagnostics, expr.span, "unknown intrinsic '%s!'", symbol_text(checker, expr.name))
|
||||
}
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
if callee, handled, ok := build_qualified_value_field(checker, expr, locals, global_reads, pkg, file); handled {
|
||||
if !ok {
|
||||
last = callee
|
||||
@@ -6996,7 +7013,7 @@ build_expr :: proc(
|
||||
if frame.stage == 9 {
|
||||
result, ok := types.replace_pointer_child(&checker.module.types, checker.module.exprs[last].type, frame.target_type)
|
||||
if !ok {
|
||||
id := source.add(checker.diagnostics, expr.span, "ptr_cast operand must be a pointer or optional pointer")
|
||||
id := source.add(checker.diagnostics, expr.span, "ptrcast! operand must be a pointer or optional pointer")
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
} else {
|
||||
last = add_hir_expr(checker, hir.Expr{
|
||||
|
||||
@@ -1862,7 +1862,7 @@ ct_eval_binary :: proc(state: ^Ct_State, op: ast.Expr_Kind, left_id, right_id: C
|
||||
if op == .Div {
|
||||
return INVALID_CT_VALUE, ct_flow(.Normal), ct_fail(
|
||||
state, .Integer_Division, span,
|
||||
"integer '/' is not allowed; use div_trunc, div_floor, div_exact, or div_ceil",
|
||||
"integer '/' is not allowed; use divtrunc!, divfloor!, divexact!, or divceil!",
|
||||
)
|
||||
}
|
||||
value: i128
|
||||
@@ -2059,7 +2059,7 @@ ct_eval_call_expr :: proc(state: ^Ct_State, expr: ast.Expr, expected: types.Type
|
||||
}
|
||||
if builtin := type_builtin_call(checker, expr); builtin != .None {
|
||||
if len(expr.args) != 1 {
|
||||
return INVALID_CT_VALUE, ct_flow(.Normal), ct_failf(state, .Not_Comptime, expr.span, "%s expects 1 argument, got %d", symbol_text(checker, expr.name), len(expr.args))
|
||||
return INVALID_CT_VALUE, ct_flow(.Normal), ct_failf(state, .Not_Comptime, expr.span, "%s! expects 1 argument, got %d", symbol_text(checker, expr.name), len(expr.args))
|
||||
}
|
||||
target, target_ok := resolve_type_argument(checker, expr.args[0], state.pkg, state.file)
|
||||
if !target_ok {
|
||||
@@ -2078,6 +2078,12 @@ ct_eval_call_expr :: proc(state: ^Ct_State, expr: ast.Expr, expected: types.Type
|
||||
if builtin := division_builtin_call(checker, expr); builtin != .None {
|
||||
return ct_eval_division_call(state, expr, builtin, expected, depth+1)
|
||||
}
|
||||
if expr.intrinsic {
|
||||
if symbol.is_valid(expr.qualifier) {
|
||||
return INVALID_CT_VALUE, ct_flow(.Normal), ct_fail(state, .Not_Comptime, expr.span, "intrinsic calls must be unqualified")
|
||||
}
|
||||
return INVALID_CT_VALUE, ct_flow(.Normal), ct_failf(state, .Not_Comptime, expr.span, "unknown intrinsic '%s!'", symbol_text(checker, expr.name))
|
||||
}
|
||||
target_pkg, available := expr_package(checker, expr, state.pkg, state.file, false)
|
||||
if !available {
|
||||
return INVALID_CT_VALUE, ct_flow(.Normal), ct_fail(state, .Not_Comptime, expr.span, "unavailable function package")
|
||||
|
||||
@@ -399,7 +399,7 @@ parse_type_atom :: proc(parser: ^Parser) -> ast.Type_Syntax {
|
||||
!symbol.is_valid(qualifier) && file_hidden_name(parser, name),
|
||||
)
|
||||
if current(parser).kind == .Left_Paren {
|
||||
call := parse_call(parser, qualifier, first, name, 0)
|
||||
call := parse_call(parser, qualifier, first, name, 0, false)
|
||||
return types.intern(&parser.module.type_store, types.Node{
|
||||
kind=.Type_Call,
|
||||
count_expr=u32(call),
|
||||
@@ -490,7 +490,7 @@ parse_call_args :: proc(parser: ^Parser, nesting: int) -> ([]ast.Expr_Id, token.
|
||||
return args[:], right_paren
|
||||
}
|
||||
|
||||
parse_call :: proc(parser: ^Parser, qualifier: symbol.Id, first, name: token.Token, nesting: int) -> ast.Expr_Id {
|
||||
parse_call :: proc(parser: ^Parser, qualifier: symbol.Id, first, name: token.Token, nesting: int, intrinsic: bool) -> ast.Expr_Id {
|
||||
if nesting >= MAX_EXPRESSION_NESTING {
|
||||
span := skip_parenthesized(parser)
|
||||
return invalid_expr(parser, span, "expression nesting exceeds 256 levels")
|
||||
@@ -502,6 +502,7 @@ parse_call :: proc(parser: ^Parser, qualifier: symbol.Id, first, name: token.Tok
|
||||
qualifier=qualifier,
|
||||
name=name.symbol,
|
||||
args=args[:],
|
||||
intrinsic=intrinsic,
|
||||
left=ast.INVALID_EXPR,
|
||||
right=ast.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
@@ -885,9 +886,10 @@ parse_primary :: proc(parser: ^Parser, nesting: int) -> ast.Expr_Id {
|
||||
qualifier = first.symbol
|
||||
name = member
|
||||
}
|
||||
_, intrinsic := allow(parser, .Bang)
|
||||
if current(parser).kind == .Left_Paren {
|
||||
call := parse_call(parser, qualifier, first, name, nesting)
|
||||
if current(parser).kind == .Left_Brace && !(parser.no_struct_literal && parser.delimiter_depth == 0) {
|
||||
call := parse_call(parser, qualifier, first, name, nesting, intrinsic)
|
||||
if !intrinsic && current(parser).kind == .Left_Brace && !(parser.no_struct_literal && parser.delimiter_depth == 0) {
|
||||
left_brace := advance(parser)
|
||||
args, right_brace := parse_keyed_initializers(parser, left_brace, nesting, "expected '}' after struct literal")
|
||||
return add_expr(parser, ast.Expr{
|
||||
@@ -901,6 +903,9 @@ parse_primary :: proc(parser: ^Parser, nesting: int) -> ast.Expr_Id {
|
||||
}
|
||||
return call
|
||||
}
|
||||
if intrinsic {
|
||||
return invalid_expr(parser, previous(parser).span, "expected '(' after intrinsic name")
|
||||
}
|
||||
if current(parser).kind == .Left_Brace && !(parser.no_struct_literal && parser.delimiter_depth == 0) {
|
||||
return parse_struct_literal(parser, qualifier, first, name, nesting)
|
||||
}
|
||||
@@ -1156,6 +1161,21 @@ parse_expression_bp :: proc(parser: ^Parser, minimum_binding_power, nesting: int
|
||||
}
|
||||
continue
|
||||
}
|
||||
if current(parser).kind == .Bang {
|
||||
marker := advance(parser)
|
||||
if current(parser).kind != .Left_Paren {
|
||||
left = invalid_expr(parser, marker.span, "expected '(' after '!'")
|
||||
continue
|
||||
}
|
||||
left_expr := parser.module.exprs[left]
|
||||
call_span := skip_parenthesized(parser)
|
||||
left = invalid_expr(
|
||||
parser,
|
||||
span_from(left_expr.span, call_span),
|
||||
"intrinsic calls require a direct name",
|
||||
)
|
||||
continue
|
||||
}
|
||||
if current(parser).kind == .Left_Paren {
|
||||
if nesting >= MAX_EXPRESSION_NESTING {
|
||||
span := skip_parenthesized(parser)
|
||||
|
||||
Reference in New Issue
Block a user