mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
Allow for @indent for attributes that don't require any parameters; Add -ignore-unknown-attributes
This commit is contained in:
@@ -774,32 +774,38 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
|||||||
parse_attribute :: proc(p: ^Parser, tok: token.Token, open_kind, close_kind: token.Kind) -> ^ast.Stmt {
|
parse_attribute :: proc(p: ^Parser, tok: token.Token, open_kind, close_kind: token.Kind) -> ^ast.Stmt {
|
||||||
elems: [dynamic]^ast.Expr;
|
elems: [dynamic]^ast.Expr;
|
||||||
|
|
||||||
open := expect_token(p, open_kind);
|
open, close: token.Token;
|
||||||
p.expr_level += 1;
|
|
||||||
for p.curr_tok.kind != close_kind &&
|
|
||||||
p.curr_tok.kind != token.EOF {
|
|
||||||
elem: ^ast.Expr;
|
|
||||||
elem = parse_ident(p);
|
|
||||||
if p.curr_tok.kind == token.Eq {
|
|
||||||
eq := expect_token(p, token.Eq);
|
|
||||||
value := parse_value(p);
|
|
||||||
fv := ast.new(ast.Field_Value, elem.pos, value.end);
|
|
||||||
fv.field = elem;
|
|
||||||
fv.sep = eq.pos;
|
|
||||||
fv.value = value;
|
|
||||||
|
|
||||||
elem = fv;
|
if p.curr_tok.kind == token.Ident {
|
||||||
}
|
elem := parse_ident(p);
|
||||||
append(&elems, elem);
|
append(&elems, elem);
|
||||||
|
} else {
|
||||||
|
open = expect_token(p, open_kind);
|
||||||
|
p.expr_level += 1;
|
||||||
|
for p.curr_tok.kind != close_kind &&
|
||||||
|
p.curr_tok.kind != token.EOF {
|
||||||
|
elem: ^ast.Expr;
|
||||||
|
elem = parse_ident(p);
|
||||||
|
if p.curr_tok.kind == token.Eq {
|
||||||
|
eq := expect_token(p, token.Eq);
|
||||||
|
value := parse_value(p);
|
||||||
|
fv := ast.new(ast.Field_Value, elem.pos, value.end);
|
||||||
|
fv.field = elem;
|
||||||
|
fv.sep = eq.pos;
|
||||||
|
fv.value = value;
|
||||||
|
|
||||||
if !allow_token(p, token.Comma) {
|
elem = fv;
|
||||||
break;
|
}
|
||||||
|
append(&elems, elem);
|
||||||
|
|
||||||
|
if !allow_token(p, token.Comma) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
p.expr_level -= 1;
|
||||||
|
close = expect_token_after(p, close_kind, "attribute");
|
||||||
}
|
}
|
||||||
|
|
||||||
p.expr_level -= 1;
|
|
||||||
close := expect_token_after(p, close_kind, "attribute");
|
|
||||||
|
|
||||||
attribute := ast.new(ast.Attribute, tok.pos, end_pos(close));
|
attribute := ast.new(ast.Attribute, tok.pos, end_pos(close));
|
||||||
attribute.tok = tok.kind;
|
attribute.tok = tok.kind;
|
||||||
attribute.open = open.pos;
|
attribute.open = open.pos;
|
||||||
|
|||||||
@@ -159,9 +159,11 @@ using Kind :: enum i32 {
|
|||||||
Yield,
|
Yield,
|
||||||
Await,
|
Await,
|
||||||
B_Keyword_End,
|
B_Keyword_End,
|
||||||
|
|
||||||
|
COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
tokens := [len(Kind)]string {
|
tokens := [Kind.COUNT]string {
|
||||||
"Invalid",
|
"Invalid",
|
||||||
"EOF",
|
"EOF",
|
||||||
"Comment",
|
"Comment",
|
||||||
|
|||||||
+37
-37
@@ -344,7 +344,7 @@ __init_context :: proc "contextless" (c: ^Context) {
|
|||||||
c.logger.data = nil;
|
c.logger.data = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
init_global_temporary_allocator :: proc(data: []byte, backup_allocator := context.allocator) {
|
init_global_temporary_allocator :: proc(data: []byte, backup_allocator := context.allocator) {
|
||||||
mem.scratch_allocator_init(&global_scratch_allocator_data, data, backup_allocator);
|
mem.scratch_allocator_init(&global_scratch_allocator_data, data, backup_allocator);
|
||||||
}
|
}
|
||||||
@@ -364,7 +364,7 @@ default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
copy :: proc "contextless" (dst, src: $T/[]$E) -> int {
|
copy :: proc "contextless" (dst, src: $T/[]$E) -> int {
|
||||||
n := max(0, min(len(dst), len(src)));
|
n := max(0, min(len(dst), len(src)));
|
||||||
if n > 0 do mem.copy(&dst[0], &src[0], n*size_of(E));
|
if n > 0 do mem.copy(&dst[0], &src[0], n*size_of(E));
|
||||||
@@ -373,7 +373,7 @@ copy :: proc "contextless" (dst, src: $T/[]$E) -> int {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
pop :: proc "contextless" (array: ^$T/[dynamic]$E) -> E {
|
pop :: proc "contextless" (array: ^$T/[dynamic]$E) -> E {
|
||||||
if array == nil do return E{};
|
if array == nil do return E{};
|
||||||
assert(len(array) > 0);
|
assert(len(array) > 0);
|
||||||
@@ -382,7 +382,7 @@ pop :: proc "contextless" (array: ^$T/[dynamic]$E) -> E {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) {
|
unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) {
|
||||||
bounds_check_error_loc(loc, index, len(array));
|
bounds_check_error_loc(loc, index, len(array));
|
||||||
n := len(array)-1;
|
n := len(array)-1;
|
||||||
@@ -392,7 +392,7 @@ unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_loca
|
|||||||
pop(array);
|
pop(array);
|
||||||
}
|
}
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) {
|
ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) {
|
||||||
bounds_check_error_loc(loc, index, len(array));
|
bounds_check_error_loc(loc, index, len(array));
|
||||||
copy(array[index:], array[index+1:]);
|
copy(array[index:], array[index+1:]);
|
||||||
@@ -400,29 +400,29 @@ ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_locati
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
clear :: proc{clear_dynamic_array, clear_map};
|
clear :: proc{clear_dynamic_array, clear_map};
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
reserve :: proc{reserve_dynamic_array, reserve_map};
|
reserve :: proc{reserve_dynamic_array, reserve_map};
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
resize :: proc{resize_dynamic_array};
|
resize :: proc{resize_dynamic_array};
|
||||||
|
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
new :: proc{mem.new};
|
new :: proc{mem.new};
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
new_clone :: proc{mem.new_clone};
|
new_clone :: proc{mem.new_clone};
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
free :: proc{mem.free};
|
free :: proc{mem.free};
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
free_all :: proc{mem.free_all};
|
free_all :: proc{mem.free_all};
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
delete :: proc{
|
delete :: proc{
|
||||||
mem.delete_string,
|
mem.delete_string,
|
||||||
mem.delete_cstring,
|
mem.delete_cstring,
|
||||||
@@ -431,7 +431,7 @@ delete :: proc{
|
|||||||
mem.delete_map,
|
mem.delete_map,
|
||||||
};
|
};
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
make :: proc{
|
make :: proc{
|
||||||
mem.make_slice,
|
mem.make_slice,
|
||||||
mem.make_dynamic_array,
|
mem.make_dynamic_array,
|
||||||
@@ -443,7 +443,7 @@ make :: proc{
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) {
|
clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) {
|
||||||
if m == nil do return;
|
if m == nil do return;
|
||||||
raw_map := (^mem.Raw_Map)(m);
|
raw_map := (^mem.Raw_Map)(m);
|
||||||
@@ -454,19 +454,19 @@ clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int) {
|
reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int) {
|
||||||
if m != nil do __dynamic_map_reserve(__get_map_header(m), capacity);
|
if m != nil do __dynamic_map_reserve(__get_map_header(m), capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
delete_key :: proc(m: ^$T/map[$K]$V, key: K) {
|
delete_key :: proc(m: ^$T/map[$K]$V, key: K) {
|
||||||
if m != nil do __dynamic_map_delete_key(__get_map_header(m), __get_map_key(key));
|
if m != nil do __dynamic_map_delete_key(__get_map_header(m), __get_map_key(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) {
|
append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) {
|
||||||
if array == nil do return;
|
if array == nil do return;
|
||||||
|
|
||||||
@@ -485,7 +485,7 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) {
|
|||||||
a.len += arg_len;
|
a.len += arg_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@(builtin)
|
@builtin
|
||||||
append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) {
|
append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) {
|
||||||
if array == nil do return;
|
if array == nil do return;
|
||||||
|
|
||||||
@@ -506,23 +506,23 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
|
|||||||
a.len += arg_len;
|
a.len += arg_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@(builtin) append :: proc{append_elem, append_elems};
|
@builtin append :: proc{append_elem, append_elems};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) {
|
append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) {
|
||||||
for arg in args {
|
for arg in args {
|
||||||
append(array = array, args = ([]E)(arg), loc = loc);
|
append(array = array, args = ([]E)(arg), loc = loc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
clear_dynamic_array :: inline proc "contextless" (array: ^$T/[dynamic]$E) {
|
clear_dynamic_array :: inline proc "contextless" (array: ^$T/[dynamic]$E) {
|
||||||
if array != nil do (^mem.Raw_Dynamic_Array)(array).len = 0;
|
if array != nil do (^mem.Raw_Dynamic_Array)(array).len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
|
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
|
||||||
if array == nil do return false;
|
if array == nil do return false;
|
||||||
a := (^mem.Raw_Dynamic_Array)(array);
|
a := (^mem.Raw_Dynamic_Array)(array);
|
||||||
@@ -549,7 +549,7 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> bool {
|
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> bool {
|
||||||
if array == nil do return false;
|
if array == nil do return false;
|
||||||
a := (^mem.Raw_Dynamic_Array)(array);
|
a := (^mem.Raw_Dynamic_Array)(array);
|
||||||
@@ -582,42 +582,42 @@ resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
incl_elem :: inline proc(s: ^$S/bit_set[$E; $U], elem: E) -> S {
|
incl_elem :: inline proc(s: ^$S/bit_set[$E; $U], elem: E) -> S {
|
||||||
s^ |= {elem};
|
s^ |= {elem};
|
||||||
return s^;
|
return s^;
|
||||||
}
|
}
|
||||||
@(builtin)
|
@builtin
|
||||||
incl_elems :: inline proc(s: ^$S/bit_set[$E; $U], elems: ..E) -> S {
|
incl_elems :: inline proc(s: ^$S/bit_set[$E; $U], elems: ..E) -> S {
|
||||||
for elem in elems do s^ |= {elem};
|
for elem in elems do s^ |= {elem};
|
||||||
return s^;
|
return s^;
|
||||||
}
|
}
|
||||||
@(builtin)
|
@builtin
|
||||||
incl_bit_set :: inline proc(s: ^$S/bit_set[$E; $U], other: S) -> S {
|
incl_bit_set :: inline proc(s: ^$S/bit_set[$E; $U], other: S) -> S {
|
||||||
s^ |= other;
|
s^ |= other;
|
||||||
return s^;
|
return s^;
|
||||||
}
|
}
|
||||||
@(builtin)
|
@builtin
|
||||||
excl_elem :: inline proc(s: ^$S/bit_set[$E; $U], elem: E) -> S {
|
excl_elem :: inline proc(s: ^$S/bit_set[$E; $U], elem: E) -> S {
|
||||||
s^ &~= {elem};
|
s^ &~= {elem};
|
||||||
return s^;
|
return s^;
|
||||||
}
|
}
|
||||||
@(builtin)
|
@builtin
|
||||||
excl_elems :: inline proc(s: ^$S/bit_set[$E; $U], elems: ..E) -> S {
|
excl_elems :: inline proc(s: ^$S/bit_set[$E; $U], elems: ..E) -> S {
|
||||||
for elem in elems do s^ &~= {elem};
|
for elem in elems do s^ &~= {elem};
|
||||||
return s^;
|
return s^;
|
||||||
}
|
}
|
||||||
@(builtin)
|
@builtin
|
||||||
excl_bit_set :: inline proc(s: ^$S/bit_set[$E; $U], other: S) -> S {
|
excl_bit_set :: inline proc(s: ^$S/bit_set[$E; $U], other: S) -> S {
|
||||||
s^ &~= other;
|
s^ &~= other;
|
||||||
return s^;
|
return s^;
|
||||||
}
|
}
|
||||||
|
|
||||||
@(builtin) incl :: proc{incl_elem, incl_elems, incl_bit_set};
|
@builtin incl :: proc{incl_elem, incl_elems, incl_bit_set};
|
||||||
@(builtin) excl :: proc{excl_elem, excl_elems, excl_bit_set};
|
@builtin excl :: proc{excl_elem, excl_elems, excl_bit_set};
|
||||||
|
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
card :: proc(s: $S/bit_set[$E; $U]) -> int {
|
card :: proc(s: $S/bit_set[$E; $U]) -> int {
|
||||||
when size_of(S) == 1 {
|
when size_of(S) == 1 {
|
||||||
foreign { @(link_name="llvm.ctpop.i8") count_ones :: proc(i: u8) -> u8 --- }
|
foreign { @(link_name="llvm.ctpop.i8") count_ones :: proc(i: u8) -> u8 --- }
|
||||||
@@ -642,7 +642,7 @@ card :: proc(s: $S/bit_set[$E; $U]) -> int {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
assert :: proc "contextless" (condition: bool, message := "", loc := #caller_location) -> bool {
|
assert :: proc "contextless" (condition: bool, message := "", loc := #caller_location) -> bool {
|
||||||
if !condition {
|
if !condition {
|
||||||
p := context.assertion_failure_proc;
|
p := context.assertion_failure_proc;
|
||||||
@@ -654,7 +654,7 @@ assert :: proc "contextless" (condition: bool, message := "", loc := #caller_loc
|
|||||||
return condition;
|
return condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
panic :: proc "contextless" (message: string, loc := #caller_location) -> ! {
|
panic :: proc "contextless" (message: string, loc := #caller_location) -> ! {
|
||||||
p := context.assertion_failure_proc;
|
p := context.assertion_failure_proc;
|
||||||
if p == nil {
|
if p == nil {
|
||||||
@@ -663,7 +663,7 @@ panic :: proc "contextless" (message: string, loc := #caller_location) -> ! {
|
|||||||
p("Panic", message, loc);
|
p("Panic", message, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
unimplemented :: proc "contextless" (message := "", loc := #caller_location) -> ! {
|
unimplemented :: proc "contextless" (message := "", loc := #caller_location) -> ! {
|
||||||
p := context.assertion_failure_proc;
|
p := context.assertion_failure_proc;
|
||||||
if p == nil {
|
if p == nil {
|
||||||
@@ -672,7 +672,7 @@ unimplemented :: proc "contextless" (message := "", loc := #caller_location) ->
|
|||||||
p("not yet implemented", message, loc);
|
p("not yet implemented", message, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@(builtin)
|
@builtin
|
||||||
unreachable :: proc "contextless" (message := "", loc := #caller_location) -> ! {
|
unreachable :: proc "contextless" (message := "", loc := #caller_location) -> ! {
|
||||||
p := context.assertion_failure_proc;
|
p := context.assertion_failure_proc;
|
||||||
if p == nil {
|
if p == nil {
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ struct BuildContext {
|
|||||||
i32 optimization_level;
|
i32 optimization_level;
|
||||||
bool show_timings;
|
bool show_timings;
|
||||||
bool keep_temp_files;
|
bool keep_temp_files;
|
||||||
|
bool ignore_unknown_attributes;
|
||||||
bool no_bounds_check;
|
bool no_bounds_check;
|
||||||
bool no_output_files;
|
bool no_output_files;
|
||||||
bool no_crt;
|
bool no_crt;
|
||||||
|
|||||||
+3
-1
@@ -2150,7 +2150,9 @@ void check_decl_attributes(CheckerContext *c, Array<Ast *> const &attributes, De
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!proc(c, elem, name, value, ac)) {
|
if (!proc(c, elem, name, value, ac)) {
|
||||||
error(elem, "Unknown attribute element name '%.*s'", LIT(name));
|
if (!build_context.ignore_unknown_attributes) {
|
||||||
|
error(elem, "Unknown attribute element name '%.*s'", LIT(name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ enum BuildFlagKind {
|
|||||||
BuildFlag_NoCRT,
|
BuildFlag_NoCRT,
|
||||||
BuildFlag_UseLLD,
|
BuildFlag_UseLLD,
|
||||||
BuildFlag_Vet,
|
BuildFlag_Vet,
|
||||||
|
BuildFlag_IgnoreUnknownAttributes,
|
||||||
|
|
||||||
BuildFlag_COUNT,
|
BuildFlag_COUNT,
|
||||||
};
|
};
|
||||||
@@ -258,6 +259,7 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None);
|
add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None);
|
||||||
add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None);
|
add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None);
|
||||||
add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None);
|
add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None);
|
||||||
|
add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("-ignore-unknown-attributes"), BuildFlagParam_None);
|
||||||
|
|
||||||
GB_ASSERT(args.count >= 3);
|
GB_ASSERT(args.count >= 3);
|
||||||
Array<String> flag_args = array_slice(args, 3, args.count);
|
Array<String> flag_args = array_slice(args, 3, args.count);
|
||||||
@@ -569,6 +571,10 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
case BuildFlag_Vet:
|
case BuildFlag_Vet:
|
||||||
build_context.vet = true;
|
build_context.vet = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BuildFlag_IgnoreUnknownAttributes:
|
||||||
|
build_context.ignore_unknown_attributes = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+27
-19
@@ -3650,30 +3650,38 @@ Ast *parse_foreign_decl(AstFile *f) {
|
|||||||
|
|
||||||
Ast *parse_attribute(AstFile *f, Token token, TokenKind open_kind, TokenKind close_kind) {
|
Ast *parse_attribute(AstFile *f, Token token, TokenKind open_kind, TokenKind close_kind) {
|
||||||
Array<Ast *> elems = {};
|
Array<Ast *> elems = {};
|
||||||
Token open = expect_token(f, open_kind);
|
Token open = {};
|
||||||
f->expr_level++;
|
Token close = {};
|
||||||
if (f->curr_token.kind != close_kind) {
|
|
||||||
elems = array_make<Ast *>(heap_allocator());
|
|
||||||
while (f->curr_token.kind != close_kind &&
|
|
||||||
f->curr_token.kind != Token_EOF) {
|
|
||||||
Ast *elem = nullptr;
|
|
||||||
elem = parse_ident(f);
|
|
||||||
if (f->curr_token.kind == Token_Eq) {
|
|
||||||
Token eq = expect_token(f, Token_Eq);
|
|
||||||
Ast *value = parse_value(f);
|
|
||||||
elem = ast_field_value(f, elem, value, eq);
|
|
||||||
}
|
|
||||||
|
|
||||||
array_add(&elems, elem);
|
if (f->curr_token.kind == Token_Ident) {
|
||||||
|
elems = array_make<Ast *>(heap_allocator(), 0, 1);
|
||||||
|
Ast *elem = parse_ident(f);
|
||||||
|
array_add(&elems, elem);
|
||||||
|
} else {
|
||||||
|
open = expect_token(f, open_kind);
|
||||||
|
f->expr_level++;
|
||||||
|
if (f->curr_token.kind != close_kind) {
|
||||||
|
elems = array_make<Ast *>(heap_allocator());
|
||||||
|
while (f->curr_token.kind != close_kind &&
|
||||||
|
f->curr_token.kind != Token_EOF) {
|
||||||
|
Ast *elem = nullptr;
|
||||||
|
elem = parse_ident(f);
|
||||||
|
if (f->curr_token.kind == Token_Eq) {
|
||||||
|
Token eq = expect_token(f, Token_Eq);
|
||||||
|
Ast *value = parse_value(f);
|
||||||
|
elem = ast_field_value(f, elem, value, eq);
|
||||||
|
}
|
||||||
|
|
||||||
if (!allow_token(f, Token_Comma)) {
|
array_add(&elems, elem);
|
||||||
break;
|
|
||||||
|
if (!allow_token(f, Token_Comma)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
f->expr_level--;
|
||||||
|
close = expect_closing(f, close_kind, str_lit("attribute"));
|
||||||
}
|
}
|
||||||
f->expr_level--;
|
|
||||||
Token close = expect_closing(f, close_kind, str_lit("attribute"));
|
|
||||||
|
|
||||||
Ast *attribute = ast_attribute(f, token, open, close, elems);
|
Ast *attribute = ast_attribute(f, token, open, close, elems);
|
||||||
|
|
||||||
Ast *decl = parse_stmt(f);
|
Ast *decl = parse_stmt(f);
|
||||||
|
|||||||
Reference in New Issue
Block a user