New faults and syntax (#2034)

- Remove `[?]` syntax.
- Change `int!` to `int?` syntax.
- New `fault` declarations.
- Enum associated values can reference the calling enum.
This commit is contained in:
Christoffer Lerno
2025-03-10 00:11:35 +01:00
committed by GitHub
parent fefce25081
commit 25bccf4883
392 changed files with 3129 additions and 3658 deletions

View File

@@ -1,11 +1,10 @@
module base64;
fault INVALID_CHARACTER;
// Based on the C2 version.
fault DecodingError
{
INVALID_CHARACTER
}
const char[64] LUT_ENC = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
@@ -76,7 +75,7 @@ fn void encode(char[] in, char *out)
}
fn int! decode(String in, char* out, int* invalid_char_index = null)
fn int? decode(String in, char* out, int* invalid_char_index = null)
{
int j = 0;
@@ -89,7 +88,7 @@ fn int! decode(String in, char* out, int* invalid_char_index = null)
if (c == ERR)
{
if (invalid_char_index) *invalid_char_index = i;
return DecodingError.INVALID_CHARACTER?;
return INVALID_CHARACTER?;
}
@@ -127,7 +126,7 @@ fn void main()
encode(helloworld[0..12], &buffer);
printf("Result: %s\n", &buffer);
char *to_decode = "aGVsbG8gd29ybGRcMA==";
char[?] result = b64"aGVsbG8gd29ybGRcMA==";
char[*] result = b64"aGVsbG8gd29ybGRcMA==";
decode((String)to_decode[0..19], &buffer)!!;
printf("Result: %s\n", &buffer);
printf("Result direct: %.*s\n", 13, &result);

View File

@@ -4,18 +4,15 @@ import std::io;
const BF_MEM = 30000;
char[BF_MEM] memory;
fault InterpretError
{
INTEPRET_FAILED
}
fault INTEPRET_FAILED;
fn void! print_error_type_at(usz pos, String err)
fn void? print_error_type_at(usz pos, String err)
{
io::printfn("Error at %s: %s", pos, err);
return InterpretError.INTEPRET_FAILED?;
return INTEPRET_FAILED?;
}
fn void! brainf(String program)
fn void? brainf(String program)
{
usz sp = 0;
usz mem = 0;

View File

@@ -4,15 +4,8 @@ import libc;
import std::io;
import std::collections::maybe;
fault TitleResult
{
TITLE_MISSING
}
fault ReadError
{
BAD_READ,
}
fault TITLE_MISSING;
fault BAD_READ;
struct Doc
{
@@ -30,14 +23,14 @@ struct Summary
bool ok;
}
fn void! Summary.print(Summary* s, OutStream out)
fn void? Summary.print(Summary* s, OutStream out)
{
io::fprintf(out, "Summary({ .title = %s, .ok = %s})", s.title.get() ?? "missing", s.ok)!;
}
fn Doc! read_doc(String url)
fn Doc? read_doc(String url)
{
if (url.contains("fail")) return ReadError.BAD_READ?;
if (url.contains("fail")) return BAD_READ?;
if (url.contains("head-missing")) return { };
if (url.contains("title-missing")) return { .head = maybe::value{Head}({}) };
if (url.contains("title-empty")) return { .head = maybe::value{Head}({ .title = maybe::value{String}("")}) };
@@ -57,14 +50,14 @@ fn Summary read_and_build_summary(String url)
return build_summary(read_doc(url)) ?? {};
}
fn bool! is_title_non_empty(Doc doc)
fn bool? is_title_non_empty(Doc doc)
{
String! title = doc.head.get().title.get();
if (catch title) return TitleResult.TITLE_MISSING?;
String? title = doc.head.get().title.get();
if (catch title) return TITLE_MISSING?;
return title.len > 0;
}
fn bool! read_whether_title_non_empty(String url)
fn bool? read_whether_title_non_empty(String url)
{
return is_title_non_empty(read_doc(url));
}
@@ -90,7 +83,7 @@ fn void main()
summary.print(out)!!;
io::fprintn(out, "")!!;
io::fprintf(out, " Title: %s\n", summary.title.get() ?? "")!!;
bool! has_title = read_whether_title_non_empty(url);
bool? has_title = read_whether_title_non_empty(url);
// This looks a bit less than elegant, but as you see it's mostly due to having to
// use printf here.
io::fprintf(out, " Has title: %s vs %s\n", bool_to_string(has_title) ?? (@catch(has_title)).nameof, has_title ?? false)!!;

View File

@@ -6,12 +6,9 @@ struct Resource
String name;
}
fault Error
{
WELCOME_TO_YOUR_DOOM
}
fault WELCOME_TO_YOUR_DOOM;
fn Resource! resource_init(String name)
fn Resource? resource_init(String name)
{
io::printfn("open %s", name);
return { name };
@@ -19,7 +16,7 @@ fn Resource! resource_init(String name)
fn void Resource.deinit(Resource this) => io::printfn("close %s", this.name);
macro void! @open_with(String name; @body(Resource resource))
macro void? @open_with(String name; @body(Resource resource))
{
Resource resource = resource_init(name)!;
defer
@@ -30,7 +27,7 @@ macro void! @open_with(String name; @body(Resource resource))
@body(resource);
}
fn Resource! prep_out(String out_name, String[] prep_names)
fn Resource? prep_out(String out_name, String[] prep_names)
{
Resource writer = resource_init(out_name)!; // Rethrow the optional result
defer catch writer.deinit();
@@ -39,7 +36,7 @@ fn Resource! prep_out(String out_name, String[] prep_names)
@open_with(name; Resource reader)
{
io::printfn("use %s", reader.name);
// if (true) return Error.WELCOME_TO_YOUR_DOOM?;
// if (true) return WELCOME_TO_YOUR_DOOM?;
}!;
}
return writer;

View File

@@ -11,27 +11,23 @@ struct Game
int high;
}
fault InputResult
{
NOT_AN_INT,
FAILED_TO_READ,
}
fault NOT_AN_INT, FAILED_TO_READ;
int err_count = 0;
fn int! ask_guess(int high)
fn int? ask_guess(int high)
{
io::printf("Guess a number between 1 and %d: ", high);
String text = io::treadline() ?? InputResult.FAILED_TO_READ?!;
return text.to_int() ?? InputResult.NOT_AN_INT?;
String text = io::treadline() ?? FAILED_TO_READ?!;
return text.to_int() ?? NOT_AN_INT?;
}
fn int! ask_guess_multi(int high)
fn int? ask_guess_multi(int high)
{
while (true)
{
int! result = ask_guess(high);
if (@catch(result) == InputResult.NOT_AN_INT)
int? result = ask_guess(high);
if (@catch(result) == NOT_AN_INT)
{
io::printn("I didn't understand that.");
err_count++;
@@ -41,7 +37,7 @@ fn int! ask_guess_multi(int high)
}
}
fn void! Game.play(Game *game)
fn void? Game.play(Game *game)
{
while (!game.done)
{

View File

@@ -4,7 +4,7 @@ struct Foo(Printable)
int a;
}
fn usz! Foo.to_format(&self, Formatter* f) @dynamic
fn usz? Foo.to_format(&self, Formatter* f) @dynamic
{
return f.printf("Foo[%d]", self.a);
}

View File

@@ -1,10 +1,8 @@
module std::container::map{Key, Type};
import std::core::builtin;
import std::io;
fault MapResult
{
KEY_NOT_FOUND
}
fault KEY_NOT_FOUND;
struct Entry
{
@@ -33,22 +31,22 @@ fn void Map.init(Map *map, uint capacity = 128)
map.mod = capacity - 1;
}
fn Type! Map.valueForKey(Map *map, Key key)
fn Type? Map.valueForKey(Map *map, Key key)
{
if (!map.map) return MapResult.KEY_NOT_FOUND?;
if (!map.map) return KEY_NOT_FOUND?;
uint hash = key.hash();
usz pos = hash & map.mod;
Entry* entry = &map.map[pos];
if (!entry) return MapResult.KEY_NOT_FOUND?;
if (!entry) return KEY_NOT_FOUND?;
while (entry)
{
if (entry.hash == hash && entry.key == key) return entry.value;
entry = entry.next;
}
return MapResult.KEY_NOT_FOUND?;
return KEY_NOT_FOUND?;
}
fn Type! Map.set(Map *map, Key key, Type value) @maydiscard
fn Type? Map.set(Map *map, Key key, Type value) @maydiscard
{
if (!map.map)
{
@@ -67,7 +65,7 @@ fn Type! Map.set(Map *map, Key key, Type value) @maydiscard
entry.value = value;
entry.hash = hash;
entry.key = key;
return MapResult.KEY_NOT_FOUND?;
return KEY_NOT_FOUND?;
}
if (entry.hash == hash && entry.key == key)
{
@@ -87,7 +85,7 @@ fn Type! Map.set(Map *map, Key key, Type value) @maydiscard
new.next = null;
new.used = true;
entry.next = new;
return MapResult.KEY_NOT_FOUND?;
return KEY_NOT_FOUND?;
}
}

View File

@@ -81,7 +81,7 @@ fn void offset_momentum(Planet[] bodies)
bodies[0].vz = - pz / SOLAR_MASS;
}
Planet[?] planet_bodies = {
Planet[*] planet_bodies = {
{ /* sun */
0, 0, 0, 0, 0, 0, SOLAR_MASS
},

View File

@@ -2,10 +2,7 @@ module test;
import std::io;
import libc;
fault TokenResult
{
NO_MORE_TOKENS
}
fault NO_MORE_TOKENS;
// While we could have written this with libc
@@ -36,7 +33,7 @@ fn void main(String[] args)
val = add ? val + i : val - i;
// Read an optional token.
String! op = read_next(&numbers);
String? op = read_next(&numbers);
// If it's an error, then we're done.
if (catch op) break;
@@ -56,7 +53,7 @@ fn void main(String[] args)
io::printfn("%d", val);
}
fn String! read_next(String* remaining)
fn String? read_next(String* remaining)
{
while (remaining.len > 0 && (*remaining)[0] == ' ')
{
@@ -77,7 +74,7 @@ fn String! read_next(String* remaining)
}
// If it's a zero length token, return an optional result.
if (!len) return TokenResult.NO_MORE_TOKENS?;
if (!len) return NO_MORE_TOKENS?;
// Otherwise create a slice from the pointer start and length.
return (String)ptr_start[:len];

View File

@@ -76,7 +76,7 @@ fn void init_game()
counter_tail = 1;
allow_move = false;
snake_direction = SnakeDirection.RIGHT;
snake_direction = RIGHT;
offset.x = SCREEN_WIDTH % SQUARE_SIZE;
offset.y = SCREEN_HEIGHT % SQUARE_SIZE;

View File

@@ -257,7 +257,7 @@ fn void update_game()
{
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
{
if (grid[i][j] == GridSquare.FULL)
if (grid[i][j] == FULL)
{
game_over = true;
}
@@ -404,7 +404,7 @@ fn bool create_piece()
{
for (int j = 0; j < 4; j++)
{
if (piece[i - (int)piece_position_x][j] == GridSquare.MOVING) grid[i][j] = MOVING;
if (piece[i - (int)piece_position_x][j] == MOVING) grid[i][j] = MOVING;
}
}
@@ -474,7 +474,7 @@ fn void resolve_falling_movement(bool* detection_ref, bool* piece_active_ref)
{
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
{
if (grid[i][j] == GridSquare.MOVING)
if (grid[i][j] == MOVING)
{
grid[i][j] = FULL;
*detection_ref = false;
@@ -489,7 +489,7 @@ fn void resolve_falling_movement(bool* detection_ref, bool* piece_active_ref)
{
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
{
if (grid[i][j] == GridSquare.MOVING)
if (grid[i][j] == MOVING)
{
grid[i][j+1] = MOVING;
grid[i][j] = EMPTY;
@@ -513,10 +513,10 @@ fn bool resolve_lateral_movement()
{
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
{
if (grid[i][j] == GridSquare.MOVING)
if (grid[i][j] == MOVING)
{
// Check if we are touching the left wall or we have a full square at the left
if ((i-1 == 0) || (grid[i-1][j] == GridSquare.FULL)) collision = true;
if ((i-1 == 0) || (grid[i-1][j] == FULL)) collision = true;
}
}
}

View File

@@ -1,15 +1,12 @@
module test;
import libc;
fault TestErr
{
NOPE
}
fault NOPE;
fn int! eventually_succeed()
fn int? eventually_succeed()
{
static int i = 0;
if (i++ < 3) return TestErr.NOPE?;
if (i++ < 3) return NOPE?;
return i * 3;
}
@@ -19,7 +16,7 @@ macro @retry(#function, int retries = 3)
anyfault e;
do
{
$Type! result = #function;
$Type? result = #function;
if (catch err = result)
{
e = err;
@@ -32,7 +29,7 @@ macro @retry(#function, int retries = 3)
fn void main()
{
int! result = @retry(eventually_succeed());
int? result = @retry(eventually_succeed());
if (try result)
{
libc::printf("Got result: %d\n", result);

View File

@@ -5,7 +5,7 @@ struct Foo(Printable)
int a;
}
fn usz! Foo.to_format(&self, Formatter* f) @dynamic
fn usz? Foo.to_format(&self, Formatter* f) @dynamic
{
return f.printf("Foo[%d]", self.a);
}

View File

@@ -578,7 +578,7 @@ type
optional_type
: type
| type '!'
| type '?'
;
local_decl_after_type

View File

@@ -3,7 +3,7 @@ import std::io;
import std::collections::map;
import std::os;
fn void! test2()
fn void? test2()
{
builtin::print_backtrace("hello", 1);
}