aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-05-23 13:09:59 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-05-23 13:09:59 -0400
commitbf3cdc3dfa4dcd0d17f182fe875d718cb4a4272f (patch)
tree8b1c2c9088576fc25d753f7ec106baf54ca18ede
parente7beacb460803556485794aba6b36af1472ff706 (diff)
Refine the parsing of blocks so it's always ':' [inline-block] [indent indented-block]
-rw-r--r--parse.c124
-rw-r--r--test/arrays.tm4
-rw-r--r--test/lambdas.tm10
3 files changed, 63 insertions, 75 deletions
diff --git a/parse.c b/parse.c
index bde0b8d0..fbb82871 100644
--- a/parse.c
+++ b/parse.c
@@ -84,10 +84,8 @@ static PARSER(parse_expr);
static PARSER(parse_extended_expr);
static PARSER(parse_term_no_suffix);
static PARSER(parse_term);
-static PARSER(parse_inline_block);
static PARSER(parse_statement);
static PARSER(parse_block);
-static PARSER(parse_opt_indented_block);
static PARSER(parse_var);
static PARSER(parse_enum_def);
static PARSER(parse_struct_def);
@@ -881,9 +879,7 @@ PARSER(parse_if) {
if (!condition) condition = expect(ctx, start, &pos, parse_expr,
"I expected to find an expression for this 'if'");
- expect_str(ctx, start, &pos, ":", "I expected a ':' here");
-
- ast_t *body = expect(ctx, start, &pos, parse_opt_indented_block, "I expected a body for this 'if' statement");
+ ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'if' statement");
const char *tmp = pos;
whitespace(&tmp);
@@ -891,9 +887,10 @@ PARSER(parse_if) {
const char *else_start = pos;
if (get_indent(ctx, tmp) == starting_indent && match_word(&tmp, "else")) {
pos = tmp;
- if (!match_word(&tmp, "if"))
- expect_str(ctx, start, &pos, ":", "I expected a ':' here");
- else_body = expect(ctx, else_start, &pos, parse_opt_indented_block, "I expected a body for this 'else'");
+ spaces(&pos);
+ else_body = optional(ctx, &pos, parse_if);
+ if (!else_body)
+ else_body = expect(ctx, else_start, &pos, parse_block, "I expected a body for this 'else'");
}
return NewAST(ctx->file, start, pos, If, .condition=condition, .body=body, .else_body=else_body);
}
@@ -933,9 +930,7 @@ PARSER(parse_when) {
REVERSE_LIST(args);
}
- expect_str(ctx, start, &pos, ":", "I expected a ':' here");
-
- ast_t *body = expect(ctx, start, &pos, parse_opt_indented_block, "I expected a body for this 'when' clause");
+ ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'when' clause");
clauses = new(when_clause_t, .tag_name=tag_name, .args=args, .body=body, .next=clauses);
tmp = pos;
whitespace(&tmp);
@@ -946,8 +941,7 @@ PARSER(parse_when) {
const char *else_start = pos;
if (get_indent(ctx, tmp) == starting_indent && match_word(&tmp, "else")) {
pos = tmp;
- expect_str(ctx, start, &pos, ":", "I expected a ':' here");
- else_body = expect(ctx, else_start, &pos, parse_opt_indented_block, "I expected a body for this 'else'");
+ else_body = expect(ctx, else_start, &pos, parse_block, "I expected a body for this 'else'");
}
return NewAST(ctx->file, start, pos, When, .subject=subject, .clauses=clauses, .else_body=else_body);
}
@@ -965,17 +959,14 @@ PARSER(parse_for) {
}
expect_str(ctx, start, &pos, "in", "I expected an 'in' for this 'for'");
ast_t *iter = expect(ctx, start, &pos, parse_expr, "I expected an iterable value for this 'for'");
- expect_str(ctx, start, &pos, ":", "I expected a ':' here");
- match(&pos, "do"); // optional
- ast_t *body = expect(ctx, start, &pos, parse_opt_indented_block, "I expected a body for this 'for'");
+ ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'for'");
const char *else_start = pos;
whitespace(&else_start);
ast_t *empty = NULL;
if (match_word(&else_start, "else") && get_indent(ctx, else_start) == starting_indent) {
pos = else_start;
- expect_str(ctx, start, &pos, ":", "I expected a ':' here");
- empty = expect(ctx, pos, &pos, parse_opt_indented_block, "I expected a body for this 'else'");
+ empty = expect(ctx, pos, &pos, parse_block, "I expected a body for this 'else'");
}
return NewAST(ctx->file, start, pos, For, .index=value ? index : NULL, .value=value ? value : index, .iter=iter, .body=body, .empty=empty);
}
@@ -984,8 +975,7 @@ PARSER(parse_do) {
// do: [<indent>] body
const char *start = pos;
if (!match_word(&pos, "do")) return NULL;
- expect_str(ctx, start, &pos, ":", "I expected a ':' here");
- ast_t *body = expect(ctx, start, &pos, parse_opt_indented_block, "I expected a body for this 'while'");
+ ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'while'");
return NewAST(ctx->file, start, pos, Block, .statements=Match(body, Block)->statements);
}
@@ -1002,8 +992,7 @@ PARSER(parse_while) {
return NewAST(ctx->file, start, pos, While, .body=when);
}
ast_t *condition = expect(ctx, start, &pos, parse_expr, "I don't see a viable condition for this 'while'");
- expect_str(ctx, start, &pos, ":", "I expected a ':' here");
- ast_t *body = expect(ctx, start, &pos, parse_opt_indented_block, "I expected a body for this 'while'");
+ ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'while'");
return NewAST(ctx->file, start, pos, While, .condition=condition, .body=body);
}
@@ -1226,7 +1215,7 @@ PARSER(parse_lambda) {
arg_ast_t *args = parse_args(ctx, &pos, false);
spaces(&pos);
expect_closing(ctx, &pos, ")", "I was expecting a ')' to finish this anonymous function's arguments");
- ast_t *body = optional(ctx, &pos, parse_opt_indented_block);
+ ast_t *body = optional(ctx, &pos, parse_block);
return NewAST(ctx->file, start, pos, Lambda, .args=args, .body=body);
}
@@ -1567,43 +1556,59 @@ PARSER(parse_extended_expr) {
}
PARSER(parse_block) {
- int64_t block_indent = get_indent(ctx, pos);
const char *start = pos;
- whitespace(&pos);
- ast_list_t *statements = NULL;
- while (*pos) {
- ast_t *stmt = optional(ctx, &pos, parse_statement);
- if (!stmt) {
- const char *line_start = pos;
- if (match_word(&pos, "struct"))
- parser_err(ctx, line_start, strchrnul(pos, '\n'), "Struct definitions are only allowed at the top level");
- else if (match_word(&pos, "enum"))
- parser_err(ctx, line_start, strchrnul(pos, '\n'), "Enum definitions are only allowed at the top level");
- else if (match_word(&pos, "func"))
- parser_err(ctx, line_start, strchrnul(pos, '\n'), "Function definitions are only allowed at the top level");
- else if (match_word(&pos, "use"))
- parser_err(ctx, line_start, strchrnul(pos, '\n'), "'use' statements are only allowed at the top level");
+ if (!match(&pos, ":")) return NULL;
+ ast_list_t *statements = NULL;
+ if (!indent(ctx, &pos)) {
+ // Inline block
+ spaces(&pos);
+ while (*pos) {
spaces(&pos);
- if (*pos && *pos != '\r' && *pos != '\n')
- parser_err(ctx, pos, strchrnul(pos, '\n'), "I couldn't parse this line");
- break;
+ ast_t *stmt = optional(ctx, &pos, parse_statement);
+ if (!stmt) break;
+ statements = new(ast_list_t, .ast=stmt, .next=statements);
+ spaces(&pos);
+ if (!match(&pos, ";")) break;
}
- statements = new(ast_list_t, .ast=stmt, .next=statements);
- whitespace(&pos); // TODO: check for newline
- if (get_indent(ctx, pos) != block_indent) {
- pos = stmt->end; // backtrack
- break;
+ } else {
+ goto indented;
+ }
+
+ if (indent(ctx, &pos)) {
+ indented:;
+ int64_t block_indent = get_indent(ctx, pos);
+ whitespace(&pos);
+ while (*pos) {
+ ast_t *stmt = optional(ctx, &pos, parse_statement);
+ if (!stmt) {
+ const char *line_start = pos;
+ if (match_word(&pos, "struct"))
+ parser_err(ctx, line_start, strchrnul(pos, '\n'), "Struct definitions are only allowed at the top level");
+ else if (match_word(&pos, "enum"))
+ parser_err(ctx, line_start, strchrnul(pos, '\n'), "Enum definitions are only allowed at the top level");
+ else if (match_word(&pos, "func"))
+ parser_err(ctx, line_start, strchrnul(pos, '\n'), "Function definitions are only allowed at the top level");
+ else if (match_word(&pos, "use"))
+ parser_err(ctx, line_start, strchrnul(pos, '\n'), "'use' statements are only allowed at the top level");
+
+ spaces(&pos);
+ if (*pos && *pos != '\r' && *pos != '\n')
+ parser_err(ctx, pos, strchrnul(pos, '\n'), "I couldn't parse this line");
+ break;
+ }
+ statements = new(ast_list_t, .ast=stmt, .next=statements);
+ whitespace(&pos); // TODO: check for newline
+ if (get_indent(ctx, pos) != block_indent) {
+ pos = stmt->end; // backtrack
+ break;
+ }
}
}
REVERSE_LIST(statements);
return NewAST(ctx->file, start, pos, Block, .statements=statements);
}
-PARSER(parse_opt_indented_block) {
- return indent(ctx, &pos) ? parse_block(ctx, pos) : parse_inline_block(ctx, pos);
-}
-
PARSER(parse_namespace) {
const char *start = pos;
whitespace(&pos);
@@ -1925,8 +1930,7 @@ PARSER(parse_func_def) {
if (match(&pos, "->"))
ret_type = optional(ctx, &pos, parse_type);
- expect_str(ctx, start, &pos, ":", "I expected a ':' here");
- ast_t *body = expect(ctx, start, &pos, parse_opt_indented_block,
+ ast_t *body = expect(ctx, start, &pos, parse_block,
"This function needs a body block");
return NewAST(ctx->file, start, pos, FunctionDef,
.name=name, .args=args, .ret_type=ret_type, .body=body, .cache=cache_ast,
@@ -2019,22 +2023,6 @@ PARSER(parse_linker) {
return NewAST(ctx->file, start, pos, LinkerDirective, .directive=directive);
}
-PARSER(parse_inline_block) {
- spaces(&pos);
- const char *start = pos;
- ast_list_t *statements = NULL;
- while (*pos) {
- spaces(&pos);
- ast_t *stmt = optional(ctx, &pos, parse_statement);
- if (!stmt) break;
- statements = new(ast_list_t, .ast=stmt, .next=statements);
- spaces(&pos);
- if (!match(&pos, ";")) break;
- }
- REVERSE_LIST(statements);
- return NewAST(ctx->file, start, pos, Block, .statements=statements);
-}
-
ast_t *parse_file(file_t *file, jmp_buf *on_err) {
parse_ctx_t ctx = {
.file=file,
diff --git a/test/arrays.tm b/test/arrays.tm
index de1771b7..95b4fe38 100644
--- a/test/arrays.tm
+++ b/test/arrays.tm
@@ -87,10 +87,10 @@ func main():
>> nums
= [-20, 10, 30]
// Custom sort functions:
- >> nums:sort(func(x:&%Int,y:&%Int) x:abs() <> y:abs())
+ >> nums:sort(func(x:&%Int,y:&%Int): x:abs() <> y:abs())
>> nums
= [10, -20, 30]
- >> nums:sort(func(x:&%Int,y:&%Int) y[] <> x[])
+ >> nums:sort(func(x:&%Int,y:&%Int): y[] <> x[])
>> nums
= [30, 10, -20]
diff --git a/test/lambdas.tm b/test/lambdas.tm
index 0ec0826b..15a8f23b 100644
--- a/test/lambdas.tm
+++ b/test/lambdas.tm
@@ -1,18 +1,18 @@
func make_adder(x:Int)-> func(y:Int)->Int:
- return func(y:Int) x + y
+ return func(y:Int): x + y
func suffix_fn(fn:func(t:Text)->Text, suffix:Text)->func(t:Text)->Text:
- return func(t:Text) fn(t)++suffix
+ return func(t:Text): fn(t)++suffix
func mul_func(n:Int, fn:func(x:Int)->Int)-> func(x:Int)->Int:
- return func(x:Int) n*fn(x)
+ return func(x:Int): n*fn(x)
func main():
- >> add_one := func(x:Int) x + 1
+ >> add_one := func(x:Int): x + 1
>> add_one(10)
= 11
- >> shout := func(msg:Text) say("{msg:upper()}!")
+ >> shout := func(msg:Text): say("{msg:upper()}!")
>> shout("hello")
>> asdf := add_one