aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.md4
-rw-r--r--src/ast.c5
-rw-r--r--src/ast.h3
-rw-r--r--src/compile/expressions.c1
-rw-r--r--src/compile/functions.c4
-rw-r--r--src/compile/optionals.c7
-rw-r--r--src/compile/optionals.h1
-rw-r--r--src/formatter/formatter.c9
-rw-r--r--src/parse/binops.c3
-rw-r--r--src/parse/expressions.c15
-rw-r--r--src/parse/suffixes.c7
-rw-r--r--src/parse/suffixes.h1
-rw-r--r--src/typecheck.c6
-rw-r--r--test/iterators.tm8
-rw-r--r--test/lists.tm8
-rw-r--r--test/nums.tm4
-rw-r--r--test/optionals.tm50
-rw-r--r--test/paths.tm2
-rw-r--r--test/reductions.tm6
-rw-r--r--test/serialization.tm2
-rw-r--r--test/tables.tm10
-rw-r--r--test/when.tm2
22 files changed, 58 insertions, 100 deletions
diff --git a/CHANGES.md b/CHANGES.md
index 1e0b840e..dd015b5f 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,6 +1,6 @@
# Version History
-## v0.4
+## v1.0
- Tomo libraries are now installed to `$TOMO_PATH/lib/tomo_vX.Y/module_vZ.W`
instead of `$TOMO_PATH/share/tomo_vX.Y/installed/module_vZ.W`
- Core libraries are no longer shipped with the compiler, they have moved to
@@ -14,6 +14,8 @@
- Tables now have `and`, `or`, `xor`, and `-` (minus) metamethods.
- Deprecated `extern` keyword for declaring external symbols from C.
- Use `C_code` instead.
+- Deprecated the postfix `?` to make values optional.
+ - Explicitly optional values can be declared as `my_var : T? = value`.
- Added a `--format` flag to the `tomo` binary that autoformats your code
(currently unstable, do not rely on it just yet).
- Standardized text methods for Unicode encodings:
diff --git a/src/ast.c b/src/ast.c
index 4dfd7d0f..0dcda5dc 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -269,7 +269,6 @@ Text_t ast_to_sexp(ast_t *ast) {
T(LangDef, "(LangDef \"", data.name, "\" ", ast_to_sexp(data.namespace), ")");
T(Index, "(Index ", ast_to_sexp(data.indexed), " ", ast_to_sexp(data.index), ")");
T(FieldAccess, "(FieldAccess ", ast_to_sexp(data.fielded), " \"", data.field, "\")");
- T(Optional, "(Optional ", ast_to_sexp(data.value), ")");
T(NonOptional, "(NonOptional ", ast_to_sexp(data.value), ")");
T(DocTest, "(DocTest ", ast_to_sexp(data.expr), optional_sexp("expected", data.expected), ")");
T(Assert, "(Assert ", ast_to_sexp(data.expr), " ", optional_sexp("message", data.message), ")");
@@ -655,10 +654,6 @@ void ast_visit(ast_t *ast, void (*visitor)(ast_t *, void *), void *userdata) {
ast_visit(Match(ast, FieldAccess)->fielded, visitor, userdata);
return;
}
- case Optional: {
- ast_visit(Match(ast, Optional)->value, visitor, userdata);
- return;
- }
case NonOptional: {
ast_visit(Match(ast, NonOptional)->value, visitor, userdata);
return;
diff --git a/src/ast.h b/src/ast.h
index 53685b28..90191219 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -269,7 +269,6 @@ typedef enum {
LangDef,
Index,
FieldAccess,
- Optional,
NonOptional,
DocTest,
Assert,
@@ -438,7 +437,7 @@ struct ast_s {
} FieldAccess;
struct {
ast_t *value;
- } Optional, NonOptional;
+ } NonOptional;
struct {
ast_t *expr, *expected;
bool skip_source : 1;
diff --git a/src/compile/expressions.c b/src/compile/expressions.c
index cd244fec..f4326b00 100644
--- a/src/compile/expressions.c
+++ b/src/compile/expressions.c
@@ -113,7 +113,6 @@ Text_t compile(env_t *env, ast_t *ast) {
}
case HeapAllocate:
case StackReference: return compile_typed_allocation(env, ast, get_type(env, ast));
- case Optional: return compile_optional(env, ast);
case NonOptional: return compile_non_optional(env, ast);
case Power:
case Multiply:
diff --git a/src/compile/functions.c b/src/compile/functions.c
index e2fa8a11..5f6f7e91 100644
--- a/src/compile/functions.c
+++ b/src/compile/functions.c
@@ -552,10 +552,6 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t
add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, FieldAccess)->fielded);
break;
}
- case Optional: {
- add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, Optional)->value);
- break;
- }
case NonOptional: {
add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, NonOptional)->value);
break;
diff --git a/src/compile/optionals.c b/src/compile/optionals.c
index 86b4f771..d74f0f31 100644
--- a/src/compile/optionals.c
+++ b/src/compile/optionals.c
@@ -113,13 +113,6 @@ Text_t check_none(type_t *t, Text_t value) {
}
public
-Text_t compile_optional(env_t *env, ast_t *ast) {
- ast_t *value = Match(ast, Optional)->value;
- Text_t value_code = compile(env, value);
- return promote_to_optional(get_type(env, value), value_code);
-}
-
-public
Text_t compile_non_optional(env_t *env, ast_t *ast) {
ast_t *value = Match(ast, NonOptional)->value;
if (value->tag == Index && Match(value, Index)->index != NULL) return compile_indexing(env, value, true);
diff --git a/src/compile/optionals.h b/src/compile/optionals.h
index d30aaefb..28ee25b9 100644
--- a/src/compile/optionals.h
+++ b/src/compile/optionals.h
@@ -11,5 +11,4 @@ Text_t optional_into_nonnone(type_t *t, Text_t value);
Text_t promote_to_optional(type_t *t, Text_t code);
Text_t compile_none(type_t *t);
Text_t check_none(type_t *t, Text_t value);
-Text_t compile_optional(env_t *env, ast_t *ast);
Text_t compile_non_optional(env_t *env, ast_t *ast);
diff --git a/src/formatter/formatter.c b/src/formatter/formatter.c
index a07b903d..69c1a213 100644
--- a/src/formatter/formatter.c
+++ b/src/formatter/formatter.c
@@ -269,10 +269,6 @@ OptionalText_t format_inline_code(ast_t *ast, Table_t comments) {
ast_t *val = Match(ast, StackReference)->value;
return Texts("&", must(termify_inline(val, comments)));
}
- /*inline*/ case Optional: {
- ast_t *val = Match(ast, Optional)->value;
- return Texts(must(termify_inline(val, comments)), "?");
- }
/*inline*/ case NonOptional: {
ast_t *val = Match(ast, NonOptional)->value;
return Texts(must(termify_inline(val, comments)), "!");
@@ -698,11 +694,6 @@ Text_t format_code(ast_t *ast, Table_t comments, Text_t indent) {
ast_t *val = Match(ast, StackReference)->value;
return Texts("&(", termify(val, comments, indent), ")");
}
- /*multiline*/ case Optional: {
- if (inlined_fits) return inlined;
- ast_t *val = Match(ast, Optional)->value;
- return Texts(termify(val, comments, indent), "?");
- }
/*multiline*/ case NonOptional: {
if (inlined_fits) return inlined;
ast_t *val = Match(ast, NonOptional)->value;
diff --git a/src/parse/binops.c b/src/parse/binops.c
index 4676b249..dd1ac3c2 100644
--- a/src/parse/binops.c
+++ b/src/parse/binops.c
@@ -73,8 +73,7 @@ ast_t *parse_infix_expr(parse_ctx_t *ctx, const char *pos, int min_tightness) {
progress =
(false || (new_term = parse_index_suffix(ctx, key))
|| (new_term = parse_method_call_suffix(ctx, key)) || (new_term = parse_field_suffix(ctx, key))
- || (new_term = parse_fncall_suffix(ctx, key)) || (new_term = parse_optional_suffix(ctx, key))
- || (new_term = parse_non_optional_suffix(ctx, key)));
+ || (new_term = parse_fncall_suffix(ctx, key)) || (new_term = parse_non_optional_suffix(ctx, key)));
if (progress) key = new_term;
}
if (key && key->tag == Var) key = NULL;
diff --git a/src/parse/expressions.c b/src/parse/expressions.c
index 7410f678..3cb47669 100644
--- a/src/parse/expressions.c
+++ b/src/parse/expressions.c
@@ -54,10 +54,9 @@ ast_t *parse_reduction(parse_ctx_t *ctx, const char *pos) {
ast_t *key = NewAST(ctx->file, pos, pos, Var, .name = op_str);
for (bool progress = true; progress;) {
ast_t *new_term;
- progress =
- (false || (new_term = parse_index_suffix(ctx, key)) || (new_term = parse_method_call_suffix(ctx, key))
- || (new_term = parse_field_suffix(ctx, key)) || (new_term = parse_fncall_suffix(ctx, key))
- || (new_term = parse_optional_suffix(ctx, key)) || (new_term = parse_non_optional_suffix(ctx, key)));
+ progress = (false || (new_term = parse_index_suffix(ctx, key))
+ || (new_term = parse_method_call_suffix(ctx, key)) || (new_term = parse_field_suffix(ctx, key))
+ || (new_term = parse_fncall_suffix(ctx, key)) || (new_term = parse_non_optional_suffix(ctx, key)));
if (progress) key = new_term;
}
if (key && key->tag == Var) key = NULL;
@@ -98,8 +97,7 @@ ast_t *parse_heap_alloc(parse_ctx_t *ctx, const char *pos) {
ast_t *ast = NewAST(ctx->file, start, pos, HeapAllocate, .value = val);
for (;;) {
- ast_t *next = parse_optional_suffix(ctx, ast);
- if (!next) next = parse_non_optional_suffix(ctx, ast);
+ ast_t *next = parse_non_optional_suffix(ctx, ast);
if (!next) break;
ast = next;
}
@@ -123,8 +121,7 @@ ast_t *parse_stack_reference(parse_ctx_t *ctx, const char *pos) {
ast_t *ast = NewAST(ctx->file, start, pos, StackReference, .value = val);
for (;;) {
- ast_t *next = parse_optional_suffix(ctx, ast);
- if (!next) next = parse_non_optional_suffix(ctx, ast);
+ ast_t *next = parse_non_optional_suffix(ctx, ast);
if (!next) break;
ast = next;
}
@@ -212,7 +209,7 @@ ast_t *parse_term(parse_ctx_t *ctx, const char *pos) {
progress =
(false || (new_term = parse_index_suffix(ctx, term)) || (new_term = parse_method_call_suffix(ctx, term))
|| (new_term = parse_field_suffix(ctx, term)) || (new_term = parse_fncall_suffix(ctx, term))
- || (new_term = parse_optional_suffix(ctx, term)) || (new_term = parse_non_optional_suffix(ctx, term)));
+ || (new_term = parse_non_optional_suffix(ctx, term)));
if (progress) term = new_term;
}
return term;
diff --git a/src/parse/suffixes.c b/src/parse/suffixes.c
index 312f958f..7493a65d 100644
--- a/src/parse/suffixes.c
+++ b/src/parse/suffixes.c
@@ -25,13 +25,6 @@ ast_t *parse_field_suffix(parse_ctx_t *ctx, ast_t *lhs) {
return NewAST(ctx->file, lhs->start, pos, FieldAccess, .fielded = lhs, .field = field);
}
-ast_t *parse_optional_suffix(parse_ctx_t *ctx, ast_t *lhs) {
- if (!lhs) return NULL;
- const char *pos = lhs->end;
- if (match(&pos, "?")) return NewAST(ctx->file, lhs->start, pos, Optional, .value = lhs);
- else return NULL;
-}
-
ast_t *parse_non_optional_suffix(parse_ctx_t *ctx, ast_t *lhs) {
if (!lhs) return NULL;
const char *pos = lhs->end;
diff --git a/src/parse/suffixes.h b/src/parse/suffixes.h
index da2f23a2..23ca7182 100644
--- a/src/parse/suffixes.h
+++ b/src/parse/suffixes.h
@@ -11,4 +11,3 @@ ast_t *parse_index_suffix(parse_ctx_t *ctx, ast_t *lhs);
ast_t *parse_method_call_suffix(parse_ctx_t *ctx, ast_t *self);
ast_t *parse_non_optional_suffix(parse_ctx_t *ctx, ast_t *lhs);
ast_t *parse_optional_conditional_suffix(parse_ctx_t *ctx, ast_t *stmt);
-ast_t *parse_optional_suffix(parse_ctx_t *ctx, ast_t *lhs);
diff --git a/src/typecheck.c b/src/typecheck.c
index 64bf0fd8..b4798768 100644
--- a/src/typecheck.c
+++ b/src/typecheck.c
@@ -798,12 +798,6 @@ type_t *get_type(env_t *env, ast_t *ast) {
default: return Type(PointerType, .pointed = get_type(env, value), .is_stack = true);
}
}
- case Optional: {
- ast_t *value = Match(ast, Optional)->value;
- type_t *t = get_type(env, value);
- if (t->tag == OptionalType) code_err(ast, "This value is already optional, it can't be converted to optional");
- return Type(OptionalType, .type = t);
- }
case NonOptional: {
ast_t *value = Match(ast, NonOptional)->value;
type_t *t = get_type(env, value);
diff --git a/test/iterators.tm b/test/iterators.tm
index c48e572b..ed08f73d 100644
--- a/test/iterators.tm
+++ b/test/iterators.tm
@@ -3,17 +3,17 @@ struct Pair(x:Text, y:Text)
func pairwise(strs:[Text] -> func(->Pair?))
i := 1
- return func()
+ return func(-> Pair?)
i += 1
- return Pair(strs[i-1] or return none, strs[i] or return none)?
+ return Pair(strs[i-1] or return none, strs[i] or return none)
func range(first:Int, last:Int -> func(->Int?))
i := first
- return func()
+ return func(->Int?)
if i > last
return none
i += 1
- return (i-1)?
+ return (i-1)
func main()
values := ["A", "B", "C", "D"]
diff --git a/test/lists.tm b/test/lists.tm
index 05001f19..2342c570 100644
--- a/test/lists.tm
+++ b/test/lists.tm
@@ -162,23 +162,23 @@ func main()
= [1, 2, 3, 4, 5]
>> ["a", "b", "c"].find("b")
- = 2?
+ = 2
>> ["a", "b", "c"].find("XXX")
= none
>> [10, 20].where(func(i:&Int) i.is_prime())
= none
>> [4, 5, 6].where(func(i:&Int) i.is_prime())
- = 2?
+ = 2
do
>> nums := &[10, 20, 30, 40, 50]
>> nums.pop()
- = 50?
+ = 50
>> nums[]
= [10, 20, 30, 40]
>> nums.pop(2)
- = 20?
+ = 20
>> nums[]
= [10, 30, 40]
>> nums.clear()
diff --git a/test/nums.tm b/test/nums.tm
index 362f590f..1ca09d7b 100644
--- a/test/nums.tm
+++ b/test/nums.tm
@@ -51,7 +51,9 @@ func main()
= no
>> Num32.sqrt(16)
- = Num32(4)?
+ = Num32(4)
+ >> Num32.sqrt(-1)
+ = none
>> (0.25).mix(10, 20)
= 12.5
diff --git a/test/optionals.tm b/test/optionals.tm
index 1f7d640e..dcec904d 100644
--- a/test/optionals.tm
+++ b/test/optionals.tm
@@ -57,28 +57,28 @@ func maybe_lambda(should_i:Bool-> func()?)
func maybe_c_string(should_i:Bool->CString?)
if should_i
- return ("hi".as_c_string())?
+ return "hi".as_c_string()
else
return none
func main()
- >> 5?
- = 5?
+ >> optional : Int? = 5
+ = 5
>> if no
x : Int? = none
x
else
5
- = 5?
+ = 5
- >> 5? or -1
+ >> optional or -1
= 5
- >> 5? or fail("Non-none is falsey")
+ >> optional or fail("Non-none is falsey")
= 5
- >> 5? or exit("Non-none is falsey")
+ >> optional or exit("Non-none is falsey")
= 5
>> none_int : Int? = none
@@ -88,7 +88,7 @@ func main()
do
say("Ints:")
>> yep := maybe_int(yes)
- = 123?
+ = 123
>> nope := maybe_int(no)
= none
>> if yep
@@ -102,7 +102,7 @@ func main()
do
say("Int64s:")
>> yep := maybe_int64(yes)
- = Int64(123)?
+ = Int64(123)
>> nope := maybe_int64(no)
= none
>> if yep
@@ -116,7 +116,7 @@ func main()
do
say("Lists:")
>> yep := maybe_list(yes)
- = [10, 20, 30]?
+ = [10, 20, 30]
>> nope := maybe_list(no)
= none
>> if yep
@@ -131,7 +131,7 @@ func main()
say("...")
say("Bools:")
>> yep := maybe_bool(yes)
- = no?
+ = no
>> nope := maybe_bool(no)
= none
>> if yep
@@ -146,7 +146,7 @@ func main()
say("...")
say("Text:")
>> yep := maybe_text(yes)
- = "Hello"?
+ = "Hello"
>> nope := maybe_text(no)
= none
>> if yep
@@ -161,7 +161,7 @@ func main()
say("...")
say("Nums:")
>> yep := maybe_num(yes)
- = 12.3?
+ = 12.3
>> nope := maybe_num(no)
= none
>> if yep
@@ -191,7 +191,7 @@ func main()
say("...")
say("Structs:")
>> yep := Struct.maybe(yes)
- = Struct(x=123, y="hello")?
+ = Struct(x=123, y="hello")
>> nope := Struct.maybe(no)
= none
>> if yep
@@ -206,7 +206,7 @@ func main()
say("...")
say("Enums:")
>> yep := Enum.maybe(yes)
- = Enum.Y(123)?
+ = Enum.Y(123)
>> nope := Enum.maybe(no)
= none
>> if yep
@@ -221,7 +221,7 @@ func main()
say("...")
say("C Strings:")
>> yep := maybe_c_string(yes)
- = CString("hi")?
+ = CString("hi")
>> nope := maybe_c_string(no)
= none
>> if yep
@@ -241,16 +241,16 @@ func main()
= 123
# Test comparisons, hashing, equality:
- assert none != 5?
- assert 5? == 5?
+ assert none != optional
+ assert optional == 5
>> nones : {Int?=Bool} = {none=yes, none=yes}
>> nones.keys
= [none]
- >> [5?, none, none, 6?].sorted()
+ >> [5, none, none, 6].sorted()
= [none, none, 5, 6]
do
- >> value := if var := 5?
+ >> value := if var := optional
var
else
0
@@ -264,7 +264,7 @@ func main()
= 0
do
- >> opt := 5?
+ >> opt : Int? = 5
>> if opt
>> opt
else
@@ -277,17 +277,17 @@ func main()
else
>> opt
- >> not 5?
+ >> not optional
= no
>> nah : Int? = none
>> not nah
= yes
- >> [Struct(5,"A")?, Struct(6,"B"), Struct(7,"C")]
- = [Struct(x=5, y="A")?, Struct(x=6, y="B")?, Struct(x=7, y="C")?]
+ >> [none, Struct(5,"A"), Struct(6,"B"), Struct(7,"C")]
+ = [none, Struct(x=5, y="A"), Struct(x=6, y="B"), Struct(x=7, y="C")]
- if 5? or no
+ if optional or no
say("Binary op 'or' works with optionals")
else
fail("Failed to do binary op 'or' on optional")
diff --git a/test/paths.tm b/test/paths.tm
index d92d4623..22f79c7b 100644
--- a/test/paths.tm
+++ b/test/paths.tm
@@ -20,7 +20,7 @@ func main()
>> tmpfile.write("Hello world")
>> tmpfile.append("!")
>> tmpfile.read()
- = "Hello world!"?
+ = "Hello world!"
>> tmpfile.read_bytes()!
= [0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x21]
assert tmpdir.files().has(tmpfile)
diff --git a/test/reductions.tm b/test/reductions.tm
index 3ec2ef5e..15c3d454 100644
--- a/test/reductions.tm
+++ b/test/reductions.tm
@@ -2,7 +2,7 @@ struct Foo(x,y:Int)
func main()
>> (+: [10, 20, 30])
- = 60?
+ = 60
>> empty_ints : [Int]
>> (+: empty_ints)
@@ -15,10 +15,10 @@ func main()
= 0
>> (_max_: [3, 5, 2, 1, 4])
- = 5?
+ = 5
>> (_max_.abs(): [1, -10, 5])
- = -10?
+ = -10
>> (_max_: [Foo(0, 0), Foo(1, 0), Foo(0, 10)])!
= Foo(x=1, y=0)
diff --git a/test/serialization.tm b/test/serialization.tm
index e2fa38a3..0e5be1ae 100644
--- a/test/serialization.tm
+++ b/test/serialization.tm
@@ -62,7 +62,7 @@ func main()
assert deserialize(bytes -> MyEnum) == obj
do
- >> obj := "Hello"?
+ >> obj : Text? = "Hello"
>> bytes := obj.serialized()
assert deserialize(bytes -> Text?) == obj
diff --git a/test/tables.tm b/test/tables.tm
index 587a02c8..66318f11 100644
--- a/test/tables.tm
+++ b/test/tables.tm
@@ -3,9 +3,9 @@ func main()
= {"one"=1, "two"=2}
>> t["one"]
- = 1?
+ = 1
>> t["two"]
- = 2?
+ = 2
>> t["???"]
= none
>> t["one"]!
@@ -33,16 +33,16 @@ func main()
= {"three"=3; fallback={"one"=1, "two"=2}}
>> t2["one"]
- = 1?
+ = 1
>> t2["three"]
- = 3?
+ = 3
>> t2["???"]
= none
>> t2.length
= 1
>> t2.fallback
- = {"one"=1, "two"=2}?
+ = {"one"=1, "two"=2}
t2_str := ""
for k,v in t2
diff --git a/test/when.tm b/test/when.tm
index d18f5276..57de4c2c 100644
--- a/test/when.tm
+++ b/test/when.tm
@@ -15,4 +15,4 @@ func main()
>> when n is 1 Int64(1)
is 2 Int64(2)
is 21 + 2 Int64(23)
- = Int64(23)?
+ = Int64(23)