~sircmpwn/hare-dev

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
2 2

[PATCH hare] Handle negation in parse instead of lex

Details
Message ID
<20220514033444.22944-1-sebastian@sebsite.pw>
DKIM signature
pass
Download raw message
Patch: +75 -81
Fixes: https://todo.sr.ht/~sircmpwn/hare/376
Signed-off-by: Sebastian <sebastian@sebsite.pw>
---
 hare/ast/expr.ha     |  5 ++--
 hare/lex/+test.ha    | 20 ++++++++------
 hare/lex/lex.ha      | 48 ++++----------------------------
 hare/lex/token.ha    |  2 +-
 hare/parse/expr.ha   | 65 ++++++++++++++++++++++++++++++++++----------
 hare/unit/expr.ha    |  2 +-
 hare/unit/process.ha |  8 +-----
 hare/unparse/expr.ha |  2 --
 scripts/gen-stdlib   |  2 +-
 stdlib.mk            |  2 +-
 10 files changed, 75 insertions(+), 81 deletions(-)

diff --git a/hare/ast/expr.ha b/hare/ast/expr.ha
index 3b913867..bf340ba7 100644
--- a/hare/ast/expr.ha
+++ b/hare/ast/expr.ha
@@ -222,7 +222,7 @@ export type tuple_constant = []*expr;
export type _null = void;

// A scalar value.
export type value = (bool | _null | ...lex::value);
export type value = (bool | _null | str | rune | void);

