~turminal/hare

ae8c094a0720fa6c55467cee33abfe37aea6379a — Bor Grošelj Simić 1 year, 5 months ago 1d18562 abort
fmt: extract part of error checking to separate functions
1 files changed, 22 insertions(+), 76 deletions(-)

M fmt/fmt.ha
M fmt/fmt.ha => fmt/fmt.ha +22 -76
@@ 196,15 196,10 @@ export fn fprintf(
		};

		if (r == '{') {
			r = match (strings::next(&iter)) {
			case void =>
				abort("Invalid format string (unterminated '{')");
			case let r: rune =>
				yield r;
			};
			r = next_or_abort(&iter, "Invalid format string (unterminated '{')");

			if (r == '{') {
				n += io::write(h, utf8::encoderune('{'))?;
				n += io::write(h, ['{'])?;
				continue;
			};



@@ 226,12 221,7 @@ export fn fprintf(
				abort("Invalid formattable");
			};

			r = match (strings::next(&iter)) {
			case void =>
				abort("Invalid format string (unterminated '{')");
			case let r: rune =>
				yield r;
			};
			r = next_or_abort(&iter, "Invalid format string (unterminated '{')");

			let mod = &modifiers { ... };
			let pi: paramindex = void;


@@ 271,14 261,9 @@ export fn fprintf(

			n += format(h, arg, mod)?;
		} else if (r == '}') {
			match (strings::next(&iter)) {
			case void =>
				abort("Invalid format string (hanging '}')");
			case let r: rune =>
				assert(r == '}', "Invalid format string (hanging '}')");
			};
			expect('}', &iter, "Invalid format string (hanging '}')");

			n += io::write(h, utf8::encoderune('}'))?;
			n += io::write(h, ['}'])?;
		} else {
			n += io::write(h, utf8::encoderune(r))?;
		};


@@ 408,13 393,7 @@ fn is_negative(n: types::numeric) bool = {
fn scan_uint(iter: *strings::iterator) uint = {
	let copy = *iter;
	for (true) {
		let r = match (strings::next(iter)) {
		case void =>
			abort("Invalid format string (unterminated '{')");
		case let r: rune =>
			yield r;
		};

		let r = next_or_abort(iter, "Invalid format string (unterminated '{')");
		if (!ascii::isdigit(r)) {
			strings::prev(iter);
			match (strconv::stou(strings::slice(&copy, iter))) {


@@ 432,13 411,7 @@ fn scan_modifier_flags(iter: *strings::iterator, mod: *modifiers) void = {
	let flags = modflags::NONE;

	for (true) {
		let r = match (strings::next(iter)) {
		case void =>
			abort("Invalid format string (unterminated '{')");
		case let r: rune =>
			yield r;
		};

		let r = next_or_abort(iter, "Invalid format string (unterminated '{')");
		switch (r) {
		case '0' =>
			flags |= modflags::ZERO;


@@ 470,13 443,7 @@ fn scan_modifier_flags(iter: *strings::iterator, mod: *modifiers) void = {
};

fn scan_modifier_width(iter: *strings::iterator, mod: *modifiers) void = {
	let r = match (strings::next(iter)) {
	case void =>
		abort("Invalid format string (unterminated '{')");
	case let r: rune =>
		yield r;
	};

	let r = next_or_abort(iter, "Invalid format string (unterminated '{')");
	let is_digit = ascii::isdigit(r);
	strings::prev(iter);



@@ 486,13 453,7 @@ fn scan_modifier_width(iter: *strings::iterator, mod: *modifiers) void = {
};

fn scan_modifier_precision(iter: *strings::iterator, mod: *modifiers) void = {
	let r = match (strings::next(iter)) {
	case void =>
		abort("Invalid format string (unterminated '{')");
	case let r: rune =>
		yield r;
	};

	let r = next_or_abort(iter, "Invalid format string (unterminated '{')");
	if (r == '.') {
		mod.precision = scan_uint(iter);
	} else {


@@ 501,13 462,7 @@ fn scan_modifier_precision(iter: *strings::iterator, mod: *modifiers) void = {
};

fn scan_modifier_base(iter: *strings::iterator, mod: *modifiers) void = {
	let r = match (strings::next(iter)) {
	case void =>
		abort("Invalid format string (unterminated '{')");
	case let r: rune =>
		yield r;
	};

	let r = next_or_abort(iter, "Invalid format string (unterminated '{')");
	switch (r) {
	case 'x' =>
		mod.base = strconv::base::HEX_LOWER;


@@ 527,25 482,11 @@ fn scan_inline_modifiers(iter: *strings::iterator, mod: *modifiers) void = {
	scan_modifier_width(iter, mod);
	scan_modifier_precision(iter, mod);
	scan_modifier_base(iter, mod);

	// eat '}'
	let terminated = match (strings::next(iter)) {
	case void =>
		yield false;
	case let r: rune =>
		yield r == '}';
	};
	assert(terminated, "Invalid format string (unterminated '{')");
	expect('}', iter, "Invalid format string (unterminated '{')");
};

fn scan_parameter_index(iter: *strings::iterator, pi: *paramindex) void = {
	let r = match (strings::next(iter)) {
	case void =>
		abort("Invalid format string (unterminated '{')");
	case let r: rune =>
		yield r;
	};

	let r = next_or_abort(iter, "Invalid format string (unterminated '{')");
	let is_digit = ascii::isdigit(r);
	strings::prev(iter);
	if (is_digit) {


@@ 557,15 498,20 @@ fn scan_parameter_index(iter: *strings::iterator, pi: *paramindex) void = {

fn scan_parametric_modifiers(iter: *strings::iterator, pi: *paramindex) void = {
	scan_parameter_index(iter, pi);
	expect('}', iter, "Invalid format string (unterminated '{')");
};

fn expect(r: rune, iter: *strings::iterator, reason: str) void = {
	assert(next_or_abort(iter, reason) == r, reason);
};

	// eat '}'
	let terminated = match (strings::next(iter)) {
fn next_or_abort(iter: *strings::iterator, reason: str) rune = {
	match (strings::next(iter)) {
	case void =>
		yield false;
		abort(reason);
	case let r: rune =>
		yield r == '}';
		return r;
	};
	assert(terminated, "Invalid format string (unterminated '{')");
};

@test fn fmt() void = {