├── .gitattributes ├── .github └── workflows │ └── deploy.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── examples.txt ├── examples ├── arrays │ ├── arrays.hash │ ├── arrays.sh │ └── arrays.zig ├── assignment │ ├── assignment.hash │ └── assignment.zig ├── floats │ ├── floats.hash │ ├── floats.sh │ └── floats.zig ├── for │ ├── for.hash │ ├── for.sh │ └── for.zig ├── hello-world │ ├── hello-world.hash │ ├── hello-world.sh │ └── hello-world.zig ├── if-else │ ├── if-else.hash │ ├── if-else.sh │ └── if-else.zig ├── integers │ ├── integers.hash │ ├── integers.sh │ └── integers.zig ├── pointers │ ├── pointers.hash │ ├── pointers.sh │ └── pointers.zig ├── slices │ ├── slices.hash │ ├── slices.sh │ └── slices.zig ├── switch │ ├── switch.hash │ ├── switch.sh │ └── switch.zig └── while │ ├── while.hash │ ├── while.sh │ └── while.zig ├── go.mod ├── go.sum ├── templates ├── 404.html ├── clipboard.png ├── example.tmpl ├── favicon.ico ├── footer.tmpl ├── index.tmpl ├── play.png ├── site.css └── site.js └── tools ├── build ├── build-loop ├── format ├── generate ├── generate.go ├── measure ├── measure.go ├── serve ├── serve.go └── test /.gitattributes: -------------------------------------------------------------------------------- 1 | public/** linguist-generated 2 | 3 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | concurrency: ci-${{ github.ref }} 13 | 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v3 17 | 18 | - name: Go 19 | uses: actions/setup-go@v3 20 | with: 21 | go-version: '>=1.18.0' 22 | 23 | - name: Zig 24 | uses: goto-bus-stop/setup-zig@v1 25 | with: 26 | version: master 27 | 28 | - name: Build 29 | run: tools/build 30 | env: 31 | VERBOSE: 1 32 | 33 | - name: Deploy 34 | uses: s0/git-publish-subdir-action@develop 35 | env: 36 | REPO: self 37 | BRANCH: docs 38 | FOLDER: public 39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .idea 3 | .vscode 4 | 5 | public/ 6 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thanks for your interest in contributing to Zig by Example! 4 | 5 | * When sending a PR that affects the displayed contents of the site, run 6 | `tools/build` locally and include the generated HTML in the PR. If you 7 | only want to submit a simple typo suggestion (for example, through the 8 | Github website), feel free to send a PR anyway - we'll regenerate the 9 | HTML and merge with your commit. 10 | 11 | * We're open to adding more examples to the site. They should be on things 12 | used by many programmers and only require the standard library. If you're 13 | interested in adding an example, _please open an issue to discuss the topic 14 | first_. 15 | 16 | * We're not going to change the navigation of the site, in particular adding 17 | a "previous section" link or an "index" link other than the one on the title 18 | text. 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE 2 | COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY 3 | COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS 4 | AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. 5 | 6 | BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE 7 | BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE 8 | CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE 9 | IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. 10 | 11 | 1. Definitions 12 | 13 | "Adaptation" means a work based upon the Work, or upon the Work and other 14 | pre-existing works, such as a translation, adaptation, derivative work, 15 | arrangement of music or other alterations of a literary or artistic work, 16 | or phonogram or performance and includes cinematographic adaptations or any 17 | other form in which the Work may be recast, transformed, or adapted 18 | including in any form recognizably derived from the original, except that a 19 | work that constitutes a Collection will not be considered an Adaptation for 20 | the purpose of this License. For the avoidance of doubt, where the Work is 21 | a musical work, performance or phonogram, the synchronization of the Work 22 | in timed-relation with a moving image ("synching") will be considered an 23 | Adaptation for the purpose of this License. "Collection" means a collection 24 | of literary or artistic works, such as encyclopedias and anthologies, or 25 | performances, phonograms or broadcasts, or other works or subject matter 26 | other than works listed in Section 1(f) below, which, by reason of the 27 | selection and arrangement of their contents, constitute intellectual 28 | creations, in which the Work is included in its entirety in unmodified form 29 | along with one or more other contributions, each constituting separate and 30 | independent works in themselves, which together are assembled into a 31 | collective whole. A work that constitutes a Collection will not be 32 | considered an Adaptation (as defined above) for the purposes of this 33 | License. "Distribute" means to make available to the public the original 34 | and copies of the Work or Adaptation, as appropriate, through sale or other 35 | transfer of ownership. "Licensor" means the individual, individuals, entity 36 | or entities that offer(s) the Work under the terms of this License. 37 | "Original Author" means, in the case of a literary or artistic work, the 38 | individual, individuals, entity or entities who created the Work or if no 39 | individual or entity can be identified, the publisher; and in addition (i) 40 | in the case of a performance the actors, singers, musicians, dancers, and 41 | other persons who act, sing, deliver, declaim, play in, interpret or 42 | otherwise perform literary or artistic works or expressions of folklore; 43 | (ii) in the case of a phonogram the producer being the person or legal 44 | entity who first fixes the sounds of a performance or other sounds; and, 45 | (iii) in the case of broadcasts, the organization that transmits the 46 | broadcast. "Work" means the literary and/or artistic work offered under the 47 | terms of this License including without limitation any production in the 48 | literary, scientific and artistic domain, whatever may be the mode or form 49 | of its expression including digital form, such as a book, pamphlet and 50 | other writing; a lecture, address, sermon or other work of the same nature; 51 | a dramatic or dramatico-musical work; a choreographic work or entertainment 52 | in dumb show; a musical composition with or without words; a 53 | cinematographic work to which are assimilated works expressed by a process 54 | analogous to cinematography; a work of drawing, painting, architecture, 55 | sculpture, engraving or lithography; a photographic work to which are 56 | assimilated works expressed by a process analogous to photography; a work 57 | of applied art; an illustration, map, plan, sketch or three-dimensional 58 | work relative to geography, topography, architecture or science; a 59 | performance; a broadcast; a phonogram; a compilation of data to the extent 60 | it is protected as a copyrightable work; or a work performed by a variety 61 | or circus performer to the extent it is not otherwise considered a literary 62 | or artistic work. "You" means an individual or entity exercising rights 63 | under this License who has not previously violated the terms of this 64 | License with respect to the Work, or who has received express permission 65 | from the Licensor to exercise rights under this License despite a previous 66 | violation. "Publicly Perform" means to perform public recitations of the 67 | Work and to communicate to the public those public recitations, by any 68 | means or process, including by wire or wireless means or public digital 69 | performances; to make available to the public Works in such a way that 70 | members of the public may access these Works from a place and at a place 71 | individually chosen by them; to perform the Work to the public by any means 72 | or process and the communication to the public of the performances of the 73 | Work, including by public digital performance; to broadcast and rebroadcast 74 | the Work by any means including signs, sounds or images. "Reproduce" means 75 | to make copies of the Work by any means including without limitation by 76 | sound or visual recordings and the right of fixation and reproducing 77 | fixations of the Work, including storage of a protected performance or 78 | phonogram in digital form or other electronic medium. 79 | 80 | 2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, 81 | or restrict any uses free from copyright or rights arising from limitations or 82 | exceptions that are provided for in connection with the copyright protection 83 | under copyright law or other applicable laws. 84 | 85 | 3. License Grant. Subject to the terms and conditions of this License, Licensor 86 | hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the 87 | duration of the applicable copyright) license to exercise the rights in the 88 | Work as stated below: 89 | 90 | to Reproduce the Work, to incorporate the Work into one or more 91 | Collections, and to Reproduce the Work as incorporated in the Collections; 92 | to create and Reproduce Adaptations provided that any such Adaptation, 93 | including any translation in any medium, takes reasonable steps to clearly 94 | label, demarcate or otherwise identify that changes were made to the 95 | original Work. For example, a translation could be marked "The original 96 | work was translated from English to Spanish," or a modification could 97 | indicate "The original work has been modified."; to Distribute and Publicly 98 | Perform the Work including as incorporated in Collections; and, to 99 | Distribute and Publicly Perform Adaptations. 100 | 101 | For the avoidance of doubt: Non-waivable Compulsory License Schemes. In 102 | those jurisdictions in which the right to collect royalties through any 103 | statutory or compulsory licensing scheme cannot be waived, the Licensor 104 | reserves the exclusive right to collect such royalties for any exercise by 105 | You of the rights granted under this License; Waivable Compulsory License 106 | Schemes. In those jurisdictions in which the right to collect royalties 107 | through any statutory or compulsory licensing scheme can be waived, the 108 | Licensor waives the exclusive right to collect such royalties for any 109 | exercise by You of the rights granted under this License; and, Voluntary 110 | License Schemes. The Licensor waives the right to collect royalties, 111 | whether individually or, in the event that the Licensor is a member of a 112 | collecting society that administers voluntary licensing schemes, via that 113 | society, from any exercise by You of the rights granted under this License. 114 | 115 | The above rights may be exercised in all media and formats whether now known or 116 | hereafter devised. The above rights include the right to make such 117 | modifications as are technically necessary to exercise the rights in other 118 | media and formats. Subject to Section 8(f), all rights not expressly granted by 119 | Licensor are hereby reserved. 120 | 121 | 4. Restrictions. The license granted in Section 3 above is expressly made 122 | subject to and limited by the following restrictions: 123 | 124 | You may Distribute or Publicly Perform the Work only under the terms of 125 | this License. You must include a copy of, or the Uniform Resource 126 | Identifier (URI) for, this License with every copy of the Work You 127 | Distribute or Publicly Perform. You may not offer or impose any terms on 128 | the Work that restrict the terms of this License or the ability of the 129 | recipient of the Work to exercise the rights granted to that recipient 130 | under the terms of the License. You may not sublicense the Work. You must 131 | keep intact all notices that refer to this License and to the disclaimer of 132 | warranties with every copy of the Work You Distribute or Publicly Perform. 133 | When You Distribute or Publicly Perform the Work, You may not impose any 134 | effective technological measures on the Work that restrict the ability of a 135 | recipient of the Work from You to exercise the rights granted to that 136 | recipient under the terms of the License. This Section 4(a) applies to the 137 | Work as incorporated in a Collection, but this does not require the 138 | Collection apart from the Work itself to be made subject to the terms of 139 | this License. If You create a Collection, upon notice from any Licensor You 140 | must, to the extent practicable, remove from the Collection any credit as 141 | required by Section 4(b), as requested. If You create an Adaptation, upon 142 | notice from any Licensor You must, to the extent practicable, remove from 143 | the Adaptation any credit as required by Section 4(b), as requested. If You 144 | Distribute, or Publicly Perform the Work or any Adaptations or Collections, 145 | You must, unless a request has been made pursuant to Section 4(a), keep 146 | intact all copyright notices for the Work and provide, reasonable to the 147 | medium or means You are utilizing: (i) the name of the Original Author (or 148 | pseudonym, if applicable) if supplied, and/or if the Original Author and/or 149 | Licensor designate another party or parties (e.g., a sponsor institute, 150 | publishing entity, journal) for attribution ("Attribution Parties") in 151 | Licensor's copyright notice, terms of service or by other reasonable means, 152 | the name of such party or parties; (ii) the title of the Work if supplied; 153 | (iii) to the extent reasonably practicable, the URI, if any, that Licensor 154 | specifies to be associated with the Work, unless such URI does not refer to 155 | the copyright notice or licensing information for the Work; and (iv) , 156 | consistent with Section 3(b), in the case of an Adaptation, a credit 157 | identifying the use of the Work in the Adaptation (e.g., "French 158 | translation of the Work by Original Author," or "Screenplay based on 159 | original Work by Original Author"). The credit required by this Section 4 160 | (b) may be implemented in any reasonable manner; provided, however, that in 161 | the case of a Adaptation or Collection, at a minimum such credit will 162 | appear, if a credit for all contributing authors of the Adaptation or 163 | Collection appears, then as part of these credits and in a manner at least 164 | as prominent as the credits for the other contributing authors. For the 165 | avoidance of doubt, You may only use the credit required by this Section 166 | for the purpose of attribution in the manner set out above and, by 167 | exercising Your rights under this License, You may not implicitly or 168 | explicitly assert or imply any connection with, sponsorship or endorsement 169 | by the Original Author, Licensor and/or Attribution Parties, as 170 | appropriate, of You or Your use of the Work, without the separate, express 171 | prior written permission of the Original Author, Licensor and/or 172 | Attribution Parties. Except as otherwise agreed in writing by the Licensor 173 | or as may be otherwise permitted by applicable law, if You Reproduce, 174 | Distribute or Publicly Perform the Work either by itself or as part of any 175 | Adaptations or Collections, You must not distort, mutilate, modify or take 176 | other derogatory action in relation to the Work which would be prejudicial 177 | to the Original Author's honor or reputation. Licensor agrees that in those 178 | jurisdictions (e.g. Japan), in which any exercise of the right granted in 179 | Section 3(b) of this License (the right to make Adaptations) would be 180 | deemed to be a distortion, mutilation, modification or other derogatory 181 | action prejudicial to the Original Author's honor and reputation, the 182 | Licensor will waive or not assert, as appropriate, this Section, to the 183 | fullest extent permitted by the applicable national law, to enable You to 184 | reasonably exercise Your right under Section 3(b) of this License (right to 185 | make Adaptations) but not otherwise. 186 | 187 | 5. Representations, Warranties and Disclaimer 188 | 189 | UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS 190 | THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND 191 | CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, 192 | WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A 193 | PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, 194 | ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. 195 | SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH 196 | EXCLUSION MAY NOT APPLY TO YOU. 197 | 198 | 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN 199 | NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, 200 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS 201 | LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE 202 | POSSIBILITY OF SUCH DAMAGES. 203 | 204 | 7. Termination 205 | 206 | This License and the rights granted hereunder will terminate automatically 207 | upon any breach by You of the terms of this License. Individuals or 208 | entities who have received Adaptations or Collections from You under this 209 | License, however, will not have their licenses terminated provided such 210 | individuals or entities remain in full compliance with those licenses. 211 | Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. 212 | Subject to the above terms and conditions, the license granted here is 213 | perpetual (for the duration of the applicable copyright in the Work). 214 | Notwithstanding the above, Licensor reserves the right to release the Work 215 | under different license terms or to stop distributing the Work at any time; 216 | provided, however that any such election will not serve to withdraw this 217 | License (or any other license that has been, or is required to be, granted 218 | under the terms of this License), and this License will continue in full 219 | force and effect unless terminated as stated above. 220 | 221 | 8. Miscellaneous 222 | 223 | Each time You Distribute or Publicly Perform the Work or a Collection, the 224 | Licensor offers to the recipient a license to the Work on the same terms 225 | and conditions as the license granted to You under this License. Each time 226 | You Distribute or Publicly Perform an Adaptation, Licensor offers to the 227 | recipient a license to the original Work on the same terms and conditions 228 | as the license granted to You under this License. If any provision of this 229 | License is invalid or unenforceable under applicable law, it shall not 230 | affect the validity or enforceability of the remainder of the terms of this 231 | License, and without further action by the parties to this agreement, such 232 | provision shall be reformed to the minimum extent necessary to make such 233 | provision valid and enforceable. No term or provision of this License shall 234 | be deemed waived and no breach consented to unless such waiver or consent 235 | shall be in writing and signed by the party to be charged with such waiver 236 | or consent. This License constitutes the entire agreement between the 237 | parties with respect to the Work licensed here. There are no 238 | understandings, agreements or representations with respect to the Work not 239 | specified here. Licensor shall not be bound by any additional provisions 240 | that may appear in any communication from You. This License may not be 241 | modified without the mutual written agreement of the Licensor and You. The 242 | rights granted under, and the subject matter referenced, in this License 243 | were drafted utilizing the terminology of the Berne Convention for the 244 | Protection of Literary and Artistic Works (as amended on September 28, 245 | 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the 246 | WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright 247 | Convention (as revised on July 24, 1971). These rights and subject matter 248 | take effect in the relevant jurisdiction in which the License terms are 249 | sought to be enforced according to the corresponding provisions of the 250 | implementation of those treaty provisions in the applicable national law. 251 | If the standard suite of rights granted under applicable copyright law 252 | includes additional rights not granted under this License, such additional 253 | rights are deemed to be included in the License; this License is not 254 | intended to restrict the license of any rights under applicable law. 255 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Zig by Example

2 |

Content and build toolchain for Zig by Example.

3 | 4 | ## Building 5 | 6 | To build the site: 7 | 8 | ```sh 9 | tools/build 10 | ``` 11 | 12 | To build the site continuously in a loop: 13 | 14 | ```sh 15 | tools/build-loop 16 | ``` 17 | 18 | To serve the site locally: 19 | 20 | ```sh 21 | tools/serve 22 | ``` 23 | 24 | ## License 25 | 26 | This work is a derivative of "Go by Example" by [Mark McGranaghan](https://markmcgranaghan.com), used under [CC BY 3.0](https://creativecommons.org/licenses/by/3.0/). 27 | 28 | This work is licensed under [CC BY 3.0](https://github.com/ibokuri/zig-by-example/blob/main/LICENSE) by Jason Phan. 29 | -------------------------------------------------------------------------------- /examples.txt: -------------------------------------------------------------------------------- 1 | Hello World 2 | Assignment 3 | Integers 4 | Floats 5 | Arrays 6 | Pointers 7 | Slices 8 | While 9 | For 10 | If/Else 11 | Switch 12 | -------------------------------------------------------------------------------- /examples/arrays/arrays.hash: -------------------------------------------------------------------------------- 1 | 48e80a6fe6a42fbd2f67a5da0c5335fceaf5d8cf 2 | dSMbW-t2Vlk 3 | -------------------------------------------------------------------------------- /examples/arrays/arrays.sh: -------------------------------------------------------------------------------- 1 | $ zig run arrays.zig 2 | len: 3 3 | repeat: { 1, 2, 3, 1, 2, 3 } 4 | concat: { 1, 2, 3, 4, 5, 6 } 5 | elem: 10 6 | elem: 11 7 | elem: 12 8 | -------------------------------------------------------------------------------- /examples/arrays/arrays.zig: -------------------------------------------------------------------------------- 1 | // _Arrays_ are fixed-size, sequential collections of elements of the same 2 | // type. 3 | 4 | const std = @import("std"); 5 | const print = std.debug.print; 6 | 7 | pub fn main() !void { 8 | 9 | // Here, we define an array using the _array literal_ syntax. 10 | const a = [3]i32{ 1, 2, 3 }; 11 | 12 | // Here, we define an array with a size of `_`. This tells the compiler 13 | // to infer the array's size for us (in this case, `3`). 14 | const b = [_]i32{ 4, 5, 6 }; 15 | 16 | // Here, we define an array using an _anonymous list literal_. The value on 17 | // the right-hand side will coerce to the array type specified on the 18 | // left-hand side. 19 | const c: [3]i32 = .{ 7, 8, 9 }; 20 | 21 | // To access the elements of an array, use the `[N]` syntax, where `N` is 22 | // the position of the element (starting from 0). 23 | var d: [3]i32 = undefined; 24 | d[0] = 10; 25 | d[1] = 11; 26 | d[2] = 12; 27 | 28 | // Every array has a `len` field that stores the array's size. 29 | print("len: {}\n", .{c.len}); 30 | 31 | // If an array is compile-time known, it can be repeated. 32 | print("repeat: {any}\n", .{a ** 2}); 33 | 34 | // If two arrays are compile-time known, they can be concatenated. 35 | print("concat: {any}\n", .{a ++ b}); 36 | 37 | // To iterate over an array, you can use a For loop. 39 | for (d) |elem| { 40 | print("elem: {}\n", .{elem}); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/assignment/assignment.hash: -------------------------------------------------------------------------------- 1 | 971bc3f601839dc617312bc66be421914becf09e 2 | Gxn3ZX4UkvR 3 | -------------------------------------------------------------------------------- /examples/assignment/assignment.zig: -------------------------------------------------------------------------------- 1 | // In Zig, values can be assigned to _constants_ or _variables_. 2 | 3 | const std = @import("std"); 4 | 5 | pub fn main() !void { 6 | 7 | // Here, we assign the value `true` to the `bool` constant `c`. 8 | // Constants are immutable, so the value of `c` _cannot_ change. 9 | const c: bool = true; 10 | 11 | // Here, we assign the value `false` to the `bool` variable `v`. 12 | // Variables are mutable, so the value of `v` _can_ change. 13 | var v: bool = false; 14 | v = true; 15 | 16 | // Note that the compiler can often infer types for you. 17 | const inferred = true; 18 | 19 | // To create an uninitialized constant or variable, assign `undefined` 20 | // to it. Using undefined values will result in either a crash or undefined 21 | // behavior, so be careful! 22 | var u: bool = undefined; 23 | u = true; 24 | 25 | // Assignments can also be used to ignore expressions. 26 | _ = c; 27 | _ = inferred; 28 | } 29 | -------------------------------------------------------------------------------- /examples/floats/floats.hash: -------------------------------------------------------------------------------- 1 | 94867780541df91398ffd677e011d2a8863391cd 2 | _sPA-kcDfjH 3 | -------------------------------------------------------------------------------- /examples/floats/floats.sh: -------------------------------------------------------------------------------- 1 | $ zig run floats.zig 2 | float: 1.0e+06 3 | -------------------------------------------------------------------------------- /examples/floats/floats.zig: -------------------------------------------------------------------------------- 1 | // _Floating-points_ in Zig are similar to integers, though they cannot have 2 | // arbitrary bit-widths. 3 | 4 | const std = @import("std"); 5 | const print = std.debug.print; 6 | 7 | // Here, we define some common floating types. 8 | const a: f16 = 1.0; 9 | const b: f32 = 100.0; 10 | const c: f64 = 1_000.0; 11 | const d: f128 = 10_000.0; 12 | 13 | // Here, we define some _compile-time_ known floats. These have 14 | // no size limit and are written as float literals. 15 | const e: comptime_float = 100_000.0; 16 | const f = 1_000_000.0; 17 | 18 | pub fn main() !void { 19 | print("float: {}\n", .{f}); 20 | } 21 | -------------------------------------------------------------------------------- /examples/for/for.hash: -------------------------------------------------------------------------------- 1 | 40567346ab254e077af385e1b18fffce8d91b4f8 2 | q2r2dKpHybg 3 | -------------------------------------------------------------------------------- /examples/for/for.sh: -------------------------------------------------------------------------------- 1 | $ zig run for.zig 2 | by val: 1 3 | by val: 2 4 | by val: 3 5 | by ref: 101 6 | by ref: 102 7 | by ref: 103 8 | 0: 101 9 | 1: 102 10 | 2: 103 11 | -------------------------------------------------------------------------------- /examples/for/for.zig: -------------------------------------------------------------------------------- 1 | // _For loops_ can be used to iterate over sequences. 2 | 3 | const std = @import("std"); 4 | const print = std.debug.print; 5 | 6 | pub fn main() !void { 7 | var array = [_]u32{ 1, 2, 3 }; 8 | 9 | // Here, we iterate over `array` by _value_, storing a copy of each element 10 | // in `elem`. Note that since `elem` is just a copy, we cannot use it to 11 | // modify `array`'s contents. 12 | for (array) |elem| { 13 | print("by val: {}\n", .{elem}); 14 | } 15 | 16 | // To iterate by _reference_, we can loop over a slice of `array` and 17 | // prefix `elem` with a `*`. Here, `elem` is a pointer to an element in 18 | // `array`, which we can use to modify `array`'s contents. 19 | for (&array) |*elem| { 20 | elem.* += 100; 21 | print("by ref: {}\n", .{elem.*}); 22 | } 23 | 24 | // Here, we iterate over multiple sequences. Note that both sequences 25 | // _must_ have the same length. 26 | for (array, &array) |val, *ref| { 27 | _ = val; 28 | _ = ref; 29 | } 30 | 31 | // You may also specify a _range_ with the `start..end` syntax. Note that 32 | // `end` may be omitted if another sequence is being iterated over as well; 33 | // the compiler will infer the range's size. 34 | for (0.., array) |i, elem| { 35 | print("{}: {}\n", .{ i, elem }); 36 | } 37 | 38 | // To ignore the elements of a sequence, use `_`. 39 | for (array) |_| {} 40 | } 41 | -------------------------------------------------------------------------------- /examples/hello-world/hello-world.hash: -------------------------------------------------------------------------------- 1 | 3ef639a74858666cf0067fb8d998c7b235c49d1d 2 | 5r0ltDMySoG 3 | -------------------------------------------------------------------------------- /examples/hello-world/hello-world.sh: -------------------------------------------------------------------------------- 1 | # To run this Zig program, use `zig run`. 2 | $ zig run hello-world.zig 3 | Hello, World! 4 | 5 | # To compile this Zig program, use `zig build-exe`. 6 | $ zig build-exe hello-world.zig 7 | $ ./hello-world 8 | Hello, World! 9 | -------------------------------------------------------------------------------- /examples/hello-world/hello-world.zig: -------------------------------------------------------------------------------- 1 | // To start, we'll print the classic "Hello, World!" message. 2 | const std = @import("std"); 3 | 4 | pub fn main() !void { 5 | std.debug.print("Hello, World!\n", .{}); 6 | } 7 | -------------------------------------------------------------------------------- /examples/if-else/if-else.hash: -------------------------------------------------------------------------------- 1 | a81fdd9d6c236e84a56bb2d375f4ee1ac85f2df7 2 | yI8u6Y4uba3 3 | -------------------------------------------------------------------------------- /examples/if-else/if-else.sh: -------------------------------------------------------------------------------- 1 | $ zig run if-else.zig 2 | x = 1? true 3 | x now is: 2 4 | -------------------------------------------------------------------------------- /examples/if-else/if-else.zig: -------------------------------------------------------------------------------- 1 | // _If statements_ accept bool values (i.e. true or false). 2 | 3 | const std = @import("std"); 4 | const print = std.debug.print; 5 | 6 | pub fn main() !void { 7 | 8 | // Here we assign _a_ as _true_ to be validated further and use _x_. 9 | const a: bool = true; 10 | var x: u16 = 0; 11 | 12 | // Unlike languages like C or Javascript, there are no values that implicitly coerce to bool values, but the parentheses _(...)_ are always required. 13 | if (a) { 14 | x += 1; 15 | } else { 16 | x += 2; 17 | } 18 | 19 | // Here we use a boolean expression to evaluate _x_. 20 | print("x = 1? {}\n", .{x == 1}); 21 | 22 | // If statements also work as expressions. 23 | x += if (x == 1) 1 else 2; 24 | print("x now is: {d}\n", .{x}); 25 | } 26 | -------------------------------------------------------------------------------- /examples/integers/integers.hash: -------------------------------------------------------------------------------- 1 | b32fe016bb2316379df38eaace8ee61f212ebe66 2 | EXvPF056zbi 3 | -------------------------------------------------------------------------------- /examples/integers/integers.sh: -------------------------------------------------------------------------------- 1 | $ zig run integers.zig 2 | integer: 128175 3 | unicode: 💯 4 | -------------------------------------------------------------------------------- /examples/integers/integers.zig: -------------------------------------------------------------------------------- 1 | // _Integers_ in Zig can have arbitrary bit-widths. 2 | 3 | const std = @import("std"); 4 | const print = std.debug.print; 5 | 6 | // Here, we define some common integer types. 7 | const a: u8 = 1; 8 | const b: u32 = 10; 9 | const c: i64 = 100; 10 | const d: isize = 1_000; 11 | 12 | // Here, we define some not so common integer types. 13 | const e: u21 = 10_000; 14 | const f: i42 = 100_000; 15 | 16 | // Here, we define some _compile-time_ known integers. These have no size limit 17 | // and can be written as either integer literals or Unicode code point 18 | // literals. 19 | const g: comptime_int = 1_000_000; 20 | const h = 10_000_000; 21 | const i = '💯'; 22 | 23 | pub fn main() !void { 24 | print("integer: {d}\n", .{i}); 25 | print("unicode: {u}\n", .{i}); 26 | } 27 | -------------------------------------------------------------------------------- /examples/pointers/pointers.hash: -------------------------------------------------------------------------------- 1 | e26d2489d03df9f279e4779705585e9618b92b4b 2 | BCJqEpLCb5V 3 | -------------------------------------------------------------------------------- /examples/pointers/pointers.sh: -------------------------------------------------------------------------------- 1 | $ zig run pointers.zig 2 | pointer: bool@7ff7b26e24a7 3 | value: true 4 | -------------------------------------------------------------------------------- /examples/pointers/pointers.zig: -------------------------------------------------------------------------------- 1 | // _Pointers_ are objects that store a memory address. 2 | 3 | const std = @import("std"); 4 | const print = std.debug.print; 5 | 6 | // _Single-item pointers_ point to exactly one value. 7 | const Single = *bool; 8 | 9 | // _Many-item pointers_ point to an unknown number of values. Unless you're 10 | // interfacing with C code, you probably won't use these types of pointers, so 11 | // we'll skip over them. 12 | const Many = [*]bool; 13 | 14 | // All pointers in Zig point to a non-`null` value. To define a `null` pointer, 15 | // you must make the pointer type 16 | // optional. 17 | const Null = ?*bool; 18 | 19 | pub fn main() !void { 20 | 21 | // To create a single-item pointer, use the `&` operator. 22 | var v = false; 23 | const ptr: *bool = &v; 24 | print("pointer: {}\n", .{ptr}); 25 | 26 | // To access the value located at the memory address stored by a 27 | // single-item pointer, use the `*` operator. 28 | ptr.* = true; 29 | print("value: {}\n", .{ptr.*}); 30 | 31 | // If a _pointer_ is `const`, the value of its pointee can be modified, but 32 | // the pointer itself cannot be re-assigned. 33 | const const_ptr: *bool = &v; 34 | const_ptr.* = false; 35 | 36 | // If a _pointee_ is `const`, its pointer type will reflect that. The value 37 | // of `const` pointees cannot be modified, but the pointer itself can be 38 | // re-assigned. 39 | const cf = false; 40 | const ct = true; 41 | var ptr_to_const: *const bool = &cf; 42 | ptr_to_const = &ct; 43 | } 44 | -------------------------------------------------------------------------------- /examples/slices/slices.hash: -------------------------------------------------------------------------------- 1 | 2fbb741d28d804029df631527c3f6cfacb8fe3fc 2 | 5p6zYKzzpdP 3 | -------------------------------------------------------------------------------- /examples/slices/slices.sh: -------------------------------------------------------------------------------- 1 | $ zig run slices.zig 2 | len: 3 3 | first: 2 4 | elem: 2 5 | elem: 3 6 | elem: 4 7 | len: 3 8 | first: 2 9 | elem: 2 10 | elem: 3 11 | elem: 4 12 | -------------------------------------------------------------------------------- /examples/slices/slices.zig: -------------------------------------------------------------------------------- 1 | // _Slices_ are a special kind of pointer that reference a contiguous subset of 2 | // elements in a sequence. 3 | 4 | const std = @import("std"); 5 | const print = std.debug.print; 6 | 7 | // The easiest way to understand slices is to think of them as a single-item 8 | // pointer plus a length. The pointer tells you where the slice begins and the 9 | // length tells you its size. 10 | const Slice = []bool; 11 | 12 | pub fn main() !void { 13 | 14 | // Here, we define a slice using the `[start..end]` syntax. 15 | // `slice` begins at `array[1]` and ends just before `array[4]`. 16 | var array = [5]i32{ 1, 2, 3, 4, 5 }; 17 | const end: usize = 4; 18 | const slice = array[1..end]; 19 | 20 | // Functionally, slices are very similar to arrays. You can get their 21 | // length, index into them, and iterate over them. 22 | print("len: {}\n", .{slice.len}); 23 | print("first: {}\n", .{slice[0]}); 24 | for (slice) |elem| { 25 | print("elem: {}\n", .{elem}); 26 | } 27 | 28 | // All slices _must_ have a runtime-known length. If, instead, their 29 | // lengths are compile-time known, the compiler will convert the slice into 30 | // a single-item array pointer for us. 31 | const ptr: *[3]i32 = array[1..4]; 32 | 33 | // In practice, single-item array pointers are just like slices. 34 | // The only real difference is that with array pointers, bounds checking 35 | // occurs at compile-time. 36 | print("len: {}\n", .{ptr.len}); 37 | print("first: {}\n", .{ptr[0]}); 38 | for (ptr) |elem| { 39 | print("elem: {}\n", .{elem}); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /examples/switch/switch.hash: -------------------------------------------------------------------------------- 1 | b00ee7f4813b5a0b11b79cd4ff7171da3d2b120a 2 | 7z0D0yJ4XrZ 3 | -------------------------------------------------------------------------------- /examples/switch/switch.sh: -------------------------------------------------------------------------------- 1 | $ zig run switch.zig 2 | x: 10 3 | 1 4 | 2 5 | Fizz 6 | 4 7 | Buzz 8 | Fizz 9 | 7 10 | 8 11 | Fizz 12 | Buzz 13 | 11 14 | Fizz 15 | 13 16 | 14 17 | FizzBuzz 18 | x: 1 19 | -------------------------------------------------------------------------------- /examples/switch/switch.zig: -------------------------------------------------------------------------------- 1 | // _Switch_ works as both a statement and an expression. 2 | 3 | const std = @import("std"); 4 | const print = std.debug.print; 5 | 6 | pub fn main() !void { 7 | var x: i8 = 10; 8 | 9 | // An example of a _switch_ statement. The _else_ is required to satisfy the exhaustiveness of this _switch_. All possible values must have an associated branch, values cannot be left out. Cases cannot fall through to other branches. 10 | switch (x) { 11 | -1...1 => { 12 | x = -x; 13 | }, 14 | 10, 100 => print("x: {d}\n", .{x}), 15 | else => {}, 16 | } 17 | // Here the classic FizzBuzz exercise using a _switch_ statement. 18 | var count: u8 = 1; 19 | while (count <= 15) : (count += 1) { 20 | 21 | // After define _while_ to count until 15 we use _@intFromBool_ which converts true to 1 and false to 0 resulting into a u1 value (i.e. a 1 bit unsigned integer). 22 | const div3: u2 = @intFromBool(count % 3 == 0); 23 | 24 | // You may notice that we haven't given _div5_ an explicit type, this is because it is inferred from the value that is assigned to it. 25 | const div5 = @intFromBool(count % 5 == 0); 26 | 27 | // We need _u2_ to fit two booleans and perform this multiplication of _div3_, you can see the binary notation in action as result to satisfy the expression evaluated. 28 | // We can rewrite the _switch_ value to use bitwise operations: _switch_ _(div3 << 1 | div5)_. 29 | switch (div3 * 2 + div5) { 30 | 0b10 => print("Fizz\n", .{}), 31 | 0b01 => print("Buzz\n", .{}), 32 | 0b11 => { 33 | print("Fizz", .{}); 34 | print("Buzz\n", .{}); 35 | }, 36 | else => print("{d}\n", .{count}), 37 | } 38 | } 39 | 40 | // _switch_ can also be used as expression. 41 | x = switch (x) { 42 | -1...1 => -x, 43 | 10, 100 => @divExact(x, 10), 44 | else => x, 45 | }; 46 | print("x: {d}\n", .{x}); 47 | } 48 | -------------------------------------------------------------------------------- /examples/while/while.hash: -------------------------------------------------------------------------------- 1 | c00bb418ad78f8a32f923fc069a3610341cd2d7c 2 | NWDAi0L1wmZ 3 | -------------------------------------------------------------------------------- /examples/while/while.sh: -------------------------------------------------------------------------------- 1 | $ zig run while.zig 2 | a: 0 3 | a: 1 4 | b: 0 5 | b: 1 6 | c: 0 7 | c: 2 8 | d: 0 9 | d: 1 10 | -------------------------------------------------------------------------------- /examples/while/while.zig: -------------------------------------------------------------------------------- 1 | // _While_ loops can be used to repeat expressions. 2 | 3 | const std = @import("std"); 4 | const print = std.debug.print; 5 | 6 | pub fn main() !void { 7 | var a: usize = 0; 8 | var b: usize = 0; 9 | var c: usize = 0; 10 | var d: usize = 0; 11 | 12 | // The body of a while loop will repeatedly execute until the loop's 13 | // condition is no longer true. 14 | while (a < 2) { 15 | print("a: {}\n", .{a}); 16 | a += 1; 17 | } 18 | 19 | // _Continue expressions_ can be used to evaluate an expression after each 20 | // execution of a while loop's body. 21 | while (b < 2) : (b += 1) { 22 | print("b: {}\n", .{b}); 23 | } 24 | 25 | // You can specify multiple continue expressions by using the `{ ; ; ... }` syntax. 26 | while (c < 4) : ({ 27 | c += 1; 28 | c += 1; 29 | }) { 30 | print("c: {}\n", .{c}); 31 | } 32 | 33 | // To break out of a while loop, use the `break` keyword. 34 | while (true) { 35 | break; 36 | } 37 | 38 | // To jump to the next iteration of a while loop, use the `continue` 39 | // keyword. 40 | while (true) : (d += 1) { 41 | if (d < 2) { 42 | print("d: {}\n", .{d}); 43 | continue; 44 | } 45 | 46 | break; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ibokuri/zig-by-example 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/alecthomas/chroma v0.8.2 7 | github.com/russross/blackfriday/v2 v2.1.0 8 | ) 9 | 10 | require ( 11 | github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect 12 | github.com/dlclark/regexp2 v1.2.0 // indirect 13 | ) 14 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U= 2 | github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI= 3 | github.com/alecthomas/chroma v0.8.2 h1:x3zkuE2lUk/RIekyAJ3XRqSCP4zwWDfcw/YJCuCAACg= 4 | github.com/alecthomas/chroma v0.8.2/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM= 5 | github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo= 6 | github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0= 7 | github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE= 8 | github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY= 9 | github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= 10 | github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ= 11 | github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk= 12 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 13 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 14 | github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk= 15 | github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= 16 | github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 17 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 18 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 19 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 20 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 21 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 22 | github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= 23 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 24 | github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= 25 | github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= 26 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 27 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 28 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 29 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 30 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 31 | golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY= 32 | golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 33 | -------------------------------------------------------------------------------- /templates/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Zig by Example: Not Found 6 | 7 | 8 | 9 |
10 |

Zig by Example

11 |

Whoops, this page doesn't exist :-(

12 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /templates/clipboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phan-do/zig-by-example/7eefd71fdfc95afc9fe4d2f3de86dd973b63b4ad/templates/clipboard.png -------------------------------------------------------------------------------- /templates/example.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Zig by Example: {{.Name}} 6 | 7 | 8 | 22 | 23 |
24 |

Zig by Example: {{.Name}}

25 | {{range .Segs}} 26 | 27 | {{range .}} 28 | 29 | 32 | 36 | 37 | {{end}} 38 |
30 | {{.DocsRendered}} 31 | 33 | {{if .CodeRun}}{{end}} 34 | {{.CodeRendered}} 35 |
39 | {{end}} 40 | {{if .NextExample}} 41 |

42 | Next example: {{.NextExample.Name}}. 43 |

44 | {{end}} 45 | {{ template "footer" }} 46 |
47 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /templates/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phan-do/zig-by-example/7eefd71fdfc95afc9fe4d2f3de86dd973b63b4ad/templates/favicon.ico -------------------------------------------------------------------------------- /templates/footer.tmpl: -------------------------------------------------------------------------------- 1 | {{define "footer"}} 2 | 5 | {{end}} 6 | -------------------------------------------------------------------------------- /templates/index.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Zig by Example 6 | 7 | 8 | 9 |
10 |

Zig by Example

11 |

12 | Zig is a general-purpose programming 13 | language and toolchain for maintaining robust, optimal, and reusable 14 | software. 15 |

16 | 17 |

18 | Zig by Example is a hands-on introduction to Zig using 19 | annotated example programs. 20 |

21 | 22 |
    23 | {{range .}} 24 |
  • {{.Name}}
  • 25 | {{end}} 26 |
27 | {{ template "footer" }} 28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /templates/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phan-do/zig-by-example/7eefd71fdfc95afc9fe4d2f3de86dd973b63b4ad/templates/play.png -------------------------------------------------------------------------------- /templates/site.css: -------------------------------------------------------------------------------- 1 | /* CSS reset: http://meyerweb.com/eric/tools/css/reset/ */ 2 | html, body, div, span, applet, object, iframe, 3 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 4 | a, abbr, acronym, address, big, cite, code, 5 | del, dfn, em, img, ins, kbd, q, s, samp, 6 | small, strike, strong, sub, sup, tt, var, 7 | b, u, i, center, 8 | dl, dt, dd, ol, ul, li, 9 | fieldset, form, label, legend, 10 | table, caption, tbody, tfoot, thead, tr, th, td, 11 | article, aside, canvas, details, embed, 12 | figure, figcaption, footer, header, hgroup, 13 | menu, nav, output, ruby, section, summary, 14 | time, mark, audio, video { 15 | margin: 0; 16 | padding: 0; 17 | border: 0; 18 | font-size: 100%; 19 | font: inherit; 20 | vertical-align: baseline; 21 | } 22 | article, aside, details, figcaption, figure, 23 | footer, header, hgroup, menu, nav, section { 24 | display: block; 25 | } 26 | body { 27 | line-height: 1; 28 | } 29 | ol, ul { 30 | list-style: none; 31 | } 32 | blockquote, q { 33 | quotes: none; 34 | } 35 | blockquote:before, blockquote:after, 36 | q:before, q:after { 37 | content: ''; 38 | content: none; 39 | } 40 | table { 41 | border-collapse: collapse; 42 | border-spacing: 0; 43 | } 44 | 45 | /* Layout and typography */ 46 | body { 47 | font-family: 'Georgia', serif; 48 | font-size: 16px; 49 | line-height: 20px; 50 | color: #252519; 51 | } 52 | em { 53 | font-style: italic; 54 | } 55 | a, a:visited { 56 | color: #261a3b; 57 | } 58 | h2 { 59 | font-size: 32px; 60 | line-height: 40px; 61 | margin-top: 40px; 62 | } 63 | h2 a { 64 | text-decoration: none; 65 | } 66 | div.example { 67 | width: 900px; 68 | min-width: 900px; 69 | max-width: 900px; 70 | margin-left: auto; 71 | margin-right: auto; 72 | margin-bottom: 120px; 73 | } 74 | div.example table { 75 | margin-top: 15px; 76 | margin-bottom: 20px; 77 | } 78 | p.next { 79 | margin-bottom: 20px; 80 | } 81 | p.footer { 82 | color: grey; 83 | } 84 | p.footer a, p.footer a:visited { 85 | color: grey; 86 | } 87 | div#intro { 88 | width: 420px; 89 | min-width: 420px; 90 | max-width: 420px; 91 | margin-left: auto; 92 | margin-right: auto; 93 | margin-bottom: 120px; 94 | } 95 | div#intro p { 96 | padding-top: 20px; 97 | } 98 | div#intro ul { 99 | padding-top: 20px; 100 | } 101 | table td { 102 | border: 0; 103 | outline: 0; 104 | } 105 | td.docs { 106 | width: 420px; 107 | max-width: 420px; 108 | min-width: 420px; 109 | min-height: 5px; 110 | vertical-align: top; 111 | text-align: left; 112 | } 113 | td.docs p { 114 | padding-right: 5px; 115 | padding-top: 5px; 116 | padding-bottom: 15px; 117 | } 118 | td.code { 119 | width: 480px; 120 | max-width: 480px; 121 | min-width: 480px; 122 | padding-top: 5px; 123 | padding-right: 5px; 124 | padding-left: 5px; 125 | padding-bottom: 5px; 126 | vertical-align: top; 127 | background: #f0f0f0; 128 | } 129 | td.code.leading { 130 | padding-bottom: 11px; 131 | } 132 | td.code.empty { 133 | background: #ffffff; 134 | } 135 | pre, code { 136 | font-size: 14px; line-height: 18px; 137 | font-family: 'Menlo', 'Monaco', 'Consolas', 'Lucida Console', monospace; 138 | } 139 | img.copy, img.run { 140 | height: 16px; 141 | width: 16px; 142 | float: right 143 | } 144 | img.copy, img.run { 145 | cursor: pointer; 146 | } 147 | img.copy { 148 | margin-right: 4px; 149 | } 150 | 151 | /* Syntax highlighting */ 152 | body .hll { background-color: #ffffcc } 153 | body .err { border: 1px solid #FF0000 } /* Error */ 154 | body .c { color: #408080; font-style: italic } /* Comment */ 155 | body .k { color: #954121 } /* Keyword */ 156 | body .o { color: #666666 } /* Operator */ 157 | body .cm { color: #408080; font-style: italic } /* Comment.Multiline */ 158 | body .cp { color: #BC7A00 } /* Comment.Preproc */ 159 | body .c1 { color: #408080; font-style: italic } /* Comment.Single */ 160 | body .cs { color: #408080; font-style: italic } /* Comment.Special */ 161 | body .gd { color: #A00000 } /* Generic.Deleted */ 162 | body .ge { font-style: italic } /* Generic.Emph */ 163 | body .gr { color: #FF0000 } /* Generic.Error */ 164 | body .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 165 | body .gi { color: #00A000 } /* Generic.Inserted */ 166 | body .go { color: #808080 } /* Generic.Output */ 167 | body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 168 | body .gs { font-weight: bold } /* Generic.Strong */ 169 | body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 170 | body .gt { color: #0040D0 } /* Generic.Traceback */ 171 | body .kc { color: #954121 } /* Keyword.Constant */ 172 | body .kd { color: #954121 } /* Keyword.Declaration */ 173 | body .kn { color: #954121 } /* Keyword.Namespace */ 174 | body .kp { color: #954121 } /* Keyword.Pseudo */ 175 | body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */ 176 | body .kt { color: #B00040 } /* Keyword.Type */ 177 | body .m { color: #666666 } /* Literal.Number */ 178 | body .s { color: #219161 } /* Literal.String */ 179 | body .na { color: #7D9029 } /* Name.Attribute */ 180 | body .nb { color: #954121 } /* Name.Builtin */ 181 | body .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 182 | body .no { color: #880000 } /* Name.Constant */ 183 | body .nd { color: #AA22FF } /* Name.Decorator */ 184 | body .ni { color: #999999; font-weight: bold } /* Name.Entity */ 185 | body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 186 | body .nf { } /* Name.Function */ 187 | body .nl { color: #A0A000 } /* Name.Label */ 188 | body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 189 | body .nt { color: #954121; font-weight: bold } /* Name.Tag */ 190 | body .nv { color: #19469D } /* Name.Variable */ 191 | body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 192 | body .w { color: #bbbbbb } /* Text.Whitespace */ 193 | body .mf { color: #666666 } /* Literal.Number.Float */ 194 | body .mh { color: #666666 } /* Literal.Number.Hex */ 195 | body .mi { color: #666666 } /* Literal.Number.Integer */ 196 | body .mo { color: #666666 } /* Literal.Number.Oct */ 197 | body .sb { color: #219161 } /* Literal.String.Backtick */ 198 | body .sc { color: #219161 } /* Literal.String.Char */ 199 | body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */ 200 | body .s2 { color: #219161 } /* Literal.String.Double */ 201 | body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 202 | body .sh { color: #219161 } /* Literal.String.Heredoc */ 203 | body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 204 | body .sx { color: #954121 } /* Literal.String.Other */ 205 | body .sr { color: #BB6688 } /* Literal.String.Regex */ 206 | body .s1 { color: #219161 } /* Literal.String.Single */ 207 | body .ss { color: #19469D } /* Literal.String.Symbol */ 208 | body .bp { color: #954121 } /* Name.Builtin.Pseudo */ 209 | body .vc { color: #19469D } /* Name.Variable.Class */ 210 | body .vg { color: #19469D } /* Name.Variable.Global */ 211 | body .vi { color: #19469D } /* Name.Variable.Instance */ 212 | body .il { color: #666666 } /* Literal.Number.Integer.Long */ 213 | -------------------------------------------------------------------------------- /templates/site.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * clipboard.js v1.5.13 3 | * https://zenorocha.github.io/clipboard.js 4 | * 5 | * Licensed MIT © Zeno Rocha 6 | */ 7 | !function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.Clipboard=t()}}(function(){var t,e,n;return function t(e,n,o){function r(c,a){if(!n[c]){if(!e[c]){var l="function"==typeof require&&require;if(!a&&l)return l(c,!0);if(i)return i(c,!0);var s=new Error("Cannot find module '"+c+"'");throw s.code="MODULE_NOT_FOUND",s}var u=n[c]={exports:{}};e[c][0].call(u.exports,function(t){var n=e[c][1][t];return r(n?n:t)},u,u.exports,t,e,n,o)}return n[c].exports}for(var i="function"==typeof require&&require,c=0;c 0 32 | } 33 | 34 | func check(err error) { 35 | if err != nil { 36 | panic(err) 37 | } 38 | } 39 | 40 | func ensureDir(dir string) { 41 | err := os.MkdirAll(dir, 0755) 42 | check(err) 43 | } 44 | 45 | func copyFile(src, dst string) { 46 | dat, err := os.ReadFile(src) 47 | check(err) 48 | err = os.WriteFile(dst, dat, 0644) 49 | check(err) 50 | } 51 | 52 | func pipe(bin string, arg []string, src string) []byte { 53 | cmd := exec.Command(bin, arg...) 54 | in, err := cmd.StdinPipe() 55 | check(err) 56 | out, err := cmd.StdoutPipe() 57 | check(err) 58 | err = cmd.Start() 59 | check(err) 60 | _, err = in.Write([]byte(src)) 61 | check(err) 62 | err = in.Close() 63 | check(err) 64 | bytes, err := io.ReadAll(out) 65 | check(err) 66 | err = cmd.Wait() 67 | check(err) 68 | return bytes 69 | } 70 | 71 | func sha1Sum(s string) string { 72 | h := sha1.New() 73 | h.Write([]byte(s)) 74 | b := h.Sum(nil) 75 | return fmt.Sprintf("%x", b) 76 | } 77 | 78 | func mustReadFile(path string) string { 79 | bytes, err := os.ReadFile(path) 80 | check(err) 81 | return string(bytes) 82 | } 83 | 84 | func markdown(src string) string { 85 | return string(blackfriday.Run([]byte(src))) 86 | } 87 | 88 | func readLines(path string) []string { 89 | src := mustReadFile(path) 90 | return strings.Split(src, "\n") 91 | } 92 | 93 | func mustGlob(glob string) []string { 94 | paths, err := filepath.Glob(glob) 95 | check(err) 96 | return paths 97 | } 98 | 99 | func whichLexer(path string) string { 100 | if strings.HasSuffix(path, ".zig") { 101 | return "zig" 102 | } else if strings.HasSuffix(path, ".sh") { 103 | return "console" 104 | } 105 | 106 | panic("No lexer for " + path) 107 | } 108 | 109 | func debug(msg string) { 110 | if os.Getenv("DEBUG") == "1" { 111 | fmt.Fprintln(os.Stderr, msg) 112 | } 113 | } 114 | 115 | var docsPat = regexp.MustCompile("^\\s*(\\/\\/|#)\\s") 116 | var dashPat = regexp.MustCompile("\\-+") 117 | 118 | // Seg is a segment of an example 119 | type Seg struct { 120 | Docs, DocsRendered string 121 | Code, CodeRendered, CodeForJs string 122 | CodeEmpty, CodeLeading, CodeRun bool 123 | } 124 | 125 | // Example is info extracted from an example file 126 | type Example struct { 127 | ID, Name string 128 | Code, CodeHash, URLHash string 129 | Segs [][]*Seg 130 | PrevExample *Example 131 | NextExample *Example 132 | } 133 | 134 | func parseHashFile(sourcePath string) (string, string) { 135 | lines := readLines(sourcePath) 136 | return lines[0], lines[1] 137 | } 138 | 139 | func resetURLHashFile(codehash, code, sourcePath string) string { 140 | if verbose() { 141 | fmt.Println(" Sending request to play.golang.org") 142 | } 143 | payload := strings.NewReader(code) 144 | resp, err := http.Post("https://zig.fly.dev/share", "text/plain", payload) 145 | check(err) 146 | defer resp.Body.Close() 147 | body, err := io.ReadAll(resp.Body) 148 | check(err) 149 | urlkey := string(body) 150 | data := fmt.Sprintf("%s\n%s\n", codehash, urlkey) 151 | os.WriteFile(sourcePath, []byte(data), 0644) 152 | return urlkey 153 | } 154 | 155 | func parseSegs(sourcePath string) ([]*Seg, string) { 156 | var ( 157 | lines []string 158 | source []string 159 | ) 160 | 161 | // Convert tabs to spaces for uniform rendering. 162 | for _, line := range readLines(sourcePath) { 163 | lines = append(lines, strings.Replace(line, "\t", " ", -1)) 164 | source = append(source, line) 165 | } 166 | 167 | filecontent := strings.Join(source, "\n") 168 | 169 | segs := []*Seg{} 170 | lastSeen := "" 171 | for _, line := range lines { 172 | if line == "" { 173 | lastSeen = "" 174 | continue 175 | } 176 | matchDocs := docsPat.MatchString(line) 177 | matchCode := !matchDocs 178 | newDocs := (lastSeen == "") || ((lastSeen != "docs") && (segs[len(segs)-1].Docs != "")) 179 | newCode := (lastSeen == "") || ((lastSeen != "code") && (segs[len(segs)-1].Code != "")) 180 | if newDocs || newCode { 181 | debug("NEWSEG") 182 | } 183 | if matchDocs { 184 | trimmed := docsPat.ReplaceAllString(line, "") 185 | if newDocs { 186 | newSeg := Seg{Docs: trimmed, Code: ""} 187 | segs = append(segs, &newSeg) 188 | } else { 189 | segs[len(segs)-1].Docs = segs[len(segs)-1].Docs + "\n" + trimmed 190 | } 191 | 192 | debug("DOCS: " + line) 193 | lastSeen = "docs" 194 | } else if matchCode { 195 | if newCode { 196 | newSeg := Seg{Docs: "", Code: line} 197 | segs = append(segs, &newSeg) 198 | } else { 199 | segs[len(segs)-1].Code = segs[len(segs)-1].Code + "\n" + line 200 | } 201 | 202 | debug("CODE: " + line) 203 | lastSeen = "code" 204 | } 205 | } 206 | 207 | for i, seg := range segs { 208 | seg.CodeEmpty = (seg.Code == "") 209 | seg.CodeLeading = (i < (len(segs) - 1)) 210 | seg.CodeRun = strings.Contains(seg.Code, "const std = @import(\"std\");") 211 | } 212 | 213 | return segs, filecontent 214 | } 215 | 216 | func chromaFormat(code, filePath string) string { 217 | // Without this workaround, the copy icon for a code example appears on its 218 | // own, blank line. 219 | if strings.HasSuffix(filePath, ".zig") { 220 | code = strings.Trim(code, "\n") 221 | } 222 | 223 | lexer := lexers.Get(filePath) 224 | if lexer == nil { 225 | lexer = lexers.Fallback 226 | } 227 | if strings.HasSuffix(filePath, ".sh") { 228 | lexer = SimpleShellOutputLexer 229 | } 230 | lexer = chroma.Coalesce(lexer) 231 | 232 | style := styles.Get("swapoff") 233 | if style == nil { 234 | style = styles.Fallback 235 | } 236 | 237 | formatter := html.New(html.WithClasses(true)) 238 | iterator, err := lexer.Tokenise(nil, string(code)) 239 | check(err) 240 | 241 | buf := new(bytes.Buffer) 242 | err = formatter.Format(buf, style, iterator) 243 | check(err) 244 | 245 | return buf.String() 246 | } 247 | 248 | func parseAndRenderSegs(sourcePath string) ([]*Seg, string) { 249 | segs, filecontent := parseSegs(sourcePath) 250 | for _, seg := range segs { 251 | if seg.Docs != "" { 252 | seg.DocsRendered = markdown(seg.Docs) 253 | } 254 | 255 | if seg.Code != "" { 256 | seg.CodeRendered = chromaFormat(seg.Code, sourcePath) 257 | 258 | // Add content to the JS code for copying to the clipboard. 259 | if strings.HasSuffix(sourcePath, ".zig") { 260 | seg.CodeForJs = strings.Trim(seg.Code, "\n") + "\n" 261 | } 262 | } 263 | } 264 | 265 | // When passing code to play.ziglang.org, we only care about Zig code. 266 | if lexer := whichLexer(sourcePath); lexer != "zig" { 267 | filecontent = "" 268 | } 269 | 270 | return segs, filecontent 271 | } 272 | 273 | func parseExamples() []*Example { 274 | // Gather example names. 275 | var exampleNames []string 276 | for _, line := range readLines("examples.txt") { 277 | if line != "" && !strings.HasPrefix(line, "#") { 278 | exampleNames = append(exampleNames, line) 279 | } 280 | } 281 | 282 | // Create examples. 283 | examples := make([]*Example, 0) 284 | for i, exampleName := range exampleNames { 285 | if verbose() { 286 | fmt.Printf("Processing %s [%d/%d]\n", exampleName, i+1, len(exampleNames)) 287 | } 288 | 289 | example := Example{Name: exampleName} 290 | exampleID := strings.ToLower(exampleName) 291 | exampleID = strings.Replace(exampleID, " ", "-", -1) 292 | exampleID = strings.Replace(exampleID, "/", "-", -1) 293 | exampleID = strings.Replace(exampleID, "'", "", -1) 294 | exampleID = dashPat.ReplaceAllString(exampleID, "-") 295 | example.ID = exampleID 296 | example.Segs = make([][]*Seg, 0) 297 | 298 | // Zig files are globbed after shell files, but must be rendered first. 299 | // So, we just reverse the slice of file paths to fix that. 300 | sourcePaths := mustGlob("examples/" + exampleID + "/*") 301 | sort.Sort(sort.Reverse(sort.StringSlice(sourcePaths))) 302 | for _, sourcePath := range sourcePaths { 303 | if strings.HasSuffix(sourcePath, ".hash") { 304 | example.CodeHash, example.URLHash = parseHashFile(sourcePath) 305 | } else { 306 | sourceSegs, filecontents := parseAndRenderSegs(sourcePath) 307 | if filecontents != "" { 308 | example.Code = filecontents 309 | } 310 | example.Segs = append(example.Segs, sourceSegs) 311 | } 312 | } 313 | 314 | newCodeHash := sha1Sum(example.Code) 315 | if example.CodeHash != newCodeHash { 316 | example.URLHash = resetURLHashFile(newCodeHash, example.Code, "examples/"+example.ID+"/"+example.ID+".hash") 317 | } 318 | 319 | examples = append(examples, &example) 320 | } 321 | 322 | for i, example := range examples { 323 | if i > 0 { 324 | example.PrevExample = examples[i-1] 325 | } 326 | if i < (len(examples) - 1) { 327 | example.NextExample = examples[i+1] 328 | } 329 | } 330 | return examples 331 | } 332 | 333 | func renderIndex(examples []*Example) { 334 | if verbose() { 335 | fmt.Println("Rendering index") 336 | } 337 | indexTmpl := template.New("index") 338 | _, err := indexTmpl.Parse(mustReadFile("templates/footer.tmpl")) 339 | check(err) 340 | _, err = indexTmpl.Parse(mustReadFile("templates/index.tmpl")) 341 | check(err) 342 | indexF, err := os.Create(siteDir + "/index.html") 343 | check(err) 344 | err = indexTmpl.Execute(indexF, examples) 345 | check(err) 346 | } 347 | 348 | func renderExamples(examples []*Example) { 349 | if verbose() { 350 | fmt.Println("Rendering examples") 351 | } 352 | exampleTmpl := template.New("example") 353 | _, err := exampleTmpl.Parse(mustReadFile("templates/footer.tmpl")) 354 | check(err) 355 | _, err = exampleTmpl.Parse(mustReadFile("templates/example.tmpl")) 356 | check(err) 357 | for _, example := range examples { 358 | exampleF, err := os.Create(siteDir + "/" + example.ID) 359 | check(err) 360 | exampleTmpl.Execute(exampleF, example) 361 | } 362 | } 363 | 364 | func main() { 365 | if len(os.Args) > 1 { 366 | siteDir = os.Args[1] 367 | } 368 | ensureDir(siteDir) 369 | 370 | copyFile("templates/site.css", siteDir+"/site.css") 371 | copyFile("templates/site.js", siteDir+"/site.js") 372 | copyFile("templates/favicon.ico", siteDir+"/favicon.ico") 373 | copyFile("templates/404.html", siteDir+"/404.html") 374 | copyFile("templates/play.png", siteDir+"/play.png") 375 | copyFile("templates/clipboard.png", siteDir+"/clipboard.png") 376 | 377 | examples := parseExamples() 378 | renderIndex(examples) 379 | renderExamples(examples) 380 | } 381 | 382 | var SimpleShellOutputLexer = chroma.MustNewLexer( 383 | &chroma.Config{ 384 | Name: "Shell Output", 385 | Aliases: []string{"console"}, 386 | Filenames: []string{"*.sh"}, 387 | MimeTypes: []string{}, 388 | }, 389 | chroma.Rules{ 390 | "root": { 391 | // $ or > triggers the start of prompt formatting 392 | {`^\$`, chroma.GenericPrompt, chroma.Push("prompt")}, 393 | {`^>`, chroma.GenericPrompt, chroma.Push("prompt")}, 394 | 395 | // empty lines are just text 396 | {`^$\n`, chroma.Text, nil}, 397 | 398 | // otherwise its all output 399 | {`[^\n]+$\n?`, chroma.GenericOutput, nil}, 400 | }, 401 | "prompt": { 402 | // when we find newline, do output formatting rules 403 | {`\n`, chroma.Text, chroma.Push("output")}, 404 | // otherwise its all text 405 | {`[^\n]+$`, chroma.Text, nil}, 406 | }, 407 | "output": { 408 | // sometimes there isn't output so we go right back to prompt 409 | {`^\$`, chroma.GenericPrompt, chroma.Pop(1)}, 410 | {`^>`, chroma.GenericPrompt, chroma.Pop(1)}, 411 | // otherwise its all output 412 | {`[^\n]+$\n?`, chroma.GenericOutput, nil}, 413 | }, 414 | }, 415 | ) 416 | -------------------------------------------------------------------------------- /tools/measure: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec go run tools/measure.go 4 | -------------------------------------------------------------------------------- /tools/measure.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | "regexp" 8 | "strings" 9 | "unicode/utf8" 10 | ) 11 | 12 | func check(err error) { 13 | if err != nil { 14 | panic(err) 15 | } 16 | } 17 | 18 | func readLines(path string) []string { 19 | srcBytes, err := os.ReadFile(path) 20 | check(err) 21 | return strings.Split(string(srcBytes), "\n") 22 | } 23 | 24 | var commentPat = regexp.MustCompile("\\s*\\/\\/") 25 | 26 | func main() { 27 | sourcePaths, err := filepath.Glob("./examples/*/*") 28 | check(err) 29 | foundLongFile := false 30 | for _, sourcePath := range sourcePaths { 31 | foundLongLine := false 32 | lines := readLines(sourcePath) 33 | for i, line := range lines { 34 | // Convert tabs to spaces before measuring, so we get an accurate measure 35 | // of how long the output will end up being. 36 | line := strings.Replace(line, "\t", " ", -1) 37 | if !foundLongLine && !commentPat.MatchString(line) && (utf8.RuneCountInString(line) > 58) { 38 | fmt.Printf("measure: %s:%d\n", sourcePath, i+1) 39 | foundLongLine = true 40 | foundLongFile = true 41 | } 42 | } 43 | } 44 | if foundLongFile { 45 | os.Exit(1) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tools/serve: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec go run tools/serve.go 4 | -------------------------------------------------------------------------------- /tools/serve.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func main() { 9 | port := "8000" 10 | publicDir := "public" 11 | fmt.Printf("Serving Zig by Example at http://127.0.0.1:%s\n", port) 12 | http.ListenAndServe(":"+port, http.FileServer(http.Dir(publicDir))) 13 | } 14 | -------------------------------------------------------------------------------- /tools/test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Sanity testing of the examples. 4 | 5 | set -eo pipefail 6 | 7 | # go vet will attempt to build each example, making sure it compiles. It will 8 | # also report known issues with the code. Disabling the -unreachable check 9 | # because it will fire false positives for some examples demonstrating panics. 10 | go vet -unreachable=false ./examples/... 11 | --------------------------------------------------------------------------------