diff --git a/CMakeLists.txt b/CMakeLists.txt index 8114f4315..e4bbed243 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,6 +118,7 @@ set(C_HEADERS set(ZIG_STD_SRC "${CMAKE_SOURCE_DIR}/std/bootstrap.zig" "${CMAKE_SOURCE_DIR}/std/std.zig" + "${CMAKE_SOURCE_DIR}/std/rand.zig" ) set(C_HEADERS_DEST "lib/zig/include") diff --git a/doc/langref.md b/doc/langref.md index 8de57e387..ac857a563 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -36,7 +36,7 @@ TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl | Variabl 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(StructMember) token(RBrace) +StructDecl : many(Directive) option(FnVisibleMod) token(Struct) token(Symbol) token(LBrace) many(StructMember) token(RBrace) StructMember: StructField | FnDecl diff --git a/example/guess_number/main.zig b/example/guess_number/main.zig index 5d245a38c..b70a89085 100644 --- a/example/guess_number/main.zig +++ b/example/guess_number/main.zig @@ -1,6 +1,7 @@ export executable "guess_number"; use "std.zig"; +use "rand.zig"; // TODO don't duplicate these; implement pub const const stdout_fileno : isize = 1; @@ -11,16 +12,16 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { var seed : u32; var err : isize; - // TODO #sizeof(u32) instead of 4 - if ({err = os_get_random_bytes(&seed as &u8, 4); err != 4}) { + if ({err = os_get_random_bytes(&seed as &u8, #sizeof(u32)); err != #sizeof(u32)}) { // TODO full error message fprint_str(stderr_fileno, "unable to get random bytes"); return 1; } - var rand_state = rand_init(seed); + var rand : Rand; + rand.init(seed); - const answer = rand_u64(&rand_state, 0, 100) + 1; + const answer = rand.range_u64(0, 100) + 1; print_str("Answer: "); print_u64(answer); diff --git a/src/analyze.cpp b/src/analyze.cpp index 51f53fa80..162c2ab58 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -474,7 +474,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t add_node_error(g, child->data.param_decl.type, buf_sprintf("parameter of type 'unreachable' not allowed")); } else if (type_entry->id == TypeTableEntryIdVoid) { - if (node->data.fn_proto.visib_mod == FnProtoVisibModExport) { + if (node->data.fn_proto.visib_mod == VisibModExport) { add_node_error(g, child->data.param_decl.type, buf_sprintf("parameter of type 'void' not allowed on exported functions")); } @@ -599,8 +599,8 @@ static void preview_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node, auto entry = fn_table->maybe_get(proto_name); bool skip = false; - bool is_internal = (proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport); - bool is_pub = (proto_node->data.fn_proto.visib_mod != FnProtoVisibModPrivate); + bool is_internal = (proto_node->data.fn_proto.visib_mod != VisibModExport); + bool is_pub = (proto_node->data.fn_proto.visib_mod != VisibModPrivate); if (entry) { add_node_error(g, node, buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); @@ -2199,7 +2199,7 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo node->codegen_node->data.fn_def_node.block_context = context; AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto; - bool is_exported = (fn_proto->visib_mod == FnProtoVisibModExport); + bool is_exported = (fn_proto->visib_mod == VisibModExport); for (int i = 0; i < fn_proto->params.length; i += 1) { AstNode *param_decl_node = fn_proto->params.at(i); assert(param_decl_node->type == NodeTypeParamDecl); @@ -2293,7 +2293,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, break; FnTableEntry *fn_entry = entry->value; - bool is_pub = (fn_entry->proto_node->data.fn_proto.visib_mod != FnProtoVisibModPrivate); + bool is_pub = (fn_entry->proto_node->data.fn_proto.visib_mod != VisibModPrivate); if (is_pub) { auto existing_entry = import->fn_table.maybe_get(entry->key); if (existing_entry) { @@ -2306,6 +2306,32 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, } } } + + // import all the public types + { + auto it = target_import->type_table.entry_iterator(); + for (;;) { + auto *entry = it.next(); + if (!entry) + break; + + TypeTableEntry *type_entry = entry->value; + if (type_entry->id == TypeTableEntryIdStruct) { + AstNode *decl_node = type_entry->data.structure.decl_node; + bool is_pub = (decl_node->data.struct_decl.visib_mod != VisibModPrivate); + if (is_pub) { + auto existing_entry = import->type_table.maybe_get(entry->key); + if (existing_entry) { + add_node_error(g, node, + buf_sprintf("import of type '%s' overrides existing definition", + buf_ptr(&type_entry->name))); + } else { + import->type_table.put(entry->key, entry->value); + } + } + } + } + } break; } case NodeTypeStructDecl: diff --git a/src/codegen.cpp b/src/codegen.cpp index a69f9e30b..f87ca7ef2 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2164,7 +2164,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path, assert(proto_node->type == NodeTypeFnProto); Buf *proto_name = &proto_node->data.fn_proto.name; - bool is_private = (proto_node->data.fn_proto.visib_mod == FnProtoVisibModPrivate); + bool is_private = (proto_node->data.fn_proto.visib_mod == VisibModPrivate); if (buf_eql_str(proto_name, "main") && !is_private) { g->have_exported_main = true; @@ -2287,7 +2287,7 @@ static void generate_h_file(CodeGen *g) { assert(proto_node->type == NodeTypeFnProto); AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; - if (fn_proto->visib_mod != FnProtoVisibModExport) + if (fn_proto->visib_mod != VisibModExport) continue; Buf return_type_c = BUF_INIT; diff --git a/src/parser.cpp b/src/parser.cpp index 24daca886..fbada2245 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2387,34 +2387,40 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type) */ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory) { - Token *token = &pc->tokens->at(*token_index); + Token *first_token = &pc->tokens->at(*token_index); - FnProtoVisibMod visib_mod; + VisibMod visib_mod; - if (token->id == TokenIdKeywordPub) { - visib_mod = FnProtoVisibModPub; - *token_index += 1; - - Token *fn_token = &pc->tokens->at(*token_index); - *token_index += 1; - ast_expect_token(pc, fn_token, TokenIdKeywordFn); - } else if (token->id == TokenIdKeywordExport) { - visib_mod = FnProtoVisibModExport; - *token_index += 1; - - Token *fn_token = &pc->tokens->at(*token_index); - *token_index += 1; - ast_expect_token(pc, fn_token, TokenIdKeywordFn); - } else if (token->id == TokenIdKeywordFn) { - visib_mod = FnProtoVisibModPrivate; + if (first_token->id == TokenIdKeywordPub) { + Token *next_token = &pc->tokens->at(*token_index + 1); + if (next_token->id == TokenIdKeywordFn) { + visib_mod = VisibModPub; + *token_index += 2; + } else if (mandatory) { + ast_invalid_token_error(pc, first_token); + } else { + return nullptr; + } + } else if (first_token->id == TokenIdKeywordExport) { + Token *next_token = &pc->tokens->at(*token_index + 1); + if (next_token->id == TokenIdKeywordFn) { + visib_mod = VisibModExport; + *token_index += 2; + } else if (mandatory) { + ast_invalid_token_error(pc, first_token); + } else { + return nullptr; + } + } else if (first_token->id == TokenIdKeywordFn) { + visib_mod = VisibModPrivate; *token_index += 1; } else if (mandatory) { - ast_invalid_token_error(pc, token); + ast_invalid_token_error(pc, first_token); } else { return nullptr; } - AstNode *node = ast_create_node(pc, NodeTypeFnProto, token); + AstNode *node = ast_create_node(pc, NodeTypeFnProto, first_token); node->data.fn_proto.visib_mod = visib_mod; node->data.fn_proto.directives = pc->directive_list; pc->directive_list = nullptr; @@ -2584,22 +2590,45 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index) { } /* -StructDecl : many(Directive) token(Struct) token(Symbol) token(LBrace) many(StructMember) token(RBrace) +StructDecl : many(Directive) option(FnVisibleMod) token(Struct) token(Symbol) token(LBrace) many(StructMember) token(RBrace) StructMember: StructField | FnDecl StructField : token(Symbol) token(Colon) Type token(Comma) */ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) { - Token *struct_kw = &pc->tokens->at(*token_index); - if (struct_kw->id != TokenIdKeywordStruct) + Token *first_token = &pc->tokens->at(*token_index); + + VisibMod visib_mod; + + if (first_token->id == TokenIdKeywordPub) { + Token *next_token = &pc->tokens->at(*token_index + 1); + if (next_token->id == TokenIdKeywordStruct) { + visib_mod = VisibModPub; + *token_index += 2; + } else { + return nullptr; + } + } else if (first_token->id == TokenIdKeywordExport) { + Token *next_token = &pc->tokens->at(*token_index + 1); + if (next_token->id == TokenIdKeywordStruct) { + visib_mod = VisibModExport; + *token_index += 2; + } else { + return nullptr; + } + } else if (first_token->id == TokenIdKeywordStruct) { + visib_mod = VisibModPrivate; + *token_index += 1; + } else { return nullptr; - *token_index += 1; + } Token *struct_name = &pc->tokens->at(*token_index); *token_index += 1; ast_expect_token(pc, struct_name, TokenIdSymbol); - AstNode *node = ast_create_node(pc, NodeTypeStructDecl, struct_kw); + AstNode *node = ast_create_node(pc, NodeTypeStructDecl, first_token); ast_buf_from_token(pc, struct_name, &node->data.struct_decl.name); + node->data.struct_decl.visib_mod = visib_mod; ast_eat_token(pc, token_index, TokenIdLBrace); diff --git a/src/parser.hpp b/src/parser.hpp index 8a3246fb3..9f64e777a 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -65,15 +65,15 @@ struct AstNodeRoot { ZigList top_level_decls; }; -enum FnProtoVisibMod { - FnProtoVisibModPrivate, - FnProtoVisibModPub, - FnProtoVisibModExport, +enum VisibMod { + VisibModPrivate, + VisibModPub, + VisibModExport, }; struct AstNodeFnProto { ZigList *directives; - FnProtoVisibMod visib_mod; + VisibMod visib_mod; Buf name; ZigList params; AstNode *return_type; @@ -284,6 +284,7 @@ struct AstNodeStructDecl { ZigList fields; ZigList fns; ZigList *directives; + VisibMod visib_mod; }; struct AstNodeStructField { diff --git a/std/errno.zig b/std/errno.zig deleted file mode 100644 index 6f50b5022..000000000 --- a/std/errno.zig +++ /dev/null @@ -1,146 +0,0 @@ -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/example/rand/main.zig b/std/rand.zig similarity index 79% rename from example/rand/main.zig rename to std/rand.zig index ad0c185bd..8d30c74c9 100644 --- a/example/rand/main.zig +++ b/std/rand.zig @@ -1,17 +1,26 @@ -export executable "rand"; - -use "std.zig"; - // Mersenne Twister const ARRAY_SIZE : u16 = 624; /// Use `rand_init` to initialize this state. -struct Rand { +pub struct Rand { // TODO use ARRAY_SIZE here array: [624]u32, // TODO use #typeof(ARRAY_SIZE) here index: u16, + /// Initialize random state with the given seed. + pub fn init(r: &Rand, seed: u32) { + r.index = 0; + r.array[0] = seed; + var i : #typeof(ARRAY_SIZE) = 1; + while (i < ARRAY_SIZE) { + const prev_value : u64 = r.array[i - 1]; + r.array[i] = ((prev_value ^ (prev_value << 30)) * 0x6c078965 + i) as u32; + i += 1; + } + } + + /// Get 32 bits of randomness. pub fn get_u32(r: &Rand) -> u32 { if (r.index == 0) { @@ -90,31 +99,3 @@ struct Rand { } } -/// Initialize random state with the given seed. -pub fn rand_init(r: &Rand, seed: u32) { - r.index = 0; - r.array[0] = seed; - var i : #typeof(ARRAY_SIZE) = 1; - while (i < ARRAY_SIZE) { - const prev_value : u64 = r.array[i - 1]; - r.array[i] = ((prev_value ^ (prev_value << 30)) * 0x6c078965 + i) as u32; - i += 1; - } -} - -pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { - var rand : Rand; - var i : u8 = 0; - while (i < 20) { - rand_init(&rand, i); - var j : u8 = 0; - while (j < 20) { - print_u64(rand.range_u64(0, 100) + 1); - print_str(" "); - j += 1; - } - print_str("\n"); - i += 1; - } - return 0; -}