printf will now show errors in the output when there are errors.

This commit is contained in:
Christoffer Lerno
2024-08-31 19:36:18 +02:00
parent 6cb6113c57
commit d635cfb90f
5 changed files with 105 additions and 52 deletions

View File

@@ -104,13 +104,29 @@ fn void default_panic(String message, String file, String function, uint line) @
$$trap();
}
macro void abort(String string = "Unrecoverable error reached", ...) @builtin @noreturn
{
panicf(string, $$FILE, $$FUNC, $$LINE, $vasplat);
$$trap();
}
bool in_panic @local = false;
fn void default_panic(String message, String file, String function, uint line) @if(!env::NATIVE_STACKTRACE)
{
if (in_panic)
{
io::eprintn("Panic inside of panic.");
return;
}
in_panic = true;
$if $defined(io::stderr):
io::eprint("\nERROR: '");
io::eprint(message);
io::eprintfn("', in %s (%s:%d)", function, file, line);
$endif
in_panic = false;
$$trap();
}
@@ -120,11 +136,19 @@ PanicFn panic = &default_panic;
fn void panicf(String fmt, String file, String function, uint line, args...)
{
if (in_panic)
{
io::eprint("Panic inside of panic: ");
io::eprintn(fmt);
return;
}
in_panic = true;
@stack_mem(512; Allocator allocator)
{
DString s;
s.new_init(.allocator = allocator);
s.appendf(fmt, ...args);
in_panic = false;
panic(s.str_view(), file, function, line);
};
}

View File