// An integer or float constant.
export type number_constant = struct {
@@ -496,7 +496,6 @@ case let e: expr =>
		free(c.label);
	case let c: constant_expr =>
		match (c) {
		case (void | _null | ...lex::value) => void;
		case let a: array_constant =>
			for (let i = 0z; i < len(a.values); i += 1) {
				expr_finish(a.values[i]);
@@ -509,7 +508,7 @@ case let e: expr =>
				expr_finish(t[i]);
			};
			free(t);
		case number_constant => void;
		case (value | number_constant) => void;
		};
	case let c: continue_expr =>
		free(c);
diff --git a/hare/lex/+test.ha b/hare/lex/+test.ha
index c03fb3d2..a7f6896a 100644
--- a/hare/lex/+test.ha
+++ b/hare/lex/+test.ha
@@ -50,8 +50,6 @@ fn vassert(expected: value, actual: value) void = {
		assert(actual as str == expected);
	case let expected: rune =>
		assert(actual as rune == expected);
	case let expected: i64 =>
		assert(actual as i64 == expected);
	case let expected: u64 =>
		assert(actual as u64 == expected);
	case let expected: f64 =>
@@ -267,18 +265,22 @@ fn loc(line: uint, col: uint) location = location {
		"0b00000010000001100000011100001111000000100000011000000111i64\n"
		"13.37 13.37f32 13.37f64 6.022e23 1.616255e-35f64 1e-1";
	const expected: [_]token = [
		(ltok::LIT_ICONST, 1e5i64, loc(1, 1)),
		(ltok::LIT_I32, -1i64, loc(1, 5)),
		(ltok::LIT_U64, 9223372036854775809u64, loc(1, 11)),
		(ltok::LIT_ICONST, 1e5u64, loc(1, 1)),
		(ltok::MINUS, void, loc(1, 5)),
		(ltok::LIT_I32, 1u64, loc(1, 6)),
		(ltok::LIT_ICONST, 9223372036854775809u64, loc(1, 11)),
		(ltok::LIT_SIZE, 1e2u64, loc(1, 31)),
		(ltok::LIT_U8, 255u64, loc(1, 36)),
		(ltok::LIT_U16, 0o42u64, loc(1, 42)),
		(ltok::LIT_U32, 0b1000101u64, loc(2, 1)),
		(ltok::LIT_U64, 0xDEADBEEFu64, loc(2, 14)),
		(ltok::LIT_I8, -0b10i64, loc(2, 28)),
		(ltok::LIT_I16, -5e0i64, loc(2, 36)),
		(ltok::LIT_I32, -0o16i64, loc(2, 44)),
		(ltok::LIT_I64, 0b00000010000001100000011100001111000000100000011000000111i64, loc(3, 1)),
		(ltok::MINUS, void, loc(2, 28)),
		(ltok::LIT_I8, 0b10u64, loc(2, 29)),
		(ltok::MINUS, void, loc(2, 36)),
		(ltok::LIT_I16, 5e0u64, loc(2, 37)),
		(ltok::MINUS, void, loc(2, 44)),
		(ltok::LIT_I32, 0o16u64, loc(2, 45)),
		(ltok::LIT_I64, 0b00000010000001100000011100001111000000100000011000000111u64, loc(3, 1)),
		(ltok::LIT_FCONST, 13.37, loc(4, 1)),
		(ltok::LIT_F32, 13.37, loc(4, 7)),
		(ltok::LIT_F64, 13.37, loc(4, 16)),
diff --git a/hare/lex/lex.ha b/hare/lex/lex.ha
index 7dc67f97..7b1929b9 100644
--- a/hare/lex/lex.ha
+++ b/hare/lex/lex.ha
@@ -386,22 +386,13 @@ fn lex_literal(lex: *lexer) (token | error) = {
	case let r: (rune, location) =>
		yield r;
	};
	if (r.0 == '-') {
		append(chars, utf8::encoderune(r.0)...);
		r = match (next(lex)?) {
		case io::EOF =>
			return (ltok::EOF, void, loc);
		case let r: (rune, location) =>
			yield r;
		};
	};

	let base = 10u;
	if (r.0 == '0') {
		append(chars, utf8::encoderune(r.0)...);
		r = match (next(lex)?) {
		case io::EOF =>
			return (ltok::LIT_ICONST, 0i64, loc);
			return (ltok::LIT_ICONST, 0u64, loc);
		case let r: (rune, location) =>
			yield r;
		};
@@ -563,27 +554,11 @@ fn lex_literal(lex: *lexer) (token | error) = {

	let val = strings::fromutf8(chars[..end]);
	let val = switch (suff) {
	case ltok::LIT_U8, ltok::LIT_U16, ltok::LIT_U32, ltok::LIT_U64,
	ltok::LIT_UINT, ltok::LIT_SIZE =>
		yield strconv::stou64b(val, base);
	case ltok::LIT_ICONST =>
		yield match (strconv::stoi64b(val, base)) {
		case let i: i64 =>
			yield i;
		case strconv::invalid =>
			abort();
		case strconv::overflow =>
			yield if (chars[0] != '-') {
				suff = ltok::LIT_U64;
				yield strconv::stou64b(val, base);
			} else strconv::overflow;
		};
	case ltok::LIT_I8, ltok::LIT_I16, ltok::LIT_I32, ltok::LIT_I64,
	ltok::LIT_INT =>
		yield strconv::stoi64b(val, base);
	case ltok::LIT_F32, ltok::LIT_F64, ltok::LIT_FCONST =>
		val = strings::fromutf8(chars[..floatend]);
		yield strconv::stof64(val);
	case =>
		yield strconv::stou64b(val, base);
	};
	let val = match (val) {
	case let val: u64 =>
@@ -591,11 +566,6 @@ fn lex_literal(lex: *lexer) (token | error) = {
			val *= 10;
		};
		yield val;
	case let val: i64 =>
		for (let i = 0z; i < exp; i += 1) {
			val *= 10;
		};
		yield val;
	case let val: f64 =>
		yield val;
	case strconv::invalid =>
@@ -642,15 +612,9 @@ fn lex2(lexr: *lexer) (token | error) = {
				line_comment(lexr)?;
				return (ltok::MINUSEQ, void, first.1);
			case =>
				if (ascii::isdigit(r.0)) {
					unget(lexr, r);
					unget(lexr, first);
					return lex_literal(lexr);
				} else {
					unget(lexr, r);
					line_comment(lexr)?;
					return (ltok::MINUS, void, first.1);
				};
				unget(lexr, r);
				line_comment(lexr)?;
				return (ltok::MINUS, void, first.1);
			};
		case io::EOF =>
			return (ltok::MINUS, void, first.1);
diff --git a/hare/lex/token.ha b/hare/lex/token.ha
index 19f21dd2..e461ab08 100644
--- a/hare/lex/token.ha
+++ b/hare/lex/token.ha
@@ -282,7 +282,7 @@ const bmap: [_]str = [
export type _null = void;

// A token value, used for tokens such as '1337' (an integer).
export type value = (str | rune | i64 | u64 | f64 | void);
export type value = (str | rune | u64 | f64 | void);

// A location within a source file.
// The path is borrowed from the file name given to the lexer.
diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha
index fbe86ea8..b5bd9f36 100644
--- a/hare/parse/expr.ha
+++ b/hare/parse/expr.ha
@@ -7,6 +7,7 @@
use hare::ast;
use hare::lex::{ltok};
use hare::lex;
use types;
use strings;

// Parses an expression.
@@ -511,19 +512,27 @@ fn constant(lexer: *lex::lexer) (ast::expr | error) = {
	const tok = want(lexer)?;
	const expr: ast::constant_expr = switch (tok.0) {
	case ltok::LIT_RUNE, ltok::LIT_STR =>
		yield tok.1;
		yield tok.1 as (rune | str);
	case ltok::LIT_U8, ltok::LIT_U16, ltok::LIT_U32, ltok::LIT_U64,
		ltok::LIT_UINT, ltok::LIT_SIZE, ltok::LIT_I8, ltok::LIT_I16,
		ltok::LIT_I32, ltok::LIT_I64, ltok::LIT_INT, ltok::LIT_ICONST,
		ltok::LIT_F32, ltok::LIT_F64, ltok::LIT_FCONST =>
		const value = match (tok.1) {
		case let v: (i64 | u64 | f64) =>
			yield v;
		case => abort();
		ltok::LIT_UINT, ltok::LIT_SIZE =>
		yield ast::number_constant {
			suff = tok.0,
			value = tok.1 as u64,
		};
	case ltok::LIT_I8, ltok::LIT_I16, ltok::LIT_I32, ltok::LIT_I64,
		ltok::LIT_INT, ltok::LIT_ICONST =>
		const n = tok.1 as u64;
		// TODO: handle n == types::I64_MIN
		synassert(lex::mkloc(lexer), n <= types::I64_MAX: u64,
			"Integer constant can't fit in specified type")?;
		yield ast::number_constant {
			suff = tok.0,
			value = value,
			value = n: i64,
		};
	case ltok::LIT_F32, ltok::LIT_F64, ltok::LIT_FCONST =>
		yield ast::number_constant {
			suff = tok.0,
			value = tok.1 as f64,
		};
	case ltok::VOID =>
		yield void;
@@ -1208,14 +1217,42 @@ fn unarithm(lexer: *lex::lexer) (ast::expr | error) = {
	case => abort();
	};

	let operand = unarithm(lexer)?;
	const operand = unarithm(lexer)?;
	const expr = :blk {
		match (operand.expr) {
		case let c: ast::constant_expr =>
			match (c) {
			case let n: ast::number_constant =>
				const val = match (n.value) {
				case let i: i64 =>
					synassert(lex::mkloc(lexer),
						i > types::I64_MIN,
						"Integer constant can't fit in specified type")?;
					yield -i;
				case let u: u64 => void;
				case let f: f64 =>
					yield -f;
				};

				if (val is void) yield;
				yield :blk, ast::number_constant {
					suff = n.suff,
					value = val as (i64 | f64),
				}: ast::constant_expr;
			case => void;
			};
		case => void;
		};

		yield ast::unarithm_expr {
			op = op,
			operand = alloc(operand),
		};
	};
	return ast::expr {
		start = tok.2,
		end = lex::prevloc(lexer),
		expr = ast::unarithm_expr {
			op = op,
			operand = alloc(operand),
		},
		expr = expr,
	};
};

diff --git a/hare/unit/expr.ha b/hare/unit/expr.ha
index 76508039..ea8dd75b 100644
--- a/hare/unit/expr.ha
+++ b/hare/unit/expr.ha
@@ -52,7 +52,7 @@ export type bindings = []binding;
export type compound = []*expr;

// The value of a constant expression.
export type constant = ast::value; // TODO: composite types
export type constant = (...ast::value | i64 | u64 | f64); // TODO: composite types

// A return expression, i.e. return <value>
export type _return = nullable *expr;
diff --git a/hare/unit/process.ha b/hare/unit/process.ha
index 2e6fd51a..95e2a816 100644
--- a/hare/unit/process.ha
+++ b/hare/unit/process.ha
@@ -283,12 +283,6 @@ fn process_constant(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
				yield ast::builtin_type::STR;
			case let r: rune =>
				yield ast::builtin_type::RUNE;
			case let i: i64 =>
				yield ast::builtin_type::INT;
			case let u: u64 =>
				yield ast::builtin_type::UINT;
			case let f: f64 =>
				yield ast::builtin_type::F64;
			case void =>
				yield ast::builtin_type::VOID;
			}),
@@ -372,7 +366,7 @@ fn process_constant(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
	assert(expr.result.repr as types::builtin == types::builtin::NULL);
	assert(expr.expr is constant);

	const cases: [_](str, types::builtin, ast::value) = [
	const cases: [_](str, types::builtin, constant) = [
		("1234", types::builtin::INT, 1234),
		("1234u", types::builtin::UINT, 1234u),
		("\"hello world\"", types::builtin::STR, "hello world"),
diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha
index 77df1ca5..30ed2529 100644
--- a/hare/unparse/expr.ha
+++ b/hare/unparse/expr.ha
@@ -483,8 +483,6 @@ fn constant(
		case void => abort();
		case ast::_null =>
			yield "null";
		case let v: (i64 | u64 | f64) =>
			yield v;
		case let b: bool =>
			return fmt::fprint(out, b);
		case let s: str =>
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
index 47c5d3b9..9225964c 100755
--- a/scripts/gen-stdlib
+++ b/scripts/gen-stdlib
@@ -756,7 +756,7 @@ hare_parse() {
	if [ $testing -eq 0 ]
	then
		gensrcs_hare_parse
		gen_ssa hare::parse ascii hare::ast hare::lex fmt strings
		gen_ssa hare::parse ascii hare::ast hare::lex fmt types strings
	else
		gensrcs_hare_parse \
			+test/expr.ha \
diff --git a/stdlib.mk b/stdlib.mk
index cc29ba94..0c392482 100644
--- a/stdlib.mk
+++ b/stdlib.mk
@@ -1244,7 +1244,7 @@ stdlib_hare_parse_any_srcs = \
	$(STDLIB)/hare/parse/type.ha \
	$(STDLIB)/hare/parse/unit.ha

$(HARECACHE)/hare/parse/hare_parse-any.ssa: $(stdlib_hare_parse_any_srcs) $(stdlib_rt) $(stdlib_ascii_$(PLATFORM)) $(stdlib_hare_ast_$(PLATFORM)) $(stdlib_hare_lex_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_strings_$(PLATFORM))
$(HARECACHE)/hare/parse/hare_parse-any.ssa: $(stdlib_hare_parse_any_srcs) $(stdlib_rt) $(stdlib_ascii_$(PLATFORM)) $(stdlib_hare_ast_$(PLATFORM)) $(stdlib_hare_lex_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_types_$(PLATFORM)) $(stdlib_strings_$(PLATFORM))
	@printf 'HAREC \t$@\n'
	@mkdir -p $(HARECACHE)/hare/parse
	@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhare::parse \
-- 
2.35.1

[hare/patches] build success

builds.sr.ht <builds@sr.ht>
Details
Message ID
<CJZ6470SO72E.2CAZR7IHG3HPB@cirno>
In-Reply-To
<20220514033444.22944-1-sebastian@sebsite.pw> (view parent)
DKIM signature
missing
Download raw message
hare/patches: SUCCESS in 1m31s

[Handle negation in parse instead of lex][0] from [Sebastian][1]

[0]: https://lists.sr.ht/~sircmpwn/hare-dev/patches/32267
[1]: sebastian@sebsite.pw

✓ #757826 SUCCESS hare/patches/alpine.yml  https://builds.sr.ht/~sircmpwn/job/757826
✓ #757827 SUCCESS hare/patches/freebsd.yml https://builds.sr.ht/~sircmpwn/job/757827
Details
Message ID
<CK15SXQ986CB.2VK4L2YQUXFQ4@taiga>
In-Reply-To
<20220514033444.22944-1-sebastian@sebsite.pw> (view parent)
DKIM signature
fail
Download raw message
DKIM signature: fail
I think I need a little bit more in the commit message to understand the
approach you've taken here.
Reply to thread Export thread (mbox)