Misc fixes
This commit is contained in:
parent
0b8074154e
commit
7b735ab6fc
@ -246,13 +246,13 @@ variable or dereference a heap pointer, it may trigger copy-on-write behavior.
|
||||
- [`func insert(arr: @[T], item: T, at: Int = 0 -> Void)`](#insert)
|
||||
- [`func insert_all(arr: @[T], items: [T], at: Int = 0 -> Void)`](#insert_all)
|
||||
- [`func pop(arr: &[T], index: Int = -1 -> T?)`](#pop)
|
||||
- [`func random(arr: [T], random: func(min,max:Int64->Int64)? = none:func(min,max:Int64->Int64) -> T)`](#random)
|
||||
- [`func random(arr: [T], random: func(min,max:Int64->Int64)? = none -> T)`](#random)
|
||||
- [`func remove_at(arr: @[T], at: Int = -1, count: Int = 1 -> Void)`](#remove_at)
|
||||
- [`func remove_item(arr: @[T], item: T, max_count: Int = -1 -> Void)`](#remove_item)
|
||||
- [`func reversed(arr: [T] -> [T])`](#reversed)
|
||||
- [`func sample(arr: [T], count: Int, weights: [Num]? = ![Num], random: func(->Num)? = none:func(->Num) -> [T])`](#sample)
|
||||
- [`func shuffle(arr: @[T], random: func(min,max:Int64->Int64)? = none:func(min,max:Int64->Int64) -> Void)`](#shuffle)
|
||||
- [`func shuffled(arr: [T], random: func(min,max:Int64->Int64)? = none:func(min,max:Int64->Int64) -> [T])`](#shuffled)
|
||||
- [`func sample(arr: [T], count: Int, weights: [Num]? = ![Num], random: func(->Num)? = none -> [T])`](#sample)
|
||||
- [`func shuffle(arr: @[T], random: func(min,max:Int64->Int64)? = none -> Void)`](#shuffle)
|
||||
- [`func shuffled(arr: [T], random: func(min,max:Int64->Int64)? = none -> [T])`](#shuffled)
|
||||
- [`func slice(arr: [T], from: Int, to: Int -> [T])`](#slice)
|
||||
- [`func sort(arr: @[T], by=T.compare -> Void)`](#sort)
|
||||
- [`sorted(arr: [T], by=T.compare -> [T])`](#sorted)
|
||||
@ -607,7 +607,7 @@ otherwise the item at the given index.
|
||||
Selects a random element from the array.
|
||||
|
||||
```tomo
|
||||
func random(arr: [T], random: func(min,max:Int64->Int64)? = none:func(min,max:Int64->Int64) -> T)
|
||||
func random(arr: [T], random: func(min,max:Int64->Int64)? = none -> T)
|
||||
```
|
||||
|
||||
- `arr`: The array from which to select a random element.
|
||||
@ -707,7 +707,7 @@ Selects a sample of elements from the array, optionally with weighted
|
||||
probabilities.
|
||||
|
||||
```tomo
|
||||
func sample(arr: [T], count: Int, weights: [Num]? = ![Num], random: func(->Num)? = none:func(->Num) -> [T])
|
||||
func sample(arr: [T], count: Int, weights: [Num]? = ![Num], random: func(->Num)? = none -> [T])
|
||||
```
|
||||
|
||||
- `arr`: The array to sample from.
|
||||
@ -744,7 +744,7 @@ A list of sampled elements from the array.
|
||||
Shuffles the elements of the array in place.
|
||||
|
||||
```tomo
|
||||
func shuffle(arr: @[T], random: func(min,max:Int64->Int64)? = none:func(min,max:Int64->Int64) -> Void)
|
||||
func shuffle(arr: @[T], random: func(min,max:Int64->Int64)? = none -> Void)
|
||||
```
|
||||
|
||||
- `arr`: The mutable reference to the array to be shuffled.
|
||||
@ -766,7 +766,7 @@ Nothing.
|
||||
Creates a new array with elements shuffled.
|
||||
|
||||
```tomo
|
||||
func shuffled(arr: [T], random: func(min,max:Int64->Int64)? = none:func(min,max:Int64->Int64) -> [T])
|
||||
func shuffled(arr: [T], random: func(min,max:Int64->Int64)? = none -> [T])
|
||||
```
|
||||
|
||||
- `arr`: The array to be shuffled.
|
||||
|
@ -135,7 +135,7 @@ can be called either on the type itself: `Int.sqrt(x)` or as a method call:
|
||||
- [`func parse(text: Text -> Int?)`](#parse)
|
||||
- [`func prev_prime(x: Int -> Int)`](#prev_prime)
|
||||
- [`func sqrt(x: Int -> Int)`](#sqrt)
|
||||
- [`func to(first: Int, last: Int, step : Int? = none:Int -> func(->Int?))`](#to)
|
||||
- [`func to(first: Int, last: Int, step : Int? = none -> func(->Int?))`](#to)
|
||||
|
||||
### `abs`
|
||||
Calculates the absolute value of an integer.
|
||||
@ -458,7 +458,7 @@ Returns an iterator function that iterates over the range of numbers specified.
|
||||
Iteration is assumed to be nonempty and
|
||||
|
||||
```tomo
|
||||
func to(first: Int, last: Int, step : Int? = none:Int -> func(->Int?))
|
||||
func to(first: Int, last: Int, step : Int? = none -> func(->Int?))
|
||||
```
|
||||
|
||||
- `first`: The starting value of the range.
|
||||
|
@ -40,7 +40,7 @@ example, if you wanted to declare a variable that could be either an integer
|
||||
value or `none` and initialize it as none, you would write it as:
|
||||
|
||||
```tomo
|
||||
x := none:Int
|
||||
x : Int = none
|
||||
```
|
||||
|
||||
Similarly, if you wanted to declare a variable that could be an array of texts
|
||||
@ -57,7 +57,7 @@ keep open the possibility of assigning `none` later, you can use the postfix
|
||||
```tomo
|
||||
x := 5?
|
||||
# Later on, assign none:
|
||||
x = !Int
|
||||
x = none
|
||||
```
|
||||
|
||||
## Type Inference
|
||||
@ -86,7 +86,7 @@ Non-none values can also be automatically promoted to optional values without
|
||||
the need for an explicit `?` operator in the cases listed above:
|
||||
|
||||
```tomo
|
||||
x := !Int
|
||||
x : Int? = none
|
||||
x = 5
|
||||
|
||||
func doop(arg:Int?)->Text?:
|
||||
@ -109,7 +109,7 @@ maybe_x := 5?
|
||||
>> maybe_x or fail("No value!")
|
||||
= 5 : Int
|
||||
|
||||
maybe_x = !Int
|
||||
maybe_x = none
|
||||
>> maybe_x or -1
|
||||
= -1 : Int
|
||||
>> maybe_x or fail("No value!")
|
||||
|
@ -68,7 +68,7 @@ intended. Paths can be created from text with slashes using
|
||||
- [`func relative_to(path: Path, relative_to=(./) -> Path)`](#relative_to)
|
||||
- [`func remove(path: Path, ignore_missing=no -> Void)`](#remove)
|
||||
- [`func resolved(path: Path, relative_to=(./) -> Path)`](#resolved)
|
||||
- [`func set_owner(path:Path, owner=none:Text, group=none:Text, follow_symlinks=yes)`](#set_owner)
|
||||
- [`func set_owner(path:Path, owner:Text?=none, group:Text?=none, follow_symlinks=yes)`](#set_owner)
|
||||
- [`func subdirectories(path: Path, include_hidden=no -> [Path])`](#subdirectories)
|
||||
- [`func unique_directory(path: Path -> Path)`](#unique_directory)
|
||||
- [`func write(path: Path, text: Text, permissions=0o644[32] -> Void)`](#write)
|
||||
@ -95,7 +95,7 @@ accessed, or `none` if no such file or directory exists.
|
||||
>> (./file.txt):accessed()
|
||||
= 1704221100?
|
||||
>> (./not-a-file):accessed()
|
||||
= none:Int64?
|
||||
= none
|
||||
```
|
||||
|
||||
---
|
||||
@ -289,7 +289,7 @@ changed, or `none` if no such file or directory exists.
|
||||
>> (./file.txt):changed()
|
||||
= 1704221100?
|
||||
>> (./not-a-file):changed()
|
||||
= none:Int64
|
||||
= none
|
||||
```
|
||||
|
||||
---
|
||||
@ -535,7 +535,7 @@ The name of the group which owns the file or directory, or `none` if the path do
|
||||
>> (/bin):group()
|
||||
= "root"
|
||||
>> (/non/existent/file):group()
|
||||
= none:Text
|
||||
= none
|
||||
```
|
||||
|
||||
---
|
||||
@ -648,7 +648,7 @@ modified, or `none` if no such file or directory exists.
|
||||
>> (./file.txt):modified()
|
||||
= 1704221100?
|
||||
>> (./not-a-file):modified()
|
||||
= none:Int64
|
||||
= none
|
||||
```
|
||||
|
||||
---
|
||||
@ -671,7 +671,7 @@ The name of the user who owns the file or directory, or `none` if the path does
|
||||
>> (/bin):owner()
|
||||
= "root"
|
||||
>> (/non/existent/file):owner()
|
||||
= none:Text
|
||||
= none
|
||||
```
|
||||
|
||||
---
|
||||
@ -717,7 +717,7 @@ raised.
|
||||
= "Hello"?
|
||||
|
||||
>> (./nosuchfile.xxx):read()
|
||||
= none:Text
|
||||
= none
|
||||
```
|
||||
---
|
||||
|
||||
@ -741,7 +741,7 @@ returned.
|
||||
= [72[B], 101[B], 108[B], 108[B], 111[B]]?
|
||||
|
||||
>> (./nosuchfile.xxx):read()
|
||||
= none:[Byte]
|
||||
= none
|
||||
```
|
||||
|
||||
---
|
||||
@ -815,7 +815,7 @@ The resolved absolute path.
|
||||
Set the owning user and/or group for a path.
|
||||
|
||||
```tomo
|
||||
func set_owner(path:Path, owner: Text? = none:Text, group: Text? = none:Text, follow_symlinks: Bool = yes)
|
||||
func set_owner(path:Path, owner: Text? = none, group: Text? = none, follow_symlinks: Bool = yes)
|
||||
```
|
||||
|
||||
- `path`: The path to change the permissions for.
|
||||
|
@ -52,7 +52,7 @@ cyclic datastructures correctly, enabling you to serialize cyclic structures
|
||||
like circularly linked lists or graphs:
|
||||
|
||||
```tomo
|
||||
struct Cycle(name:Text, next=none:@Cycle)
|
||||
struct Cycle(name:Text, next:@Cycle?=none)
|
||||
|
||||
c := @Cycle("A")
|
||||
c.next = @Cycle("B", next=c)
|
||||
|
@ -43,7 +43,7 @@ table := {"A"=1, "B"=2}
|
||||
>> table["A"]
|
||||
= 1?
|
||||
>> table["missing"]
|
||||
= none:Int
|
||||
= none
|
||||
```
|
||||
|
||||
As with all optional values, you can use the `!` postfix operator to assert
|
||||
@ -77,7 +77,7 @@ table value:
|
||||
>> t2.fallback
|
||||
= {"A"=10}?
|
||||
>> t.fallback
|
||||
= none:{Text=Int}
|
||||
= none
|
||||
```
|
||||
|
||||
### Default Values
|
||||
@ -225,7 +225,7 @@ The value associated with the key or `none` if the key is not found.
|
||||
= 1?
|
||||
|
||||
>> t:get("????")
|
||||
= none:Int
|
||||
= none
|
||||
|
||||
>> t:get("A")!
|
||||
= 1
|
||||
|
@ -11,12 +11,12 @@ enum ExitType(Exited(status:Int32), Signaled(signal:Int32), Failed):
|
||||
when e is Exited(status): return (status == 0)
|
||||
else: return no
|
||||
|
||||
func or_fail(e:ExitType, message=none:Text):
|
||||
func or_fail(e:ExitType, message:Text?=none):
|
||||
if not e:succeeded():
|
||||
fail(message or "Program failed: $e")
|
||||
|
||||
struct ProgramResult(stdout:[Byte], stderr:[Byte], exit_type:ExitType):
|
||||
func or_fail(r:ProgramResult, message=none:Text -> ProgramResult):
|
||||
func or_fail(r:ProgramResult, message:Text?=none -> ProgramResult):
|
||||
when r.exit_type is Exited(status):
|
||||
if status == 0:
|
||||
return r
|
||||
|
@ -12,7 +12,7 @@ struct ConnectionQueue(_connections:@[Int32]=@[], _mutex=pthread_mutex_t.new(),
|
||||
|
||||
|
||||
func dequeue(queue:ConnectionQueue -> Int32):
|
||||
conn := none:Int32
|
||||
conn : Int32? = none
|
||||
|
||||
queue._mutex:lock()
|
||||
|
||||
|
@ -93,7 +93,7 @@ func put(url:Text, data="", headers=["Content-Type: application/json", "Accept:
|
||||
func patch(url:Text, data="", headers=["Content-Type: application/json", "Accept: application/json"] -> HTTPResponse):
|
||||
return _send(PATCH, url, data, headers)
|
||||
|
||||
func delete(url:Text, data=none:Text, headers=["Content-Type: application/json", "Accept: application/json"] -> HTTPResponse):
|
||||
func delete(url:Text, data:Text?=none, headers=["Content-Type: application/json", "Accept: application/json"] -> HTTPResponse):
|
||||
return _send(DELETE, url, data, headers)
|
||||
|
||||
func main():
|
||||
|
@ -332,7 +332,7 @@ not match the pattern.
|
||||
>> "123 boxes":pattern_captures($Pat"{int} {id}")
|
||||
= ["123", "boxes"]?
|
||||
>> "xxx":pattern_captures($Pat"{int} {id}")
|
||||
= none:[Text]
|
||||
= none
|
||||
```
|
||||
|
||||
---
|
||||
|
@ -25,7 +25,7 @@ func _os_random_bytes(count:Int64 -> [Byte]):
|
||||
}
|
||||
|
||||
struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret):
|
||||
func new(seed=none:[Byte], -> @RandomNumberGenerator):
|
||||
func new(seed:[Byte]?=none, -> @RandomNumberGenerator):
|
||||
ctx := chacha_ctx.from_seed(seed or _os_random_bytes(40))
|
||||
return @RandomNumberGenerator(ctx, [])
|
||||
|
||||
|
@ -40,7 +40,7 @@ func main(paths:[Path]):
|
||||
say("Already installed: $url")
|
||||
skip
|
||||
|
||||
alias := none:Text
|
||||
alias : Text? = none
|
||||
curl_flags := ["-L"]
|
||||
if github := url_without_protocol:pattern_captures($Pat"github.com/{!/}/{!/}#{..}"):
|
||||
user := github[1]
|
||||
|
@ -19,7 +19,7 @@ struct Vec2(x,y:Num):
|
||||
func divided_by(v:Vec2, divisor:Num->Vec2; inline):
|
||||
return Vec2(v.x/divisor, v.y/divisor)
|
||||
func length(v:Vec2->Num; inline):
|
||||
return (v.x*v.x + v.y*v.y)!:sqrt()
|
||||
return (v.x*v.x + v.y*v.y):sqrt()
|
||||
func dist(a,b:Vec2->Num; inline):
|
||||
return a:minus(b):length()
|
||||
func angle(v:Vec2->Num; inline):
|
||||
@ -58,7 +58,7 @@ struct Vec3(x,y,z:Num):
|
||||
func divided_by(v:Vec3, divisor:Num->Vec3; inline):
|
||||
return Vec3(v.x/divisor, v.y/divisor, v.z/divisor)
|
||||
func length(v:Vec3->Num; inline):
|
||||
return (v.x*v.x + v.y*v.y + v.z*v.z)!:sqrt()
|
||||
return (v.x*v.x + v.y*v.y + v.z*v.z):sqrt()
|
||||
func dist(a,b:Vec3->Num; inline):
|
||||
return a:minus(b):length()
|
||||
func norm(v:Vec3->Vec3; inline):
|
||||
|
@ -134,12 +134,13 @@ CORD ast_to_xml(ast_t *ast)
|
||||
T(Path, "<Path>%s</Path>", data.path)
|
||||
T(Declare, "<Declare var=\"%r\">%r%r</Declare>", ast_to_xml(data.var), type_ast_to_xml(data.type), ast_to_xml(data.value))
|
||||
T(Assign, "<Assign><targets>%r</targets><values>%r</values></Assign>", ast_list_to_xml(data.targets), ast_list_to_xml(data.values))
|
||||
#define BINOP(name) T(name, "<" #name ">%r %r</" #name ">", data.lhs, data.rhs)
|
||||
#define BINOP(name) T(name, "<" #name ">%r %r</" #name ">", ast_to_xml(data.lhs), ast_to_xml(data.rhs))
|
||||
BINOP(Power) BINOP(PowerUpdate) BINOP(Multiply) BINOP(MultiplyUpdate) BINOP(Divide) BINOP(DivideUpdate) BINOP(Mod) BINOP(ModUpdate)
|
||||
BINOP(Mod1) BINOP(Mod1Update) BINOP(Plus) BINOP(PlusUpdate) BINOP(Minus) BINOP(MinusUpdate) BINOP(Concat) BINOP(ConcatUpdate)
|
||||
BINOP(LeftShift) BINOP(LeftShiftUpdate) BINOP(RightShift) BINOP(RightShiftUpdate) BINOP(UnsignedLeftShift) BINOP(UnsignedLeftShiftUpdate)
|
||||
BINOP(UnsignedRightShift) BINOP(UnsignedRightShiftUpdate) BINOP(And) BINOP(AndUpdate) BINOP(Or) BINOP(OrUpdate)
|
||||
BINOP(Xor) BINOP(XorUpdate)
|
||||
BINOP(Xor) BINOP(XorUpdate) BINOP(Compare)
|
||||
BINOP(Equals) BINOP(NotEquals) BINOP(LessThan) BINOP(LessThanOrEquals) BINOP(GreaterThan) BINOP(GreaterThanOrEquals)
|
||||
#undef BINOP
|
||||
T(Negative, "<Negative>%r</Negative>", ast_to_xml(data.value))
|
||||
T(Not, "<Not>%r</Not>", ast_to_xml(data.value))
|
||||
|
@ -552,7 +552,7 @@ static CORD compile_update_assignment(env_t *env, ast_t *ast)
|
||||
binop->tag = binop_tag(binop->tag);
|
||||
if (needs_idemotency_fix)
|
||||
binop->__data.Plus.lhs = WrapAST(update.lhs, InlineCCode, .code="*lhs", .type=lhs_t);
|
||||
update_assignment = CORD_all(lhs, " = ", compile_to_type(env, binop, lhs_t));
|
||||
update_assignment = CORD_all(lhs, " = ", compile_to_type(env, binop, lhs_t), ";");
|
||||
}
|
||||
|
||||
if (needs_idemotency_fix)
|
||||
@ -1154,7 +1154,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
|
||||
}
|
||||
|
||||
ast_t *update_var = new(ast_t);
|
||||
*update_var = *ast;
|
||||
*update_var = *test->expr;
|
||||
update_var->__data.PlusUpdate.lhs = WrapAST(update.lhs, InlineCCode, .code="(*expr)", .type=lhs_t); // UNSAFE
|
||||
test_code = CORD_all("({",
|
||||
compile_declaration(Type(PointerType, lhs_t), "expr"), " = &(", compile_lvalue(env, update.lhs), "); ",
|
||||
@ -1855,6 +1855,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
|
||||
}
|
||||
}
|
||||
default:
|
||||
// print("Is discardable: ", ast_to_xml_str(ast), " ==> ", is_discardable(env, ast));
|
||||
if (!is_discardable(env, ast))
|
||||
code_err(ast, "The ", type_to_str(get_type(env, ast)), " result of this statement cannot be discarded");
|
||||
return CORD_asprintf("(void)%r;", compile(env, ast));
|
||||
@ -1952,6 +1953,10 @@ CORD compile_to_type(env_t *env, ast_t *ast, type_t *t)
|
||||
default: code_err(ast, "This is not a valid number bit width");
|
||||
}
|
||||
} else if (ast->tag == None) {
|
||||
if (t->tag != OptionalType)
|
||||
code_err(ast, "This is not supposed to be an optional type");
|
||||
else if (Match(t, OptionalType)->type == NULL)
|
||||
code_err(ast, "I don't know what kind of `none` this is supposed to be!\nPlease tell me by declaring a variable like `foo : Type = none`");
|
||||
return compile_none(t);
|
||||
} else if (t->tag == PointerType && (ast->tag == HeapAllocate || ast->tag == StackReference)) {
|
||||
return compile_typed_allocation(env, ast, t);
|
||||
@ -2377,9 +2382,15 @@ static bool string_literal_is_all_ascii(CORD literal)
|
||||
|
||||
CORD compile_none(type_t *t)
|
||||
{
|
||||
if (t == NULL)
|
||||
compiler_err(NULL, NULL, NULL, "I can't compile a `none` value with no type");
|
||||
|
||||
if (t->tag == OptionalType)
|
||||
t = Match(t, OptionalType)->type;
|
||||
|
||||
if (t == NULL)
|
||||
compiler_err(NULL, NULL, NULL, "I can't compile a `none` value with no type");
|
||||
|
||||
if (t == PATH_TYPE) return "NONE_PATH";
|
||||
else if (t == PATH_TYPE_TYPE) return "((OptionalPathType_t){})";
|
||||
|
||||
@ -2435,7 +2446,7 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
{
|
||||
switch (ast->tag) {
|
||||
case None: {
|
||||
code_err(ast, "This 'none' needs to specify what type it is using `none:Type` syntax");
|
||||
code_err(ast, "I can't figure out what this `none`'s type is!");
|
||||
}
|
||||
case Bool: return Match(ast, Bool)->b ? "yes" : "no";
|
||||
case Var: {
|
||||
@ -2535,30 +2546,43 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
type_t *lhs_t = get_type(env, binop.lhs);
|
||||
type_t *rhs_t = get_type(env, binop.rhs);
|
||||
type_t *operand_t;
|
||||
CORD lhs, rhs;
|
||||
if (can_compile_to_type(env, binop.rhs, lhs_t)) {
|
||||
lhs = compile(env, binop.lhs);
|
||||
rhs = compile_to_type(env, binop.rhs, lhs_t);
|
||||
if (is_numeric_type(lhs_t) && binop.rhs->tag == Int) {
|
||||
operand_t = lhs_t;
|
||||
} else if (can_compile_to_type(env, binop.lhs, rhs_t)) {
|
||||
rhs = compile(env, binop.rhs);
|
||||
lhs = compile_to_type(env, binop.lhs, rhs_t);
|
||||
} else if (is_numeric_type(rhs_t) && binop.lhs->tag == Int) {
|
||||
operand_t = rhs_t;
|
||||
} else {
|
||||
code_err(ast, "I can't do comparisons between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
|
||||
switch (compare_precision(lhs_t, rhs_t)) {
|
||||
case NUM_PRECISION_LESS: operand_t = rhs_t; break;
|
||||
case NUM_PRECISION_MORE: operand_t = lhs_t; break;
|
||||
case NUM_PRECISION_EQUAL: operand_t = lhs_t; break;
|
||||
default: {
|
||||
if (can_compile_to_type(env, binop.rhs, lhs_t)) {
|
||||
operand_t = lhs_t;
|
||||
} else if (can_compile_to_type(env, binop.lhs, rhs_t)) {
|
||||
operand_t = rhs_t;
|
||||
} else {
|
||||
code_err(ast, "I can't do comparisons between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CORD lhs, rhs;
|
||||
lhs = compile_to_type(env, binop.lhs, operand_t);
|
||||
rhs = compile_to_type(env, binop.rhs, operand_t);
|
||||
|
||||
switch (operand_t->tag) {
|
||||
case BigIntType:
|
||||
return CORD_all(ast->tag == Equals ? CORD_EMPTY : "!", "Int$equal_value(", lhs, ", ", rhs, ")");
|
||||
case BoolType: case ByteType: case IntType: case NumType: case PointerType: case FunctionType:
|
||||
return CORD_all("(", lhs, ast->tag == Equals ? " == " : " != ", rhs, ")");
|
||||
default:
|
||||
return CORD_asprintf(ast->tag == Equals ? CORD_EMPTY : "!",
|
||||
"generic_equal(stack(%r), stack(%r), %r)", lhs, rhs, compile_type_info(operand_t));
|
||||
return CORD_all(ast->tag == Equals ? CORD_EMPTY : "!",
|
||||
"generic_equal(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(operand_t), ")");
|
||||
}
|
||||
}
|
||||
case LessThan: case LessThanOrEquals: case GreaterThan: case GreaterThanOrEquals: {
|
||||
case LessThan: case LessThanOrEquals: case GreaterThan: case GreaterThanOrEquals: case Compare: {
|
||||
binary_operands_t cmp = BINARY_OPERANDS(ast);
|
||||
|
||||
type_t *lhs_t = get_type(env, cmp.lhs);
|
||||
@ -2577,6 +2601,10 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
code_err(ast, "I can't do comparisons between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
|
||||
}
|
||||
|
||||
if (ast->tag == Compare)
|
||||
return CORD_all("generic_compare(stack(", lhs, "), stack(", rhs, "), ",
|
||||
compile_type_info(operand_t), ")");
|
||||
|
||||
const char *op = binop_operator(ast->tag);
|
||||
switch (operand_t->tag) {
|
||||
case BigIntType:
|
||||
@ -2584,7 +2612,8 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
case BoolType: case ByteType: case IntType: case NumType: case PointerType: case FunctionType:
|
||||
return CORD_all("(", lhs, " ", op, " ", rhs, ")");
|
||||
default:
|
||||
return CORD_all("(generic_compare(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(Type(OptionalType, operand_t)), ") ", op, " 0)");
|
||||
return CORD_all("(generic_compare(stack(", lhs, "), stack(", rhs, "), ",
|
||||
compile_type_info(operand_t), ") ", op, " 0)");
|
||||
}
|
||||
}
|
||||
case TextLiteral: {
|
||||
@ -2896,31 +2925,27 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
compile_type_info(self_value_t), ")");
|
||||
} else if (streq(call->name, "sample")) {
|
||||
type_t *random_num_type = parse_type_string(env, "func(->Num)?");
|
||||
ast_t *none_rng = parse_expression("none:func(->Num)");
|
||||
self = compile_to_pointer_depth(env, call->self, 0, false);
|
||||
arg_t *arg_spec = new(arg_t, .name="count", .type=INT_TYPE,
|
||||
.next=new(arg_t, .name="weights", .type=Type(ArrayType, .item_type=Type(NumType)),
|
||||
.next=new(arg_t, .name="weights", .type=Type(ArrayType, .item_type=Type(NumType, .bits=TYPE_NBITS64)),
|
||||
.default_val=FakeAST(None),
|
||||
.next=new(arg_t, .name="random", .type=random_num_type, .default_val=none_rng)));
|
||||
.next=new(arg_t, .name="random", .type=random_num_type, .default_val=FakeAST(None))));
|
||||
return CORD_all("Array$sample(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
|
||||
padded_item_size, ")");
|
||||
} else if (streq(call->name, "shuffle")) {
|
||||
type_t *random_int64_type = parse_type_string(env, "func(min,max:Int64->Int64)?");
|
||||
ast_t *none_rng = parse_expression("none:func(min,max:Int64->Int64)");
|
||||
EXPECT_POINTER("an", "array");
|
||||
arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=none_rng);
|
||||
arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=FakeAST(None));
|
||||
return CORD_all("Array$shuffle(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", padded_item_size, ")");
|
||||
} else if (streq(call->name, "shuffled")) {
|
||||
type_t *random_int64_type = parse_type_string(env, "func(min,max:Int64->Int64)?");
|
||||
ast_t *none_rng = parse_expression("none:func(min,max:Int64->Int64)");
|
||||
self = compile_to_pointer_depth(env, call->self, 0, false);
|
||||
arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=none_rng);
|
||||
arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=FakeAST(None));
|
||||
return CORD_all("Array$shuffled(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", padded_item_size, ")");
|
||||
} else if (streq(call->name, "random")) {
|
||||
type_t *random_int64_type = parse_type_string(env, "func(min,max:Int64->Int64)?");
|
||||
ast_t *none_rng = parse_expression("none:func(min,max:Int64->Int64)");
|
||||
self = compile_to_pointer_depth(env, call->self, 0, false);
|
||||
arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=none_rng);
|
||||
arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=FakeAST(None));
|
||||
return CORD_all("Array$random_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type(item_t), ")");
|
||||
} else if (streq(call->name, "sort") || streq(call->name, "sorted")) {
|
||||
if (streq(call->name, "sort"))
|
||||
@ -3290,10 +3315,16 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
|
||||
CORD condition_code;
|
||||
if (condition->tag == Declare) {
|
||||
type_t *condition_type = get_type(env, Match(condition, Declare)->value);
|
||||
auto decl = Match(condition, Declare);
|
||||
type_t *condition_type =
|
||||
decl->type ? parse_type_ast(env, decl->type)
|
||||
: get_type(env, Match(condition, Declare)->value);
|
||||
if (condition_type->tag != OptionalType)
|
||||
code_err(condition, "This `if var := ...:` declaration should be an optional type, not ", type_to_str(condition_type));
|
||||
|
||||
if (is_incomplete_type(condition_type))
|
||||
code_err(condition, "This type is incomplete!");
|
||||
|
||||
decl_code = compile_statement(env, condition);
|
||||
ast_t *var = Match(condition, Declare)->var;
|
||||
truthy_scope = fresh_scope(env);
|
||||
@ -3632,7 +3663,7 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
case Declare: case Assign: case UPDATE_CASES: case For: case While: case Repeat: case StructDef: case LangDef: case Extend:
|
||||
case EnumDef: case FunctionDef: case ConvertDef: case Skip: case Stop: case Pass: case Return: case DocTest: case PrintStatement:
|
||||
code_err(ast, "This is not a valid expression");
|
||||
default: case Unknown: code_err(ast, "Unknown AST");
|
||||
default: case Unknown: code_err(ast, "Unknown AST: ", ast_to_xml_str(ast));
|
||||
}
|
||||
}
|
||||
|
||||
|
26
src/parse.c
26
src/parse.c
@ -1685,19 +1685,19 @@ PARSER(parse_update) {
|
||||
if (!lhs) return NULL;
|
||||
spaces(&pos);
|
||||
ast_e op;
|
||||
if (match(&pos, "+=")) op = Plus;
|
||||
else if (match(&pos, "++=")) op = Concat;
|
||||
else if (match(&pos, "-=")) op = Minus;
|
||||
else if (match(&pos, "*=")) op = Multiply;
|
||||
else if (match(&pos, "/=")) op = Divide;
|
||||
else if (match(&pos, "^=")) op = Power;
|
||||
else if (match(&pos, "<<=")) op = LeftShift;
|
||||
else if (match(&pos, "<<<=")) op = UnsignedLeftShift;
|
||||
else if (match(&pos, ">>=")) op = RightShift;
|
||||
else if (match(&pos, ">>>=")) op = UnsignedRightShift;
|
||||
else if (match(&pos, "and=")) op = And;
|
||||
else if (match(&pos, "or=")) op = Or;
|
||||
else if (match(&pos, "xor=")) op = Xor;
|
||||
if (match(&pos, "+=")) op = PlusUpdate;
|
||||
else if (match(&pos, "++=")) op = ConcatUpdate;
|
||||
else if (match(&pos, "-=")) op = MinusUpdate;
|
||||
else if (match(&pos, "*=")) op = MultiplyUpdate;
|
||||
else if (match(&pos, "/=")) op = DivideUpdate;
|
||||
else if (match(&pos, "^=")) op = PowerUpdate;
|
||||
else if (match(&pos, "<<=")) op = LeftShiftUpdate;
|
||||
else if (match(&pos, "<<<=")) op = UnsignedLeftShiftUpdate;
|
||||
else if (match(&pos, ">>=")) op = RightShiftUpdate;
|
||||
else if (match(&pos, ">>>=")) op = UnsignedRightShiftUpdate;
|
||||
else if (match(&pos, "and=")) op = AndUpdate;
|
||||
else if (match(&pos, "or=")) op = OrUpdate;
|
||||
else if (match(&pos, "xor=")) op = XorUpdate;
|
||||
else return NULL;
|
||||
ast_t *rhs = expect(ctx, start, &pos, parse_extended_expr, "I expected an expression here");
|
||||
return new(ast_t, .file=ctx->file, .start=start, .end=pos, .tag=op, .__data.PlusUpdate.lhs=lhs, .__data.PlusUpdate.rhs=rhs);
|
||||
|
@ -1163,6 +1163,26 @@ type_t *get_type(env_t *env, ast_t *ast)
|
||||
code_err(binop.rhs, "I only know how to do bit shifting by integer amounts, not ", type_to_str(rhs_t));
|
||||
}
|
||||
|
||||
if (is_numeric_type(lhs_t) && binop.rhs->tag == Int) {
|
||||
return lhs_t;
|
||||
} else if (is_numeric_type(rhs_t) && binop.lhs->tag == Int) {
|
||||
return rhs_t;
|
||||
} else {
|
||||
switch (compare_precision(lhs_t, rhs_t)) {
|
||||
case NUM_PRECISION_LESS: return rhs_t;
|
||||
case NUM_PRECISION_MORE: return lhs_t;
|
||||
case NUM_PRECISION_EQUAL: return lhs_t;
|
||||
default: {
|
||||
if (can_compile_to_type(env, binop.rhs, lhs_t)) {
|
||||
return lhs_t;
|
||||
} else if (can_compile_to_type(env, binop.lhs, rhs_t)) {
|
||||
return rhs_t;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type_t *overall_t = (can_promote(rhs_t, lhs_t) ? lhs_t : (can_promote(lhs_t, rhs_t) ? rhs_t : NULL));
|
||||
if (ast->tag == Multiply || ast->tag == Divide) {
|
||||
binding_t *b = is_numeric_type(lhs_t) ? get_metamethod_binding(env, ast->tag, binop.lhs, binop.rhs, lhs_t)
|
||||
@ -1588,9 +1608,11 @@ PUREFUNC bool is_constant(env_t *env, ast_t *ast)
|
||||
|
||||
PUREFUNC bool can_compile_to_type(env_t *env, ast_t *ast, type_t *needed)
|
||||
{
|
||||
if (needed->tag == OptionalType && ast->tag == None) {
|
||||
if (is_incomplete_type(needed))
|
||||
return false;
|
||||
|
||||
if (needed->tag == OptionalType && ast->tag == None)
|
||||
return true;
|
||||
}
|
||||
|
||||
needed = non_optional(needed);
|
||||
if (needed->tag == ArrayType && ast->tag == Array) {
|
||||
|
@ -111,6 +111,8 @@ PUREFUNC const char *get_type_name(type_t *t)
|
||||
bool type_eq(type_t *a, type_t *b)
|
||||
{
|
||||
if (a == b) return true;
|
||||
if (!a && !b) return true;
|
||||
if (!a || !b) return false;
|
||||
if (a->tag != b->tag) return false;
|
||||
return (CORD_cmp(type_to_cord(a), type_to_cord(b)) == 0);
|
||||
}
|
||||
@ -208,10 +210,8 @@ static PUREFUNC INLINE double type_max_magnitude(type_t *t)
|
||||
|
||||
PUREFUNC precision_cmp_e compare_precision(type_t *a, type_t *b)
|
||||
{
|
||||
if (a->tag == OptionalType && Match(a, OptionalType)->type->tag == NumType)
|
||||
a = Match(a, OptionalType)->type;
|
||||
if (b->tag == OptionalType && Match(b, OptionalType)->type->tag == NumType)
|
||||
b = Match(b, OptionalType)->type;
|
||||
if (a == NULL || b == NULL)
|
||||
return NUM_PRECISION_INCOMPARABLE;
|
||||
|
||||
if (is_int_type(a) && b->tag == NumType)
|
||||
return NUM_PRECISION_LESS;
|
||||
|
@ -107,7 +107,7 @@ func main():
|
||||
sorted : @[Int] = @[]
|
||||
repeat:
|
||||
sorted:insert(heap:heap_pop() or stop)
|
||||
>> sorted == sorted:sorted()
|
||||
>> sorted[] == sorted:sorted()
|
||||
= yes
|
||||
for i in 10:
|
||||
heap:heap_push((i*13337) mod 37)
|
||||
@ -115,7 +115,7 @@ func main():
|
||||
sorted = @[]
|
||||
repeat:
|
||||
sorted:insert(heap:heap_pop() or stop)
|
||||
>> sorted == sorted:sorted()
|
||||
>> sorted[] == sorted:sorted()
|
||||
= yes
|
||||
|
||||
do:
|
||||
@ -162,10 +162,10 @@ func main():
|
||||
>> ["a", "b", "c"]:find("b")
|
||||
= 2?
|
||||
>> ["a", "b", "c"]:find("XXX")
|
||||
= none:Int
|
||||
= none
|
||||
|
||||
>> [10, 20]:first(func(i:&Int): i:is_prime())
|
||||
= none:Int
|
||||
= none
|
||||
>> [4, 5, 6]:first(func(i:&Int): i:is_prime())
|
||||
= 2?
|
||||
|
||||
@ -183,4 +183,4 @@ func main():
|
||||
>> nums
|
||||
= &[]
|
||||
>> nums:pop()
|
||||
= none:Int
|
||||
= none
|
||||
|
@ -4,7 +4,7 @@ struct Pair(x:Text, y:Text)
|
||||
func pairwise(strs:[Text] -> func(->Pair?)):
|
||||
i := 1
|
||||
return func():
|
||||
if i + 1 > strs.length: return none:Pair
|
||||
if i + 1 > strs.length: return none
|
||||
i += 1
|
||||
return Pair(strs[i-1], strs[i])?
|
||||
|
||||
@ -12,7 +12,7 @@ func range(first:Int, last:Int -> func(->Int?)):
|
||||
i := first
|
||||
return func():
|
||||
if i > last:
|
||||
return none:Int
|
||||
return none
|
||||
i += 1
|
||||
return (i-1)?
|
||||
|
||||
|
@ -22,8 +22,8 @@ func main():
|
||||
>> Num.INF:isinf()
|
||||
= yes
|
||||
|
||||
>> nan := none : Num
|
||||
= none:Num
|
||||
>> nan : Num = none
|
||||
= none
|
||||
>> nan == nan
|
||||
= yes
|
||||
>> nan < nan
|
||||
@ -46,10 +46,10 @@ func main():
|
||||
= Int32(-1)
|
||||
|
||||
>> nan + 1
|
||||
= none:Num
|
||||
= none
|
||||
|
||||
>> 0./0.
|
||||
= none:Num
|
||||
= none
|
||||
|
||||
>> Num.PI:cos()!:near(-1)
|
||||
= yes
|
||||
|
@ -66,7 +66,8 @@ func main():
|
||||
= 5?
|
||||
|
||||
>> if no:
|
||||
none:Int
|
||||
x : Int? = none
|
||||
x
|
||||
else:
|
||||
5
|
||||
= 5?
|
||||
@ -80,7 +81,8 @@ func main():
|
||||
>> 5? or exit("Non-null is falsey")
|
||||
= 5
|
||||
|
||||
>> (none:Int) or -1
|
||||
>> none_int : Int? = none
|
||||
>> none_int or -1
|
||||
= -1
|
||||
|
||||
do:
|
||||
@ -88,7 +90,7 @@ func main():
|
||||
>> yep := maybe_int(yes)
|
||||
= 123?
|
||||
>> nope := maybe_int(no)
|
||||
= none:Int
|
||||
= none
|
||||
>> if yep:
|
||||
>> yep
|
||||
= 123
|
||||
@ -103,7 +105,7 @@ func main():
|
||||
>> yep := maybe_int64(yes)
|
||||
= Int64(123)?
|
||||
>> nope := maybe_int64(no)
|
||||
= none:Int64
|
||||
= none
|
||||
>> if yep:
|
||||
>> yep
|
||||
= Int64(123)
|
||||
@ -118,7 +120,7 @@ func main():
|
||||
>> yep := maybe_array(yes)
|
||||
= [10, 20, 30]?
|
||||
>> nope := maybe_array(no)
|
||||
= none:[Int]
|
||||
= none
|
||||
>> if yep:
|
||||
>> yep
|
||||
= [10, 20, 30]
|
||||
@ -133,7 +135,7 @@ func main():
|
||||
>> yep := maybe_bool(yes)
|
||||
= no?
|
||||
>> nope := maybe_bool(no)
|
||||
= none:Bool
|
||||
= none
|
||||
>> if yep:
|
||||
>> yep
|
||||
= no
|
||||
@ -148,7 +150,7 @@ func main():
|
||||
>> yep := maybe_text(yes)
|
||||
= "Hello"?
|
||||
>> nope := maybe_text(no)
|
||||
= none:Text
|
||||
= none
|
||||
>> if yep:
|
||||
>> yep
|
||||
= "Hello"
|
||||
@ -163,7 +165,7 @@ func main():
|
||||
>> yep := maybe_num(yes)
|
||||
= 12.3?
|
||||
>> nope := maybe_num(no)
|
||||
= none:Num
|
||||
= none
|
||||
>> if yep:
|
||||
>> yep
|
||||
= 12.3
|
||||
@ -178,7 +180,7 @@ func main():
|
||||
# >> yep := maybe_lambda(yes)
|
||||
# = func() [optionals.tm:54] : func()?
|
||||
>> nope := maybe_lambda(no)
|
||||
= none : func()
|
||||
= none
|
||||
# >> if yep:
|
||||
# >> yep
|
||||
# = func() [optionals.tm:54]
|
||||
@ -193,7 +195,7 @@ func main():
|
||||
>> yep := Struct.maybe(yes)
|
||||
= Struct(x=123, y="hello")?
|
||||
>> nope := Struct.maybe(no)
|
||||
= none:Struct
|
||||
= none
|
||||
>> if yep:
|
||||
>> yep
|
||||
= Struct(x=123, y="hello")
|
||||
@ -208,7 +210,7 @@ func main():
|
||||
>> yep := Enum.maybe(yes)
|
||||
= Enum.Y(123)?
|
||||
>> nope := Enum.maybe(no)
|
||||
= none : Enum
|
||||
= none
|
||||
>> if yep:
|
||||
>> yep
|
||||
= Enum.Y(123)
|
||||
@ -223,7 +225,7 @@ func main():
|
||||
>> yep := maybe_c_string(yes)
|
||||
= CString("hi")?
|
||||
>> nope := maybe_c_string(no)
|
||||
= none : CString
|
||||
= none
|
||||
>> if yep:
|
||||
>> yep
|
||||
= CString("hi")
|
||||
@ -241,16 +243,15 @@ func main():
|
||||
= 123
|
||||
|
||||
# Test comparisons, hashing, equality:
|
||||
>> (none:Int == 5?)
|
||||
>> (none == 5?)
|
||||
= no
|
||||
>> (5? == 5?)
|
||||
= yes
|
||||
>> {none:Int, none:Int}
|
||||
= {none:Int}
|
||||
>> nones : {Int?} = {none, none}
|
||||
= {none}
|
||||
>> [5?, none:Int, none:Int, 6?]:sorted()
|
||||
= [none:Int, none:Int, 5, 6]
|
||||
>> also_nones : {Int?} = {none}
|
||||
>> nones == also_nones
|
||||
>> [5?, none, none, 6?]:sorted()
|
||||
= [none, none, 5, 6]
|
||||
|
||||
do:
|
||||
>> value := if var := 5?:
|
||||
@ -260,7 +261,7 @@ func main():
|
||||
= 5
|
||||
|
||||
do:
|
||||
>> value := if var := none:Int:
|
||||
>> value := if var : Int? = none:
|
||||
var
|
||||
else:
|
||||
0
|
||||
@ -274,7 +275,7 @@ func main():
|
||||
>> opt
|
||||
|
||||
do:
|
||||
>> opt := none:Int
|
||||
>> opt : Int? = none
|
||||
>> if opt:
|
||||
>> opt
|
||||
else:
|
||||
@ -283,7 +284,8 @@ func main():
|
||||
>> not 5?
|
||||
= no
|
||||
|
||||
>> not none:Int
|
||||
>> nah : Int? = none
|
||||
>> not nah
|
||||
= yes
|
||||
|
||||
>> [Struct(5,"A")?, Struct(6,"B"), Struct(7,"C")]
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
struct Foo(name:Text, next=none:@Foo)
|
||||
struct Foo(name:Text, next:@Foo?=none)
|
||||
|
||||
enum MyEnum(Zero, One(x:Int), Two(x:Num, y:Text))
|
||||
|
||||
@ -82,7 +82,7 @@ func main():
|
||||
= yes
|
||||
|
||||
do:
|
||||
>> obj := none:Num
|
||||
>> obj : Num? = none
|
||||
>> bytes := obj:serialized()
|
||||
>> deserialize(bytes -> Num?) == obj
|
||||
= yes
|
||||
|
@ -2,11 +2,11 @@
|
||||
struct Single(x:Int)
|
||||
struct Pair(x,y:Int)
|
||||
struct Mixed(x:Int, text:Text)
|
||||
struct LinkedList(x:Int, next=none:@LinkedList)
|
||||
struct LinkedList(x:Int, next:@LinkedList?=none)
|
||||
struct Password(text:Text; secret)
|
||||
|
||||
struct CorecursiveA(other:@CorecursiveB?)
|
||||
struct CorecursiveB(other=none:@CorecursiveA)
|
||||
struct CorecursiveB(other:@CorecursiveA?=none)
|
||||
|
||||
func test_literals():
|
||||
>> Single(123)
|
||||
|
@ -7,7 +7,7 @@ func main():
|
||||
>> t["two"]
|
||||
= 2?
|
||||
>> t["???"]
|
||||
= none:Int
|
||||
= none
|
||||
>> t["one"]!
|
||||
= 1
|
||||
>> t["???"] or -1
|
||||
@ -37,7 +37,7 @@ func main():
|
||||
>> t2["three"]
|
||||
= 3?
|
||||
>> t2["???"]
|
||||
= none:Int
|
||||
= none
|
||||
|
||||
>> t2.length
|
||||
= 1
|
||||
|
@ -59,7 +59,7 @@ func main():
|
||||
>> Text.from_bytes([0x6D, 0xC3, 0xA9, 0x6C, 0x69, 0x65])!
|
||||
= "Amélie"
|
||||
>> Text.from_bytes([Byte(0xFF)])
|
||||
= none:Text
|
||||
= none
|
||||
|
||||
amelie2 := "Am$(\U65\U301)lie"
|
||||
>> amelie2:split()
|
||||
|
Loading…
Reference in New Issue
Block a user