From: Brendan Hansen Date: Sun, 6 Feb 2022 23:58:20 +0000 (-0600) Subject: started standard way of parsing anything from a string X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=2fbdb0c54e67c2c9a8df96577af822e3d5bc958b;p=onyx.git started standard way of parsing anything from a string --- diff --git a/core/conv.onyx b/core/conv.onyx index edf14d6a..dcb6ce4d 100644 --- a/core/conv.onyx +++ b/core/conv.onyx @@ -4,11 +4,15 @@ Enable_Custom_Formatters :: true #local { map :: package core.map + string :: package core.string + custom_formatters: Map(type_expr, (^Format_Output, ^Format, rawptr) -> void); + custom_parsers : Map(type_expr, (rawptr, str, Allocator) -> bool); } custom_formatters_initialized :: #init () { map.init(^custom_formatters, default=null_proc); + map.init(^custom_parsers, default=null_proc); #if Enable_Custom_Formatters { use type_info; @@ -19,10 +23,15 @@ custom_formatters_initialized :: #init () { s_info := cast(^Type_Info_Struct) type; for s_info.tags { - if it.type != Custom_Format do continue; + if it.type == Custom_Format { + custom_format := cast(^Custom_Format) it.data; + custom_formatters[cast(type_expr) type_idx] = custom_format.format; + } - custom_format := cast(^Custom_Format) it.data; - custom_formatters[cast(type_expr) type_idx] = custom_format.format; + if it.type == Custom_Parse { + custom_parse := cast(^Custom_Parse) it.data; + custom_parsers[cast(type_expr) type_idx] = custom_parse.parse; + } } } } @@ -32,10 +41,18 @@ register_custom_formatter :: (formatter: (^Format_Output, ^Format, ^$T) -> void) custom_formatters[T] = formatter; } +register_custom_parser :: (parser: (^$T, str, Allocator) -> bool) { + custom_parsers[T] = parser; +} + Custom_Format :: struct { format: (^Format_Output, ^Format, rawptr) -> void; } +Custom_Parse :: struct { + parse: (rawptr, str, Allocator) -> bool; +} + str_to_i64 :: (s: str, base: u32 = 10) -> i64 { use package core @@ -277,6 +294,7 @@ Format :: struct { quote_strings := false; dereference := false; custom_format := true; + interpret_numbers := true; digits_after_decimal := cast(u32) 4; indentation := cast(u32) 0; @@ -385,6 +403,11 @@ format_va :: #match {} formatting.quote_strings = true; } + case #char "d" { + i += 1; + formatting.interpret_numbers = false; + } + case #char "}" { arg := va[vararg_index]; vararg_index += 1; @@ -664,6 +687,11 @@ format_any :: (output: ^Format_Output, formatting: ^Format, v: any) { case #default do assert(false, "Bad enum backing type"); } + if !formatting.interpret_numbers { + format_any(output, formatting, .{^value, u64}); + break; + } + if !e.is_flags { for ^member: e.members { if value == member.value { @@ -693,11 +721,97 @@ format_any :: (output: ^Format_Output, formatting: ^Format, v: any) { if info.kind == .Distinct { d := cast(^Type_Info_Distinct) info; - output->write(d.name); - output->write("["); + if formatting.interpret_numbers { + output->write(d.name); + output->write("["); + } + format_any(output, formatting, any.{ v.data, d.base_type }); - output->write("]"); + + if formatting.interpret_numbers { + output->write("]"); + } } } } } + +// +// This should be called with a pointer for the first argument. +// +// x: i32; +// parse_any(^x, "12.34"); +parse_any :: #match {} +#match parse_any (v: any, to_parse: str, string_allocator := context.allocator) -> bool { + use type_info; + + info := get_type_info(v.type); + if info.kind != .Pointer do return false; + + data_type := (cast(^Type_Info_Pointer) info).to; + target := *cast(^rawptr) v.data; + return parse_any(target, data_type, to_parse, string_allocator); +} + +#match parse_any (target: rawptr, data_type: type_expr, to_parse: str, string_allocator := context.allocator) -> bool { + if custom_parsers->has(data_type) { + return custom_parsers[data_type](target, to_parse, string_allocator); + } + + use type_info; + info := get_type_info(data_type); + + switch data_type { + case bool { + dest := cast(^bool) target; + *dest = false; + if to_parse[0] == #char "t" || to_parse[0] == #char "T" { + *dest = true; + } + return true; + } + + case i32, u32 { + dest := cast(^i32) target; + *dest = ~~ str_to_i64(to_parse); + return true; + } + + case f32 { + dest := cast(^f32) target; + *dest = ~~ str_to_f64(to_parse); + return true; + } + + case f64 { + dest := cast(^f64) target; + *dest = ~~ str_to_f64(to_parse); + return true; + } + + case str { + if to_parse[0] != #char "\"" do return false; + line := to_parse; + string.advance(^line); + + // + // For now, this will return a substring in the original to_parse. + dest := cast(^str) target; + *dest = string.read_until(^line, #char "\"") |> string.alloc_copy(string_allocator); @BUG // This does not handle escaped strings! + return true; + } + + case #default { + if info.kind == .Enum { + // TEMPORARY this needs to look at the backing type for the + // enum in order to know how large this integer should be. + *cast(^u32) target = ~~ str_to_i64(to_parse); + return true; + } + } + } + + return false; +} + + diff --git a/src/utils.c b/src/utils.c index c06a25b7..f65c26ad 100644 --- a/src/utils.c +++ b/src/utils.c @@ -850,7 +850,9 @@ TypeMatch check_arguments_against_type(Arguments* args, TypeFunction* func_type, if (arg_arr[arg_pos]->value->type && arg_arr[arg_pos]->value->type->id != any_type_id && formal_params[arg_pos]->id == any_type_id) { resolve_expression_type(arg_arr[arg_pos]->value); - arg_arr[arg_pos]->pass_as_any = 1; + if (error != NULL) { + arg_arr[arg_pos]->pass_as_any = 1; + } } arg_arr[arg_pos]->va_kind = VA_Kind_Not_VA;