mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
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:
committed by
GitHub
parent
fefce25081
commit
25bccf4883
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)!!;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
},
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user