aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-13 08:47:52 +0000
committer_ov4 <ov4@ov4.org>2026-10-13 08:47:52 +0000
commit5d5c14920a9aa3397d4b479c22e37392be5557f4 (patch)
tree31eec35c4ef9b7afc310fb624ce1abdb43e3e497
parent58e2cfe505ba9942524f06bb1b1419e6c579efad (diff)
feat: support comma-separated OUTPUT expressions
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
-rw-r--r--AGENTS/PITFALLS.md13
-rw-r--r--AGENTS/SUBSYSTEMS.md7
-rw-r--r--include/cps/AST.h6
-rw-r--r--lib/CodeGen/CodeGen.cc27
-rw-r--r--lib/Parser/Parser.cc12
5 files changed, 38 insertions, 27 deletions
diff --git a/AGENTS/PITFALLS.md b/AGENTS/PITFALLS.md
index fd53883..ea6a4d7 100644
--- a/AGENTS/PITFALLS.md
+++ b/AGENTS/PITFALLS.md
@@ -5,10 +5,11 @@
Every bullet below was confirmed against the source, most also by compiling and running
test programs.
-- **OUTPUT takes exactly one expression.** `OUTPUT a, ", ", b` prints `a`, then the
- stray `, ", ", b` produces parse errors (recovery resyncs at the next statement
- start, so following statements survive; the compile still fails). Concatenate with
- `&`. Similarly INPUT only accepts a plain identifier — no `INPUT arr[i]`.
+- **OUTPUT accepts comma-separated expressions (§5.1).** Values are evaluated and
+ printed left to right without automatic separators; the final scalar adds a newline.
+ Whole arrays and subarrays still print each element on its own line, including in
+ mixed output lists; a final array adds no extra newline. INPUT only accepts a plain
+ identifier — no `INPUT arr[i]`.
- **Arrays cross function boundaries only as parameters.** `ArrayTable` is scoped per
function now, so referencing another function's array fails cleanly as
"Undeclared array". Whole arrays pass as `ARRAY OF T` / `ARRAY[l:u,...] OF T`
@@ -44,7 +45,7 @@ test programs.
iteration.)
- **File handling (§9.1) sharp edges.** `READ`/`WRITE`/`APPEND`/`RANDOM` are reserved
keywords now — `DECLARE READ : INTEGER` no longer compiles. `WRITEFILE f, a, b` takes
- exactly two operands (the stray `, b` is a parse error, like multi-expression OUTPUT).
+ exactly two operands (the stray `, b` is a parse error).
READFILE's target must be a plain STRING variable — no CHAR, no `arr[i]` (mirrors
INPUT). The CIE guide's empty-line test `IF LineOfText = ""` compares contents.
At most 16 files open at once. All runtime misuse (not open, wrong mode, reopen,
@@ -75,6 +76,6 @@ test programs.
CASE OF, CONSTANT, SET types (`SET`/`DEFINE` are reserved with dedicated errors),
random files (OPENFILE...FOR RANDOM/SEEK/GETRECORD/PUTRECORD — TYPE is done, so these
are unblocked now; the RANDOM keyword is reserved and gives a dedicated parse error),
-DATE, multi-expression OUTPUT, INPUT into array elements, string escape sequences,
+DATE, INPUT into array elements, string escape sequences,
array-typed record fields, whole-array RETURN. No tests and no CI exist; verify
changes by compiling sample programs end-to-end (command sequence in `ARCH.md`).
diff --git a/AGENTS/SUBSYSTEMS.md b/AGENTS/SUBSYSTEMS.md
index d4d1189..ecdf3ff 100644
--- a/AGENTS/SUBSYSTEMS.md
+++ b/AGENTS/SUBSYSTEMS.md
@@ -16,9 +16,10 @@ hand-roll indexing or element loads. Array parameters: `bindArrayParameter` rebu
callee-side metadata from the flattened `ptr + 2R bounds` ABI (BYVAL = malloc+memcpy
whole copy), `emitArrayArgument` validates and pushes the caller side.
`OUTPUT arr` (and partially-indexed accesses) is intercepted by
-`ArrayHandler::tryEmitArrayOutput` — the first branch of OUTPUT dispatch, emitting
-nested print loops (element kinds that are not outputtable, i.e. records/pointers,
-are a compile error there) — so any rework of OUTPUT must preserve that interception.
+`ArrayHandler::tryEmitArrayOutput` — the first branch for each expression in an OUTPUT
+list, emitting nested print loops (element kinds that are not outputtable, i.e. records/pointers,
+are a compile error there). Arrays keep their per-element newlines and dispatch
+continues with the next expression; a final array requires no extra newline.
**Functions** (`FunctionGen`): plain LLVM functions, external linkage, exact pseudocode
name. Params are `ParamDecl{name, typeString, mode, array rank/bounds}`. BYVAL args are
diff --git a/include/cps/AST.h b/include/cps/AST.h
index f24d987..d98613d 100644
--- a/include/cps/AST.h
+++ b/include/cps/AST.h
@@ -150,10 +150,10 @@ public:
};
class OutputStmtAST : public StmtAST {
- std::unique_ptr<ExprAST> Expr;
+ std::vector<std::unique_ptr<ExprAST>> Exprs;
public:
- OutputStmtAST(std::unique_ptr<ExprAST> Expr) : Expr(std::move(Expr)) {}
- ExprAST *getExpr() const { return Expr.get(); }
+ OutputStmtAST(std::vector<std::unique_ptr<ExprAST>> Exprs) : Exprs(std::move(Exprs)) {}
+ const std::vector<std::unique_ptr<ExprAST>> &getExprs() const { return Exprs; }
};
class IfStmtAST : public StmtAST {
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc
index d5942e9..c0da7ee 100644
--- a/lib/CodeGen/CodeGen.cc
+++ b/lib/CodeGen/CodeGen.cc
@@ -1138,20 +1138,23 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
}
if (auto *Out = dynamic_cast<OutputStmtAST*>(Stmt)) {
- bool Handled = Arrays->tryEmitArrayOutput(Out->getExpr(), *this);
- if (Handled) return;
+ const auto &Exprs = Out->getExprs();
+ for (size_t I = 0; I < Exprs.size(); ++I) {
+ ExprAST *Expr = Exprs[I].get();
+ if (Arrays->tryEmitArrayOutput(Expr, *this)) continue;
- Value *Val = emitExpr(Out->getExpr());
- const TypeInfo *TypeInfo = getExprTypeInfo(Out->getExpr());
- if (!TypeInfo) {
- reportError("Cannot infer the type of the OUTPUT expression");
- return;
- }
- if (TypeInfo->isVoid()) {
- reportError("Cannot OUTPUT the result of a PROCEDURE call");
- return;
+ Value *Val = emitExpr(Expr);
+ const TypeInfo *TypeInfo = getExprTypeInfo(Expr);
+ if (!TypeInfo) {
+ reportError("Cannot infer the type of the OUTPUT expression");
+ continue;
+ }
+ if (TypeInfo->isVoid()) {
+ reportError("Cannot OUTPUT the result of a PROCEDURE call");
+ continue;
+ }
+ emitOutputValue(Val, TypeInfo, I + 1 == Exprs.size());
}
- emitOutputValue(Val, TypeInfo, true);
return;
}
diff --git a/lib/Parser/Parser.cc b/lib/Parser/Parser.cc
index 260472c..25fc342 100644
--- a/lib/Parser/Parser.cc
+++ b/lib/Parser/Parser.cc
@@ -555,9 +555,15 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() {
}
else if (CurTok == tok_output) {
getNextToken();
- auto Expr = ParseExpression();
- if (!Expr) return nullptr;
- return std::make_unique<OutputStmtAST>(std::move(Expr));
+ std::vector<std::unique_ptr<ExprAST>> Exprs;
+ while (true) {
+ auto Expr = ParseExpression();
+ if (!Expr) return nullptr;
+ Exprs.push_back(std::move(Expr));
+ if (CurTok != ',') break;
+ getNextToken();
+ }
+ return std::make_unique<OutputStmtAST>(std::move(Exprs));
}
else if (CurTok == tok_if) {
return ParseIfStmt();