commit d69fc2db25622b16c1f873a647b5d3ccfc1ba0e2
parent 038db64a25f09c70eba2ee347da754e89bfed527
Author: Sebastian <sebastian@sebsite.pw>
Date: Thu, 17 Feb 2022 20:18:43 -0500
ast: add number_constant type
This type carries information about the suffix of the literal. For
instance, `1234` can now be differentiated from `1234z` in the AST.
Fixes: https://todo.sr.ht/~sircmpwn/hare/422
Signed-off-by: Sebastian <sebastian@sebsite.pw>
Diffstat:
6 files changed, 105 insertions(+), 12 deletions(-)
diff --git a/hare/ast/expr.ha b/hare/ast/expr.ha
@@ -206,8 +206,15 @@ export type _null = void;
// A scalar value.
export type value = (void | bool | _null | ...lex::value);
+// An integer or float constant.
+export type number_constant = struct {
+ suff: lex::ltok,
+ value: (i64 | u64 | f64),
+};
+
// A constant expression.
-export type constant_expr = (value | array_constant | struct_constant | tuple_constant);
+export type constant_expr = (value | array_constant | number_constant |
+ struct_constant | tuple_constant);
// A continue expression. The label is set to empty string if absent.
//
@@ -463,6 +470,7 @@ case let e: expr =>
expr_free(t[i]);
};
free(t);
+ case number_constant => void;
};
case let c: continue_expr =>
free(c);
diff --git a/hare/parse/+test/expr.ha b/hare/parse/+test/expr.ha
@@ -130,10 +130,20 @@
...
};
13.37;
- 13.37;
- 13.37;
+ 13.37f32;
+ 13.37f64;
6.022e23;
1.616255e-35;
+ 1337z;
+ 1337u;
+ 1337i8;
+ 1337u8;
+ 1337i16;
+ 1337u16;
+ 1337i32;
+ 1337u32;
+ 1337i64;
+ 1337u64;
};
");
};
diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha
@@ -467,13 +467,22 @@ fn cast(lexer: *lex::lexer, lvalue: (ast::expr | void)) (ast::expr | error) = {
fn constant(lexer: *lex::lexer) (ast::expr | error) = {
const tok = want(lexer)?;
- const expr: ast::value = switch (tok.0) {
+ const expr: ast::constant_expr = switch (tok.0) {
+ case ltok::LIT_RUNE, ltok::LIT_STR =>
+ yield tok.1;
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, ltok::LIT_RUNE,
- ltok::LIT_STR =>
- yield tok.1;
+ ltok::LIT_F32, ltok::LIT_F64, ltok::LIT_FCONST =>
+ const value = match (tok.1) {
+ case let v: (i64 | u64 | f64) =>
+ yield v;
+ case => abort();
+ };
+ yield ast::number_constant {
+ suff = tok.0,
+ value = value,
+ };
case ltok::VOID =>
yield void;
case ltok::TRUE =>
@@ -960,10 +969,11 @@ fn postfix_dot(
case void =>
let con = constant(lexer)?;
let val = con.expr as ast::constant_expr;
- synassert(lex::mkloc(lexer), val is ast::value,
+ synassert(lex::mkloc(lexer), val is ast::number_constant,
"Expected integer constant")?;
- let val = val as ast::value;
- synassert(lex::mkloc(lexer), val is i64,
+ let val = val as ast::number_constant;
+ synassert(lex::mkloc(lexer),
+ val.value is i64 && val.suff == ltok::LIT_ICONST,
"Expected integer constant")?;
return ast::expr {
start = lvalue.start,
diff --git a/hare/types/+test.ha b/hare/types/+test.ha
@@ -40,8 +40,8 @@ fn resolve(
expr: const *ast::expr,
) (size | deferred | error) = {
let expr = expr.expr as ast::constant_expr;
- let val = expr as ast::value;
- let ival = val as i64;
+ let n = expr as ast::number_constant;
+ let ival = n.value as i64;
assert(ival >= 0);
return ival: size;
};
diff --git a/hare/unit/process.ha b/hare/unit/process.ha
@@ -289,6 +289,38 @@ fn process_constant(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
);
case ast::array_constant =>
abort(); // TODO
+ case let v: ast::number_constant =>
+ yield (
+ types::lookup_builtin(ctx.store, switch (v.suff) {
+ case lex::ltok::LIT_U8 =>
+ yield ast::builtin_type::U8;
+ case lex::ltok::LIT_U16 =>
+ yield ast::builtin_type::U16;
+ case lex::ltok::LIT_U32 =>
+ yield ast::builtin_type::U32;
+ case lex::ltok::LIT_U64 =>
+ yield ast::builtin_type::U64;
+ case lex::ltok::LIT_UINT =>
+ yield ast::builtin_type::UINT;
+ case lex::ltok::LIT_SIZE =>
+ yield ast::builtin_type::SIZE;
+ case lex::ltok::LIT_I8 =>
+ yield ast::builtin_type::I8;
+ case lex::ltok::LIT_I16 =>
+ yield ast::builtin_type::I16;
+ case lex::ltok::LIT_I32 =>
+ yield ast::builtin_type::I32;
+ case lex::ltok::LIT_I64 =>
+ yield ast::builtin_type::I64;
+ case lex::ltok::LIT_INT, lex::ltok::LIT_ICONST =>
+ yield ast::builtin_type::INT;
+ case lex::ltok::LIT_F32 =>
+ yield ast::builtin_type::F32;
+ case lex::ltok::LIT_F64, lex::ltok::LIT_FCONST =>
+ yield ast::builtin_type::F64;
+ }),
+ v.value,
+ );
case ast::struct_constant =>
abort(); // TODO
case ast::tuple_constant =>
diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha
@@ -1,6 +1,7 @@
use io;
use fmt;
use hare::ast;
+use hare::lex::{ltok};
use hare::lex;
// Unparses an [[ast::expr]].
@@ -432,6 +433,38 @@ fn constant(
z += fmt::fprintf(out, "{}]",
if (ac.expand) "..." else "")?;
return z;
+ case let v: ast::number_constant =>
+ return fmt::fprintf(out, "{}{}", v.value, switch (v.suff) {
+ case ltok::LIT_U8 =>
+ yield "u8";
+ case ltok::LIT_U16 =>
+ yield "u16";
+ case ltok::LIT_U32 =>
+ yield "u32";
+ case ltok::LIT_U64 =>
+ yield "u64";
+ case ltok::LIT_UINT =>
+ yield "u";
+ case ltok::LIT_SIZE =>
+ yield "z";
+ case ltok::LIT_I8 =>
+ yield "i8";
+ case ltok::LIT_I16 =>
+ yield "i16";
+ case ltok::LIT_I32 =>
+ yield "i32";
+ case ltok::LIT_I64 =>
+ yield "i64";
+ case ltok::LIT_INT =>
+ yield "i";
+ case ltok::LIT_ICONST, ltok::LIT_FCONST =>
+ yield "";
+ case ltok::LIT_F32 =>
+ yield "f32";
+ case ltok::LIT_F64 =>
+ yield "f64";
+ case => abort();
+ });
case let sc: ast::struct_constant =>
return struct_constant(out, indent, sc)?;
case let tu: ast::tuple_constant =>