From: cassowarii Date: Sun, 28 Jun 2026 01:16:30 +0000 (-0700) Subject: <~ syntax was weird to parse, so use invisible () to clarify X-Git-Url: https://www.git.cassowary.me/gitweb.cgi?a=commitdiff_plain;h=4ddbed63138c16b2d075b1fefb7a6d56bc473b24;p=sarabande.git <~ syntax was weird to parse, so use invisible () to clarify --- diff --git a/src/parse/lexer.c b/src/parse/lexer.c index 4a86fbc..80f3085 100644 --- a/src/parse/lexer.c +++ b/src/parse/lexer.c @@ -214,8 +214,9 @@ static flag begins_brace_terminated_state(sbTokenType type) { } /* things we can potentially insert a ( after because they may be a call */ -static flag can_end_expression(sbTokenType type) { +static flag can_open_paren_after(sbTokenType type) { return type == T_IDENTIFIER + || type == T_BACKSQUIGARROW || type == T_RPAREN || type == T_RBRACKET; } @@ -223,7 +224,7 @@ static flag can_end_expression(sbTokenType type) { /* when in brace-terminated state, one of these must precede a { character * in order to exit brace-terminated state */ static flag block_header_can_end_after(sbTokenType type) { - return can_end_expression(type) + return can_open_paren_after(type) || is_literal(type) || type == T_FATARROW || type == T_SQUIGARROW @@ -366,7 +367,11 @@ static void unstack_visible_bracket(hLexer lx, sbLexToken closing_token) { } } - enqueue_output_token(lx, (sbLexToken) { .type = T_WRONGBRACKET }); + sbLexToken error_token = { + .type = T_WRONGBRACKET, + }; + + enqueue_output_token(lx, error_token); } static void compute_next_token(hLexer lx) { @@ -416,13 +421,13 @@ static void compute_next_token(hLexer lx) { input_peek_ahead(lx, 0).type, is_in_brace_terminated_state(lx) ); - if (can_end_expression(token.type) && input_peek_ahead(lx, 0).type == T_COLONBRACE) { + if (can_open_paren_after(token.type) && input_peek_ahead(lx, 0).type == T_COLONBRACE) { /* end-of-expr followed by colon-brace with no space between gets this special * invisible bracket */ /* invisible = 2 makes it a sticky H bracket */ invisible_lparen.invisible = 2; enqueue_output_token(lx, invisible_lparen); - } else if (can_end_expression(token.type)) { + } else if (can_open_paren_after(token.type)) { /* otherwise, if it can end an expression (in particular if it's still an identifier and not a * reserved word), we might need to insert a magic ( into the output stream. so look ahead at * what's coming up. */ @@ -441,7 +446,12 @@ static void compute_next_token(hLexer lx) { space_offset = 1; } - if (lx->last_token_seen.type == T_DOT && token.type == T_IDENTIFIER) { + if (token.type == T_BACKSQUIGARROW) { + /* <~ always gets a ( after it to include its parameters. we don't care about a space here. */ + if (input_peek_ahead(lx, space_offset).type != T_LPAREN) { + enqueue_output_token(lx, invisible_lparen); + } + } else if (lx->last_token_seen.type == T_DOT && token.type == T_IDENTIFIER) { /* an identifier after a dot always gets an invisible parentheses after it, * unless there is a visible parentheses immediately after it. */ if (input_peek_ahead(lx, 0).type != T_LPAREN) { diff --git a/src/parse/parser.c b/src/parse/parser.c index 78cc5a6..8bbc813 100644 --- a/src/parse/parser.c +++ b/src/parse/parser.c @@ -400,10 +400,6 @@ static sbAst parse_comma_exprs(hParser pr, sbAst after) { *put_here = seq_node(pr, AST_NODE_MULTIVAL, expr, NO_NODE); put_here = &(*put_here)->seq.right; - - /* these | and <~ operators can break a comma list */ - if (expect(pr, T_PIPE)) break; - if (expect(pr, T_BACKSQUIGARROW)) break; } while (expect(pr, T_COMMA)); return result; @@ -618,7 +614,9 @@ static sbAst parse_expr(hParser pr, u8 min_precedence) { rhs = seq_node(pr, AST_NODE_NEXT, method_name, params); } else if (op.type == T_BACKSQUIGARROW) { /* a <~ b, c, d can have multiple comma things on the right side */ + if (!expect(pr, T_LPAREN)) return syntax_error(pr); rhs = parse_comma_exprs(pr, NULL); + if (!expect(pr, T_RPAREN)) return syntax_error(pr); } else if (op.type == T_PAAMAYIM_NEKUDOTAYIM) { /* :: is similar to . and -> above, will parse the thing to the right * as a symbol unless using the syntax a::[expr] */