From 3937233dc2ea4463805cccff5ab364d8402281e6 Mon Sep 17 00:00:00 2001 From: cassowarii Date: Tue, 7 Jul 2026 00:20:08 -0700 Subject: [PATCH] plain 'return' + postfix 'if'/'unless' --- src/compile/ir.c | 3 ++- src/parse/lexer.c | 19 ++++++++++++++----- src/parse/parser.c | 4 ++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/compile/ir.c b/src/compile/ir.c index 42e37d5..a0387e8 100644 --- a/src/compile/ir.c +++ b/src/compile/ir.c @@ -668,7 +668,8 @@ static void compile_ast_stmt(hIrChunk ck, sbAst node, flag implicit_return) { * OK, this one's pretty simple. */ if (node->seq.left == NO_NODE) { - E1 = NULL; + /* plain 'return' with no qualifier means 'return nil' */ + E1 = NIL_EXPR; } else { /* TODO handle multival here */ E1 = compile_ast_expr(ck, node->seq.left->seq.left, FALSE); diff --git a/src/parse/lexer.c b/src/parse/lexer.c index faa18a2..268042c 100644 --- a/src/parse/lexer.c +++ b/src/parse/lexer.c @@ -233,10 +233,12 @@ static flag block_header_can_end_after(sbTokenType type) { } /* these are operators that look weird if they get captured inside - * of parentheses. */ + * of parentheses, and also if and unless in postfix form */ static flag close_invisible_parens_before(sbTokenType type) { return type == T_rAND || type == T_rOR + || type == T_rIF + || type == T_rUNLESS || type == T_DOUBLEEQUALS || type == T_NOTEQUALS || type == T_LESS @@ -399,6 +401,10 @@ static void compute_next_token(hLexer lx) { brackets_stack_pop(lx); /* remove 'B' state from bracket stack */ } + if (close_invisible_parens_before(token.type)) { + unstack_all_invisible_parentheses(lx); + } + if (begins_brace_terminated_state(token.type)) { /* don't start brace-terminated state if we are directly after a '}' (otherwise it gets * confused by things like repeat..until */ @@ -407,10 +413,6 @@ static void compute_next_token(hLexer lx) { } } - if (close_invisible_parens_before(token.type)) { - unstack_all_invisible_parentheses(lx); - } - /* --- HERE IS WHERE THE TOKEN ACTUALLY GETS OUTPUT TO THE STREAM --- */ /* Everything before this gets put into the stream ahead of this token. */ /* Everything after this comes after the token. */ @@ -536,6 +538,13 @@ static void compute_next_token(hLexer lx) { }; enqueue_output_token(lx, invisible_semicolon); lx->last_token_seen = invisible_semicolon; + + if (brackets_stack_top(lx) == 'B') { + /* if we're in brace-terminated state but encounter an end of line, it's + * ok to leave brace-terminated state. this applies to postfix 'if' and + * 'unless' in particular */ + brackets_stack_pop(lx); + } } } } diff --git a/src/parse/parser.c b/src/parse/parser.c index 30e8c10..077bee8 100644 --- a/src/parse/parser.c +++ b/src/parse/parser.c @@ -684,10 +684,10 @@ static sbAst with_trailing_conditional(hParser pr, sbAst stmt) { if (expect(pr, T_rIF)) { sbAst condition = parse_expr(pr, 0); - result = tri_node(pr, AST_NODE_IF, condition, stmt, NO_NODE); + result = tri_node(pr, AST_NODE_IF, condition, seq_node(pr, AST_NODE_SEQ, stmt, NO_NODE), NO_NODE); } else if (expect(pr, T_rUNLESS)) { sbAst condition = parse_expr(pr, 0); - result = tri_node(pr, AST_NODE_IF, unop_node(pr, AST_OP_NOT, condition), stmt, NO_NODE); + result = tri_node(pr, AST_NODE_IF, unop_node(pr, AST_OP_NOT, condition), seq_node(pr, AST_NODE_SEQ, stmt, NO_NODE), NO_NODE); } return result; -- 1.8.3.1