From 968b85ad77892da945d478799d4e775222248f1f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 2 Jan 2016 03:38:45 -0700 Subject: [PATCH] closer to guess number example working --- doc/langref.md | 4 +- example/guess_number/main.zig | 23 +++++- src/analyze.cpp | 38 ++++++--- src/analyze.hpp | 1 + src/codegen.cpp | 4 + src/parser.cpp | 68 +++++++++++++++- src/parser.hpp | 6 ++ src/tokenizer.cpp | 19 +++++ src/tokenizer.hpp | 1 + std/errno.zig | 146 ++++++++++++++++++++++++++++++++++ std/std.zig | 71 ++++++++++++++++- 11 files changed, 360 insertions(+), 21 deletions(-) create mode 100644 std/errno.zig diff --git a/doc/langref.md b/doc/langref.md index 10ed66ac80..6485042709 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -34,7 +34,7 @@ Root : many(TopLevelDecl) token(EOF) TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl | VariableDeclaration -VariableDeclaration : (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression)) +VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression)) StructDecl : many(Directive) token(Struct) token(Symbol) token(LBrace) many(StructField) token(RBrace) @@ -150,7 +150,7 @@ ArrayAccessExpression : token(LBracket) Expression token(RBracket) PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const))) -PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression +PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace) diff --git a/example/guess_number/main.zig b/example/guess_number/main.zig index cbef1fb7dc..6b59eb8053 100644 --- a/example/guess_number/main.zig +++ b/example/guess_number/main.zig @@ -2,19 +2,33 @@ export executable "guess_number"; use "std.zig"; -fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { +// TODO don't duplicate these; implement pub const +const stdout_fileno : isize = 1; +const stderr_fileno : isize = 2; + +pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { print_str("Welcome to the Guess Number Game in Zig.\n"); var seed : u32; - ok_or_panic(os_get_random_bytes(&seed, 4)); + if (os_get_random_bytes(&seed as &u8, 4) != 0) { + // TODO full error message + fprint_str(stderr_fileno, "unable to get random bytes"); + return 1; + } + + print_str("Seed: "); + print_u64(seed); + print_str("\n"); + + /* var rand_state = rand_init(seed); const answer = rand_int(&rand_state, 0, 100) + 1; - while true { + while (true) { const line = readline("\nGuess a number between 1 and 100: "); - if const guess ?= parse_number(line) { + if (const guess ?= parse_number(line)) { if (guess > answer) { print_str("Guess lower.\n"); } else if (guess < answer) { @@ -27,6 +41,7 @@ fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { print_str("Invalid number format.\n"); } } + */ return 0; } diff --git a/src/analyze.cpp b/src/analyze.cpp index cb651995e2..e30c0c29b6 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -38,6 +38,7 @@ static AstNode *first_executing_node(AstNode *node) { case NodeTypeCastExpr: case NodeTypeNumberLiteral: case NodeTypeStringLiteral: + case NodeTypeCharLiteral: case NodeTypeUnreachable: case NodeTypeSymbol: case NodeTypePrefixOpExpr: @@ -588,6 +589,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, case NodeTypeArrayAccessExpr: case NodeTypeNumberLiteral: case NodeTypeStringLiteral: + case NodeTypeCharLiteral: case NodeTypeUnreachable: case NodeTypeVoid: case NodeTypeBoolLiteral: @@ -659,6 +661,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) { case NodeTypeArrayAccessExpr: case NodeTypeNumberLiteral: case NodeTypeStringLiteral: + case NodeTypeCharLiteral: case NodeTypeUnreachable: case NodeTypeVoid: case NodeTypeBoolLiteral: @@ -891,6 +894,17 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont return expected_type; } + // implicit non-const to const + if (expected_type->id == TypeTableEntryIdPointer && + actual_type->id == TypeTableEntryIdPointer && + expected_type->data.pointer.is_const && + !actual_type->data.pointer.is_const) + { + return resolve_type_compatibility(g, context, node, + expected_type->data.pointer.child_type, + actual_type->data.pointer.child_type); + } + add_node_error(g, node, buf_sprintf("expected type '%s', got '%s'", buf_ptr(&expected_type->name), @@ -1013,6 +1027,9 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i Buf *name = &node->data.field_access_expr.field_name; if (buf_eql_str(name, "len")) { return_type = g->builtin_types.entry_usize; + } else if (buf_eql_str(name, "ptr")) { + // TODO determine whether the pointer should be const + return_type = get_pointer_to_type(g, struct_type->data.array.child_type, false); } else { add_node_error(g, node, buf_sprintf("no member named '%s' in '%s'", buf_ptr(name), @@ -1160,6 +1177,11 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B codegen_num_lit->resolved_type = wanted_type; cast_node->op = CastOpNothing; return wanted_type; + } else if (actual_type->id == TypeTableEntryIdPointer && + wanted_type->id == TypeTableEntryIdPointer) + { + cast_node->op = CastOpPointerReinterpret; + return wanted_type; } else { add_node_error(g, node, buf_sprintf("invalid cast from type '%s' to '%s'", @@ -1286,6 +1308,9 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, } case BinOpTypeAdd: case BinOpTypeSub: + case BinOpTypeMult: + case BinOpTypeDiv: + case BinOpTypeMod: { AstNode *op1 = node->data.bin_op_expr.op1; AstNode *op2 = node->data.bin_op_expr.op2; @@ -1294,15 +1319,6 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, return resolve_peer_type_compatibility(g, context, node, op1, op2, lhs_type, rhs_type); } - case BinOpTypeMult: - case BinOpTypeDiv: - case BinOpTypeMod: - { - // TODO: don't require i32 - analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.bin_op_expr.op1); - analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.bin_op_expr.op2); - return g->builtin_types.entry_i32; - } case BinOpTypeInvalid: zig_unreachable(); } @@ -1746,6 +1762,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, return_type = get_array_type(g, g->builtin_types.entry_u8, buf_len(&node->data.string_literal.buf)); } break; + case NodeTypeCharLiteral: + return_type = g->builtin_types.entry_u8; + break; case NodeTypeUnreachable: return_type = g->builtin_types.entry_unreachable; break; @@ -1959,6 +1978,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, case NodeTypeArrayAccessExpr: case NodeTypeNumberLiteral: case NodeTypeStringLiteral: + case NodeTypeCharLiteral: case NodeTypeUnreachable: case NodeTypeVoid: case NodeTypeBoolLiteral: diff --git a/src/analyze.hpp b/src/analyze.hpp index dfe1dfce83..8152e16686 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -277,6 +277,7 @@ enum CastOp { CastOpIntWidenOrShorten, CastOpArrayToString, CastOpMaybeWrap, + CastOpPointerReinterpret, }; struct CastNode { diff --git a/src/codegen.cpp b/src/codegen.cpp index e99f335f9c..52cb58387b 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -390,6 +390,8 @@ static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_v } case CastOpPtrToInt: return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, ""); + case CastOpPointerReinterpret: + return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, ""); case CastOpIntWidenOrShorten: if (actual_type->size_in_bits == wanted_type->size_in_bits) { return expr_val; @@ -1236,6 +1238,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { LLVMValueRef ptr_val = LLVMBuildInBoundsGEP(g->builder, str_val, indices, 2, ""); return ptr_val; } + case NodeTypeCharLiteral: + return LLVMConstInt(LLVMInt8Type(), node->data.char_literal.value, false); case NodeTypeSymbol: { VariableTableEntry *variable = find_variable( diff --git a/src/parser.cpp b/src/parser.cpp index ecbb2d2e3b..c061725a65 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -102,6 +102,8 @@ const char *node_type_str(NodeType node_type) { return "NumberLiteral"; case NodeTypeStringLiteral: return "StringLiteral"; + case NodeTypeCharLiteral: + return "CharLiteral"; case NodeTypeUnreachable: return "Unreachable"; case NodeTypeSymbol: @@ -313,6 +315,11 @@ void ast_print(AstNode *node, int indent) { buf_ptr(&node->data.string_literal.buf)); break; } + case NodeTypeCharLiteral: + { + fprintf(stderr, "%s '%c'\n", node_type_str(node->type), node->data.char_literal.value); + break; + } case NodeTypeUnreachable: fprintf(stderr, "Unreachable\n"); break; @@ -575,6 +582,55 @@ static void parse_asm_template(ParseContext *pc, AstNode *node) { } } +static uint8_t parse_char_literal(ParseContext *pc, Token *token) { + // skip the single quotes at beginning and end + // convert escape sequences + bool escape = false; + int return_count = 0; + uint8_t return_value; + for (int i = token->start_pos + 1; i < token->end_pos - 1; i += 1) { + uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i); + if (escape) { + switch (c) { + case '\\': + return_value = '\\'; + return_count += 1; + break; + case 'r': + return_value = '\r'; + return_count += 1; + break; + case 'n': + return_value = '\n'; + return_count += 1; + break; + case 't': + return_value = '\t'; + return_count += 1; + break; + case '\'': + return_value = '\''; + return_count += 1; + break; + default: + ast_error(pc, token, "invalid escape character"); + } + escape = false; + } else if (c == '\\') { + escape = true; + } else { + return_value = c; + return_count += 1; + } + } + if (return_count == 0) { + ast_error(pc, token, "character literal too short"); + } else if (return_count > 1) { + ast_error(pc, token, "character literal too long"); + } + return return_count; +} + static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool *out_c_str, ZigList *offset_map) { @@ -620,6 +676,9 @@ static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool buf_append_char(buf, '"'); if (offset_map) offset_map->append(pos); break; + default: + ast_error(pc, token, "invalid escape character"); + break; } escape = false; } else if (c == '\\') { @@ -1136,7 +1195,7 @@ static AstNode *ast_parse_struct_val_expr(ParseContext *pc, int *token_index) { } /* -PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression +PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression */ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) { Token *token = &pc->tokens->at(*token_index); @@ -1151,6 +1210,11 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool parse_string_literal(pc, token, &node->data.string_literal.buf, &node->data.string_literal.c, nullptr); *token_index += 1; return node; + } else if (token->id == TokenIdCharLiteral) { + AstNode *node = ast_create_node(pc, NodeTypeCharLiteral, token); + node->data.char_literal.value = parse_char_literal(pc, token); + *token_index += 1; + return node; } else if (token->id == TokenIdKeywordUnreachable) { AstNode *node = ast_create_node(pc, NodeTypeUnreachable, token); *token_index += 1; @@ -1733,7 +1797,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m } /* -VariableDeclaration : (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression)) +VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression)) */ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token_index, bool mandatory) { Token *var_or_const_tok = &pc->tokens->at(*token_index); diff --git a/src/parser.hpp b/src/parser.hpp index 4f1db6b4de..6e3c71f2e8 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -35,6 +35,7 @@ enum NodeType { NodeTypeCastExpr, NodeTypeNumberLiteral, NodeTypeStringLiteral, + NodeTypeCharLiteral, NodeTypeUnreachable, NodeTypeSymbol, NodeTypePrefixOpExpr, @@ -289,6 +290,10 @@ struct AstNodeStringLiteral { bool c; }; +struct AstNodeCharLiteral { + uint8_t value; +}; + enum NumLit { NumLitF32, NumLitF64, @@ -359,6 +364,7 @@ struct AstNode { AstNodeStructDecl struct_decl; AstNodeStructField struct_field; AstNodeStringLiteral string_literal; + AstNodeCharLiteral char_literal; AstNodeNumberLiteral number_literal; AstNodeStructValueExpr struct_val_expr; AstNodeStructValueField struct_val_field; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 084e0ec28d..7a783d952d 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -103,6 +103,7 @@ enum TokenizeState { TokenizeStateFloatExponentUnsigned, // "123.456e", "123e", "0x123p" TokenizeStateFloatExponentNumber, // "123.456e-", "123.456e5", "123.456e5e-5" TokenizeStateString, + TokenizeStateCharLiteral, TokenizeStateSawStar, TokenizeStateSawSlash, TokenizeStateSawPercent, @@ -307,6 +308,10 @@ void tokenize(Buf *buf, Tokenization *out) { begin_token(&t, TokenIdStringLiteral); t.state = TokenizeStateString; break; + case '\'': + begin_token(&t, TokenIdCharLiteral); + t.state = TokenizeStateCharLiteral; + break; case '(': begin_token(&t, TokenIdLParen); end_token(&t); @@ -773,6 +778,16 @@ void tokenize(Buf *buf, Tokenization *out) { break; } break; + case TokenizeStateCharLiteral: + switch (c) { + case '\'': + end_token(&t); + t.state = TokenizeStateStart; + break; + default: + break; + } + break; case TokenizeStateZero: switch (c) { case 'b': @@ -912,6 +927,9 @@ void tokenize(Buf *buf, Tokenization *out) { case TokenizeStateString: tokenize_error(&t, "unterminated string"); break; + case TokenizeStateCharLiteral: + tokenize_error(&t, "unterminated character literal"); + break; case TokenizeStateSymbol: case TokenizeStateSymbolFirst: case TokenizeStateZero: @@ -993,6 +1011,7 @@ static const char * token_name(Token *token) { case TokenIdLBracket: return "LBracket"; case TokenIdRBracket: return "RBracket"; case TokenIdStringLiteral: return "StringLiteral"; + case TokenIdCharLiteral: return "CharLiteral"; case TokenIdSemicolon: return "Semicolon"; case TokenIdNumberLiteral: return "NumberLiteral"; case TokenIdPlus: return "Plus"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index 213b55b8c2..cf4ba57a71 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -44,6 +44,7 @@ enum TokenId { TokenIdLBracket, TokenIdRBracket, TokenIdStringLiteral, + TokenIdCharLiteral, TokenIdSemicolon, TokenIdNumberLiteral, TokenIdPlus, diff --git a/std/errno.zig b/std/errno.zig new file mode 100644 index 0000000000..6f50b50225 --- /dev/null +++ b/std/errno.zig @@ -0,0 +1,146 @@ +pub const EPERM = 1; // Operation not permitted +pub const ENOENT = 2; // No such file or directory +pub const ESRCH = 3; // No such process +pub const EINTR = 4; // Interrupted system call +pub const EIO = 5; // I/O error +pub const ENXIO = 6; // No such device or address +pub const E2BIG = 7; // Arg list too long +pub const ENOEXEC = 8; // Exec format error +pub const EBADF = 9; // Bad file number +pub const ECHILD = 10; // No child processes +pub const EAGAIN = 11; // Try again +pub const ENOMEM = 12; // Out of memory +pub const EACCES = 13; // Permission denied +pub const EFAULT = 14; // Bad address +pub const ENOTBLK = 15; // Block device required +pub const EBUSY = 16; // Device or resource busy +pub const EEXIST = 17; // File exists +pub const EXDEV = 18; // Cross-device link +pub const ENODEV = 19; // No such device +pub const ENOTDIR = 20; // Not a directory +pub const EISDIR = 21; // Is a directory +pub const EINVAL = 22; // Invalid argument +pub const ENFILE = 23; // File table overflow +pub const EMFILE = 24; // Too many open files +pub const ENOTTY = 25; // Not a typewriter +pub const ETXTBSY = 26; // Text file busy +pub const EFBIG = 27; // File too large +pub const ENOSPC = 28; // No space left on device +pub const ESPIPE = 29; // Illegal seek +pub const EROFS = 30; // Read-only file system +pub const EMLINK = 31; // Too many links +pub const EPIPE = 32; // Broken pipe +pub const EDOM = 33; // Math argument out of domain of func +pub const ERANGE = 34; // Math result not representable +pub const EDEADLK = 35; // Resource deadlock would occur +pub const ENAMETOOLONG = 36; // File name too long +pub const ENOLCK = 37; // No record locks available +pub const ENOSYS = 38; // Function not implemented +pub const ENOTEMPTY = 39; // Directory not empty +pub const ELOOP = 40; // Too many symbolic links encountered +pub const EWOULDBLOCK = EAGAIN; // Operation would block +pub const ENOMSG = 42; // No message of desired type +pub const EIDRM = 43; // Identifier removed +pub const ECHRNG = 44; // Channel number out of range +pub const EL2NSYNC = 45; // Level 2 not synchronized +pub const EL3HLT = 46; // Level 3 halted +pub const EL3RST = 47; // Level 3 reset +pub const ELNRNG = 48; // Link number out of range +pub const EUNATCH = 49; // Protocol driver not attached +pub const ENOCSI = 50; // No CSI structure available +pub const EL2HLT = 51; // Level 2 halted +pub const EBADE = 52; // Invalid exchange +pub const EBADR = 53; // Invalid request descriptor +pub const EXFULL = 54; // Exchange full +pub const ENOANO = 55; // No anode +pub const EBADRQC = 56; // Invalid request code +pub const EBADSLT = 57; // Invalid slot + +pub const EBFONT = 59; // Bad font file format +pub const ENOSTR = 60; // Device not a stream +pub const ENODATA = 61; // No data available +pub const ETIME = 62; // Timer expired +pub const ENOSR = 63; // Out of streams resources +pub const ENONET = 64; // Machine is not on the network +pub const ENOPKG = 65; // Package not installed +pub const EREMOTE = 66; // Object is remote +pub const ENOLINK = 67; // Link has been severed +pub const EADV = 68; // Advertise error +pub const ESRMNT = 69; // Srmount error +pub const ECOMM = 70; // Communication error on send +pub const EPROTO = 71; // Protocol error +pub const EMULTIHOP = 72; // Multihop attempted +pub const EDOTDOT = 73; // RFS specific error +pub const EBADMSG = 74; // Not a data message +pub const EOVERFLOW = 75; // Value too large for defined data type +pub const ENOTUNIQ = 76; // Name not unique on network +pub const EBADFD = 77; // File descriptor in bad state +pub const EREMCHG = 78; // Remote address changed +pub const ELIBACC = 79; // Can not access a needed shared library +pub const ELIBBAD = 80; // Accessing a corrupted shared library +pub const ELIBSCN = 81; // .lib section in a.out corrupted +pub const ELIBMAX = 82; // Attempting to link in too many shared libraries +pub const ELIBEXEC = 83; // Cannot exec a shared library directly +pub const EILSEQ = 84; // Illegal byte sequence +pub const ERESTART = 85; // Interrupted system call should be restarted +pub const ESTRPIPE = 86; // Streams pipe error +pub const EUSERS = 87; // Too many users +pub const ENOTSOCK = 88; // Socket operation on non-socket +pub const EDESTADDRREQ = 89; // Destination address required +pub const EMSGSIZE = 90; // Message too long +pub const EPROTOTYPE = 91; // Protocol wrong type for socket +pub const ENOPROTOOPT = 92; // Protocol not available +pub const EPROTONOSUPPORT = 93; // Protocol not supported +pub const ESOCKTNOSUPPORT = 94; // Socket type not supported +pub const EOPNOTSUPP = 95; // Operation not supported on transport endpoint +pub const EPFNOSUPPORT = 96; // Protocol family not supported +pub const EAFNOSUPPORT = 97; // Address family not supported by protocol +pub const EADDRINUSE = 98; // Address already in use +pub const EADDRNOTAVAIL = 99; // Cannot assign requested address +pub const ENETDOWN = 100; // Network is down +pub const ENETUNREACH = 101; // Network is unreachable +pub const ENETRESET = 102; // Network dropped connection because of reset +pub const ECONNABORTED = 103; // Software caused connection abort +pub const ECONNRESET = 104; // Connection reset by peer +pub const ENOBUFS = 105; // No buffer space available +pub const EISCONN = 106; // Transport endpoint is already connected +pub const ENOTCONN = 107; // Transport endpoint is not connected +pub const ESHUTDOWN = 108; // Cannot send after transport endpoint shutdown +pub const ETOOMANYREFS = 109; // Too many references: cannot splice +pub const ETIMEDOUT = 110; // Connection timed out +pub const ECONNREFUSED = 111; // Connection refused +pub const EHOSTDOWN = 112; // Host is down +pub const EHOSTUNREACH = 113; // No route to host +pub const EALREADY = 114; // Operation already in progress +pub const EINPROGRESS = 115; // Operation now in progress +pub const ESTALE = 116; // Stale NFS file handle +pub const EUCLEAN = 117; // Structure needs cleaning +pub const ENOTNAM = 118; // Not a XENIX named type file +pub const ENAVAIL = 119; // No XENIX semaphores available +pub const EISNAM = 120; // Is a named type file +pub const EREMOTEIO = 121; // Remote I/O error +pub const EDQUOT = 122; // Quota exceeded + +pub const ENOMEDIUM = 123; // No medium found +pub const EMEDIUMTYPE = 124; // Wrong medium type + +// nameserver query return codes +pub const ENSROK = 0; // DNS server returned answer with no data +pub const ENSRNODATA = 160; // DNS server returned answer with no data +pub const ENSRFORMERR = 161; // DNS server claims query was misformatted +pub const ENSRSERVFAIL = 162; // DNS server returned general failure +pub const ENSRNOTFOUND = 163; // Domain name not found +pub const ENSRNOTIMP = 164; // DNS server does not implement requested operation +pub const ENSRREFUSED = 165; // DNS server refused query +pub const ENSRBADQUERY = 166; // Misformatted DNS query +pub const ENSRBADNAME = 167; // Misformatted domain name +pub const ENSRBADFAMILY = 168; // Unsupported address family +pub const ENSRBADRESP = 169; // Misformatted DNS reply +pub const ENSRCONNREFUSED = 170; // Could not contact DNS servers +pub const ENSRTIMEOUT = 171; // Timeout while contacting DNS servers +pub const ENSROF = 172; // End of file +pub const ENSRFILE = 173; // Error reading file +pub const ENSRNOMEM = 174; // Out of memory +pub const ENSRDESTRUCTION = 175; // Application terminated lookup +pub const ENSRQUERYDOMAINTOOLONG = 176; // Domain name is too long +pub const ENSRCNAMELOOP = 177; // Domain name is too long diff --git a/std/std.zig b/std/std.zig index 132a22e996..42967e1c5f 100644 --- a/std/std.zig +++ b/std/std.zig @@ -1,6 +1,9 @@ const SYS_write : isize = 1; const SYS_exit : isize = 60; +const SYS_getrandom : isize = 278; + const stdout_fileno : isize = 1; +const stderr_fileno : isize = 2; fn syscall1(number: isize, arg1: isize) -> isize { asm volatile ("syscall" @@ -16,6 +19,12 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize { : "rcx", "r11") } +/* +pub fn getrandom(buf: &u8, count: usize, flags: u32) -> isize { + return syscall3(SYS_getrandom, buf as isize, count as isize, flags as isize); +} +*/ + pub fn write(fd: isize, buf: &const u8, count: usize) -> isize { return syscall3(SYS_write, fd, buf as isize, count as isize); } @@ -25,8 +34,62 @@ pub fn exit(status: i32) -> unreachable { unreachable; } -// TODO error handling -// TODO handle buffering and flushing -pub fn print_str(str : string) -> isize { - return write(stdout_fileno, str.ptr, str.len); +/* +fn digit_to_char(digit: u64) -> u8 { '0' + (digit as u8) } + +const max_u64_base10_digits: usize = 20; + +fn buf_print_u64(out_buf: &u8, x: u64) -> usize { + // TODO use max_u64_base10_digits instead of hardcoding 20 + var buf: [u8; 20]; + var a = x; + var index = max_u64_base10_digits; + + while (true) { + const digit = a % 10; + index -= 1; + buf[index] = digit_to_char(digit); + a /= 10; + if (a == 0) + break; + } + + const len = max_u64_base10_digits - index; + + // TODO memcpy intrinsic + var i: usize = 0; + while (i < len) { + out_buf[i] = buf[index + i]; + i += 1; + } + + return len; } + +// TODO handle buffering and flushing (mutex protected) +// TODO error handling +pub fn print_u64(x: u64) -> isize { + // TODO use max_u64_base10_digits instead of hardcoding 20 + var buf: [u8; 20]; + const len = buf_print_u64(buf.ptr, x); + return write(stdout_fileno, buf.ptr, len); +} +*/ + + +// TODO error handling +// TODO handle buffering and flushing (mutex protected) +pub fn print_str(str: string) -> isize { fprint_str(stdout_fileno, str) } + +// TODO error handling +// TODO handle buffering and flushing (mutex protected) +pub fn fprint_str(fd: isize, str: string) -> isize { + return write(fd, str.ptr, str.len); +} + +/* +// TODO error handling +pub fn os_get_random_bytes(buf: &u8, count: usize) -> isize { + return getrandom(buf, count, 0); +} +*/