hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Mhare/ast/expr.ha | 10+++++++++-
Mhare/parse/+test/expr.ha | 14++++++++++++--
Mhare/parse/expr.ha | 24+++++++++++++++++-------
Mhare/types/+test.ha | 4++--
Mhare/unit/process.ha | 32++++++++++++++++++++++++++++++++
Mhare/unparse/expr.ha | 33+++++++++++++++++++++++++++++++++
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 =>