diff --git a/README.md b/README.md index f20c388d9..d35f90de1 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ There are some small work being done on the parser here, but most of the structu - Improved integration with C. - Generic macros. +- Update of error system #### What's working? diff --git a/resources/examples/acornvm/avm_array.c3 b/resources/examples/acornvm/avm_array.c3 index 64c9c7998..80670eec5 100644 --- a/resources/examples/acornvm/avm_array.c3 +++ b/resources/examples/acornvm/avm_array.c3 @@ -8,15 +8,12 @@ module acorn::arr; * See Copyright Notice in avm.h */ -error SearchError -{ - NOT_FOUND -} + /* Return a new Array, allocating len slots for Values. */ func Value new(Value th, Value *dest, Value type, AuintIdx len) { // Create an array object - ArrInfo* val = @cast(mem::new(th, ArrEnc, sizeof(ArrInfo), ArrInfo*); + ArrInfo* val = cast(mem::new(th, ArrEnc, sizeof(ArrInfo), ArrInfo*); val.flags1 = 0; // Initialize Flags1 flags val.type = type; val.avail = len; @@ -30,7 +27,7 @@ func Value new(Value th, Value *dest, Value type, AuintIdx len) func Value newClosure(Value *th, Value *dest, Value type, AuintIdx len) { // Create an array object - ArrInfo* val = @cast(mem::new(th, ArrEnc, sizeof(ArrInfo), ArrInfo*); + ArrInfo* val = cast(mem::new(th, ArrEnc, sizeof(ArrInfo), ArrInfo*); val.flags1 = TypeClo; // Initialize Flags1 flags val.type = type; val.avail = len; diff --git a/resources/examples/acornvm/avm_memory.c3 b/resources/examples/acornvm/avm_memory.c3 index 9c84a145b..184a46608 100644 --- a/resources/examples/acornvm/avm_memory.c3 +++ b/resources/examples/acornvm/avm_memory.c3 @@ -14,18 +14,16 @@ module acorn::mem; * It returns the location of the new block or NULL (if freed). */ func void* gcrealloc(Value th, void *block, Auint osize, Auint nsize) { - Value newblock; - // Check consistency of block and osize (both must be null or specified) Auint realosize = block ? osize : 0; assert((realosize == 0) == (block == nil)); // Allocate/free/resize the memory block - newblock = @cast(frealloc(block, nsize), Value); + Value newblock = cast(frealloc(block, nsize), Value); $if (defined(MEMORYLOG)) { - if (nsize==0) + if (nsize == 0) { vmLog("Freeing %p size %d", block, osize); } @@ -40,7 +38,7 @@ func void* gcrealloc(Value th, void *block, Auint osize, Auint nsize) { // realloc cannot fail when shrinking a block gcfull(th, 1); // try to free some memory... - newblock = @cast(frealloc(block, nsize), Value); // try again + newblock = cast(frealloc(block, nsize), Value); // try again if (newblock == nil) { logSevere("Out of memory trying allocate or grow a memory block."); @@ -57,7 +55,7 @@ func void* gcreallocv(Value th, void* block, Auint osize, Auint nsize, Auint esi { // Ensure we are not asking for more memory than available in address space // If we do not do this, calculating the needed memory will overflow - if (nsize+1 > ~((Auint)0) / esize) + if (nsize + 1 > ~(cast(0, Auint)) / esize) { logSevere("Out of memory trying to ask for more memory than address space has."); } @@ -72,20 +70,17 @@ func void* gcreallocv(Value th, void* block, Auint osize, Auint nsize, Auint esi **/ func void* frealloc(void* block, Auint size) { - if (size == 0) + if (!size) { free(block); return NULL; } - else - { - return realloc(block, size); - } + return realloc(block, size); } macro type($type) @amalloc($type) { - return @cast(mem_frealloc(NULL, sizeof($type)), $type); + return cast(mem_frealloc(NULL, sizeof($type)), $type); } @@ -103,7 +98,7 @@ MemInfo* new(Value th, int enc, Auint sz) gccheck(th); // Incremental GC before memory allocation events } vm(th).gcnbrnew++; - MemInfo* o = (MemInfo*) (char *) gcrealloc(th, nil, 0, sz); + MemInfo* o = cast(gcrealloc(th, nil, 0, sz), MemInfo *); o.marked = vm(th).currentwhite & WHITEBITS; o.enctyp = enc; @@ -132,7 +127,7 @@ func MemInfo* newnolink(Value th, int enc, Auint sz) } vm(th)->gcnbrnew++; // Allocate and initialize - MemInfo *o = (MemInfo*) (char *) gcrealloc(th, NULL, 0, sz); + MemInfo *o = cast(gcrealloc(th, NULL, 0, sz), MemInfo*); o.marked = vm(th)->currentwhite & WHITEBITS; o.enctyp = enc; return o; @@ -142,7 +137,7 @@ func MemInfo* newnolink(Value th, int enc, Auint sz) func void growaux_(Value th, void *block, AuintIdx *size, AuintIdx size_elems, AuintIdx limit) { void* newblock; - AuintIdx newsize; + AuintIdx newsize = void; // cannot double it? if (*size >= limit / 2) { diff --git a/resources/examples/base64.c3 b/resources/examples/base64.c3 index a40c9b1f8..bf34ff049 100644 --- a/resources/examples/base64.c3 +++ b/resources/examples/base64.c3 @@ -82,7 +82,13 @@ public func void encode(byte[] in, string *out) } } -public func int decode(string in, byte[] out) throws Base64Error +error InvalidCharacter +{ + int index; + char c; +} + +public func int! decode(string in, byte[] out) { int j = 0; @@ -92,9 +98,9 @@ public func int decode(string in, byte[] out) throws Base64Error if (value == PAD) return j; - if (value < FIRST || in[i] > LAST) throw INVALID_CHARACTER; + if (value < FIRST || in[i] > LAST) return! InvalidCharacter(i, value); byte c = LUT_DEC[in[i] - FIRST); - if (c == ERR) throw INVALID_CHARACTER; + if (c == ERR) return! InvalidCharacter(i, value); switch (i % 4) { diff --git a/resources/examples/http.c3 b/resources/examples/http.c3 index 4f5e96360..5a34b6ffc 100644 --- a/resources/examples/http.c3 +++ b/resources/examples/http.c3 @@ -4,9 +4,7 @@ func int main(void) { Curl curl; - try curl.init(); - - catch (error e) + catch (e = curl.init()) { printf("Failed to create new curl: %s\n", e.message); exit(FAILURE); @@ -15,9 +13,7 @@ func int main(void) curl.setopt(URL, "http://www.rosettacode.org/"); curl.setopt(FOLLOWLOCATION, 1); - try curl.perform(); - - catch (CurlError e) + catch (e = curl.perform()) { printf("Error making request: %s\n", e.message); exit(FAILURE); diff --git a/resources/examples/madlibs.c3 b/resources/examples/madlibs.c3 index 63ce93359..9e1e272d0 100644 --- a/resources/examples/madlibs.c3 +++ b/resources/examples/madlibs.c3 @@ -7,7 +7,7 @@ func void main() string story = ""; while (1) { - try string line = stdin.readln().strip(); + string line = stdin.readln().strip() else ""; if (!line.size) break; story += line + "\n"; } @@ -21,14 +21,14 @@ func void main() { string s = match.string; printf("Enter a value for '%s': ", s.slice(1, s.size - 2)); - try string word = strin.readln().strip(); + string! word = strin.readln().strip(); + catch (word) + { + // Exit on error. + return; + } story = story.replace(s, word); } println("\nThe story becomes:\n%s\n", story); - - catch (error e) - { - // Ignore any error - } } \ No newline at end of file diff --git a/resources/examples/toml_parser_c2.c3 b/resources/examples/toml_parser_c2.c3 index a5b94a240..801ee0ff5 100644 --- a/resources/examples/toml_parser_c2.c3 +++ b/resources/examples/toml_parser_c2.c3 @@ -18,7 +18,7 @@ const uint MaxDepth = 8; $if (DEBUG_NODES): -func void Blocks.dump(const Blocks* b) +func void Blocks.dump(Blocks* b) { printf("Nodes (%u/%u) (%u bytes)\n", b.nodeCount, b.maxNodes, b.nodeCount * sizeof(Node)); for (uint i = 0; i < b.nodeCount; i++) @@ -170,7 +170,7 @@ func uint addType(uint raw, ValueType t) @(inline) return raw | (t << ValueTypeOffset); } -func void Parser.parseKeyValue(Parser* p) throws ParseError +func void! Parser.parseKeyValue(Parser* p) { //printf("parseKeyValue()\n"); char[MaxText] key; @@ -193,7 +193,7 @@ func void Parser.parseKeyValue(Parser* p) throws ParseError p.lastChild[p.numParents] = node; } -func void Parser.parseTable(Parser* p) throws ParseError +func void! Parser.parseTable(Parser* p) { //printf("parseTable()\n"); try p.consumeToken(); @@ -348,13 +348,10 @@ func u32 Parser.addTable(Parser* p, const char* name, u32 depth, bool isTop, Nod return 0; } -func Location Parser.consumeToken(Parser* p) { +func Location! Parser.consumeToken(Parser* p) +{ Location prev = p.tok.loc; - p.tokenizer.lex(&p.tok); - if (p.tok.is(TokenKind.Error)) { - strcpy(p.errorMsg, p.tok.text); - longjmp(p.jump_err, 1); - } + try p.tokenizer.lex(&p.tok); return prev; } @@ -362,16 +359,19 @@ func Token* Parser.nextToken(Parser* p) { return p.tokenizer.lookahead(); } -func void Parser.expectAndConsume(Parser* p, TokenKind k) { - if (p.tok.isNot(k)) { +func void! Parser.expectAndConsume(Parser* p, TokenKind k) { + if (p.tok.isNot(k)) + { sprintf(p.errorMsg, "expected '%s' at %s", token2str(k), p.tok.loc.str()); longjmp(p.jump_err, 1); } - p.consumeToken(); + try p.consumeToken(); } -func void Parser.expect(Parser* p, TokenKind k) { - if (p.tok.isNot(k)) { +func void Parser.expect(Parser* p, TokenKind k) +{ + if (p.tok.isNot(k)) + { sprintf(p.errorMsg, "expected '%s' at %s", token2str(k), p.tok.loc.str()); longjmp(p.jump_err, 1); } @@ -385,7 +385,7 @@ public struct TomlReader @opaque Blocks* blocks; } -public func TomlReader* TomlReader.create() +public func TomlReader* new_toml() { TomlReader* r = @malloc(TomlReader); r.blocks = @malloc(Blocks); @@ -405,7 +405,9 @@ public func const char* TomlReader.getMsg(const TomlReader* r) return r.message; } -public func void TomlReader.parse(TomlReader* r, string filename) throws ParseError, FileError +error EmptyFileError; + +public func void! TomlReader.parse(TomlReader* r, string filename) { Reader file; @@ -416,7 +418,7 @@ public func void TomlReader.parse(TomlReader* r, string filename) throws ParseEr if (file.isEmpty()) { printf("file %s is empty\n", filename); - throw ParseError.EMPTY_FILE; + raise EmptyFileError; } Parser parser; @@ -431,7 +433,8 @@ $endif // -------------------------------------------------------------- // Getters+iters -func const Node* Reader.findNode(const Reader* r, const char* key) { +func const Node* Reader.findNode(const Reader* r, const char* key) +{ char[MaxText] name; const char* cp = key; const char* start = cp; diff --git a/resources/examples/toml_tokenizer_c2.c3 b/resources/examples/toml_tokenizer_c2.c3 index d5425baeb..b61e35221 100644 --- a/resources/examples/toml_tokenizer_c2.c3 +++ b/resources/examples/toml_tokenizer_c2.c3 @@ -103,7 +103,13 @@ func void Tokenizer.init(Tokenizer* t, char* input) t.text[0] = 0; } -func void Tokenizer.lex(Tokenizer* t, Token* result) +error LexedEOF; +error LexError +{ + string error_message; +} + +func void! Tokenizer.lex(Tokenizer* t, Token* result) { if (t.haveNext) { @@ -118,16 +124,12 @@ func void Tokenizer.lex(Tokenizer* t, Token* result) switch (t.current[0]) { case 0: - result.loc = t.loc; - result.kind = TokenKind.EOF; - return; + return! LexedEOF(); case '#': if (t.loc.column != 1) { sprintf(t.text, "unexpected '#' after line start at %s", t.loc.str()); - result.kind = TokenKind.ERROR; - result.text = t.text; - return; + return! LexError(t.text); } t.parseComment(); case ' ': @@ -214,18 +216,16 @@ func void Tokenizer.lex(Tokenizer* t, Token* result) return; } sprintf(t.text, "unexpected char '%c' at %s", t.current[0], t.loc.str()); - result.kind = ERROR; - result.text = t.text; - return; + return LexError(t.text); } } } -func Token* Tokenizer.lookahead(Tokenizer* t) +func Token*! Tokenizer.lookahead(Tokenizer* t) { if (!t.haveNext) { - t.lex(&t.nextToken); + try t.lex(&t.nextToken); t.haveNext = true; } return &t.nextToken; @@ -277,7 +277,7 @@ func void Tokenizer.parseText(Tokenizer* t, Token* result) t.advance(1); } -func void Tokenizer.parseMultiText(Tokenizer* t, Token* result) +func void! Tokenizer.parseMultiText(Tokenizer* t, Token* result) { t.advance(3); if (t.current[0] == '\n') @@ -293,9 +293,7 @@ func void Tokenizer.parseMultiText(Tokenizer* t, Token* result) if (t.current[0] == 0) { sprintf(t.text, "missing end \"\"\" %s", t.loc.str()); - result.kind = TokenKind.Error; - result.text = t.text; - return; + return! LexError(t.text); } if (t.current[0] == '\n') { @@ -310,7 +308,7 @@ func void Tokenizer.parseMultiText(Tokenizer* t, Token* result) t.current++; } - uint len = cast(uint, t.current - start); + uint len = uint(t.current - start); // assert(len < MaxText); memcpy(t.text, start, len); t.text[len] = 0; @@ -325,7 +323,7 @@ func void Tokenizer.parseNumber(Tokenizer* t, Token* result) // handle hexadecimal/ocal/binary number // handle '_', like 1_000_000 - uint number = cast(atoi(t.current), uint); + uint number = uint(atoi(t.current)); result.kind = TokenKind.Number; result.number = number; while (t.current[0] && isdigit(t.current[0])) diff --git a/resources/grammar.y b/resources/grammar.y index e8c011b43..19d81cf8f 100644 --- a/resources/grammar.y +++ b/resources/grammar.y @@ -25,7 +25,7 @@ void yyerror(char *s); %token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN %token FUNC ERROR MACRO GENERIC CTIF CTELIF CTENDIF CTELSE CTSWITCH CTCASE CTDEFAULT CTFOR -%token THROWS THROW TRY CATCH SCOPE PUBLIC DEFER ATTRIBUTE IN +%token TRY CATCH SCOPE PUBLIC DEFER ATTRIBUTE IN %token FN_BLOCK_START FN_BLOCK_END %token AUTO @@ -150,8 +150,13 @@ conditional_expression | logical_expression ELVIS conditional_expression ; -assignment_expression +error_expression : conditional_expression + | conditional_expression '!' + ; + +assignment_expression + : error_expression | unary_expression assignment_operator assignment_expression | unary_expression '=' initializer_list ; @@ -159,7 +164,7 @@ assignment_expression expression : assignment_expression | TRY assignment_expression - | TRY assignment_expression ELSE assignment_expression + | assignment_expression ELSE assignment_expression ; @@ -217,8 +222,8 @@ macro_argument_list ; declaration - : type IDENT '=' initializer - | type IDENT + : failable_type IDENT '=' initializer + | failable_type IDENT ; param_declaration @@ -270,6 +275,11 @@ type | type '[' '+' ']' ; +failable_type + : type + | type '!' + ; + initializer : expression | initializer_list @@ -318,8 +328,6 @@ ct_statement | ct_for_stmt ; -throw_statement - : THROW expression ';' statement : compound_statement @@ -334,7 +342,6 @@ statement | try_statement | defer_statement | ct_statement - | throw_statement ; defer_catch_body @@ -351,8 +358,7 @@ defer_statement ; catch_statement - : CATCH '(' type IDENT ')' defer_catch_body - | CATCH '(' ERROR IDENT ')' defer_catch_body + : CATCH '(' expression ')' defer_catch_body ; try_statement @@ -469,16 +475,6 @@ error_list | error_list error_type ; -throw_declaration - : THROWS - | THROWS error_list - ; - -opt_throw_declaration - : throw_declaration - | - ; - func_name : path TYPE_IDENT '.' IDENT | TYPE_IDENT '.' IDENT @@ -486,7 +482,7 @@ func_name ; func_declaration - : FUNC type func_name opt_parameter_type_list opt_attributes opt_throw_declaration + : FUNC failable_type func_name opt_parameter_type_list opt_attributes ; func_definition @@ -567,7 +563,7 @@ const_declaration ; func_typedef - : FUNC type opt_parameter_type_list opt_throw_declaration + : FUNC failable_type opt_parameter_type_list ; typedef_declaration diff --git a/resources/lib/system/io.c3 b/resources/lib/system/io.c3 new file mode 100644 index 000000000..de871ee1e --- /dev/null +++ b/resources/lib/system/io.c3 @@ -0,0 +1,390 @@ +module system::io; + +typedef File as void; + +extern File *stdin @cname(__stdinp); +extern File *stdout @cname(__stdoutp); +extern File *stderr @cname(__stderrp); + +extern int fputc(int, aliased void*); +extern void clearerr(aliased void*); +extern int fclose(aliased void*); +extern int feof(aliased void*); +extern int ferror(aliased void*); +extern int fflush(aliased FILE *); +extern int fgetc(aliased FILE *); +extern int fgetpos(FILE *, fpos_t *); +extern int fseek(void*, long, int); +extern void* fopen(char *, char *); + + +struct File +{ + void *file; +} + +enum Seek +{ + SET = 0, + CURSOR = 1, + END = 2 +} + +errorset FileError +{ +} + +local func FileError errorFromErrno() +{ +} + +public func void File.open(File *file, char *filename, char *mode) throws FileError +{ + file.file = fopen(filename, mode); + if (!file.file) throw errorFromErrno(); +} + +public func void File.seek(File *file, long offset, Seek seekMode = Seek.SET) throws FileError +{ + if (fseek(file->file, offset, cast(seekMode, int))) throw errorFromErrno(); +} + +public func void File.putChar(File *file, char c) throws FileError +{ + if (fputc(c, file->file)) throw errorFromErrno(); +} + +pubic func void File.clearerr(File *file) @inline throws FileError +{ + clearerr(file->file); +} + +func void File.close(File *file) @inline +{ + if (fclose(file->file)) throw errorFromErrno(); +} + +func void File.eof(File *file) @inline +{ + int err = feof(file->file); +} + +func void File.error(File *file) @inline +{ + int err = ferror +} + + +#define __SLBF 0x0001 /* line buffered */ +#define __SNBF 0x0002 /* unbuffered */ +#define __SRD 0x0004 /* OK to read */ +#define __SWR 0x0008 /* OK to write */ + /* RD and WR are never simultaneously asserted */ +#define __SRW 0x0010 /* open for reading & writing */ +#define __SEOF 0x0020 /* found EOF */ +#define __SERR 0x0040 /* found error */ +#define __SMBF 0x0080 /* _buf is from malloc */ +#define __SAPP 0x0100 /* fdopen()ed in append mode */ +#define __SSTR 0x0200 /* this is an sprintf/snprintf string */ +#define __SOPT 0x0400 /* do fseek() optimisation */ +#define __SNPT 0x0800 /* do not do fseek() optimisation */ +#define __SOFF 0x1000 /* set iff _offset is in fact correct */ +#define __SMOD 0x2000 /* true => fgetln modified _p text */ +#define __SALC 0x4000 /* allocate string space dynamically */ +#define __SIGN 0x8000 /* ignore this file in _fwalk */ + +/* + * The following three definitions are for ANSI C, which took them + * from System V, which brilliantly took internal interface macros and + * made them official arguments to setvbuf(), without renaming them. + * Hence, these ugly _IOxxx names are *supposed* to appear in user code. + * + * Although numbered as their counterparts above, the implementation + * does not rely on this. + */ +#define _IOFBF 0 /* setvbuf should set fully buffered */ +#define _IOLBF 1 /* setvbuf should set line buffered */ +#define _IONBF 2 /* setvbuf should set unbuffered */ + +#define BUFSIZ 1024 /* size of buffer used by setbuf */ +#define EOF (-1) + + /* must be == _POSIX_STREAM_MAX */ +#define FOPEN_MAX 20 /* must be <= OPEN_MAX */ +#define FILENAME_MAX 1024 /* must be <= PATH_MAX */ + +/* System V/ANSI C; this is the wrong way to do this, do *not* use these. */ +#ifndef _ANSI_SOURCE +#define P_tmpdir "/var/tmp/" +#endif +#define L_tmpnam 1024 /* XXX must be == PATH_MAX */ +#define TMP_MAX 308915776 + + +#define stdin __stdinp +#define stdout __stdoutp +#define stderr __stderrp + + +/* ANSI-C */ + +__BEGIN_DECLS +char *fgets(char * __restrict, int, FILE *); +#if defined(_DARWIN_UNLIMITED_STREAMS) || defined(_DARWIN_C_SOURCE) +#else /* !_DARWIN_UNLIMITED_STREAMS && !_DARWIN_C_SOURCE */ +FILE *fopen(const char * __restrict __filename, const char * __restrict __mode) __DARWIN_ALIAS_STARTING(__MAC_10_6, __IPHONE_2_0, __DARWIN_ALIAS(fopen)); +#endif /* (DARWIN_UNLIMITED_STREAMS || _DARWIN_C_SOURCE) */ +int fprintf(FILE * __restrict, const char * __restrict, ...) __printflike(2, 3); +int fputs(const char * __restrict, FILE * __restrict) __DARWIN_ALIAS(fputs); +size_t fread(void * __restrict __ptr, size_t __size, size_t __nitems, FILE * __restrict __stream); +FILE *freopen(const char * __restrict, const char * __restrict, + FILE * __restrict) __DARWIN_ALIAS(freopen); +int fscanf(FILE * __restrict, const char * __restrict, ...) __scanflike(2, 3); +int fsetpos(FILE *, const fpos_t *); +long ftell(FILE *); +size_t fwrite(const void * __restrict __ptr, size_t __size, size_t __nitems, FILE * __restrict __stream) __DARWIN_ALIAS(fwrite); +int getc(FILE *); +int getchar(void); +char *gets(char *); +void perror(const char *) __cold; +int printf(const char * __restrict, ...) __printflike(1, 2); +int putc(int, FILE *); +int putchar(int); +int puts(const char *); +int remove(const char *); +int rename (const char *__old, const char *__new); +void rewind(FILE *); +int scanf(const char * __restrict, ...) __scanflike(1, 2); +void setbuf(FILE * __restrict, char * __restrict); +int setvbuf(FILE * __restrict, char * __restrict, int, size_t); +int sprintf(char * __restrict, const char * __restrict, ...) __printflike(2, 3) __swift_unavailable("Use snprintf instead."); +int sscanf(const char * __restrict, const char * __restrict, ...) __scanflike(2, 3); +FILE *tmpfile(void); + +__swift_unavailable("Use mkstemp(3) instead.") +#if !defined(_POSIX_C_SOURCE) +__deprecated_msg("This function is provided for compatibility reasons only. Due to security concerns inherent in the design of tmpnam(3), it is highly recommended that you use mkstemp(3) instead.") +#endif +char *tmpnam(char *); +int ungetc(int, FILE *); +int vfprintf(FILE * __restrict, const char * __restrict, va_list) __printflike(2, 0); +int vprintf(const char * __restrict, va_list) __printflike(1, 0); +int vsprintf(char * __restrict, const char * __restrict, va_list) __printflike(2, 0) __swift_unavailable("Use vsnprintf instead."); +__END_DECLS + + + +/* Additional functionality provided by: + * POSIX.1-1988 + */ + +#if __DARWIN_C_LEVEL >= 198808L +#define L_ctermid 1024 /* size for ctermid(); PATH_MAX */ + +__BEGIN_DECLS +#include <_ctermid.h> + +#if defined(_DARWIN_UNLIMITED_STREAMS) || defined(_DARWIN_C_SOURCE) +FILE *fdopen(int, const char *) __DARWIN_ALIAS_STARTING(__MAC_10_6, __IPHONE_3_2, __DARWIN_EXTSN(fdopen)); +#else /* !_DARWIN_UNLIMITED_STREAMS && !_DARWIN_C_SOURCE */ +FILE *fdopen(int, const char *) __DARWIN_ALIAS_STARTING(__MAC_10_6, __IPHONE_2_0, __DARWIN_ALIAS(fdopen)); +#endif /* (DARWIN_UNLIMITED_STREAMS || _DARWIN_C_SOURCE) */ +int fileno(FILE *); +__END_DECLS +#endif /* __DARWIN_C_LEVEL >= 198808L */ + + +/* Additional functionality provided by: + * POSIX.2-1992 C Language Binding Option + */ +#if TARGET_OS_EMBEDDED +#define __swift_unavailable_on(osx_msg, ios_msg) __swift_unavailable(ios_msg) +#else +#define __swift_unavailable_on(osx_msg, ios_msg) __swift_unavailable(osx_msg) +#endif + +#if __DARWIN_C_LEVEL >= 199209L +__BEGIN_DECLS +int pclose(FILE *) __swift_unavailable_on("Use posix_spawn APIs or NSTask instead.", "Process spawning is unavailable."); +#if defined(_DARWIN_UNLIMITED_STREAMS) || defined(_DARWIN_C_SOURCE) +FILE *popen(const char *, const char *) __DARWIN_ALIAS_STARTING(__MAC_10_6, __IPHONE_3_2, __DARWIN_EXTSN(popen)) __swift_unavailable_on("Use posix_spawn APIs or NSTask instead.", "Process spawning is unavailable."); +#else /* !_DARWIN_UNLIMITED_STREAMS && !_DARWIN_C_SOURCE */ +FILE *popen(const char *, const char *) __DARWIN_ALIAS_STARTING(__MAC_10_6, __IPHONE_2_0, __DARWIN_ALIAS(popen)) __swift_unavailable_on("Use posix_spawn APIs or NSTask instead.", "Process spawning is unavailable."); +#endif /* (DARWIN_UNLIMITED_STREAMS || _DARWIN_C_SOURCE) */ +__END_DECLS +#endif /* __DARWIN_C_LEVEL >= 199209L */ + +#undef __swift_unavailable_on + +/* Additional functionality provided by: + * POSIX.1c-1995, + * POSIX.1i-1995, + * and the omnibus ISO/IEC 9945-1: 1996 + */ + +#if __DARWIN_C_LEVEL >= 199506L + +/* Functions internal to the implementation. */ +__BEGIN_DECLS +int __srget(FILE *); +int __svfscanf(FILE *, const char *, va_list) __scanflike(2, 0); +int __swbuf(int, FILE *); +__END_DECLS + +/* + * The __sfoo macros are here so that we can + * define function versions in the C library. + */ +#define __sgetc(p) (--(p)->_r < 0 ? __srget(p) : (int)(*(p)->_p++)) +#if defined(__GNUC__) && defined(__STDC__) +__header_always_inline int __sputc(int _c, FILE *_p) { + if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n')) + return (*_p->_p++ = _c); + else + return (__swbuf(_c, _p)); +} +#else +/* + * This has been tuned to generate reasonable code on the vax using pcc. + */ +#define __sputc(c, p) \ + (--(p)->_w < 0 ? \ + (p)->_w >= (p)->_lbfsize ? \ + (*(p)->_p = (c)), *(p)->_p != '\n' ? \ + (int)*(p)->_p++ : \ + __swbuf('\n', p) : \ + __swbuf((int)(c), p) : \ + (*(p)->_p = (c), (int)*(p)->_p++)) +#endif + +#define __sfeof(p) (((p)->_flags & __SEOF) != 0) +#define __sferror(p) (((p)->_flags & __SERR) != 0) +#define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF))) +#define __sfileno(p) ((p)->_file) + +__BEGIN_DECLS +void flockfile(FILE *); +int ftrylockfile(FILE *); +void funlockfile(FILE *); +int getc_unlocked(FILE *); +int getchar_unlocked(void); +int putc_unlocked(int, FILE *); +int putchar_unlocked(int); + +/* Removed in Issue 6 */ +#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 200112L +int getw(FILE *); +int putw(int, FILE *); +#endif + +__swift_unavailable("Use mkstemp(3) instead.") +#if !defined(_POSIX_C_SOURCE) +__deprecated_msg("This function is provided for compatibility reasons only. Due to security concerns inherent in the design of tempnam(3), it is highly recommended that you use mkstemp(3) instead.") +#endif +char *tempnam(const char *__dir, const char *__prefix) __DARWIN_ALIAS(tempnam); +__END_DECLS + +#ifndef lint +#define getc_unlocked(fp) __sgetc(fp) +#define putc_unlocked(x, fp) __sputc(x, fp) +#endif /* lint */ + +#define getchar_unlocked() getc_unlocked(stdin) +#define putchar_unlocked(x) putc_unlocked(x, stdout) +#endif /* __DARWIN_C_LEVEL >= 199506L */ + + + +/* Additional functionality provided by: + * POSIX.1-2001 + * ISO C99 + */ + +#if __DARWIN_C_LEVEL >= 200112L +#include + +__BEGIN_DECLS +int fseeko(FILE * __stream, off_t __offset, int __whence); +off_t ftello(FILE * __stream); +__END_DECLS +#endif /* __DARWIN_C_LEVEL >= 200112L */ + +#if __DARWIN_C_LEVEL >= 200112L || defined(_C99_SOURCE) || defined(__cplusplus) +__BEGIN_DECLS +int snprintf(char * __restrict __str, size_t __size, const char * __restrict __format, ...) __printflike(3, 4); +int vfscanf(FILE * __restrict __stream, const char * __restrict __format, va_list) __scanflike(2, 0); +int vscanf(const char * __restrict __format, va_list) __scanflike(1, 0); +int vsnprintf(char * __restrict __str, size_t __size, const char * __restrict __format, va_list) __printflike(3, 0); +int vsscanf(const char * __restrict __str, const char * __restrict __format, va_list) __scanflike(2, 0); +__END_DECLS +#endif /* __DARWIN_C_LEVEL >= 200112L || defined(_C99_SOURCE) || defined(__cplusplus) */ + + + +/* Additional functionality provided by: + * POSIX.1-2008 + */ + +#if __DARWIN_C_LEVEL >= 200809L +#include + +__BEGIN_DECLS +int dprintf(int, const char * __restrict, ...) __printflike(2, 3) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); +int vdprintf(int, const char * __restrict, va_list) __printflike(2, 0) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); +ssize_t getdelim(char ** __restrict __linep, size_t * __restrict __linecapp, int __delimiter, FILE * __restrict __stream) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); +ssize_t getline(char ** __restrict __linep, size_t * __restrict __linecapp, FILE * __restrict __stream) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); +FILE *fmemopen(void * __restrict __buf, size_t __size, const char * __restrict __mode) __API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0)); +FILE *open_memstream(char **__bufp, size_t *__sizep) __API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0)); +__END_DECLS +#endif /* __DARWIN_C_LEVEL >= 200809L */ + + + +/* Darwin extensions */ + +#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL +__BEGIN_DECLS +extern __const int sys_nerr; /* perror(3) external variables */ +extern __const char *__const sys_errlist[]; + +int asprintf(char ** __restrict, const char * __restrict, ...) __printflike(2, 3); +char *ctermid_r(char *); +char *fgetln(FILE *, size_t *); +__const char *fmtcheck(const char *, const char *); +int fpurge(FILE *); +void setbuffer(FILE *, char *, int); +int setlinebuf(FILE *); +int vasprintf(char ** __restrict, const char * __restrict, va_list) __printflike(2, 0); +FILE *zopen(const char *, const char *, int); + + +/* + * Stdio function-access interface. + */ +FILE *funopen(const void *, + int (* _Nullable)(void *, char *, int), + int (* _Nullable)(void *, const char *, int), + fpos_t (* _Nullable)(void *, fpos_t, int), + int (* _Nullable)(void *)); +__END_DECLS +#define fropen(cookie, fn) funopen(cookie, fn, 0, 0, 0) +#define fwopen(cookie, fn) funopen(cookie, 0, fn, 0, 0) + +#define feof_unlocked(p) __sfeof(p) +#define ferror_unlocked(p) __sferror(p) +#define clearerr_unlocked(p) __sclearerr(p) +#define fileno_unlocked(p) __sfileno(p) + +#endif /* __DARWIN_C_LEVEL >= __DARWIN_C_FULL */ + + +#ifdef _USE_EXTENDED_LOCALES_ +#include +#endif /* _USE_EXTENDED_LOCALES_ */ + +#if defined (__GNUC__) && _FORTIFY_SOURCE > 0 && !defined (__cplusplus) +/* Security checking functions. */ +#include +#endif + +#endif /* _STDIO_H_ */ diff --git a/resources/testfragments/super_simple.c3 b/resources/testfragments/super_simple.c3 index 6f81152ff..24f22400d 100644 --- a/resources/testfragments/super_simple.c3 +++ b/resources/testfragments/super_simple.c3 @@ -751,6 +751,44 @@ func int oekt() throws return x; } +func int! oekt2() throws +{ + int z = testThrow(-1) else goto NEXT; + printf("Skipped.\n"); + NEXT: + int! x = testThrow(-3); + catch (err = x) + { + printf("An error %p\n", usize(e)); + return err!; + } + return x; +} + +func int! oekt3() +{ + int z = testThrow(-1) else goto NEXT; + printf("Skipped.\n"); + NEXT: + int! x = testThrow(-3); + + if (e = catch(x)) printf("An error %p\n", usize(e)); + + return x; +} + +func int! oekt3() +{ + int z = testThrow(-1) else goto NEXT; + printf("Skipped.\n"); + NEXT: + int! x = testThrow(-3); + + if (e = x!) printf("An error %p\n", usize(e)); + + return x; +} + errset Xan { EE, @@ -783,6 +821,51 @@ func void testErrorBug() } printf("End\n"); } + +func void testErrorBug2() +{ + printf("Test error multi\n"); + error e; + { + printf("Will call\n"); + e = catch(oekt()); + } + switch (e) + { + case TestErr1: + printf("Expected particular error.\n"); + default: + error foo = Err.TEST_ERR1; + printf("Not expected %p != %p\n", usize(e), usize(foo)); + printf("Unexpected any error error.\n"); + } + printf("End\n"); +} + +func void testErrorMulti() +{ + defer printf("End defer\n"); + int! z; + printf("Test error multi\n"); + { + defer printf("Defer\n"); + printf("Will call\n"); + z = oekt(); + printf("Got here\n"); + } + switch (e = z!) + { + case TestErr1: + printf("Expected particular error.\n"); + default: + error foo = Err.TEST_ERR1; + printf("Not expected %p != %p\n", usize(e), usize(foo)); + printf("Unexpected any error error.\n"); + } + printf("End\n"); +} + + func void testErrorMulti() { defer printf("End defer\n"); @@ -883,6 +966,59 @@ func void testErrors() printf("End of errors\n"); } +func void testErrors() +{ + + printf("Throws: %d\n", throwsDone.times); + + int x = testThrow(20) else 1; + printf("Value was %d, expected 400.\n", x); + + printf("Throws: %d\n", throwsDone.times); + + x = testThrow(-1) else 20; + printf("Value was %d, expected 20.\n", x); + + printf("Throws: %d\n", throwsDone.times); + + printf("Begin\n"); + int! y = testThrow(-1); + + if (y) + { + printf("Value was %d, expected 9.\n", y); + printf("Didn't expect this one.\n"); + } + else catch(y) + { + printf("Expected this catch.\n"); + } + + y = testThrow(-1); + catch (y) + { + printf("Particular error.\n"); + } + testErrorMulti(); + + catch (throwAOrB(1)) + { + case Err: + printf("A1\n"); + case Err2: + printf("A2\n"); + } + catch (throwAOrB(2)) + { + case Err: + printf("B1\n"); + case Err2: + printf("B2\n"); + } + printf("Throws: %d\n", throwsDone.times); + printf("End of errors\n"); +} + macro void arrayCallMacro($x) { printf("Array call: %d, %d\n", $x[0], $x[1]);