aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--parse.c66
-rw-r--r--test/arrays.tm30
-rw-r--r--test/corecursive_func.tm14
-rw-r--r--test/enums.tm6
-rw-r--r--test/extern.tm2
-rw-r--r--test/for.tm26
-rw-r--r--test/functions.tm6
-rw-r--r--test/integers.tm4
-rw-r--r--test/lambdas.tm8
-rw-r--r--test/lang.tm10
-rw-r--r--test/minmax.tm6
-rw-r--r--test/nums.tm2
-rw-r--r--test/reductions.tm2
-rw-r--r--test/structs.tm8
-rw-r--r--test/tables.tm6
-rw-r--r--test/text.tm2
-rw-r--r--test/use.tm4
-rw-r--r--test/use_import.tm4
19 files changed, 112 insertions, 98 deletions
diff --git a/README.md b/README.md
index 73e2160f..2e9c6037 100644
--- a/README.md
+++ b/README.md
@@ -5,12 +5,12 @@ language that cross-compiles to C. Tomo is designed to anticipate and influence
the language design decisions of the future.
```
-func greeting(name:Text)->Text
+func greeting(name:Text)->Text:
greeting := "hello {name}!"
words := greeting:split(" ")
return " ":join([w:capitalize() for w in words])
-func main(name="World")
+func main(name="World"):
to_say := greeting(name)
say(to_say)
```
diff --git a/parse.c b/parse.c
index e325ebf4..e3fdbb49 100644
--- a/parse.c
+++ b/parse.c
@@ -781,8 +781,10 @@ PARSER(parse_reduction) {
}
ast_t *fallback = NULL;
- if (match_word(&pos, "else"))
+ if (match_word(&pos, "else")) {
+ expect_str(ctx, start, &pos, ":", "I expected a ':' here");
fallback = expect(ctx, pos-4, &pos, parse_expr, "I couldn't parse the expression after this 'else'");
+ }
return NewAST(ctx->file, start, pos, Reduction, .iter=iter, .combination=combination, .fallback=fallback);
}
@@ -838,7 +840,7 @@ PARSER(parse_if) {
if (!condition) condition = expect(ctx, start, &pos, parse_expr,
"I expected to find an expression for this 'if'");
- match_word(&pos, "then"); // optional
+ 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");
@@ -848,6 +850,7 @@ PARSER(parse_if) {
const char *else_start = pos;
if (get_indent(ctx->file, 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'");
}
return NewAST(ctx->file, start, pos, If, .condition=condition, .body=body, .else_body=else_body);
@@ -881,7 +884,8 @@ PARSER(parse_when) {
var = NULL;
}
- match_word(&pos, "then"); // optional
+ 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");
clauses = new(when_clause_t, .var=var, .tag_name=tag_name, .body=body, .next=clauses);
tmp = pos;
@@ -893,6 +897,7 @@ PARSER(parse_when) {
const char *else_start = pos;
if (get_indent(ctx->file, 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'");
}
return NewAST(ctx->file, start, pos, When, .subject=subject, .clauses=clauses, .else_body=else_body);
@@ -911,6 +916,7 @@ 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'");
@@ -919,6 +925,7 @@ PARSER(parse_for) {
ast_t *empty = NULL;
if (match_word(&else_start, "else") && get_indent(ctx->file, 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'");
}
return NewAST(ctx->file, start, pos, For, .index=value ? index : NULL, .value=value ? value : index, .iter=iter, .body=body, .empty=empty);
@@ -929,7 +936,7 @@ PARSER(parse_while) {
const char *start = pos;
if (!match_word(&pos, "while")) return NULL;
ast_t *condition = expect(ctx, start, &pos, parse_expr, "I don't see a viable condition for this 'while'");
- match(&pos, "do"); // optional
+ 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'");
const char *tmp = pos;
whitespace(&tmp);
@@ -1603,7 +1610,7 @@ PARSER(parse_file_body) {
}
PARSER(parse_struct_def) {
- // struct Foo(...) \n body
+ // struct Foo(...) [: \n body]
const char *start = pos;
if (!match_word(&pos, "struct")) return NULL;
@@ -1636,13 +1643,15 @@ PARSER(parse_struct_def) {
expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this struct");
- const char *ns_pos = pos;
- whitespace(&ns_pos);
- int64_t ns_indent = get_indent(ctx->file, ns_pos);
ast_t *namespace = NULL;
- if (ns_indent > starting_indent) {
- pos = ns_pos;
- namespace = optional(ctx, &pos, parse_namespace);
+ if (match(&pos, ":")) {
+ const char *ns_pos = pos;
+ whitespace(&ns_pos);
+ int64_t ns_indent = get_indent(ctx->file, ns_pos);
+ if (ns_indent > starting_indent) {
+ pos = ns_pos;
+ namespace = optional(ctx, &pos, parse_namespace);
+ }
}
if (!namespace)
namespace = NewAST(ctx->file, pos, pos, Block, .statements=NULL);
@@ -1650,7 +1659,7 @@ PARSER(parse_struct_def) {
}
ast_t *parse_enum_def(parse_ctx_t *ctx, const char *pos) {
- // tagged union: enum Foo[a, b(x:Int,y:Int)=5, ...] \n namespace
+ // tagged union: enum Foo(a, b(x:Int,y:Int)=5, ...) [: \n namespace]
const char *start = pos;
if (!match_word(&pos, "enum")) return NULL;
int64_t starting_indent = get_indent(ctx->file, pos);
@@ -1713,13 +1722,15 @@ ast_t *parse_enum_def(parse_ctx_t *ctx, const char *pos) {
REVERSE_LIST(tags);
- const char *ns_pos = pos;
- whitespace(&ns_pos);
- int64_t ns_indent = get_indent(ctx->file, ns_pos);
ast_t *namespace = NULL;
- if (ns_indent > starting_indent) {
- pos = ns_pos;
- namespace = optional(ctx, &pos, parse_namespace);
+ if (match(&pos, ":")) {
+ const char *ns_pos = pos;
+ whitespace(&ns_pos);
+ int64_t ns_indent = get_indent(ctx->file, ns_pos);
+ if (ns_indent > starting_indent) {
+ pos = ns_pos;
+ namespace = optional(ctx, &pos, parse_namespace);
+ }
}
if (!namespace)
namespace = NewAST(ctx->file, pos, pos, Block, .statements=NULL);
@@ -1729,7 +1740,7 @@ ast_t *parse_enum_def(parse_ctx_t *ctx, const char *pos) {
PARSER(parse_lang_def) {
const char *start = pos;
- // lang Name [namespace...]
+ // lang Name: [namespace...]
if (!match_word(&pos, "lang")) return NULL;
int64_t starting_indent = get_indent(ctx->file, pos);
spaces(&pos);
@@ -1738,13 +1749,15 @@ PARSER(parse_lang_def) {
parser_err(ctx, start, pos, "I expected a name for this lang");
spaces(&pos);
- const char *ns_pos = pos;
- whitespace(&ns_pos);
- int64_t ns_indent = get_indent(ctx->file, ns_pos);
ast_t *namespace = NULL;
- if (ns_indent > starting_indent) {
- pos = ns_pos;
- namespace = optional(ctx, &pos, parse_namespace);
+ if (match(&pos, ":")) {
+ const char *ns_pos = pos;
+ whitespace(&ns_pos);
+ int64_t ns_indent = get_indent(ctx->file, ns_pos);
+ if (ns_indent > starting_indent) {
+ pos = ns_pos;
+ namespace = optional(ctx, &pos, parse_namespace);
+ }
}
if (!namespace)
namespace = NewAST(ctx->file, pos, pos, Block, .statements=NULL);
@@ -1843,9 +1856,10 @@ PARSER(parse_func_def) {
type_ast_t *ret_type = NULL;
spaces(&pos);
- if (match(&pos, "->") || match(&pos, ":"))
+ 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,
"This function needs a body block");
return NewAST(ctx->file, start, pos, FunctionDef,
diff --git a/test/arrays.tm b/test/arrays.tm
index be767fab..de1771b7 100644
--- a/test/arrays.tm
+++ b/test/arrays.tm
@@ -1,9 +1,9 @@
-func main()
- if yes
+func main():
+ if yes:
>> [:Num32]
= [] : [Num32]
- if yes
+ if yes:
>> arr := [10, 20, 30]
= [10, 20, 30]
@@ -16,18 +16,18 @@ func main()
= 3
sum := 0
- for x in arr
+ for x in arr:
sum += x
>> sum
= 60
str := ""
- for i,x in arr
+ for i,x in arr:
str ++= "({i},{x})"
>> str
= "(1,10)(2,20)(3,30)"
- if yes
+ if yes:
>> arr := [10, 20] ++ [30, 40]
= [10, 20, 30, 40]
@@ -39,7 +39,7 @@ func main()
>> arr
= [10, 20, 30, 40, 50, 60, 70]
- if yes
+ if yes:
>> arr := [10, 20]
>> copy := arr
>> arr ++= 30
@@ -48,7 +48,7 @@ func main()
>> copy
= [10, 20]
- if yes
+ if yes:
>> [10*i for i in 5]
= [10, 20, 30, 40, 50]
@@ -61,7 +61,7 @@ func main()
>> [x for x in y if x > 1 for y in [3, 4, 5] if y < 5]
= [2, 3, 2, 3, 4]
- if yes
+ if yes:
>> arr := @[10, 20]
>> copy := arr[]
>> arr:insert(30)
@@ -70,12 +70,12 @@ func main()
>> copy
= [10, 20]
- if yes
+ if yes:
>> arr := [10, 20, 30]
>> arr:reversed()
= [30, 20, 10]
- if yes
+ if yes:
>> nums := [10, -20, 30]
// Sorted function doesn't mutate original:
>> nums:sorted()
@@ -96,20 +96,20 @@ func main()
>> ["A", "B", "C"]:sample(10, [1.0, 0.5, 0.0])
- if yes
+ if yes:
>> heap := [Int.random(max=50) for _ in 10]
>> heap:heapify()
>> heap
sorted := [:Int]
- while #heap > 0
+ while #heap > 0:
sorted:insert(heap:heap_pop())
>> sorted == sorted:sorted()
= yes
- for _ in 10
+ for _ in 10:
heap:heap_push(Int.random(max=50))
>> heap
sorted = [:Int]
- while #heap > 0
+ while #heap > 0:
sorted:insert(heap:heap_pop())
>> sorted == sorted:sorted()
= yes
diff --git a/test/corecursive_func.tm b/test/corecursive_func.tm
index 22ffd627..a5c13dde 100644
--- a/test/corecursive_func.tm
+++ b/test/corecursive_func.tm
@@ -1,15 +1,15 @@
-func ping(x:Int)->[Text]
- if x > 0
+func ping(x:Int)->[Text]:
+ if x > 0:
return ["ping: {x}"] ++ pong(x-1)
- else
+ else:
return ["ping: {x}"]
-func pong(x:Int)->[Text]
- if x > 0
+func pong(x:Int)->[Text]:
+ if x > 0:
return ["pong: {x}"] ++ ping(x-1)
- else
+ else:
return ["pong: {x}"]
-func main()
+func main():
>> ping(3)
= ["ping: 3", "pong: 2", "ping: 1", "pong: 0"]
diff --git a/test/enums.tm b/test/enums.tm
index c06862a3..1bc26203 100644
--- a/test/enums.tm
+++ b/test/enums.tm
@@ -1,6 +1,6 @@
enum Foo(Zero, One(x:Int), Two(x,y:Int))
-func main()
+func main():
>> Foo.Zero
= Foo.Zero
>> Foo.One(123)
@@ -27,9 +27,9 @@ func main()
>> t[Foo.Zero]
= "missing"
- when x is o:One
+ when x is o:One:
>> o.x
= 123
- else
+ else:
fail("Oops")
diff --git a/test/extern.tm b/test/extern.tm
index 896c5730..da3b1820 100644
--- a/test/extern.tm
+++ b/test/extern.tm
@@ -1,5 +1,5 @@
extern CORD_cat:func(a:Text, b:Text)->Text
-func main()
+func main():
>> CORD_cat("hello ", "world")
= "hello world"
diff --git a/test/for.tm b/test/for.tm
index 63656380..a050c892 100644
--- a/test/for.tm
+++ b/test/for.tm
@@ -1,35 +1,35 @@
-func all_nums(nums:[Int])->Text
+func all_nums(nums:[Int])->Text:
result := ""
- for num in nums
+ for num in nums:
result ++= "{num},"
- else
+ else:
return "EMPTY"
return result
-func labeled_nums(nums:[Int])->Text
+func labeled_nums(nums:[Int])->Text:
result := ""
- for i,num in nums
+ for i,num in nums:
result ++= "{i}:{num},"
- else
+ else:
return "EMPTY"
return result
-func table_str(t:{Text:Text})->Text
+func table_str(t:{Text:Text})->Text:
str := ""
- for k,v in t
+ for k,v in t:
str ++= "{k}:{v},"
- else return "EMPTY"
+ else: return "EMPTY"
return str
-func table_key_str(t:{Text:Text})->Text
+func table_key_str(t:{Text:Text})->Text:
str := ""
- for k in t
+ for k in t:
str ++= "{k},"
- else return "EMPTY"
+ else: return "EMPTY"
return str
-func main()
+func main():
>> all_nums([10,20,30])
= "10,20,30,"
>> all_nums([:Int])
diff --git a/test/functions.tm b/test/functions.tm
index 13cdee55..426c33b1 100644
--- a/test/functions.tm
+++ b/test/functions.tm
@@ -1,10 +1,10 @@
-func add(x:Int, y:Int)->Int
+func add(x:Int, y:Int)->Int:
return x + y
-func cached_heap(x:Int; cached)->@Int
+func cached_heap(x:Int; cached)->@Int:
return @x
-func main()
+func main():
>> add(3, 5)
= 8
diff --git a/test/integers.tm b/test/integers.tm
index 9b573aac..94ab8ac6 100644
--- a/test/integers.tm
+++ b/test/integers.tm
@@ -1,4 +1,4 @@
-func main()
+func main():
>> 2 + 3
= 5
@@ -27,7 +27,7 @@ func main()
= 1
nums := ""
- for x in 5
+ for x in 5:
nums ++= "{x},"
>> nums
= "1,2,3,4,5,"
diff --git a/test/lambdas.tm b/test/lambdas.tm
index a445540b..0ec0826b 100644
--- a/test/lambdas.tm
+++ b/test/lambdas.tm
@@ -1,13 +1,13 @@
-func make_adder(x:Int)-> func(y:Int)->Int
+func make_adder(x:Int)-> func(y:Int)->Int:
return func(y:Int) x + y
-func suffix_fn(fn:func(t:Text)->Text, suffix:Text)->func(t:Text)->Text
+func suffix_fn(fn:func(t:Text)->Text, suffix:Text)->func(t:Text)->Text:
return func(t:Text) fn(t)++suffix
-func mul_func(n:Int, fn:func(x:Int)->Int)-> func(x:Int)->Int
+func mul_func(n:Int, fn:func(x:Int)->Int)-> func(x:Int)->Int:
return func(x:Int) n*fn(x)
-func main()
+func main():
>> add_one := func(x:Int) x + 1
>> add_one(10)
= 11
diff --git a/test/lang.tm b/test/lang.tm
index ad09b605..3dea6ded 100644
--- a/test/lang.tm
+++ b/test/lang.tm
@@ -1,6 +1,6 @@
-lang HTML
+lang HTML:
HEADER := $HTML{}"<!DOCTYPE HTML>"
- func escape(t:Text)->HTML
+ func escape(t:Text)->HTML:
t = t:replace("&", "&amp;")
t = t:replace("<", "&lt;")
t = t:replace(">", "&gt;")
@@ -8,13 +8,13 @@ lang HTML
t = t:replace("'", "&#39;")
return HTML.from_unsafe_text(t)
- func escape_int(i:Int)->HTML
+ func escape_int(i:Int)->HTML:
return HTML.from_unsafe_text("{i}")
- func paragraph(content:HTML)->HTML
+ func paragraph(content:HTML)->HTML:
return $HTML{}"<p>{content}</p>"
-func main()
+func main():
>> HTML.HEADER
= $HTML"<!DOCTYPE HTML>"
diff --git a/test/minmax.tm b/test/minmax.tm
index c3af68d6..c2f070f6 100644
--- a/test/minmax.tm
+++ b/test/minmax.tm
@@ -1,9 +1,9 @@
-struct Foo(x:Int, y:Int)
- func len(f:Foo)->Num
+struct Foo(x:Int, y:Int):
+ func len(f:Foo)->Num:
return Num.sqrt(f.x*f.x + f.y*f.y)
-func main()
+func main():
>> 3 _min_ 5
= 3
>> 5 _min_ 3
diff --git a/test/nums.tm b/test/nums.tm
index 4e9c81a4..94959744 100644
--- a/test/nums.tm
+++ b/test/nums.tm
@@ -1,4 +1,4 @@
-func main()
+func main():
>> n := 1.5
= 1.5
diff --git a/test/reductions.tm b/test/reductions.tm
index 6ed7823f..97ec4afc 100644
--- a/test/reductions.tm
+++ b/test/reductions.tm
@@ -1,6 +1,6 @@
struct Foo(x,y:Int)
-func main()
+func main():
>> (+) [10, 20, 30]
= 60
diff --git a/test/structs.tm b/test/structs.tm
index 9fe2f6a7..840ee847 100644
--- a/test/structs.tm
+++ b/test/structs.tm
@@ -4,7 +4,7 @@ struct Mixed(x:Int, text:Text)
struct LinkedList(x:Int, next=!LinkedList)
struct Password(text:Text; secret)
-func test_literals()
+func test_literals():
>> x := Pair(10, 20)
= Pair(x=10, y=20)
>> y := Pair(y=20, 10)
@@ -14,7 +14,7 @@ func test_literals()
>> x == Pair(-1, -2)
= no
-func test_metamethods()
+func test_metamethods():
>> x := Pair(10, 20)
>> y := Pair(100, 200)
>> x == y
@@ -32,7 +32,7 @@ func test_metamethods()
>> t2[y]
= "missing"
-func test_mixed()
+func test_mixed():
>> x := Mixed(10, "Hello")
>> y := Mixed(99, "Hello")
>> x == y
@@ -49,7 +49,7 @@ func test_mixed()
>> t[y]
= "missing"
-func main()
+func main():
test_literals()
test_metamethods()
test_mixed()
diff --git a/test/tables.tm b/test/tables.tm
index 2ba42714..8609e522 100644
--- a/test/tables.tm
+++ b/test/tables.tm
@@ -1,4 +1,4 @@
-func main()
+func main():
>> t := {"one":1, "two":2; default=999}
= {"one":1, "two":2; default=999}
@@ -10,7 +10,7 @@ func main()
= 999
t_str := ""
- for k,v in t
+ for k,v in t:
t_str ++= "({k}:{v})"
>> t_str
= "(one:1)(two:2)"
@@ -45,7 +45,7 @@ func main()
= ?%{"one":1, "two":2; default=999}
t2_str := ""
- for k,v in t2
+ for k,v in t2:
t2_str ++= "({k}:{v})"
>> t2_str
= "(three:3)"
diff --git a/test/text.tm b/test/text.tm
index bb2cc14a..9c451b89 100644
--- a/test/text.tm
+++ b/test/text.tm
@@ -1,4 +1,4 @@
-func main()
+func main():
>> str := "Hello Amélie!"
>> str:upper()
= "HELLO AMÉLIE!"
diff --git a/test/use.tm b/test/use.tm
index a759180a..95ab3c7e 100644
--- a/test/use.tm
+++ b/test/use.tm
@@ -1,9 +1,9 @@
imported := use ./use_import
-func asdf()->imported.ImportedType
+func asdf()->imported.ImportedType:
return imported.get_value()
-func main()
+func main():
>> [:imported.ImportedType]
>> asdf()
= ImportedType(name="Hello")
diff --git a/test/use_import.tm b/test/use_import.tm
index fb5f71e9..3b8e6743 100644
--- a/test/use_import.tm
+++ b/test/use_import.tm
@@ -1,7 +1,7 @@
struct ImportedType(name:Text)
-func get_value()->ImportedType
+func get_value()->ImportedType:
return ImportedType("Hello")
-func main()
+func main():
pass