commit 24c7a700cc30f1a9fa27d82483efc5a5585d9607
parent 2621ec2fcb906c4363a4f750b6b5ca5248ff0997
Author: Drew DeVault <sir@cmpwn.com>
Date: Thu, 15 Apr 2021 11:53:15 -0400
hare::parse: parse constant expressions
Diffstat:
4 files changed, 55 insertions(+), 9 deletions(-)
diff --git a/hare/ast/expr.ha b/hare/ast/expr.ha
@@ -137,8 +137,11 @@ export type struct_constant = struct {
// (foo, bar, ...)
export type tuple_constant = []*expr;
+// The value "null".
+export type _null = void;
+
// A constant
-export type constant_expr = (void | lex::value | array_constant |
+export type constant_expr = (void | bool | _null | lex::value | array_constant |
struct_constant | tuple_constant);
// continue :label
diff --git a/hare/parse/+test/expr.ha b/hare/parse/+test/expr.ha
@@ -2,6 +2,10 @@
roundtrip("export fn main() void = void + void * void / void;\n");
};
+@test fn constant() void = {
+ roundtrip("export fn main() void = 2 + -4 + void + true;\n");
+};
+
@test fn cast() void = {
roundtrip("export fn main() void = void: int;\n"
"export fn main() void = void as int;\n"
diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha
@@ -65,8 +65,31 @@ fn cast(lexer: *lex::lexer, lvalue: (ast::expr | void)) (ast::expr | error) = {
};
fn constant(lexer: *lex::lexer) (ast::expr | error) = {
- want(lexer, ltok::VOID)?;
- return void;
+ let tok = want(lexer)?;
+ return switch (tok.0) {
+ 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 => tok.1,
+ ltok::VOID => void,
+ ltok::TRUE => true,
+ ltok::FALSE => false,
+ ltok::NULL => ast::_null,
+ * => syntaxerr(mkloc(lexer), "Expected constant expression"),
+ };
};
fn control_statement(lexer: *lex::lexer) (ast::expr | error) = {
@@ -79,7 +102,7 @@ fn objsel(lexer: *lex::lexer) (ast::expr | error) = {
fn plain_expression(lexer: *lex::lexer) (ast::expr | error) = {
let tok = peek(lexer)? as lex::token;
- if (tok.0 > ltok::LAST_BTOK && tok.0 >= ltok::LAST_LITERAL) {
+ if (tok.0 >= ltok::LIT_U8 && tok.0 <= ltok::LAST_LITERAL) {
return constant(lexer);
};
return switch (tok.0) {
diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha
@@ -1,8 +1,8 @@
use io;
use fmt;
use hare::ast;
+use hare::lex;
-// TODO
export fn expr(
out: *io::stream,
indent: size,
@@ -54,10 +54,7 @@ export fn expr(
z += _type(out, indent, *e._type)?;
z;
},
- e: ast::constant_expr => {
- assert(e is void);
- fmt::fprint(out, "void")?;
- },
+ e: ast::constant_expr => constant(out, indent, e)?,
e: ast::continue_expr => abort(),
e: ast::defer_expr => abort(),
e: ast::delete_expr => abort(),
@@ -87,3 +84,22 @@ export fn expr(
},
};
};
+
+fn constant(
+ out: *io::stream,
+ indent: size,
+ e: ast::constant_expr,
+) (size | io::error) = {
+ return match (e) {
+ void => fmt::fprint(out, "void"),
+ ast::_null => fmt::fprint(out, "null"),
+ b: bool => fmt::fprint(out, b),
+ v: lex::value => fmt::fprint(out, match (v) {
+ v: (str | rune | i64 | u64 | f64) => v,
+ void => abort(),
+ }),
+ ast::array_constant => abort(), // TODO
+ ast::struct_constant => abort(), // TODO
+ ast::tuple_constant => abort(), // TODO
+ };
+};