mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-07 16:18:52 +00:00
type_info_of; enum_value_to_string and string_to_enum_value
This commit is contained in:
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
import "fmt.odin";
|
import "fmt.odin";
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
fmt.println("Hellope!");
|
v, ok := fmt.string_to_enum_value(Allocator.Mode, "FreeAll");
|
||||||
|
if ok do assert(v == Allocator.Mode.FreeAll);
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-7
@@ -20,7 +20,7 @@ import (
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// IMPORTANT NOTE(bill): `type_info` cannot be used within a
|
// IMPORTANT NOTE(bill): `type_info_of` cannot be used within a
|
||||||
// #shared_global_scope due to the internals of the compiler.
|
// #shared_global_scope due to the internals of the compiler.
|
||||||
// This could change at a later date if the all these data structures are
|
// This could change at a later date if the all these data structures are
|
||||||
// implemented within the compiler rather than in this "preload" file
|
// implemented within the compiler rather than in this "preload" file
|
||||||
@@ -38,10 +38,12 @@ CallingConvention :: enum {
|
|||||||
// The compiler relies upon this _exact_ order
|
// The compiler relies upon this _exact_ order
|
||||||
TypeInfo :: struct #ordered {
|
TypeInfo :: struct #ordered {
|
||||||
// Core Types
|
// Core Types
|
||||||
EnumValue :: struct #raw_union {
|
EnumValue :: union {
|
||||||
f: f64;
|
rune,
|
||||||
i: i128;
|
i8, i16, i32, i64, i128, int,
|
||||||
}
|
u8, u16, u32, u64, u128, uint,
|
||||||
|
f32, f64,
|
||||||
|
};
|
||||||
Record :: struct #ordered {
|
Record :: struct #ordered {
|
||||||
types: []^TypeInfo;
|
types: []^TypeInfo;
|
||||||
names: []string;
|
names: []string;
|
||||||
@@ -416,7 +418,7 @@ __get_map_header :: proc(m: ^$T/map[$K]$V) -> __MapHeader #cc_contextless {
|
|||||||
value: V;
|
value: V;
|
||||||
}
|
}
|
||||||
|
|
||||||
_, is_string := type_info_base(type_info(K)).variant.(TypeInfo.String);
|
_, is_string := type_info_base(type_info_of(K)).variant.(TypeInfo.String);
|
||||||
header.is_key_string = is_string;
|
header.is_key_string = is_string;
|
||||||
header.entry_size = size_of(Entry);
|
header.entry_size = size_of(Entry);
|
||||||
header.entry_align = align_of(Entry);
|
header.entry_align = align_of(Entry);
|
||||||
@@ -427,7 +429,7 @@ __get_map_header :: proc(m: ^$T/map[$K]$V) -> __MapHeader #cc_contextless {
|
|||||||
|
|
||||||
__get_map_key :: proc(key: $K) -> __MapKey #cc_contextless {
|
__get_map_key :: proc(key: $K) -> __MapKey #cc_contextless {
|
||||||
map_key: __MapKey;
|
map_key: __MapKey;
|
||||||
ti := type_info_base_without_enum(type_info(K));
|
ti := type_info_base_without_enum(type_info_of(K));
|
||||||
match _ in ti {
|
match _ in ti {
|
||||||
case TypeInfo.Integer:
|
case TypeInfo.Integer:
|
||||||
match 8*size_of(key) {
|
match 8*size_of(key) {
|
||||||
|
|||||||
+72
-56
@@ -183,8 +183,8 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
|
|||||||
write_string(buf, info.name);
|
write_string(buf, info.name);
|
||||||
case Integer:
|
case Integer:
|
||||||
match {
|
match {
|
||||||
case ti == type_info(int): write_string(buf, "int");
|
case ti == type_info_of(int): write_string(buf, "int");
|
||||||
case ti == type_info(uint): write_string(buf, "uint");
|
case ti == type_info_of(uint): write_string(buf, "uint");
|
||||||
case:
|
case:
|
||||||
write_string(buf, info.signed ? "i" : "u");
|
write_string(buf, info.signed ? "i" : "u");
|
||||||
write_int(buf, i64(8*ti.size), 10);
|
write_int(buf, i64(8*ti.size), 10);
|
||||||
@@ -648,6 +648,70 @@ fmt_pointer :: proc(fi: ^FmtInfo, p: rawptr, verb: rune) {
|
|||||||
_fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER);
|
_fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum_value_to_string :: proc(v: any) -> (string, bool) {
|
||||||
|
v.type_info = type_info_base(v.type_info);
|
||||||
|
|
||||||
|
using TypeInfo;
|
||||||
|
match e in v.type_info.variant {
|
||||||
|
case: return "", false;
|
||||||
|
case Enum:
|
||||||
|
get_str :: proc(i: $T, e: Enum) -> (string, bool) {
|
||||||
|
if types.is_string(e.base) {
|
||||||
|
for val, idx in e.values {
|
||||||
|
if v, ok := val.(T); ok && v == i {
|
||||||
|
return e.names[idx], true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if len(e.values) == 0 {
|
||||||
|
return "", true;
|
||||||
|
} else {
|
||||||
|
for val, idx in e.values {
|
||||||
|
if v, ok := val.(T); ok && v == i {
|
||||||
|
return e.names[idx], true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", false;
|
||||||
|
}
|
||||||
|
|
||||||
|
a := any{v.data, type_info_base(e.base)};
|
||||||
|
match v in a {
|
||||||
|
case rune: return get_str(v, e);
|
||||||
|
case i8: return get_str(v, e);
|
||||||
|
case i16: return get_str(v, e);
|
||||||
|
case i32: return get_str(v, e);
|
||||||
|
case i64: return get_str(v, e);
|
||||||
|
case i128: return get_str(v, e);
|
||||||
|
case int: return get_str(v, e);
|
||||||
|
case u8: return get_str(v, e);
|
||||||
|
case u16: return get_str(v, e);
|
||||||
|
case u32: return get_str(v, e);
|
||||||
|
case u64: return get_str(v, e);
|
||||||
|
case u128: return get_str(v, e);
|
||||||
|
case uint: return get_str(v, e);
|
||||||
|
|
||||||
|
case f32: return get_str(v, e);
|
||||||
|
case f64: return get_str(v, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string_to_enum_value :: proc(T: type, s: string) -> (T, bool) {
|
||||||
|
ti := type_info_base(type_info_of(T));
|
||||||
|
if e, ok := ti.variant.(TypeInfo.Enum); ok {
|
||||||
|
for str, idx in e.names {
|
||||||
|
if s == str {
|
||||||
|
// NOTE(bill): Unsafe cast
|
||||||
|
ptr := cast(^T)&e.values[idx];
|
||||||
|
return ptr^, true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return T{}, false;
|
||||||
|
}
|
||||||
|
|
||||||
fmt_enum :: proc(fi: ^FmtInfo, v: any, verb: rune) {
|
fmt_enum :: proc(fi: ^FmtInfo, v: any, verb: rune) {
|
||||||
if v.type_info == nil || v.data == nil {
|
if v.type_info == nil || v.data == nil {
|
||||||
write_string(fi.buf, "<nil>");
|
write_string(fi.buf, "<nil>");
|
||||||
@@ -656,64 +720,16 @@ fmt_enum :: proc(fi: ^FmtInfo, v: any, verb: rune) {
|
|||||||
|
|
||||||
using TypeInfo;
|
using TypeInfo;
|
||||||
match e in v.type_info.variant {
|
match e in v.type_info.variant {
|
||||||
case:
|
case: fmt_bad_verb(fi, verb);
|
||||||
fmt_bad_verb(fi, verb);
|
|
||||||
return;
|
|
||||||
case Enum:
|
case Enum:
|
||||||
match verb {
|
match verb {
|
||||||
|
case: fmt_bad_verb(fi, verb);
|
||||||
case 'd', 'f':
|
case 'd', 'f':
|
||||||
fmt_arg(fi, any{v.data, type_info_base(e.base)}, verb);
|
fmt_arg(fi, any{v.data, type_info_base(e.base)}, verb);
|
||||||
case 's', 'v':
|
case 's', 'v':
|
||||||
i: i128;
|
str, ok := enum_value_to_string(v);
|
||||||
f: f64;
|
if !ok do str = "!%(BAD ENUM VALUE)";
|
||||||
ok: bool;
|
write_string(fi.buf, str);
|
||||||
a := any{v.data, type_info_base(e.base)};
|
|
||||||
match v in a {
|
|
||||||
case rune: i = i128(v);
|
|
||||||
case i8: i = i128(v);
|
|
||||||
case i16: i = i128(v);
|
|
||||||
case i32: i = i128(v);
|
|
||||||
case i64: i = i128(v);
|
|
||||||
case i128: i = i128(v);
|
|
||||||
case int: i = i128(v);
|
|
||||||
case u8: i = i128(v);
|
|
||||||
case u16: i = i128(v);
|
|
||||||
case u32: i = i128(v);
|
|
||||||
case u64: i = i128(v);
|
|
||||||
case u128: i = i128(v);
|
|
||||||
case uint: i = i128(v);
|
|
||||||
|
|
||||||
case f32: f = f64(v); i = i128(transmute(i64, f));
|
|
||||||
case f64: f = f64(v); i = i128(transmute(i64, f));
|
|
||||||
}
|
|
||||||
|
|
||||||
if types.is_string(e.base) {
|
|
||||||
for val, idx in e.values {
|
|
||||||
if val.i == i {
|
|
||||||
write_string(fi.buf, e.names[idx]);
|
|
||||||
ok = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if len(e.values) == 0 {
|
|
||||||
write_string(fi.buf, "");
|
|
||||||
ok = true;
|
|
||||||
} else {
|
|
||||||
for val, idx in e.values {
|
|
||||||
if val.i == i {
|
|
||||||
write_string(fi.buf, e.names[idx]);
|
|
||||||
ok = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
write_string(fi.buf, "!%(BAD ENUM VALUE)");
|
|
||||||
}
|
|
||||||
case:
|
|
||||||
fmt_bad_verb(fi, verb);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -762,7 +778,7 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) {
|
|||||||
case String: fmt_arg(fi, v, verb);
|
case String: fmt_arg(fi, v, verb);
|
||||||
|
|
||||||
case Pointer:
|
case Pointer:
|
||||||
if v.type_info == type_info(^TypeInfo) {
|
if v.type_info == type_info_of(^TypeInfo) {
|
||||||
write_type(fi.buf, (cast(^^TypeInfo)v.data)^);
|
write_type(fi.buf, (cast(^^TypeInfo)v.data)^);
|
||||||
} else {
|
} else {
|
||||||
fmt_pointer(fi, (cast(^rawptr)v.data)^, verb);
|
fmt_pointer(fi, (cast(^rawptr)v.data)^, verb);
|
||||||
|
|||||||
+9
-5
@@ -4835,7 +4835,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
|||||||
case BuiltinProc_size_of:
|
case BuiltinProc_size_of:
|
||||||
case BuiltinProc_align_of:
|
case BuiltinProc_align_of:
|
||||||
case BuiltinProc_offset_of:
|
case BuiltinProc_offset_of:
|
||||||
case BuiltinProc_type_info:
|
case BuiltinProc_type_info_of:
|
||||||
case BuiltinProc_transmute:
|
case BuiltinProc_transmute:
|
||||||
// NOTE(bill): The first arg may be a Type, this will be checked case by case
|
// NOTE(bill): The first arg may be a Type, this will be checked case by case
|
||||||
break;
|
break;
|
||||||
@@ -5295,10 +5295,10 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case BuiltinProc_type_info: {
|
case BuiltinProc_type_info_of: {
|
||||||
// proc type_info(Type) -> ^Type_Info
|
// proc type_info_of(Type) -> ^Type_Info
|
||||||
if (c->context.scope->is_global) {
|
if (c->context.scope->is_global) {
|
||||||
compiler_error("`type_info` Cannot be declared within a #shared_global_scope due to how the internals of the compiler works");
|
compiler_error("`type_info_of` Cannot be declared within a #shared_global_scope due to how the internals of the compiler works");
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(bill): The type information may not be setup yet
|
// NOTE(bill): The type information may not be setup yet
|
||||||
@@ -5311,7 +5311,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
|||||||
}
|
}
|
||||||
Type *t = o.type;
|
Type *t = o.type;
|
||||||
if (t == nullptr || t == t_invalid || is_type_polymorphic(operand->type)) {
|
if (t == nullptr || t == t_invalid || is_type_polymorphic(operand->type)) {
|
||||||
error(ce->args[0], "Invalid argument for `type_info`");
|
error(ce->args[0], "Invalid argument for `type_info_of`");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
t = default_type(t);
|
t = default_type(t);
|
||||||
@@ -7110,6 +7110,10 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
|
|||||||
o->mode = Addressing_Builtin;
|
o->mode = Addressing_Builtin;
|
||||||
o->builtin_id = BuiltinProc_type_of;
|
o->builtin_id = BuiltinProc_type_of;
|
||||||
break;
|
break;
|
||||||
|
case Token_type_info_of:
|
||||||
|
o->mode = Addressing_Builtin;
|
||||||
|
o->builtin_id = BuiltinProc_type_info_of;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error(node, "Illegal implicit name `%.*s`", LIT(i->string));
|
error(node, "Illegal implicit name `%.*s`", LIT(i->string));
|
||||||
|
|||||||
+11
-10
@@ -40,7 +40,7 @@ enum BuiltinProcId {
|
|||||||
BuiltinProc_align_of,
|
BuiltinProc_align_of,
|
||||||
BuiltinProc_offset_of,
|
BuiltinProc_offset_of,
|
||||||
BuiltinProc_type_of,
|
BuiltinProc_type_of,
|
||||||
BuiltinProc_type_info,
|
BuiltinProc_type_info_of,
|
||||||
|
|
||||||
BuiltinProc_compile_assert,
|
BuiltinProc_compile_assert,
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
|||||||
{STR_LIT("align_of"), 1, false, Expr_Expr},
|
{STR_LIT("align_of"), 1, false, Expr_Expr},
|
||||||
{STR_LIT("offset_of"), 2, false, Expr_Expr},
|
{STR_LIT("offset_of"), 2, false, Expr_Expr},
|
||||||
{STR_LIT("type_of"), 1, false, Expr_Expr},
|
{STR_LIT("type_of"), 1, false, Expr_Expr},
|
||||||
{STR_LIT("type_info"), 1, false, Expr_Expr},
|
{STR_LIT("type_info_of"), 1, false, Expr_Expr},
|
||||||
|
|
||||||
{STR_LIT("compile_assert"), 1, false, Expr_Expr},
|
{STR_LIT("compile_assert"), 1, false, Expr_Expr},
|
||||||
|
|
||||||
@@ -521,14 +521,15 @@ void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entit
|
|||||||
if (found) {
|
if (found) {
|
||||||
Entity *e = *found;
|
Entity *e = *found;
|
||||||
if (gone_thru_proc) {
|
if (gone_thru_proc) {
|
||||||
// if (e->kind == Entity_Label) {
|
// IMPORTANT TODO(bill): Is this correct?!
|
||||||
// continue;
|
if (e->kind == Entity_Label) {
|
||||||
// }
|
continue;
|
||||||
// if (e->kind == Entity_Variable &&
|
}
|
||||||
// !e->scope->is_file &&
|
if (e->kind == Entity_Variable &&
|
||||||
// !e->scope->is_global) {
|
!e->scope->is_file &&
|
||||||
// continue;
|
!e->scope->is_global) {
|
||||||
// }
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entity_) *entity_ = e;
|
if (entity_) *entity_ = e;
|
||||||
|
|||||||
+17
-12
@@ -3866,7 +3866,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv
|
|||||||
return ir_emit_source_code_location(proc, procedure, pos);
|
return ir_emit_source_code_location(proc, procedure, pos);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case BuiltinProc_type_info: {
|
case BuiltinProc_type_info_of: {
|
||||||
Type *t = default_type(type_of_expr(proc->module->info, ce->args[0]));
|
Type *t = default_type(type_of_expr(proc->module->info, ce->args[0]));
|
||||||
return ir_type_info(proc, t);
|
return ir_type_info(proc, t);
|
||||||
} break;
|
} break;
|
||||||
@@ -4793,7 +4793,17 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
|||||||
AstNode *p = unparen_expr(ce->proc);
|
AstNode *p = unparen_expr(ce->proc);
|
||||||
if (proc_mode == Addressing_Builtin) {
|
if (proc_mode == Addressing_Builtin) {
|
||||||
Entity *e = entity_of_ident(proc->module->info, p);
|
Entity *e = entity_of_ident(proc->module->info, p);
|
||||||
BuiltinProcId id = cast(BuiltinProcId)(e != nullptr ? e->Builtin.id : BuiltinProc_DIRECTIVE);
|
BuiltinProcId id = BuiltinProc_Invalid;
|
||||||
|
if (e != nullptr) {
|
||||||
|
id = cast(BuiltinProcId)e->Builtin.id;
|
||||||
|
} else {
|
||||||
|
id = BuiltinProc_DIRECTIVE;
|
||||||
|
if (ce->proc->kind == AstNode_Implicit) {
|
||||||
|
ast_node(i, Implicit, ce->proc);
|
||||||
|
GB_ASSERT(i->kind == Token_type_info_of);
|
||||||
|
id = BuiltinProc_type_info_of;
|
||||||
|
}
|
||||||
|
}
|
||||||
return ir_build_builtin_proc(proc, expr, tv, id);
|
return ir_build_builtin_proc(proc, expr, tv, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8106,23 +8116,18 @@ void ir_gen_tree(irGen *s) {
|
|||||||
str_lit("__$enum_values"), cast(i64)entry_index);
|
str_lit("__$enum_values"), cast(i64)entry_index);
|
||||||
|
|
||||||
bool is_value_int = is_type_integer(t->Enum.base_type);
|
bool is_value_int = is_type_integer(t->Enum.base_type);
|
||||||
|
if (!is_value_int) {
|
||||||
|
GB_ASSERT(is_type_float(t->Enum.base_type));
|
||||||
|
}
|
||||||
|
|
||||||
for (isize i = 0; i < count; i++) {
|
for (isize i = 0; i < count; i++) {
|
||||||
irValue *name_ep = ir_emit_array_epi(proc, name_array, i);
|
irValue *name_ep = ir_emit_array_epi(proc, name_array, i);
|
||||||
irValue *value_ep = ir_emit_array_epi(proc, value_array, i);
|
irValue *value_ep = ir_emit_array_epi(proc, value_array, i);
|
||||||
|
|
||||||
ExactValue value = fields[i]->Constant.value;
|
ExactValue value = fields[i]->Constant.value;
|
||||||
|
irValue *v = ir_value_constant(a, t->Enum.base_type, value);
|
||||||
|
|
||||||
if (is_value_int) {
|
ir_emit_store(proc, value_ep, ir_emit_conv(proc, v, t_type_info_enum_value));
|
||||||
value_ep = ir_emit_conv(proc, value_ep, t_i128_ptr);
|
|
||||||
ir_emit_store(proc, value_ep, ir_value_constant(a, t_i128, value));
|
|
||||||
} else {
|
|
||||||
GB_ASSERT(is_type_float(t->Enum.base_type));
|
|
||||||
f64 f = value.value_float;
|
|
||||||
value_ep = ir_emit_conv(proc, value_ep, t_f64_ptr);
|
|
||||||
ir_emit_store(proc, value_ep, ir_const_f64(a, f));
|
|
||||||
}
|
|
||||||
|
|
||||||
ir_emit_store(proc, name_ep, ir_const_string(a, fields[i]->token.string));
|
ir_emit_store(proc, name_ep, ir_const_string(a, fields[i]->token.string));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2217,6 +2217,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
|||||||
case Token_size_of:
|
case Token_size_of:
|
||||||
case Token_align_of:
|
case Token_align_of:
|
||||||
case Token_offset_of:
|
case Token_offset_of:
|
||||||
|
case Token_type_info_of:
|
||||||
return parse_call_expr(f, ast_implicit(f, advance_token(f)));
|
return parse_call_expr(f, ast_implicit(f, advance_token(f)));
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -107,7 +107,6 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
|||||||
TOKEN_KIND(Token_macro, "macro"), \
|
TOKEN_KIND(Token_macro, "macro"), \
|
||||||
TOKEN_KIND(Token_struct, "struct"), \
|
TOKEN_KIND(Token_struct, "struct"), \
|
||||||
TOKEN_KIND(Token_union, "union"), \
|
TOKEN_KIND(Token_union, "union"), \
|
||||||
/* TOKEN_KIND(Token_raw_union, "raw_union"), */ \
|
|
||||||
TOKEN_KIND(Token_enum, "enum"), \
|
TOKEN_KIND(Token_enum, "enum"), \
|
||||||
TOKEN_KIND(Token_bit_field, "bit_field"), \
|
TOKEN_KIND(Token_bit_field, "bit_field"), \
|
||||||
TOKEN_KIND(Token_vector, "vector"), \
|
TOKEN_KIND(Token_vector, "vector"), \
|
||||||
@@ -123,6 +122,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
|||||||
TOKEN_KIND(Token_align_of, "align_of"), \
|
TOKEN_KIND(Token_align_of, "align_of"), \
|
||||||
TOKEN_KIND(Token_offset_of, "offset_of"), \
|
TOKEN_KIND(Token_offset_of, "offset_of"), \
|
||||||
TOKEN_KIND(Token_type_of, "type_of"), \
|
TOKEN_KIND(Token_type_of, "type_of"), \
|
||||||
|
TOKEN_KIND(Token_type_info_of, "type_info_of"), \
|
||||||
TOKEN_KIND(Token_asm, "asm"), \
|
TOKEN_KIND(Token_asm, "asm"), \
|
||||||
TOKEN_KIND(Token_yield, "yield"), \
|
TOKEN_KIND(Token_yield, "yield"), \
|
||||||
TOKEN_KIND(Token_await, "await"), \
|
TOKEN_KIND(Token_await, "await"), \
|
||||||
|
|||||||
Reference in New Issue
Block a user