commit f95b8556f86c1758fe3cf5d8b31b22add1f6a45e
parent 2d570e4371baf7ec84884c279171c7eaca759571
Author: Sebastian <sebastian@sebsite.pw>
Date: Thu, 21 Apr 2022 15:41:01 -0400
ast, lex, parse, unparse: vaargs updates
Implements: https://todo.sr.ht/~sircmpwn/hare/594
Signed-off-by: Sebastian <sebastian@sebsite.pw>
Diffstat:
10 files changed, 92 insertions(+), 5 deletions(-)
diff --git a/hare/ast/expr.ha b/hare/ast/expr.ha
@@ -382,6 +382,24 @@ export type unarithm_expr = struct {
operand: *expr,
};
+// A vastart expression.
+//
+// vastart()
+export type vastart_expr = void;
+
+// A vaarg expression.
+//
+// vaarg(ap)
+export type vaarg_expr = *expr;
+
+// A vaend expression.
+//
+// vaend(ap)
+export type vaend_expr = *expr;
+
+// A C-style variadic expression.
+export type variadic_expr = (vastart_expr | vaarg_expr | vaend_expr);
+
// A yield expression.
//
// yield foo
@@ -400,7 +418,8 @@ export type expr = struct {
defer_expr | delete_expr | for_expr | free_expr | if_expr |
insert_expr | compound_expr | match_expr | len_expr |
size_expr | offset_expr | propagate_expr | return_expr |
- slice_expr | switch_expr | unarithm_expr | yield_expr),
+ slice_expr | switch_expr | unarithm_expr | variadic_expr |
+ yield_expr),
};
// Frees resources associated with a Hare [[expr]]ession.
@@ -568,6 +587,14 @@ case let e: expr =>
free(s.cases);
case let u: unarithm_expr =>
expr_free(u.operand);
+ case let v: variadic_expr =>
+ match (v) {
+ case vastart_expr => void;
+ case let v: vaarg_expr =>
+ expr_free(v);
+ case let v: vaend_expr =>
+ expr_free(v);
+ };
case let y: yield_expr =>
free(y.label);
expr_free(y.value);
diff --git a/hare/ast/type.ha b/hare/ast/type.ha
@@ -13,7 +13,7 @@ export type alias_type = struct {
// A built-in primitive type (int, bool, str, etc).
export type builtin_type = enum {
BOOL, CHAR, F32, F64, FCONST, I16, I32, I64, I8, ICONST, INT, NULL,
- RUNE, SIZE, STR, U16, U32, U64, U8, UINT, UINTPTR, VOID,
+ RUNE, SIZE, STR, U16, U32, U64, U8, UINT, UINTPTR, VALIST, VOID,
};
// An enumeration field (and optional value).
diff --git a/hare/lex/token.ha b/hare/lex/token.ha
@@ -71,6 +71,10 @@ export type ltok = enum uint {
UINTPTR,
UNION,
USE,
+ VAARG,
+ VAEND,
+ VALIST,
+ VASTART,
VOID,
YIELD,
LAST_KEYWORD = YIELD,
@@ -216,6 +220,10 @@ const bmap: [_]str = [
"uintptr",
"union",
"use",
+ "vaarg",
+ "vaend",
+ "valist",
+ "vastart",
"void",
"yield",
"=>",
diff --git a/hare/module/scan.ha b/hare/module/scan.ha
@@ -18,7 +18,7 @@ use sort;
use strings;
use strio;
-def ABI_VERSION: u8 = 3;
+def ABI_VERSION: u8 = 4;
// Scans the files in a directory for eligible build inputs and returns a
// [[version]] which includes all applicable files and their dependencies.
diff --git a/hare/parse/+test/expr.ha b/hare/parse/+test/expr.ha
@@ -73,6 +73,9 @@
len([1, 2, 3, 4]);
offset(foo.bar);
size(u32);
+ vastart();
+ vaarg(va);
+ vaend(va);
};
`);
};
diff --git a/hare/parse/+test/loc.ha b/hare/parse/+test/loc.ha
@@ -67,6 +67,7 @@ fn expr_testloc(srcs: str...) void = for (let i = 0z; i < len(srcs); i += 1) {
expr_testloc("switch (foo) { case => bar; }");
expr_testloc("foo[bar..baz]");
expr_testloc("&foo");
+ expr_testloc("vastart()", "vaarg(ap)", "vaend(ap)");
// We want to check the location of nested expressions, so this can't
// use expr_testloc
diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha
@@ -353,7 +353,7 @@ fn builtin(lexer: *lex::lexer) (ast::expr | error) = {
const tok = match (peek(lexer, ltok::ALLOC, ltok::APPEND, ltok::FREE,
ltok::DELETE, ltok::ABORT, ltok::ASSERT, ltok::INSERT,
ltok::STATIC, ltok::SIZE, ltok::LEN, ltok::OFFSET,
- ltok::DEFER)?) {
+ ltok::DEFER, ltok::VASTART, ltok::VAARG, ltok::VAEND)?) {
case let tok: lex::token =>
yield tok;
case void =>
@@ -402,6 +402,35 @@ fn builtin(lexer: *lex::lexer) (ast::expr | error) = {
end = lex::prevloc(lexer),
expr = expr: ast::defer_expr,
};
+ case ltok::VASTART =>
+ want(lexer, ltok::VASTART)?;
+ want(lexer, ltok::LPAREN)?;
+ want(lexer, ltok::RPAREN)?;
+ return ast::expr {
+ start = tok.2,
+ end = lex::prevloc(lexer),
+ expr = void: ast::vastart_expr: ast::variadic_expr,
+ };
+ case ltok::VAARG =>
+ want(lexer, ltok::VAARG)?;
+ want(lexer, ltok::LPAREN)?;
+ const expr = alloc(expr(lexer)?);
+ want(lexer, ltok::RPAREN)?;
+ return ast::expr {
+ start = tok.2,
+ end = lex::prevloc(lexer),
+ expr = expr: ast::vaarg_expr: ast::variadic_expr,
+ };
+ case ltok::VAEND =>
+ want(lexer, ltok::VAEND)?;
+ want(lexer, ltok::LPAREN)?;
+ const expr = alloc(expr(lexer)?);
+ want(lexer, ltok::RPAREN)?;
+ return ast::expr {
+ start = tok.2,
+ end = lex::prevloc(lexer),
+ expr = expr: ast::vaend_expr: ast::variadic_expr,
+ };
case => abort(); // Invariant
};
};
diff --git a/hare/parse/type.ha b/hare/parse/type.ha
@@ -121,6 +121,8 @@ fn primitive_type(lexer: *lex::lexer) (ast::_type | error) = {
yield builtin_type::F64;
case ltok::BOOL =>
yield builtin_type::BOOL;
+ case ltok::VALIST =>
+ yield builtin_type::VALIST;
case ltok::VOID =>
yield builtin_type::VOID;
case =>
@@ -463,7 +465,7 @@ export fn _type(lexer: *lex::lexer) (ast::_type | error) = {
ltok::INT, ltok::SIZE, ltok::U16, ltok::U32, ltok::U64,
ltok::U8, ltok::UINT, ltok::UINTPTR, ltok::RUNE,
ltok::STR, ltok::F32, ltok::F64, ltok::BOOL,
- ltok::VOID, ltok::TYPE =>
+ ltok::VALIST, ltok::VOID, ltok::TYPE =>
yield primitive_type(lexer)?;
case ltok::ENUM =>
yield enum_type(lexer)?;
diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha
@@ -379,6 +379,21 @@ export fn expr(
})?;
z += expr(out, indent, *e.operand)?;
return z;
+ case let e: ast::variadic_expr =>
+ match (e) {
+ case ast::vastart_expr =>
+ return fmt::fprint(out, "vastart()")?;
+ case let e: ast::vaarg_expr =>
+ let z = fmt::fprint(out, "vaarg(")?;
+ z += expr(out, indent, *e)?;
+ z += fmt::fprint(out, ")")?;
+ return z;
+ case let e: ast::vaend_expr =>
+ let z = fmt::fprint(out, "vaend(")?;
+ z += expr(out, indent, *e)?;
+ z += fmt::fprint(out, ")")?;
+ return z;
+ };
case let e: ast::yield_expr =>
let z = fmt::fprint(out, "yield")?;
if (e.label != "") {
diff --git a/hare/unparse/type.ha b/hare/unparse/type.ha
@@ -52,6 +52,8 @@ case ast::builtin_type::UINT =>
yield "uint";
case ast::builtin_type::UINTPTR =>
yield "uintptr";
+case ast::builtin_type::VALIST =>
+ yield "valist";
case ast::builtin_type::VOID =>
yield "void";
};