@@ -15,24 +15,14 @@ fault PrintFault
{
BUFFER_EXCEEDED,
INTERNAL_BUFFER_EXCEEDED,
INVALID_FORMAT_STRING,
MISSING_ARG,
INVALID_ARGUMENT_TYPE,
}
fault FormattingFault
{
UNTERMINATED_FORMAT,
MISSING_ARG,
INVALID_WIDTH_ARG,
INVALID_FORMAT_TYPE,
INVALID_FORMAT,
NOT_ENOUGH_ARGUMENTS,
INVALID_ARGUMENT,
}
def OutputFn = fn void!(void* buffer, char c);
def FloatType = double;
fn usz! Formatter.printf(&self, String format, args...)
{
return self.vprintf(format, args) @inline;
@@ -48,6 +38,7 @@ struct Formatter
uint width;
uint prec;
usz idx;
anyfault first_fault;
}
}
@@ -69,7 +60,12 @@ fn void Formatter.init(&self, OutputFn out_fn, void* data = null)
fn usz! Formatter.out(&self, char c) @private
{
self.out_fn(self.data, c)!;
if (catch err = self.out_fn(self.data, c))
{
if (self.first_fault) return self.first_fault?;
self.first_fault = err;
return err?;
}
return 1;
}
@@ -136,7 +132,7 @@ fn usz! Formatter.out_str(&self, any arg) @private
}
self.flags = {};
self.width = 0;
return self.ntoa_any(arg, 10);
return self.ntoa_any(arg, 10) ?? self.out_substr("<INVALID>");
case FLOAT:
PrintFlags flags = self.flags;
uint width = self.width;
@@ -147,7 +143,7 @@ fn usz! Formatter.out_str(&self, any arg) @private
}
self.flags = {};
self.width = 0;
return self.ftoa(float_from_any(arg)!!);
return self.ftoa(float_from_any(arg)) ?? self.out_substr("ERR");
case BOOL:
return self.out_substr(*(bool*)arg.ptr ? "true" : "false");
default:
@@ -292,10 +288,31 @@ fn void! out_null_fn(void* data @unused, char c @unused) @private
{
}
macro usz! @report_fault(Formatter* f, $fault)
{
(void)f.out_substr($fault);
return PrintFault.INVALID_FORMAT?;
}
macro usz! @wrap_bad(Formatter* f, #action)
{
usz! len = #action;
if (catch err = len)
{
case PrintFault.BUFFER_EXCEEDED:
case PrintFault.INTERNAL_BUFFER_EXCEEDED:
return f.first_err(err)?;
default:
err = f.first_err(PrintFault.INVALID_ARGUMENT);
f.out_substr("<INVALID>")!;
return err?;
}
return len;
}
fn usz! Formatter.vprintf(&self, String format, any[] anys)
{
self.first_fault = {};
if (!self.out_fn)
{
// use null output function
@@ -315,7 +332,7 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
continue;
}
i++;
if (i >= format_len) return PrintFault.INVALID_FORMAT_STRING?;
if (i >= format_len) return @report_fault(self, "%ERR");
c = format[i];
if (c == '%')
{
@@ -335,11 +352,12 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
case '#': self.flags.hash = true;
default: break FLAG_EVAL;
}
if (++i >= format_len) return PrintFault.INVALID_FORMAT_STRING?;
if (++i >= format_len) return @report_fault(self, "%ERR");
c = format[i];
}
// evaluate width field
int w = printf_parse_format_field(anys.ptr, anys.len, &variant_index, format.ptr, format.len, &i)!;
int! w = printf_parse_format_field(anys.ptr, anys.len, &variant_index, format.ptr, format.len, &i);
if (catch w) return @report_fault(self, "%ERR");
c = format[i];
if (w < 0)
{
@@ -352,15 +370,21 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
if (c == '.')
{
self.flags.precision = true;
if (++i >= format_len) return PrintFault.INVALID_FORMAT_STRING?;
int prec = printf_parse_format_field(anys.ptr, anys.len, &variant_index, format.ptr, format.len, &i)!;
if (++i >= format_len) return @report_fault(self, "<BAD FORMAT>");
int! prec = printf_parse_format_field(anys.ptr, anys.len, &variant_index, format.ptr, format.len, &i);
if (catch prec) return @report_fault(self, "<BAD FORMAT>");
self.prec = prec < 0 ? 0 : prec;
c = format[i];
}
// evaluate specifier
uint base = 0;
if (variant_index >= anys.len) return PrintFault.MISSING_ARG?;
if (variant_index >= anys.len)
{
self.first_err(PrintFault.NOT_ENOUGH_ARGUMENTS);
total_len += self.out_substr("<MISSING>")!;
continue;
}
any current = anys[variant_index++];
switch (c)
{
@@ -386,25 +410,25 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
self.flags.uppercase = true;
nextcase;
case 'a':
total_len += self.atoa(float_from_any(current)!!)!;
total_len += @wrap_bad(self, self.atoa(float_from_any(current)))!;
continue;
case 'F' :
self.flags.uppercase = true;
nextcase;
case 'f':
total_len += self.ftoa(float_from_any(current)!!)!;
total_len += @wrap_bad(self, self.ftoa(float_from_any(current)))!;
continue;
case 'E':
self.flags.uppercase = true;
nextcase;
case 'e':
total_len += self.etoa(float_from_any(current)!!)!;
total_len += @wrap_bad(self, self.etoa(float_from_any(current)))!;
continue;
case 'G':
self.flags.uppercase = true;
nextcase;
case 'g':
total_len += self.gtoa(float_from_any(current)!!)!;
total_len += @wrap_bad(self, self.gtoa(float_from_any(current)))!;
continue;
case 'c':
total_len += self.out_char(current)!;
@@ -429,7 +453,9 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
self.flags.hash = true;
base = 16;
default:
return PrintFault.INVALID_FORMAT_STRING?;
self.first_err(PrintFault.INVALID_FORMAT);
total_len += self.out_substr("<BAD FORMAT>")!;
continue;
}
if (base != 10)
{
@@ -440,14 +466,13 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
if (self.flags.precision) self.flags.zeropad = false;
bool is_neg;
uint128 v = int_from_any(current, &is_neg)!!;
total_len += self.ntoa(v, is_neg, base)!;
total_len += @wrap_bad(self, self.ntoa(int_from_any(current, &is_neg), is_neg, base))!;
}
// termination
// out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
// return written chars without terminating \0
if (self.first_fault) return self.first_fault?;
return total_len;
}

View File

@@ -4,6 +4,18 @@ import std::math;
const char[16] XDIGITS_H = "0123456789ABCDEF";
const char[16] XDIGITS_L = "0123456789abcdef";
fault FormattingFault
{
BAD_FORMAT
}
macro Formatter.first_err(&self, anyfault f)
{
if (self.first_fault) return self.first_fault;
self.first_fault = f;
return f;
}
fn usz! Formatter.adjust(&self, usz len) @local
{
if (!self.flags.left) return 0;
@@ -21,6 +33,7 @@ fn uint128! int_from_any(any arg, bool *is_neg) @private
case TypeKind.ENUM:
return int_from_any(arg.as_inner(), is_neg);
default:
break;
}
*is_neg = false;
switch (arg)
@@ -59,7 +72,7 @@ fn uint128! int_from_any(any arg, bool *is_neg) @private
double d = *arg;
return (uint128)((*is_neg = d < 0) ? -d : d);
default:
return PrintFault.INVALID_ARGUMENT_TYPE?;
return FormattingFault.BAD_FORMAT?;
}
}
@@ -101,7 +114,7 @@ fn FloatType! float_from_any(any arg) @private
case double:
return (FloatType)*arg;
default:
return PrintFault.INVALID_ARGUMENT_TYPE?;
return FormattingFault.BAD_FORMAT?;
}
}
@@ -588,8 +601,7 @@ fn usz! Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint ba
fn usz! Formatter.ntoa_any(&self, any arg, uint base) @private
{
bool is_neg;
uint128 val = int_from_any(arg, &is_neg)!!;
return self.ntoa(val, is_neg, base) @inline;
return self.ntoa(int_from_any(arg, &is_neg)!!, is_neg, base) @inline;
}
fn usz! Formatter.out_char(&self, any arg) @private
@@ -640,17 +652,6 @@ fn usz! Formatter.out_reverse(&self, char[] buf) @private
return n;
}
fn void! printf_advance_format(usz format_len, usz *index_ptr) @inline @private
{
usz val = ++(*index_ptr);
if (val >= format_len) return FormattingFault.UNTERMINATED_FORMAT?;
}
fn any! next_any(any* args_ptr, usz args_len, usz* arg_index_ptr) @inline @private
{
if (*arg_index_ptr >= args_len) return FormattingFault.MISSING_ARG?;
return args_ptr[(*arg_index_ptr)++];
}
fn int! printf_parse_format_field(
any* args_ptr, usz args_len, usz* args_index_ptr,
@@ -659,9 +660,11 @@ fn int! printf_parse_format_field(
char c = format_ptr[*index_ptr];
if (c.is_digit()) return simple_atoi(format_ptr, format_len, index_ptr);
if (c != '*') return 0;
printf_advance_format(format_len, index_ptr)!;
any val = next_any(args_ptr, args_len, args_index_ptr)!;
if (!val.type.kindof.is_int()) return FormattingFault.INVALID_WIDTH_ARG?;
usz len = ++(*index_ptr);
if (len >= format_len) return FormattingFault.BAD_FORMAT?;
if (*args_index_ptr >= args_len) return FormattingFault.BAD_FORMAT?;
any val = args_ptr[(*args_index_ptr)++];
if (!val.type.kindof.is_int()) return FormattingFault.BAD_FORMAT?;
uint! intval = types::any_to_int(val, int);
return intval ?? FormattingFault.INVALID_WIDTH_ARG?;
return intval ?? FormattingFault.BAD_FORMAT?;
}

View File

@@ -256,7 +256,7 @@ fn usz! printfn(String format, args...) @maydiscard
{
Formatter formatter;
formatter.init(&out_putchar_fn);
usz len = formatter.vprintf(format, args)!;
usz! len = formatter.vprintf(format, args);
putchar('\n');
io::stdout().flush()!;
return len + 1;
@@ -290,10 +290,10 @@ fn usz! eprintfn(String format, args...) @maydiscard
Formatter formatter;
OutStream stream = stderr();
formatter.init(&out_putstream_fn, &stream);
usz len = formatter.vprintf(format, args)! + 1;
usz! len = formatter.vprintf(format, args);
stderr().write_byte('\n')!;
stderr().flush()!;
return len;
return len + 1;
}
/**

View File

@@ -97,6 +97,7 @@
- Methods can now properly be aliased using `def` #1393.
- Memory leak in Object when not using temp allocators.
- Tracking allocator would double the allocations in the report.
- `printf` will now show errors in the output when there are errors.
### Stdlib changes