Skip to content

Commit 4a9ccb2

Browse files
authored
Require parentheses in array_count, enum_count, embed_file (#1265)
1 parent 34ec438 commit 4a9ccb2

File tree

8 files changed

+54
-25
lines changed

8 files changed

+54
-25
lines changed

compiler/parser.jou

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,40 @@ class Parser:
677677

678678
return result
679679

680+
def parse_special_function_like_expression(self) -> AstExpression:
681+
expr = AstExpression{location = self.tokens.location}
682+
683+
assert self.tokens.kind == TokenKind.Keyword
684+
match (self.tokens++).short_string with strcmp:
685+
case "sizeof":
686+
expr.kind = AstExpressionKind.SizeOf
687+
error = "value after sizeof must be in parentheses, e.g. sizeof(foo)"
688+
case "array_count":
689+
expr.kind = AstExpressionKind.ArrayCount
690+
error = "value after array_count must be in parentheses, e.g. array_count(foo)"
691+
case "enum_count":
692+
expr.kind = AstExpressionKind.EnumCount
693+
error = "enum type after enum_count must be in parentheses, e.g. enum_count(Foo)"
694+
case "embed_file":
695+
expr.kind = AstExpressionKind.EmbedFile
696+
error = "file name after embed_file must be in parentheses, e.g. embed_file(\"foo.txt\")"
697+
case _:
698+
assert False
699+
700+
if not self.tokens.is_operator("("):
701+
fail(self.tokens.location, error)
702+
self.tokens++
703+
704+
if expr.kind == AstExpressionKind.EnumCount:
705+
expr.enumcount.enum_type_ast = self.parse_type()
706+
else:
707+
expr.operands = malloc(sizeof(expr.operands[0]))
708+
assert expr.operands != NULL
709+
*expr.operands = self.parse_expression()
710+
711+
self.eat_operator(")", True, "a ')'")
712+
return expr
713+
680714
def parse_elementary_expression(self) -> AstExpression:
681715
expr = AstExpression{location = self.tokens.location}
682716

@@ -730,20 +764,13 @@ class Parser:
730764
elif self.tokens.is_operator("["):
731765
expr.kind = AstExpressionKind.Array
732766
expr.array = self.parse_array()
733-
elif self.tokens.is_keyword("sizeof"):
734-
expr.kind = AstExpressionKind.SizeOf
735-
self.eat_keyword("sizeof", False, NULL)
736-
if not self.tokens.is_operator("("):
737-
fail(self.tokens.location, "value after sizeof must be in parentheses, e.g. sizeof(thing)")
738-
self.tokens++
739-
expr.operands = malloc(sizeof(expr.operands[0]))
740-
assert expr.operands != NULL
741-
*expr.operands = self.parse_expression()
742-
self.eat_operator(")", True, "a ')'")
743-
elif self.tokens.is_keyword("enum_count"):
744-
expr.kind = AstExpressionKind.EnumCount
745-
self.tokens++
746-
expr.enumcount.enum_type_ast = self.parse_type()
767+
elif (
768+
self.tokens.is_keyword("sizeof")
769+
or self.tokens.is_keyword("array_count")
770+
or self.tokens.is_keyword("embed_file")
771+
or self.tokens.is_keyword("enum_count")
772+
):
773+
expr = self.parse_special_function_like_expression()
747774
else:
748775
# Special error message for e.g. int(x)
749776
msg: byte[300]
@@ -845,8 +872,6 @@ class Parser:
845872
or self.tokens.is_operator("&")
846873
or self.tokens.is_operator("*")
847874
or self.tokens.is_operator("~")
848-
or self.tokens.is_keyword("embed_file")
849-
or self.tokens.is_keyword("array_count")
850875
):
851876
self.tokens++
852877
prefix_end = self.tokens
@@ -883,10 +908,6 @@ class Parser:
883908
kind = AstExpressionKind.AddressOf
884909
elif token.is_operator("~"):
885910
kind = AstExpressionKind.BitNot
886-
elif token.is_keyword("embed_file"):
887-
kind = AstExpressionKind.EmbedFile
888-
elif token.is_keyword("array_count"):
889-
kind = AstExpressionKind.ArrayCount
890911
else:
891912
assert False
892913

doc/keywords.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ Both `foo` and `bar` must be `bool`s, and `bar` is not evaluated at all if `foo`
1414
## `array_count`
1515

1616
Use `array_count(array)` to get the number of elements in [an array](types.md#pointers-and-arrays) as `int`.
17-
The parentheses are optional.
1817
The number of elements in an array is always known at compile time, and in fact,
1918
the `array` is not evaluated when the program runs.
2019

@@ -26,7 +25,6 @@ import "stdlib/io.jou"
2625
def main() -> int:
2726
array: int[10]
2827
printf("%d\n", array_count(array)) # Output: 10
29-
printf("%d\n", array_count array) # Output: 10
3028
return 0
3129
```
3230

tests/should_succeed/array.jou

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def main() -> int:
2525
foo[1] = 2
2626
foo[2] = 3
2727

28-
n = array_count foo
28+
n = array_count(foo)
2929
check_int(&n)
3030
printf("%d\n", n) # Output: 3
3131

tests/should_succeed/sizeof.jou

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def main() -> int:
3737

3838
# The "array length trick" that was used before array_count() existed
3939
printf("%d\n", sizeof(arr) / sizeof(arr[0])) # Output: 100
40-
printf("%d\n", array_count arr) # Output: 100
40+
printf("%d\n", array_count(arr)) # Output: 100
4141

4242
# Evaluating a sizeof has no side effects.
4343
printf("%d\n", sizeof(side_effect())) # Output: 4
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
def blah() -> None:
2+
thing: byte[10]
3+
x = array_count thing # Error: value after array_count must be in parentheses, e.g. array_count(foo)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
global thing = embed_file "data.bin" # Error: file name after embed_file must be in parentheses, e.g. embed_file("foo.txt")
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
enum Thing:
2+
Blah
3+
Bleh
4+
Bruh
5+
6+
const x: int = enum_count Thing # Error: enum type after enum_count must be in parentheses, e.g. enum_count(Foo)
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
def blah() -> None:
2-
x = sizeof 1 # Error: value after sizeof must be in parentheses, e.g. sizeof(thing)
2+
x = sizeof 1 # Error: value after sizeof must be in parentheses, e.g. sizeof(foo)

0 commit comments

Comments
 (0)