Embedded programming language for Zig
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Begin the rewrite!

IamPyu 60c39617 b2430590

+554 -2375
+1
.dir-locals.el
··· 1 + ((auto-mode-alist . (("\\.zexa\\'" . lisp-mode))))
+2 -1
.gitignore
··· 1 - /target 2 1 /.direnv 2 + /zig-out 3 + /.zig-cache
-566
Cargo.lock
··· 1 - # This file is automatically @generated by Cargo. 2 - # It is not intended for manual editing. 3 - version = 4 4 - 5 - [[package]] 6 - name = "anstream" 7 - version = "0.6.21" 8 - source = "registry+https://github.com/rust-lang/crates.io-index" 9 - checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" 10 - dependencies = [ 11 - "anstyle", 12 - "anstyle-parse", 13 - "anstyle-query", 14 - "anstyle-wincon", 15 - "colorchoice", 16 - "is_terminal_polyfill", 17 - "utf8parse", 18 - ] 19 - 20 - [[package]] 21 - name = "anstyle" 22 - version = "1.0.13" 23 - source = "registry+https://github.com/rust-lang/crates.io-index" 24 - checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" 25 - 26 - [[package]] 27 - name = "anstyle-parse" 28 - version = "0.2.7" 29 - source = "registry+https://github.com/rust-lang/crates.io-index" 30 - checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" 31 - dependencies = [ 32 - "utf8parse", 33 - ] 34 - 35 - [[package]] 36 - name = "anstyle-query" 37 - version = "1.1.4" 38 - source = "registry+https://github.com/rust-lang/crates.io-index" 39 - checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" 40 - dependencies = [ 41 - "windows-sys 0.60.2", 42 - ] 43 - 44 - [[package]] 45 - name = "anstyle-wincon" 46 - version = "3.0.10" 47 - source = "registry+https://github.com/rust-lang/crates.io-index" 48 - checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" 49 - dependencies = [ 50 - "anstyle", 51 - "once_cell_polyfill", 52 - "windows-sys 0.60.2", 53 - ] 54 - 55 - [[package]] 56 - name = "cc" 57 - version = "1.2.41" 58 - source = "registry+https://github.com/rust-lang/crates.io-index" 59 - checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" 60 - dependencies = [ 61 - "find-msvc-tools", 62 - "shlex", 63 - ] 64 - 65 - [[package]] 66 - name = "cfg-if" 67 - version = "1.0.4" 68 - source = "registry+https://github.com/rust-lang/crates.io-index" 69 - checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" 70 - 71 - [[package]] 72 - name = "clap" 73 - version = "4.5.49" 74 - source = "registry+https://github.com/rust-lang/crates.io-index" 75 - checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f" 76 - dependencies = [ 77 - "clap_builder", 78 - "clap_derive", 79 - ] 80 - 81 - [[package]] 82 - name = "clap_builder" 83 - version = "4.5.49" 84 - source = "registry+https://github.com/rust-lang/crates.io-index" 85 - checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730" 86 - dependencies = [ 87 - "anstream", 88 - "anstyle", 89 - "clap_lex", 90 - "strsim", 91 - ] 92 - 93 - [[package]] 94 - name = "clap_derive" 95 - version = "4.5.49" 96 - source = "registry+https://github.com/rust-lang/crates.io-index" 97 - checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" 98 - dependencies = [ 99 - "heck", 100 - "proc-macro2", 101 - "quote", 102 - "syn", 103 - ] 104 - 105 - [[package]] 106 - name = "clap_lex" 107 - version = "0.7.6" 108 - source = "registry+https://github.com/rust-lang/crates.io-index" 109 - checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" 110 - 111 - [[package]] 112 - name = "colorchoice" 113 - version = "1.0.4" 114 - source = "registry+https://github.com/rust-lang/crates.io-index" 115 - checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" 116 - 117 - [[package]] 118 - name = "either" 119 - version = "1.15.0" 120 - source = "registry+https://github.com/rust-lang/crates.io-index" 121 - checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 122 - 123 - [[package]] 124 - name = "equivalent" 125 - version = "1.0.2" 126 - source = "registry+https://github.com/rust-lang/crates.io-index" 127 - checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 128 - 129 - [[package]] 130 - name = "find-msvc-tools" 131 - version = "0.1.4" 132 - source = "registry+https://github.com/rust-lang/crates.io-index" 133 - checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" 134 - 135 - [[package]] 136 - name = "getrandom" 137 - version = "0.3.4" 138 - source = "registry+https://github.com/rust-lang/crates.io-index" 139 - checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" 140 - dependencies = [ 141 - "cfg-if", 142 - "libc", 143 - "r-efi", 144 - "wasip2", 145 - ] 146 - 147 - [[package]] 148 - name = "hashbrown" 149 - version = "0.16.0" 150 - source = "registry+https://github.com/rust-lang/crates.io-index" 151 - checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" 152 - 153 - [[package]] 154 - name = "heck" 155 - version = "0.5.0" 156 - source = "registry+https://github.com/rust-lang/crates.io-index" 157 - checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 158 - 159 - [[package]] 160 - name = "indexmap" 161 - version = "2.11.4" 162 - source = "registry+https://github.com/rust-lang/crates.io-index" 163 - checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" 164 - dependencies = [ 165 - "equivalent", 166 - "hashbrown", 167 - ] 168 - 169 - [[package]] 170 - name = "is_terminal_polyfill" 171 - version = "1.70.1" 172 - source = "registry+https://github.com/rust-lang/crates.io-index" 173 - checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 174 - 175 - [[package]] 176 - name = "libc" 177 - version = "0.2.177" 178 - source = "registry+https://github.com/rust-lang/crates.io-index" 179 - checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" 180 - 181 - [[package]] 182 - name = "once_cell_polyfill" 183 - version = "1.70.1" 184 - source = "registry+https://github.com/rust-lang/crates.io-index" 185 - checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" 186 - 187 - [[package]] 188 - name = "ppv-lite86" 189 - version = "0.2.21" 190 - source = "registry+https://github.com/rust-lang/crates.io-index" 191 - checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" 192 - dependencies = [ 193 - "zerocopy", 194 - ] 195 - 196 - [[package]] 197 - name = "proc-macro2" 198 - version = "1.0.101" 199 - source = "registry+https://github.com/rust-lang/crates.io-index" 200 - checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" 201 - dependencies = [ 202 - "unicode-ident", 203 - ] 204 - 205 - [[package]] 206 - name = "psm" 207 - version = "0.1.27" 208 - source = "registry+https://github.com/rust-lang/crates.io-index" 209 - checksum = "e66fcd288453b748497d8fb18bccc83a16b0518e3906d4b8df0a8d42d93dbb1c" 210 - dependencies = [ 211 - "cc", 212 - ] 213 - 214 - [[package]] 215 - name = "quote" 216 - version = "1.0.41" 217 - source = "registry+https://github.com/rust-lang/crates.io-index" 218 - checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" 219 - dependencies = [ 220 - "proc-macro2", 221 - ] 222 - 223 - [[package]] 224 - name = "r-efi" 225 - version = "5.3.0" 226 - source = "registry+https://github.com/rust-lang/crates.io-index" 227 - checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" 228 - 229 - [[package]] 230 - name = "rand" 231 - version = "0.9.2" 232 - source = "registry+https://github.com/rust-lang/crates.io-index" 233 - checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" 234 - dependencies = [ 235 - "rand_chacha", 236 - "rand_core", 237 - ] 238 - 239 - [[package]] 240 - name = "rand_chacha" 241 - version = "0.9.0" 242 - source = "registry+https://github.com/rust-lang/crates.io-index" 243 - checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 244 - dependencies = [ 245 - "ppv-lite86", 246 - "rand_core", 247 - ] 248 - 249 - [[package]] 250 - name = "rand_core" 251 - version = "0.9.3" 252 - source = "registry+https://github.com/rust-lang/crates.io-index" 253 - checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" 254 - dependencies = [ 255 - "getrandom", 256 - ] 257 - 258 - [[package]] 259 - name = "recursive" 260 - version = "0.1.1" 261 - source = "registry+https://github.com/rust-lang/crates.io-index" 262 - checksum = "0786a43debb760f491b1bc0269fe5e84155353c67482b9e60d0cfb596054b43e" 263 - dependencies = [ 264 - "recursive-proc-macro-impl", 265 - "stacker", 266 - ] 267 - 268 - [[package]] 269 - name = "recursive-proc-macro-impl" 270 - version = "0.1.1" 271 - source = "registry+https://github.com/rust-lang/crates.io-index" 272 - checksum = "76009fbe0614077fc1a2ce255e3a1881a2e3a3527097d5dc6d8212c585e7e38b" 273 - dependencies = [ 274 - "quote", 275 - "syn", 276 - ] 277 - 278 - [[package]] 279 - name = "shlex" 280 - version = "1.3.0" 281 - source = "registry+https://github.com/rust-lang/crates.io-index" 282 - checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 283 - 284 - [[package]] 285 - name = "stacker" 286 - version = "0.1.22" 287 - source = "registry+https://github.com/rust-lang/crates.io-index" 288 - checksum = "e1f8b29fb42aafcea4edeeb6b2f2d7ecd0d969c48b4cf0d2e64aafc471dd6e59" 289 - dependencies = [ 290 - "cc", 291 - "cfg-if", 292 - "libc", 293 - "psm", 294 - "windows-sys 0.59.0", 295 - ] 296 - 297 - [[package]] 298 - name = "strsim" 299 - version = "0.11.1" 300 - source = "registry+https://github.com/rust-lang/crates.io-index" 301 - checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 302 - 303 - [[package]] 304 - name = "strum" 305 - version = "0.27.2" 306 - source = "registry+https://github.com/rust-lang/crates.io-index" 307 - checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" 308 - dependencies = [ 309 - "strum_macros", 310 - ] 311 - 312 - [[package]] 313 - name = "strum_macros" 314 - version = "0.27.2" 315 - source = "registry+https://github.com/rust-lang/crates.io-index" 316 - checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" 317 - dependencies = [ 318 - "heck", 319 - "proc-macro2", 320 - "quote", 321 - "syn", 322 - ] 323 - 324 - [[package]] 325 - name = "syn" 326 - version = "2.0.106" 327 - source = "registry+https://github.com/rust-lang/crates.io-index" 328 - checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" 329 - dependencies = [ 330 - "proc-macro2", 331 - "quote", 332 - "unicode-ident", 333 - ] 334 - 335 - [[package]] 336 - name = "thiserror" 337 - version = "2.0.17" 338 - source = "registry+https://github.com/rust-lang/crates.io-index" 339 - checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" 340 - dependencies = [ 341 - "thiserror-impl", 342 - ] 343 - 344 - [[package]] 345 - name = "thiserror-impl" 346 - version = "2.0.17" 347 - source = "registry+https://github.com/rust-lang/crates.io-index" 348 - checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" 349 - dependencies = [ 350 - "proc-macro2", 351 - "quote", 352 - "syn", 353 - ] 354 - 355 - [[package]] 356 - name = "unicode-ident" 357 - version = "1.0.19" 358 - source = "registry+https://github.com/rust-lang/crates.io-index" 359 - checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" 360 - 361 - [[package]] 362 - name = "utf8parse" 363 - version = "0.2.2" 364 - source = "registry+https://github.com/rust-lang/crates.io-index" 365 - checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 366 - 367 - [[package]] 368 - name = "wasip2" 369 - version = "1.0.1+wasi-0.2.4" 370 - source = "registry+https://github.com/rust-lang/crates.io-index" 371 - checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" 372 - dependencies = [ 373 - "wit-bindgen", 374 - ] 375 - 376 - [[package]] 377 - name = "windows-link" 378 - version = "0.2.1" 379 - source = "registry+https://github.com/rust-lang/crates.io-index" 380 - checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 381 - 382 - [[package]] 383 - name = "windows-sys" 384 - version = "0.59.0" 385 - source = "registry+https://github.com/rust-lang/crates.io-index" 386 - checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 387 - dependencies = [ 388 - "windows-targets 0.52.6", 389 - ] 390 - 391 - [[package]] 392 - name = "windows-sys" 393 - version = "0.60.2" 394 - source = "registry+https://github.com/rust-lang/crates.io-index" 395 - checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" 396 - dependencies = [ 397 - "windows-targets 0.53.5", 398 - ] 399 - 400 - [[package]] 401 - name = "windows-targets" 402 - version = "0.52.6" 403 - source = "registry+https://github.com/rust-lang/crates.io-index" 404 - checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 405 - dependencies = [ 406 - "windows_aarch64_gnullvm 0.52.6", 407 - "windows_aarch64_msvc 0.52.6", 408 - "windows_i686_gnu 0.52.6", 409 - "windows_i686_gnullvm 0.52.6", 410 - "windows_i686_msvc 0.52.6", 411 - "windows_x86_64_gnu 0.52.6", 412 - "windows_x86_64_gnullvm 0.52.6", 413 - "windows_x86_64_msvc 0.52.6", 414 - ] 415 - 416 - [[package]] 417 - name = "windows-targets" 418 - version = "0.53.5" 419 - source = "registry+https://github.com/rust-lang/crates.io-index" 420 - checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 421 - dependencies = [ 422 - "windows-link", 423 - "windows_aarch64_gnullvm 0.53.1", 424 - "windows_aarch64_msvc 0.53.1", 425 - "windows_i686_gnu 0.53.1", 426 - "windows_i686_gnullvm 0.53.1", 427 - "windows_i686_msvc 0.53.1", 428 - "windows_x86_64_gnu 0.53.1", 429 - "windows_x86_64_gnullvm 0.53.1", 430 - "windows_x86_64_msvc 0.53.1", 431 - ] 432 - 433 - [[package]] 434 - name = "windows_aarch64_gnullvm" 435 - version = "0.52.6" 436 - source = "registry+https://github.com/rust-lang/crates.io-index" 437 - checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 438 - 439 - [[package]] 440 - name = "windows_aarch64_gnullvm" 441 - version = "0.53.1" 442 - source = "registry+https://github.com/rust-lang/crates.io-index" 443 - checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" 444 - 445 - [[package]] 446 - name = "windows_aarch64_msvc" 447 - version = "0.52.6" 448 - source = "registry+https://github.com/rust-lang/crates.io-index" 449 - checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 450 - 451 - [[package]] 452 - name = "windows_aarch64_msvc" 453 - version = "0.53.1" 454 - source = "registry+https://github.com/rust-lang/crates.io-index" 455 - checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" 456 - 457 - [[package]] 458 - name = "windows_i686_gnu" 459 - version = "0.52.6" 460 - source = "registry+https://github.com/rust-lang/crates.io-index" 461 - checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 462 - 463 - [[package]] 464 - name = "windows_i686_gnu" 465 - version = "0.53.1" 466 - source = "registry+https://github.com/rust-lang/crates.io-index" 467 - checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" 468 - 469 - [[package]] 470 - name = "windows_i686_gnullvm" 471 - version = "0.52.6" 472 - source = "registry+https://github.com/rust-lang/crates.io-index" 473 - checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 474 - 475 - [[package]] 476 - name = "windows_i686_gnullvm" 477 - version = "0.53.1" 478 - source = "registry+https://github.com/rust-lang/crates.io-index" 479 - checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" 480 - 481 - [[package]] 482 - name = "windows_i686_msvc" 483 - version = "0.52.6" 484 - source = "registry+https://github.com/rust-lang/crates.io-index" 485 - checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 486 - 487 - [[package]] 488 - name = "windows_i686_msvc" 489 - version = "0.53.1" 490 - source = "registry+https://github.com/rust-lang/crates.io-index" 491 - checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" 492 - 493 - [[package]] 494 - name = "windows_x86_64_gnu" 495 - version = "0.52.6" 496 - source = "registry+https://github.com/rust-lang/crates.io-index" 497 - checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 498 - 499 - [[package]] 500 - name = "windows_x86_64_gnu" 501 - version = "0.53.1" 502 - source = "registry+https://github.com/rust-lang/crates.io-index" 503 - checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" 504 - 505 - [[package]] 506 - name = "windows_x86_64_gnullvm" 507 - version = "0.52.6" 508 - source = "registry+https://github.com/rust-lang/crates.io-index" 509 - checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 510 - 511 - [[package]] 512 - name = "windows_x86_64_gnullvm" 513 - version = "0.53.1" 514 - source = "registry+https://github.com/rust-lang/crates.io-index" 515 - checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" 516 - 517 - [[package]] 518 - name = "windows_x86_64_msvc" 519 - version = "0.52.6" 520 - source = "registry+https://github.com/rust-lang/crates.io-index" 521 - checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 522 - 523 - [[package]] 524 - name = "windows_x86_64_msvc" 525 - version = "0.53.1" 526 - source = "registry+https://github.com/rust-lang/crates.io-index" 527 - checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" 528 - 529 - [[package]] 530 - name = "wit-bindgen" 531 - version = "0.46.0" 532 - source = "registry+https://github.com/rust-lang/crates.io-index" 533 - checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" 534 - 535 - [[package]] 536 - name = "zerocopy" 537 - version = "0.8.27" 538 - source = "registry+https://github.com/rust-lang/crates.io-index" 539 - checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" 540 - dependencies = [ 541 - "zerocopy-derive", 542 - ] 543 - 544 - [[package]] 545 - name = "zerocopy-derive" 546 - version = "0.8.27" 547 - source = "registry+https://github.com/rust-lang/crates.io-index" 548 - checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" 549 - dependencies = [ 550 - "proc-macro2", 551 - "quote", 552 - "syn", 553 - ] 554 - 555 - [[package]] 556 - name = "zexa" 557 - version = "0.1.0" 558 - dependencies = [ 559 - "clap", 560 - "either", 561 - "indexmap", 562 - "rand", 563 - "recursive", 564 - "strum", 565 - "thiserror", 566 - ]
-24
Cargo.toml
··· 1 - [package] 2 - name = "zexa" 3 - version = "0.1.0" 4 - edition = "2024" 5 - 6 - [dependencies] 7 - clap = { version = "4.5.49", features = ["derive"], optional = true } 8 - either = "1.15.0" 9 - indexmap = "2.11.4" 10 - rand = "0.9.2" 11 - recursive = "0.1.1" 12 - strum = { version = "0.27.2", features = ["derive"] } 13 - thiserror = "2.0.17" 14 - 15 - [features] 16 - bin = ["clap"] 17 - 18 - [[bin]] 19 - name = "zexa" 20 - required-features = ["bin"] 21 - 22 - [[bin]] 23 - name = "zexac" 24 - required-features = ["bin"]
+6
bin/main.zig
··· 1 + const std = @import("std"); 2 + const zexa = @import("zexa"); 3 + 4 + pub fn main() !void { 5 + std.debug.print("Hello World!\n", .{}); 6 + }
+49
build.zig
··· 1 + const std = @import("std"); 2 + 3 + pub fn build(b: *std.Build) void { 4 + const target = b.standardTargetOptions(.{}); 5 + const optimize = b.standardOptimizeOption(.{}); 6 + 7 + const mitochondria_dep = b.dependency("mitochondria", .{ 8 + .target = target, 9 + .optimize = optimize, 10 + }); 11 + const mitochondria_mod = mitochondria_dep.module("mitochondria"); 12 + 13 + const mod = b.addModule("zexa", .{ 14 + .root_source_file = b.path("src/root.zig"), 15 + .target = target, 16 + .optimize = optimize, 17 + }); 18 + mod.addImport("zexa", mod); 19 + mod.addImport("mitochondria", mitochondria_mod); 20 + 21 + const lib = b.addLibrary(.{ 22 + .name = "zexa", 23 + .root_module = mod, 24 + }); 25 + b.installArtifact(lib); 26 + 27 + const mod_tests = b.addTest(.{ 28 + .root_module = mod, 29 + }); 30 + const run_mod_tests = b.addRunArtifact(mod_tests); 31 + const test_step = b.step("test", "Run tests"); 32 + test_step.dependOn(&run_mod_tests.step); 33 + 34 + const exe_mod = b.createModule(.{ 35 + .root_source_file = b.path("bin/main.zig"), 36 + .target = target, 37 + .optimize = optimize, 38 + }); 39 + exe_mod.addImport("zexa", mod); 40 + 41 + const exe = b.addExecutable(.{ 42 + .name = "zexa", 43 + .root_module = exe_mod, 44 + }); 45 + b.installArtifact(exe); 46 + const run_zexa = b.addRunArtifact(exe); 47 + const run_step = b.step("run", "Run zexa interpreter"); 48 + run_step.dependOn(&run_zexa.step); 49 + }
+18
build.zig.zon
··· 1 + .{ 2 + .name = .zexa, 3 + .version = "0.1.0", 4 + .dependencies = .{ 5 + .mitochondria = .{ 6 + .url = "git+https://codeberg.org/IamPyu/mitochondria#22189e7af32d924691f3ebaf4719d441e3ec8ea5", 7 + .hash = "mitochondria-0.1.0-RHWHdxuBAAAOkGZKvncoVdrJctbjSaS2xt4iZ2XX6iDO", 8 + }, 9 + }, 10 + .minimum_zig_version = "0.15.2", 11 + .paths = .{ 12 + "build.zig", 13 + "build.zig.zon", 14 + "src", 15 + "README.md", 16 + }, 17 + .fingerprint = 0xb689341f9d4fe9ac, 18 + }
+14
default.nix
··· 1 + { 2 + zig, 3 + lib, 4 + stdenv, 5 + }: 6 + stdenv.mkDerivation { 7 + pname = "zexa"; 8 + version = "0.1.0"; 9 + src = lib.cleanSource ./.; 10 + 11 + nativeBuildInputs = [ 12 + zig.hook 13 + ]; 14 + }
+7 -44
flake.lock
··· 1 1 { 2 2 "nodes": { 3 - "crane": { 4 - "locked": { 5 - "lastModified": 1759893430, 6 - "narHash": "sha256-yAy4otLYm9iZ+NtQwTMEbqHwswSFUbhn7x826RR6djw=", 7 - "owner": "ipetkov", 8 - "repo": "crane", 9 - "rev": "1979a2524cb8c801520bd94c38bb3d5692419d93", 10 - "type": "github" 11 - }, 12 - "original": { 13 - "owner": "ipetkov", 14 - "repo": "crane", 15 - "type": "github" 16 - } 17 - }, 18 3 "flake-parts": { 19 4 "inputs": { 20 5 "nixpkgs-lib": [ ··· 22 7 ] 23 8 }, 24 9 "locked": { 25 - "lastModified": 1759362264, 26 - "narHash": "sha256-wfG0S7pltlYyZTM+qqlhJ7GMw2fTF4mLKCIVhLii/4M=", 10 + "lastModified": 1762980239, 11 + "narHash": "sha256-8oNVE8TrD19ulHinjaqONf9QWCKK+w4url56cdStMpM=", 27 12 "owner": "hercules-ci", 28 13 "repo": "flake-parts", 29 - "rev": "758cf7296bee11f1706a574c77d072b8a7baa881", 14 + "rev": "52a2caecc898d0b46b2b905f058ccc5081f842da", 30 15 "type": "github" 31 16 }, 32 17 "original": { ··· 37 22 }, 38 23 "nixpkgs": { 39 24 "locked": { 40 - "lastModified": 1760164275, 41 - "narHash": "sha256-gKl2Gtro/LNf8P+4L3S2RsZ0G390ccd5MyXYrTdMCFE=", 25 + "lastModified": 1762943920, 26 + "narHash": "sha256-ITeH8GBpQTw9457ICZBddQEBjlXMmilML067q0e6vqY=", 42 27 "owner": "nixos", 43 28 "repo": "nixpkgs", 44 - "rev": "362791944032cb532aabbeed7887a441496d5e6e", 29 + "rev": "91c9a64ce2a84e648d0cf9671274bb9c2fb9ba60", 45 30 "type": "github" 46 31 }, 47 32 "original": { ··· 53 38 }, 54 39 "root": { 55 40 "inputs": { 56 - "crane": "crane", 57 41 "flake-parts": "flake-parts", 58 - "nixpkgs": "nixpkgs", 59 - "rust-overlay": "rust-overlay" 60 - } 61 - }, 62 - "rust-overlay": { 63 - "inputs": { 64 - "nixpkgs": [ 65 - "nixpkgs" 66 - ] 67 - }, 68 - "locked": { 69 - "lastModified": 1760323082, 70 - "narHash": "sha256-SKhC9tyt+gVgQHnZGMVPSdptlDYNqApT56JF5t8RwBY=", 71 - "owner": "oxalica", 72 - "repo": "rust-overlay", 73 - "rev": "c73e6874fe8dce0bab82c0387b510875f1eff9f8", 74 - "type": "github" 75 - }, 76 - "original": { 77 - "owner": "oxalica", 78 - "repo": "rust-overlay", 79 - "type": "github" 42 + "nixpkgs": "nixpkgs" 80 43 } 81 44 } 82 45 },
+11 -28
flake.nix
··· 1 1 { 2 - description = "Rust template"; 2 + description = "Zig template"; 3 3 4 4 inputs = { 5 5 nixpkgs.url = "github:nixos/nixpkgs?ref=nixpkgs-unstable"; ··· 7 7 url = "github:hercules-ci/flake-parts"; 8 8 inputs.nixpkgs-lib.follows = "nixpkgs"; 9 9 }; 10 - crane.url = "github:ipetkov/crane"; 11 - rust-overlay = { 12 - url = "github:oxalica/rust-overlay"; 13 - inputs.nixpkgs.follows = "nixpkgs"; 14 - }; 15 10 }; 16 11 17 12 outputs = { 18 13 self, 19 - nixpkgs, 20 - crane, 21 - rust-overlay, 22 14 flake-parts, 23 15 ... 24 16 } @ inputs: ··· 30 22 ]; 31 23 32 24 perSystem = { 33 - # pkgs, 25 + pkgs, 34 26 system, 35 27 ... 36 - }: let 37 - overlays = [(import rust-overlay)]; 38 - pkgs = import nixpkgs { 39 - inherit system overlays; 40 - }; 41 - craneLib = (crane.mkLib pkgs).overrideToolchain ( 42 - p: p.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml 43 - ); 44 - 45 - nativeBuildInputs = []; 46 - buildInputs = []; 47 - in { 28 + }: { 48 29 formatter = pkgs.alejandra; 49 30 50 - packages.default = craneLib.buildPackage { 51 - src = craneLib.cleanCargoSource ./.; 52 - 53 - inherit buildInputs nativeBuildInputs; 31 + packages = rec { 32 + default = zexa; 33 + zexa = pkgs.callPackage ./default.nix {}; 54 34 }; 55 35 56 - devShells.default = craneLib.devShell { 57 - packages = buildInputs ++ nativeBuildInputs; 36 + devShells.default = pkgs.mkShell { 37 + buildInputs = with pkgs; [ 38 + zig 39 + zls 40 + ]; 58 41 }; 59 42 }; 60 43 };
-3
rust-toolchain.toml
··· 1 - [toolchain] 2 - channel = "stable" 3 - components = ["rustfmt", "clippy", "rust-analyzer", "rust-src"]
-61
src/bin/zexa.rs
··· 1 - use std::{fs::File, io::Read, process::exit}; 2 - 3 - use clap::Parser; 4 - use zexa::{self, lexer::lex, parser::parse_tokens}; 5 - 6 - #[derive(clap::Parser)] 7 - #[command(about = "zexa interpreter")] 8 - struct Args { 9 - file: Option<String>, 10 - } 11 - 12 - #[derive(Debug, thiserror::Error)] 13 - enum ZexaError { 14 - #[error("io error: {0}")] 15 - IOError(#[from] std::io::Error), 16 - #[error("lex error: {0}")] 17 - LexError(#[from] zexa::lexer::LexError), 18 - #[error("parse error: {0}")] 19 - ParseError(#[from] zexa::parser::ParseError), 20 - #[error("runtime error: {0}")] 21 - RuntimeError(#[from] zexa::env::RuntimeError), 22 - } 23 - 24 - fn main() -> Result<(), ZexaError> { 25 - let env = zexa::env::Environment::new(); 26 - env.load_std(); 27 - 28 - let args = Args::parse(); 29 - 30 - if let Some(p) = args.file.as_ref() { 31 - let mut f = File::open(&p)?; 32 - let mut buf = String::new(); 33 - f.read_to_string(&mut buf)?; 34 - 35 - let ast = match lex(&buf) { 36 - Ok(tokens) => match parse_tokens(tokens) { 37 - Ok(ast) => ast, 38 - Err(e) => { 39 - eprintln!("parse error: {e}"); 40 - exit(2) 41 - } 42 - }, 43 - Err(e) => { 44 - eprintln!("lex error: {e}"); 45 - exit(1) 46 - } 47 - }; 48 - 49 - match env.eval(ast) { 50 - Ok(_) => {} 51 - Err(e) => { 52 - eprintln!("runtime error: {e}"); 53 - exit(3); 54 - } 55 - } 56 - } else { 57 - todo!("REPL") 58 - } 59 - 60 - Ok(()) 61 - }
-1
src/bin/zexac.rs
··· 1 - fn main() {}
-328
src/env.rs
··· 1 - use crate::{Callable, LockError, Symbol, Value, ValueType, parser::AST, stdlib}; 2 - use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}; 3 - 4 - /// An error that can occur when evaluating code 5 - #[derive(Debug, thiserror::Error)] 6 - pub enum RuntimeError { 7 - #[error("undefined callable: {0}")] 8 - UndefinedCallable(Symbol), 9 - #[error("symbol not callable: {0}")] 10 - NotCallable(Symbol), 11 - #[error("expected Symbol, found: {0}")] 12 - ExpectedSymbol(ValueType), 13 - #[error("invalid argument type for arg {0}: expected `{1}`")] 14 - InvalidArgumentType(usize, ValueType), 15 - #[error("expected {0} (or potetionally more) arguments, received {1}")] 16 - UnexpectedArguments(usize, usize), 17 - #[error("type error: {0}")] 18 - TypeError(String), 19 - #[error("external error: {0}")] 20 - External(#[from] Arc<dyn std::error::Error>), 21 - } 22 - 23 - /// A reference-counted [`Value`] 24 - #[derive(Debug, Clone)] 25 - pub struct RefValue(Arc<RwLock<Value>>); 26 - 27 - impl RefValue { 28 - /// Create a [`RefValue`] 29 - pub fn new(v: Value) -> Self { 30 - Self(Arc::new(RwLock::new(v))) 31 - } 32 - 33 - /// Obtain a read-only reference to the underlying [`Value`] 34 - pub fn read(&self) -> RwLockReadGuard<'_, Value> { 35 - self.0.read().unwrap() 36 - } 37 - 38 - /// Obtain a mutable reference to the underlying [`Value`] 39 - pub fn write(&self) -> RwLockWriteGuard<'_, Value> { 40 - self.0.write().unwrap() 41 - } 42 - 43 - /// Same as [`Self::read`] but allows you to handle the error 44 - pub fn try_read( 45 - &self, 46 - ) -> Result<RwLockReadGuard<'_, Value>, LockError<RwLockReadGuard<'_, Value>>> { 47 - Ok(self.0.try_read()?) 48 - } 49 - 50 - /// Same as [`Self::write`] but allows you to handle the error 51 - pub fn try_write( 52 - &self, 53 - ) -> Result<RwLockWriteGuard<'_, Value>, LockError<RwLockWriteGuard<'_, Value>>> { 54 - Ok(self.0.try_write()?) 55 - } 56 - } 57 - 58 - /// The core of the [`Environment`] 59 - pub struct InnerEnvironment { 60 - parent: Option<Environment>, 61 - variables: indexmap::IndexMap<Symbol, RefValue>, 62 - } 63 - 64 - impl InnerEnvironment { 65 - /// Create an [`InnerEnvironment`] 66 - pub fn new() -> Self { 67 - Self { 68 - parent: None, 69 - variables: Default::default(), 70 - } 71 - } 72 - 73 - /// Set the parent of this environment 74 - pub fn set_parent(&mut self, parent: Environment) { 75 - self.parent = Some(parent); 76 - } 77 - 78 - /// Set the value of the variable `s` to `v` 79 - pub fn set<S: AsRef<str>>(&mut self, s: S, v: Value) { 80 - self.variables 81 - .insert(s.as_ref().to_owned(), RefValue::new(v)); 82 - } 83 - 84 - /// Get the value of variable `s` 85 - pub fn get<S: AsRef<str>>(&self, s: S) -> Option<RefValue> { 86 - match self.variables.get(s.as_ref()) { 87 - Some(v) => Some(v.clone()), 88 - None => match self.parent.clone() { 89 - Some(p) => match p.0.try_read() { 90 - Ok(p) => p.get(s), 91 - Err(_) => None, 92 - }, 93 - None => None, 94 - }, 95 - } 96 - } 97 - } 98 - 99 - /// A reference-counted [`InnerEnvironment`] 100 - #[derive(Clone)] 101 - pub struct Environment(Arc<RwLock<InnerEnvironment>>); 102 - 103 - impl Environment { 104 - /// Create a [`Environment`] 105 - pub fn new() -> Self { 106 - Self(Arc::new(RwLock::new(InnerEnvironment::new()))) 107 - } 108 - 109 - /// Load the standard library into the environment 110 - pub fn load_std(&self) { 111 - stdlib::load_std(self.clone()); 112 - } 113 - 114 - /// Get a read-only reference to the underlying [`InnerEnvironment`] 115 - pub fn read(&self) -> RwLockReadGuard<'_, InnerEnvironment> { 116 - self.0.read().unwrap() 117 - } 118 - 119 - /// Get a mutable reference to the underlying [`InnerEnvironment`] 120 - pub fn write(&self) -> RwLockWriteGuard<'_, InnerEnvironment> { 121 - self.0.write().unwrap() 122 - } 123 - 124 - /// Same as [`Self::read`] but allows you to handle the error 125 - pub fn try_read( 126 - &self, 127 - ) -> Result< 128 - RwLockReadGuard<'_, InnerEnvironment>, 129 - LockError<RwLockReadGuard<'_, InnerEnvironment>>, 130 - > { 131 - Ok(self.0.try_read()?) 132 - } 133 - 134 - /// Same as [`Self::write`] but allows you to handle the error 135 - pub fn try_write( 136 - &self, 137 - ) -> Result< 138 - RwLockWriteGuard<'_, InnerEnvironment>, 139 - LockError<RwLockWriteGuard<'_, InnerEnvironment>>, 140 - > { 141 - Ok(self.0.try_write()?) 142 - } 143 - 144 - /// Create a child environment 145 - pub fn create_child(&self) -> Self { 146 - let env = Self::new(); 147 - env.write().set_parent(self.clone()); 148 - env 149 - } 150 - 151 - /// Evalulate the code returned from [`crate::parser::parse_tokens`] 152 - pub fn eval(&self, ast: AST) -> Result<Value, RuntimeError> { 153 - let mut ast = ast.into_iter().peekable(); 154 - let mut value = None; 155 - 156 - loop { 157 - if ast.peek().is_none() { 158 - break Ok(value.unwrap_or(Value::Nil)); 159 - } 160 - 161 - value = Some(self.eval_expr(ast.next().unwrap())?); 162 - } 163 - } 164 - 165 - /// Evaluate a single expression 166 - #[recursive::recursive] 167 - pub fn eval_expr(&self, expr: Value) -> Result<Value, RuntimeError> { 168 - Ok(match expr { 169 - Value::Nil => Value::Nil, 170 - Value::Bool(b) => Value::Bool(b), 171 - Value::Number(n) => Value::Number(n), 172 - Value::String(s) => Value::String(s), 173 - Value::Symbol(s) => match self.read().get(&s) { 174 - Some(v) => v.read().to_owned(), 175 - None => Value::Nil, 176 - }, 177 - Value::Atom(a) => Value::Atom(a), 178 - Value::Quoted(v) => *v.to_owned(), 179 - Value::List(v) => { 180 - if v.is_empty() { 181 - Value::Nil 182 - } else { 183 - let sym = v.get(0).unwrap().to_owned(); 184 - let args = &v[1..].to_vec(); 185 - 186 - let Value::Symbol(sym) = sym else { 187 - return Err(RuntimeError::ExpectedSymbol(sym.value_type())); 188 - }; 189 - 190 - let func = match self.read().get(&sym) { 191 - Some(r) => match r.read().clone() { 192 - Value::Func(f) => Callable::Func(f), 193 - Value::NativeFunc(f) => Callable::NFunc(f), 194 - Value::NativeMacro(f) => Callable::NMacro(f), 195 - _ => return Err(RuntimeError::NotCallable(sym)), 196 - }, 197 - _ => return Err(RuntimeError::UndefinedCallable(sym)), 198 - }; 199 - 200 - match func { 201 - Callable::Func(f) => { 202 - let env = self.create_child(); 203 - 204 - for (aid, arg) in args.iter().enumerate() { 205 - let new_arg = self.eval_expr(arg.to_owned())?; 206 - env.write().set(&f.0[aid], new_arg); 207 - } 208 - 209 - env.eval(f.1)? 210 - } 211 - Callable::Macro(f) => { 212 - _ = f; 213 - todo!() 214 - } 215 - Callable::NFunc(f) => { 216 - let mut new_args = vec![]; 217 - 218 - for a in args { 219 - new_args.push(self.eval_expr(a.to_owned())?); 220 - } 221 - 222 - f(self.clone(), &new_args)? 223 - } 224 - Callable::NMacro(f) => { 225 - let ast = f(self.clone(), args.to_owned())?; 226 - self.eval(ast)? 227 - } 228 - } 229 - } 230 - } 231 - Value::Func(f) => Value::Func(f), 232 - Value::Macro(f) => Value::Macro(f), 233 - Value::NativeFunc(f) => Value::NativeFunc(f), 234 - Value::NativeMacro(f) => Value::NativeMacro(f), 235 - Value::UserData(u) => Value::UserData(u), 236 - }) 237 - } 238 - } 239 - 240 - #[cfg(test)] 241 - mod tests { 242 - use crate::parser::parse_str; 243 - 244 - use super::*; 245 - 246 - #[test] 247 - fn env1() { 248 - let mut env = InnerEnvironment::new(); 249 - 250 - env.set("my-number", Value::Number(43.)); 251 - env.set("this-is-true", Value::Bool(false)); 252 - 253 - assert!(env.get("my-number").is_some()); 254 - assert_eq!(*env.get("this-is-true").unwrap().read(), Value::Bool(false)); 255 - } 256 - 257 - #[test] 258 - fn env2() { 259 - let parent_env = Environment::new(); 260 - parent_env.write().set("*constant*", Value::Nil); 261 - 262 - let child_env = parent_env.create_child(); 263 - assert_eq!( 264 - *child_env.read().get("*constant*").unwrap().read(), 265 - Value::Nil 266 - ); 267 - } 268 - 269 - #[test] 270 - fn env3() { 271 - let env = Environment::new(); 272 - env.write().set("var", Value::String("hello".to_owned())); 273 - 274 - let child = env.create_child(); 275 - env.write().set("*const*", Value::Bool(false)); 276 - 277 - let ast = parse_str("1 var *const*").unwrap(); 278 - 279 - for v in ast { 280 - println!("{:?}", child.eval_expr(v)); 281 - } 282 - } 283 - 284 - #[test] 285 - fn env4() { 286 - let env = Environment::new(); 287 - env.write().set( 288 - "greet", 289 - Value::NativeFunc(|_, args| { 290 - for a in args { 291 - match a { 292 - Value::String(v) => println!("Hello {v}"), 293 - _ => println!("Hello {a:?}!"), 294 - } 295 - } 296 - 297 - Ok(Value::Nil) 298 - }), 299 - ); 300 - 301 - let ast = parse_str(include_str!("./test/test.zexa")).unwrap(); 302 - let out = env.eval(ast).unwrap(); 303 - 304 - println!("Output: {out:?}") 305 - } 306 - 307 - #[test] 308 - fn env5() { 309 - let env = Environment::new(); 310 - env.load_std(); 311 - 312 - let ast = parse_str(include_str!("./test/test2.zexa")).unwrap(); 313 - let out = env.eval(ast).unwrap(); 314 - 315 - println!("{out:?}"); 316 - } 317 - 318 - #[test] 319 - fn env6() { 320 - let env = Environment::new(); 321 - env.load_std(); 322 - 323 - let ast = parse_str(include_str!("./test/test3.zexa")).unwrap(); 324 - let out = env.eval(ast).unwrap(); 325 - 326 - println!("{out:?}"); 327 - } 328 - }
+171
src/env.zig
··· 1 + const std = @import("std"); 2 + const Allocator = std.mem.Allocator; 3 + const ArrayList = std.ArrayList; 4 + const SliceIterator = @import("mitochondria").SliceIterator; 5 + 6 + const zexa = @import("zexa"); 7 + const Scope = zexa.types.Scope; 8 + const Value = zexa.types.Value; 9 + 10 + pub const RuntimeError = error{InvalidFunction}; 11 + 12 + pub const Environment = struct { 13 + const Self = @This(); 14 + 15 + allocator: Allocator, 16 + primary_scope: Scope, 17 + 18 + pub fn init(allocator: Allocator) !Self { 19 + return Self{ 20 + .allocator = allocator, 21 + .primary_scope = Scope.init(allocator), 22 + }; 23 + } 24 + 25 + pub fn deinit(self: *Self) void { 26 + self.primary_scope.deinit(); 27 + } 28 + 29 + pub fn evalExpr(self: *Self, scope: *Scope, expr: *Value) !*Value { 30 + const val = switch (expr.*) { 31 + .atom => |atom| switch (atom) { 32 + .nil => Value{ .atom = .nil }, 33 + .bool => |b| Value{ .atom = .{ .bool = b } }, 34 + .num => |n| Value{ .atom = .{ .num = n } }, 35 + .str => |s| return try Value.initString(scope, s), 36 + .sym => |s| return scope.get(s) orelse try Value.initNil(scope), 37 + .quote => |v| return v, 38 + .native_func => return expr, 39 + }, 40 + .cons => { 41 + const slice = try expr.toSlice(scope); 42 + 43 + if (slice.len == 0) { 44 + return Value.initNil(scope); 45 + } 46 + 47 + const car = try self.evalExpr(scope, slice[0]); 48 + const cdr = slice[1..]; 49 + 50 + switch (car.*) { 51 + .atom => |atom| switch (atom) { 52 + .native_func => |f| { 53 + for (cdr) |*v| { 54 + v.* = try self.evalExpr(scope, v.*); 55 + } 56 + 57 + return f(scope, cdr); 58 + }, 59 + else => return RuntimeError.InvalidFunction, 60 + }, 61 + else => return RuntimeError.InvalidFunction, 62 + } 63 + 64 + return Value.initNil(scope); 65 + }, 66 + }; 67 + 68 + return Value.initFrom(scope, val); 69 + } 70 + 71 + pub fn evalAst(self: *Self, ast: []const *Value) !*Value { 72 + var iter = SliceIterator(*Value).init(ast); 73 + var value: ?*Value = null; 74 + 75 + while (true) { 76 + if (iter.peek() == null) { 77 + return value orelse try Value.initNil(&self.primary_scope); 78 + } 79 + 80 + value = try self.evalExpr(&self.primary_scope, iter.next().?); 81 + } 82 + } 83 + }; 84 + 85 + test "eval" { 86 + var env = try Environment.init(std.testing.allocator); 87 + defer env.deinit(); 88 + 89 + const v = try Value.initFrom(&env.primary_scope, .{ .atom = .{ .num = 34 } }); 90 + const val = try env.evalExpr(&env.primary_scope, v); 91 + 92 + try std.testing.expectEqual(Value{ .atom = .{ .num = 34 } }, val.*); 93 + } 94 + 95 + test "variable" { 96 + var env = try Environment.init(std.testing.allocator); 97 + defer env.deinit(); 98 + 99 + const key = try env.primary_scope.createString("var"); 100 + const val = try Value.initString(&env.primary_scope, "hello world!"); 101 + 102 + try env.primary_scope.insert(key, val); 103 + 104 + const sym = try Value.initFrom(&env.primary_scope, .{ 105 + .atom = .{ .sym = key }, 106 + }); 107 + 108 + const fetched = try env.evalExpr(&env.primary_scope, sym); 109 + try std.testing.expectEqualStrings("hello world!", fetched.*.atom.str); 110 + } 111 + 112 + test "ast" { 113 + var env = try Environment.init(std.testing.allocator); 114 + defer env.deinit(); 115 + 116 + const scope = &env.primary_scope; 117 + 118 + const ast = [_]*Value{ 119 + try Value.initFromAny(scope, 1), 120 + try Value.initFromAny(scope, 2), 121 + try Value.initFromAny(scope, 3), 122 + try Value.initFromAny(scope, 4), 123 + try Value.initFromAny(scope, 5), 124 + try Value.initFromAny(scope, 6), 125 + try Value.initFromAny(scope, 7), 126 + try Value.initFromAny(scope, 8), 127 + }; 128 + 129 + const final = try env.evalAst(&ast); 130 + try std.testing.expectEqual(8, final.*.atom.num); 131 + } 132 + 133 + test "cons" { 134 + var env = try Environment.init(std.testing.allocator); 135 + defer env.deinit(); 136 + 137 + const scope = &env.primary_scope; 138 + 139 + const list = try Value.initCons(scope, try Value.initFromAny(scope, 1), try Value.initNil(scope)); 140 + try list.append(scope, try Value.initFromAny(scope, 2)); 141 + try list.append(scope, try Value.initFromAny(scope, 3)); 142 + try list.append(scope, try Value.initFromAny(scope, 4)); 143 + try list.append(scope, try Value.initFromAny(scope, 5)); 144 + 145 + const slice = try list.toSlice(scope); 146 + 147 + for (slice) |v| { 148 + if (!v.isNil()) { 149 + std.debug.print("{any} ", .{v.atom.num}); 150 + } 151 + } 152 + std.debug.print("\n", .{}); 153 + 154 + std.debug.print("{any}\n", .{scope.arena.queryCapacity()}); 155 + } 156 + 157 + test "dbg" { 158 + var env = try Environment.init(std.testing.allocator); 159 + defer env.deinit(); 160 + 161 + const scope = &env.primary_scope; 162 + 163 + const list = try Value.initList(scope, &.{ 164 + try Value.initNativeFunc(scope, zexa.std.lib.dbg), 165 + try Value.initFromAny(scope, 3), 166 + try Value.initFromAny(scope, 8), 167 + try Value.initFromAny(scope, 435), 168 + }); 169 + 170 + _ = try env.evalExpr(scope, list); 171 + }
-281
src/lexer.rs
··· 1 - #[derive(Debug, Clone)] 2 - pub enum TokenValue { 3 - LParen, 4 - RParen, 5 - Quote, 6 - Atom, 7 - Num(String), 8 - Sym(String), 9 - Str(String), 10 - } 11 - 12 - #[derive(Debug, Clone)] 13 - pub struct Token { 14 - pub(crate) line: LineInfo, 15 - pub(crate) value: TokenValue, 16 - } 17 - 18 - #[derive(Clone, Copy, Debug)] 19 - pub struct LineInfo(usize, usize); 20 - 21 - impl LineInfo { 22 - pub fn line(self) -> usize { 23 - self.0 24 - } 25 - 26 - pub fn column(self) -> usize { 27 - self.1 28 - } 29 - } 30 - 31 - impl std::fmt::Display for LineInfo { 32 - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 33 - write!(f, "{}:{}", self.0 + 1, self.1) 34 - } 35 - } 36 - 37 - #[derive(Debug, thiserror::Error)] 38 - pub enum LexError { 39 - #[error("unexpected token near {0}: `{1}`")] 40 - UnexpectedToken(LineInfo, char), 41 - 42 - #[error("failed to parse float near {0}: too much decimal points")] 43 - ExtraDecimalPoint(LineInfo), 44 - 45 - #[error("invalid number near {0}")] 46 - InvalidNumber(LineInfo), 47 - 48 - #[error("invalid symbol near {0}, invalid character: {1}")] 49 - InvalidSymbol(LineInfo, char), 50 - 51 - #[error("invalid escape character near {0}: `{1}`")] 52 - InvalidEscape(LineInfo, char), 53 - 54 - #[error("string broken with newline near {0}")] 55 - StringBreak(LineInfo), 56 - } 57 - 58 - pub mod chars { 59 - pub const LPAREN: char = '('; 60 - pub const RPAREN: char = ')'; 61 - pub const QUOTE: char = '\''; 62 - pub const ATOM: char = ':'; 63 - pub const STR_DELIM: char = '"'; 64 - pub const COMMENT: char = ';'; 65 - } 66 - 67 - macro_rules! lex_pat { 68 - (ws) => { 69 - ' '|'\n'|'\r' 70 - }; 71 - (schar) => { 72 - chars::LPAREN|chars::RPAREN|chars::QUOTE|chars::ATOM 73 - }; 74 - (symbol) => { 75 - 'a'..='z'|'A'..='Z'|'_'|'+'|'='|'*'|'#'|'!'|'$'|'%'|'@'|'^'|'&'|'['|']' 76 - |'{'|'}'|'\\'|'|'|'<'|'>'|'?'|'/'|'.'|','|'~'|'`' 77 - }; 78 - (symbol_rest) => { 79 - lex_pat!(symbol) | lex_pat!(num) | ':' 80 - }; 81 - (num) => { 82 - '0'..='9'|'-' 83 - }; 84 - } 85 - 86 - pub fn lex(buf: &str) -> Result<Vec<Token>, LexError> { 87 - let mut tokens = vec![]; 88 - let mut chars = buf.chars().peekable(); 89 - let mut line = LineInfo(0, 0); 90 - 91 - while let Some(c) = chars.next() { 92 - match c { 93 - chars::LPAREN => tokens.push(Token { 94 - line, 95 - value: TokenValue::LParen, 96 - }), 97 - chars::RPAREN => tokens.push(Token { 98 - line, 99 - value: TokenValue::RParen, 100 - }), 101 - chars::QUOTE => tokens.push(Token { 102 - line, 103 - value: TokenValue::Quote, 104 - }), 105 - chars::ATOM => tokens.push(Token { 106 - line, 107 - value: TokenValue::Atom, 108 - }), 109 - chars::COMMENT => { 110 - while let Some(c) = chars.next() { 111 - if c == '\n' { 112 - break; 113 - } 114 - } 115 - } 116 - lex_pat!(num) => { 117 - let mut buf = String::from(c); 118 - let mut has_decimal = false; 119 - 120 - while let Some(c) = chars.peek() { 121 - if matches!(c, lex_pat!(num)) { 122 - buf.push(chars.next().unwrap()); 123 - } else if *c == '.' { 124 - if has_decimal { 125 - return Err(LexError::ExtraDecimalPoint(line)); 126 - } 127 - has_decimal = true; 128 - buf.push(chars.next().unwrap()); 129 - } else { 130 - break; 131 - } 132 - } 133 - 134 - tokens.push(Token { 135 - line, 136 - value: TokenValue::Num(buf), 137 - }); 138 - } 139 - lex_pat!(symbol) => { 140 - let mut buf = String::from(c); 141 - 142 - while let Some(c) = chars.peek() { 143 - if matches!(c, lex_pat!(symbol_rest)) { 144 - buf.push(chars.next().unwrap()); 145 - } else if matches!(*c, lex_pat!(ws) | lex_pat!(schar)) { 146 - break; 147 - } else { 148 - return Err(LexError::InvalidSymbol(line, *c)); 149 - } 150 - } 151 - 152 - tokens.push(Token { 153 - line, 154 - value: TokenValue::Sym(buf), 155 - }); 156 - } 157 - lex_pat!(ws) => { 158 - if c == '\n' { 159 - line.0 += 1; 160 - line.1 = 0; 161 - } else { 162 - line.1 += 1; 163 - } 164 - } 165 - chars::STR_DELIM => { 166 - let mut buf = String::new(); 167 - let mut in_escape = false; 168 - 169 - while let Some(c) = chars.peek() { 170 - if *c == '\n' { 171 - return Err(LexError::StringBreak(line)); 172 - } 173 - 174 - if *c == chars::STR_DELIM && !in_escape { 175 - chars.next().unwrap(); 176 - break; 177 - } 178 - 179 - if in_escape { 180 - let c = chars.next().unwrap(); 181 - 182 - match c { 183 - '\\' => buf.push('\\'), 184 - 'n' => buf.push('\n'), 185 - 'r' => buf.push('\r'), 186 - 't' => buf.push('\t'), 187 - 'a' => buf.push('\x07'), 188 - 'b' => buf.push('\x08'), 189 - chars::STR_DELIM => buf.push(chars::STR_DELIM), 190 - _ => return Err(LexError::InvalidEscape(line, c)), 191 - } 192 - 193 - in_escape = false; 194 - } else if *c == '\\' { 195 - in_escape = true; 196 - chars.next().unwrap(); 197 - } else { 198 - buf.push(chars.next().unwrap()); 199 - } 200 - } 201 - 202 - tokens.push(Token { 203 - line, 204 - value: TokenValue::Str(buf), 205 - }); 206 - } 207 - _ => { 208 - return Err(LexError::UnexpectedToken(line, c)); 209 - } 210 - } 211 - } 212 - 213 - Ok(tokens) 214 - } 215 - 216 - #[cfg(test)] 217 - mod tests { 218 - use super::*; 219 - 220 - #[test] 221 - fn lexer() -> Result<(), LexError> { 222 - let code = r#" (symbol 3.14 'quoted_symbol :atomized_symbol32 "my string") "#; 223 - let tokens = lex(code)?; 224 - 225 - for t in tokens { 226 - eprintln!("{:?}", t); 227 - } 228 - 229 - Ok(()) 230 - } 231 - 232 - #[test] 233 - fn lexer2() -> Result<(), LexError> { 234 - let code = r#" (defun hello () 235 - (print "Hello World"))"#; 236 - 237 - let tokens = lex(code)?; 238 - 239 - for t in tokens { 240 - eprintln!("{:?}", t); 241 - } 242 - 243 - Ok(()) 244 - } 245 - 246 - #[test] 247 - fn lexer3() -> Result<(), LexError> { 248 - let code = r#" '(1 2 3.4)"#; 249 - let tokens = lex(code)?; 250 - 251 - for t in tokens { 252 - eprintln!("{:?}", t); 253 - } 254 - 255 - Ok(()) 256 - } 257 - 258 - #[test] 259 - fn lexer4() -> Result<(), LexError> { 260 - let code = "_ *x* #y# sym -4-"; 261 - let tokens = lex(code)?; 262 - 263 - for t in tokens { 264 - eprintln!("{:?}", t); 265 - } 266 - 267 - Ok(()) 268 - } 269 - 270 - #[test] 271 - fn lexer5() -> Result<(), LexError> { 272 - let code = include_str!("./test/test.zexa"); 273 - let tokens = lex(code)?; 274 - 275 - for t in tokens { 276 - eprintln!("{:?}", t); 277 - } 278 - 279 - Ok(()) 280 - } 281 - }
-278
src/lib.rs
··· 1 - use std::{ 2 - any, 3 - cmp::Ordering, 4 - ops::{Add, Div, Mul, Sub}, 5 - sync::Arc, 6 - }; 7 - use strum::VariantNames; 8 - 9 - use crate::{env::{Environment, RuntimeError}, parser::AST}; 10 - 11 - /// Type for atoms 12 - pub type Atom = String; 13 - 14 - /// Type for symbols 15 - pub type Symbol = String; 16 - 17 - /// Type for numbers 18 - pub type Number = f64; 19 - 20 - /// Rust function 21 - pub type NativeFunc = fn(env: env::Environment, args: &[Value]) -> Result<Value, env::RuntimeError>; 22 - 23 - /// Rust macro 24 - pub type NativeMacro = fn(env: env::Environment, args: AST) -> Result<AST, env::RuntimeError>; 25 - 26 - /// Argument list 27 - pub type ArgList = Vec<Symbol>; 28 - 29 - #[derive(Debug, thiserror::Error)] 30 - pub enum LockError<T> { 31 - Poison(#[from] std::sync::PoisonError<T>), 32 - TryLock(#[from] std::sync::TryLockError<T>), 33 - } 34 - 35 - /// Zexa function 36 - #[derive(Clone, Debug)] 37 - pub struct Func(ArgList, AST); 38 - 39 - impl Func { 40 - pub fn call(&self, env: Environment) -> Result<Value, RuntimeError> { 41 - env.eval(self.1.clone()) 42 - } 43 - } 44 - 45 - /// Zexa macro 46 - #[derive(Clone, Debug)] 47 - pub struct Macro(ArgList, AST); 48 - 49 - impl Macro { 50 - pub fn fill_args_and_call(&mut self) { 51 - _ = self.0; 52 - _ = self.1; 53 - } 54 - } 55 - 56 - /// Anything that can be called 57 - pub enum Callable { 58 - Func(Func), 59 - Macro(Macro), 60 - NFunc(NativeFunc), 61 - NMacro(NativeMacro), 62 - } 63 - 64 - pub trait UserData: any::Any + 'static {} 65 - 66 - /// Any possible value 67 - #[derive(Clone, Debug, strum::VariantNames)] 68 - pub enum Value { 69 - Nil, 70 - Bool(bool), 71 - Atom(Atom), 72 - Number(Number), 73 - Symbol(Symbol), 74 - String(String), 75 - List(Vec<Value>), 76 - Quoted(Box<Value>), 77 - Func(Func), 78 - Macro(Macro), 79 - NativeFunc(NativeFunc), 80 - NativeMacro(NativeMacro), 81 - UserData(Arc<dyn any::Any + 'static>), 82 - } 83 - 84 - impl Value { 85 - /// Get the [`ValueType`] of this [`Value`] 86 - pub fn value_type(&self) -> ValueType { 87 - match self { 88 - Self::Nil => ValueType::Nil, 89 - Self::Bool(_) => ValueType::Bool, 90 - Self::Atom(_) => ValueType::Atom, 91 - Self::Number(_) => ValueType::Number, 92 - Self::Symbol(_) => ValueType::Symbol, 93 - Self::String(_) => ValueType::String, 94 - Self::List(_) => ValueType::List, 95 - Self::Quoted(_) => ValueType::Quoted, 96 - Self::Func(_) => ValueType::Func, 97 - Self::Macro(_) => ValueType::Macro, 98 - Self::NativeFunc(_) => ValueType::NativeFunc, 99 - Self::NativeMacro(_) => ValueType::NativeMacro, 100 - Self::UserData(_) => ValueType::UserData, 101 - } 102 - } 103 - 104 - /// Check whether this value is *truthy* 105 - pub fn is_truthy(&self) -> bool { 106 - match self { 107 - Self::Nil => false, 108 - Self::Bool(b) => *b, 109 - Self::Atom(_) => true, 110 - Self::Number(n) => *n != 0.0, 111 - Self::Symbol(_) => true, 112 - Self::String(s) => !s.is_empty(), 113 - Self::List(l) => !l.is_empty(), 114 - _ => false, 115 - } 116 - } 117 - 118 - /// Check whether this value is some sort of function 119 - pub fn is_function(&self) -> bool { 120 - match self { 121 - Self::Func(_) | Self::NativeFunc(_) => true, 122 - _ => false, 123 - } 124 - } 125 - 126 - pub fn len(&self) -> usize { 127 - todo!("len for Value") 128 - } 129 - } 130 - 131 - impl PartialEq for Value { 132 - fn eq(&self, other: &Self) -> bool { 133 - match (self, other) { 134 - (Value::Nil, Value::Nil) => true, 135 - (Value::Number(n1), Value::Number(n2)) => n1 == n2, 136 - (Value::Atom(a1), Value::Atom(a2)) => a1 == a2, 137 - (Value::Symbol(s1), Value::Symbol(s2)) => s1 == s2, 138 - (Value::Bool(b1), Value::Bool(b2)) => b1 == b2, 139 - (Value::String(s1), Value::String(s2)) => s1 == s2, 140 - (Value::List(l1), Value::List(l2)) => l1 == l2, 141 - (Value::Quoted(v1), Value::Quoted(v2)) => *v1 == *v2, 142 - _ => false, 143 - } 144 - } 145 - } 146 - 147 - impl PartialOrd for Value { 148 - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { 149 - match (self, other) { 150 - (Value::Nil, Value::Nil) => Some(Ordering::Equal), 151 - (Value::Number(n1), Value::Number(n2)) => n1.partial_cmp(n2), 152 - (Value::Atom(a1), Value::Atom(a2)) => a1.partial_cmp(a2), 153 - (Value::Symbol(s1), Value::Symbol(s2)) => s1.partial_cmp(s2), 154 - (Value::Bool(b1), Value::Bool(b2)) => b1.partial_cmp(b2), 155 - (Value::String(s1), Value::String(s2)) => s1.partial_cmp(s2), 156 - _ => None, 157 - } 158 - } 159 - } 160 - 161 - impl Add for Value { 162 - type Output = Value; 163 - 164 - fn add(self, rhs: Self) -> Self::Output { 165 - match (self, rhs) { 166 - (Self::Nil, _) => Self::Nil, 167 - (_, Self::Nil) => Self::Nil, 168 - (Self::Bool(b1), Self::Bool(b2)) => Self::Bool(b1 && b2), 169 - (Self::Atom(a1), Self::Atom(a2)) => Self::Atom(a1 + &a2), 170 - (Self::Number(n1), Self::Number(n2)) => Self::Number(n1 + n2), 171 - (Self::Symbol(s1), Self::Symbol(s2)) => Self::Symbol(s1 + &s2), 172 - (Self::String(s1), Self::String(s2)) => Self::String(s1 + &s2), 173 - (Self::List(mut l1), Self::List(mut l2)) => { 174 - l1.append(&mut l2); 175 - Value::List(l1) 176 - } 177 - (Self::List(mut l), v) => { 178 - l.push(v); 179 - Value::List(l) 180 - } 181 - (v, _) => v, 182 - } 183 - } 184 - } 185 - 186 - impl Sub for Value { 187 - type Output = Value; 188 - 189 - fn sub(self, rhs: Self) -> Self::Output { 190 - match (self, rhs) { 191 - (Self::Nil, _) => Self::Nil, 192 - (_, Self::Nil) => Self::Nil, 193 - (Self::Number(n1), Self::Number(n2)) => Self::Number(n1 - n2), 194 - (v, _) => v, 195 - } 196 - } 197 - } 198 - 199 - impl Mul for Value { 200 - type Output = Value; 201 - 202 - fn mul(self, rhs: Self) -> Self::Output { 203 - match (self, rhs) { 204 - (Self::Nil, _) => Self::Nil, 205 - (_, Self::Nil) => Self::Nil, 206 - (Self::Number(n1), Self::Number(n2)) => Self::Number(n1 * n2), 207 - (Self::String(s), Self::Number(n)) => Self::String(s.repeat(n as usize)), 208 - (v, _) => v, 209 - } 210 - } 211 - } 212 - 213 - impl Div for Value { 214 - type Output = Value; 215 - 216 - fn div(self, rhs: Self) -> Self::Output { 217 - match (self, rhs) { 218 - (Self::Nil, _) => Self::Nil, 219 - (_, Self::Nil) => Self::Nil, 220 - (Self::Number(n1), Self::Number(n2)) => Self::Number(n1 / n2), 221 - (v, _) => v, 222 - } 223 - } 224 - } 225 - 226 - /// A possible type for a [`Value`] 227 - #[derive( 228 - Clone, Copy, Debug, strum::IntoStaticStr, strum::AsRefStr, strum::Display, strum::VariantNames, 229 - )] 230 - pub enum ValueType { 231 - Nil, 232 - Bool, 233 - Atom, 234 - Number, 235 - Symbol, 236 - String, 237 - List, 238 - Quoted, 239 - Func, 240 - Macro, 241 - NativeFunc, 242 - NativeMacro, 243 - UserData, 244 - } 245 - 246 - const _: () = assert!( 247 - Value::VARIANTS.len() == ValueType::VARIANTS.len(), 248 - "When new type added make sure to add it to ValueType as well" 249 - ); 250 - 251 - pub mod env; 252 - pub mod lexer; 253 - pub mod parser; 254 - pub(crate) mod stdlib; 255 - 256 - /// Re-exports for the important stuff 257 - pub mod prelude { 258 - /// Either a [`crate::lexer::LexError`] or a [`crate::parser::ParseError`] 259 - #[derive(Debug, thiserror::Error)] 260 - pub enum LexParseError { 261 - #[error("lex error: {0}")] 262 - Lex(#[from] crate::lexer::LexError), 263 - #[error("parse error: {0}")] 264 - Parse(#[from] crate::parser::ParseError), 265 - } 266 - 267 - /// Lex and parse `code` 268 - pub fn parse(code: &str) -> Result<AST, LexParseError> { 269 - Ok(parse_tokens(lex(code)?)?) 270 - } 271 - 272 - pub use crate::{ 273 - Number, Symbol, Value, ValueType, 274 - env::{Environment, InnerEnvironment, RuntimeError}, 275 - parser::AST, 276 - }; 277 - use crate::{lexer::lex, parser::parse_tokens}; 278 - }
-175
src/parser.rs
··· 1 - use crate::{ 2 - Value, 3 - lexer::{LineInfo, Token, TokenValue}, 4 - }; 5 - 6 - pub type AST = Vec<Value>; 7 - 8 - #[derive(Debug, thiserror::Error)] 9 - pub enum ParseError { 10 - #[error("unexpected EOF near {0}")] 11 - UnexpectedEOF(LineInfo), 12 - #[error("invalid atom near {0}")] 13 - InvalidAtom(LineInfo), 14 - #[error("unclosed list near {0}")] 15 - UnclosedList(LineInfo), 16 - #[error("unexpected token near {0}: {1:?}")] 17 - UnexpectedToken(LineInfo, TokenValue), 18 - } 19 - 20 - pub fn parse_tokens(tokens: Vec<Token>) -> Result<AST, ParseError> { 21 - let mut ast = AST::new(); 22 - let mut tokens = tokens.into_iter(); 23 - 24 - while let Some(token) = tokens.next() { 25 - ast.push(parse_expr(&token, &mut tokens)?); 26 - } 27 - 28 - Ok(ast) 29 - } 30 - 31 - #[recursive::recursive] 32 - fn parse_expr( 33 - token: &Token, 34 - token_iter: &mut impl Iterator<Item = Token>, 35 - ) -> Result<Value, ParseError> { 36 - match &token.value { 37 - TokenValue::Num(n) => Ok(Value::Number(n.parse().unwrap())), 38 - TokenValue::Sym(s) => Ok(Value::Symbol(s.clone())), 39 - TokenValue::Str(s) => Ok(Value::String(s.clone())), 40 - TokenValue::Quote => { 41 - let next_token = token_iter 42 - .next() 43 - .ok_or(ParseError::UnexpectedEOF(token.line))?; 44 - Ok(Value::Quoted(Box::new(parse_expr( 45 - &next_token, 46 - token_iter, 47 - )?))) 48 - } 49 - TokenValue::Atom => { 50 - let next_token = token_iter 51 - .next() 52 - .ok_or(ParseError::UnexpectedEOF(token.line))?; 53 - 54 - match &next_token.value { 55 - TokenValue::Sym(s) => Ok(Value::Atom(s.to_owned())), 56 - _ => Err(ParseError::InvalidAtom(next_token.line)), 57 - } 58 - } 59 - TokenValue::LParen => { 60 - let mut list = Value::List(vec![]); 61 - 62 - while let Some(next_token) = token_iter.next() { 63 - match &next_token.value { 64 - TokenValue::RParen => { 65 - break; 66 - } 67 - 68 - _ => { 69 - let value = parse_expr(&next_token, token_iter)?; 70 - 71 - let Value::List(l) = &mut list else { 72 - panic!("This isn't possible"); 73 - }; 74 - 75 - l.push(value); 76 - } 77 - } 78 - } 79 - 80 - Ok(list) 81 - } 82 - TokenValue::RParen => Err(ParseError::UnexpectedToken(token.line, TokenValue::RParen)), 83 - } 84 - } 85 - 86 - pub fn parse_str(code: &str) -> Result<AST, Box<dyn std::error::Error>> { 87 - Ok(parse_tokens(crate::lexer::lex(code)?)?) 88 - } 89 - 90 - #[cfg(test)] 91 - mod tests { 92 - use super::*; 93 - 94 - #[test] 95 - fn parse() { 96 - let ast = parse_str("(1 2 3)").unwrap(); 97 - 98 - for expr in ast { 99 - println!("{expr:?}"); 100 - } 101 - } 102 - 103 - #[test] 104 - fn parse2() { 105 - let ast = parse_str("(defun hello () (print \"hello\"))").unwrap(); 106 - 107 - for expr in ast { 108 - println!("{expr:?}"); 109 - } 110 - } 111 - 112 - #[test] 113 - fn parse3() { 114 - let _ = parse_str("()").unwrap(); 115 - } 116 - 117 - #[test] 118 - fn parse4() { 119 - let ast = parse_str("3.14 :atom 'quoted").unwrap(); 120 - 121 - for expr in ast { 122 - println!("{expr:?}"); 123 - } 124 - } 125 - 126 - #[test] 127 - fn parse5() { 128 - let ast = parse_str("(print-quoted 'this-shall-not-be-evaluated)").unwrap(); 129 - 130 - for expr in ast { 131 - println!("{expr:?}"); 132 - } 133 - } 134 - 135 - #[test] 136 - fn parse6() { 137 - let ast = parse_str("(defmacro quote (b) b)").unwrap(); 138 - 139 - for expr in ast { 140 - println!("{expr:?}"); 141 - } 142 - } 143 - 144 - #[test] 145 - fn parse7() { 146 - let ast = parse_str("((((((1 2 3 4 5))))))").unwrap(); 147 - 148 - for expr in ast { 149 - println!("{expr:?}"); 150 - } 151 - } 152 - 153 - #[test] 154 - fn parse8() { 155 - let ast = parse_str("(cons 1 (cons 2 (cons 3 (cons 4 nil))))").unwrap(); 156 - 157 - for expr in ast { 158 - println!("{expr:?}"); 159 - } 160 - } 161 - 162 - #[test] 163 - fn parse9() { 164 - assert!(parse_str("").is_ok()); 165 - } 166 - 167 - #[test] 168 - fn parse10() { 169 - let ast = parse_str(". * $").unwrap(); 170 - 171 - for expr in ast { 172 - println!("{expr:?}"); 173 - } 174 - } 175 - }
+9
src/root.zig
··· 1 + pub const types = @import("./types.zig"); 2 + pub const env = @import("./env.zig"); 3 + pub const std = @import("./std.zig"); 4 + 5 + test { 6 + _ = types; 7 + _ = env; 8 + _ = std; 9 + }
+10
src/std.zig
··· 1 + const std = @import("std"); 2 + const zexa = @import("zexa"); 3 + const Scope = zexa.types.Scope; 4 + const Value = zexa.types.Value; 5 + 6 + pub const lib = @import("./std/root.zig"); 7 + 8 + pub fn loadStd(scope: *Scope) !void { 9 + try scope.insert("dbg", try Value.initFromAny(scope, lib.dbg)); 10 + }
+13
src/std/root.zig
··· 1 + const std = @import("std"); 2 + 3 + const zexa = @import("zexa"); 4 + const Scope = zexa.types.Scope; 5 + const Value = zexa.types.Value; 6 + 7 + pub fn dbg(scope: *Scope, args: []*Value) !*Value { 8 + for (args) |v| { 9 + std.debug.print("{any}\n", .{v.*}); 10 + } 11 + 12 + return Value.initNil(scope); 13 + }
-292
src/stdlib/funcs.rs
··· 1 - use rand::Rng; 2 - 3 - use super::{NativeFunc, RuntimeError, Value, ValueType}; 4 - 5 - pub const TYPE: NativeFunc = |_, args| { 6 - let mut ty = String::new(); 7 - 8 - if let Some(val) = args.get(0) { 9 - ty = val.value_type().to_string(); 10 - } 11 - 12 - Ok(Value::String(ty)) 13 - }; 14 - 15 - pub const DEBUG: NativeFunc = |_, args| { 16 - for a in args { 17 - println!("{a:?}") 18 - } 19 - 20 - Ok(Value::Nil) 21 - }; 22 - 23 - pub const LIST: NativeFunc = |_, args| { 24 - let mut list = vec![]; 25 - 26 - for a in args { 27 - list.push(a.clone()); 28 - } 29 - 30 - Ok(Value::List(list)) 31 - }; 32 - 33 - pub const SET: NativeFunc = |env, args| { 34 - if args.len() != 2 { 35 - return Err(RuntimeError::UnexpectedArguments(2, args.len())); 36 - } 37 - 38 - let mut args = args.to_vec(); 39 - 40 - let Value::Symbol(symbol) = args.remove(0) else { 41 - return Err(RuntimeError::InvalidArgumentType(0, ValueType::Symbol)); 42 - }; 43 - 44 - let val = args.remove(0); 45 - env.write().set(symbol, val); 46 - 47 - Ok(Value::Nil) 48 - }; 49 - 50 - pub const ADD: NativeFunc = |_, args| { 51 - if args.len() == 0 { 52 - return Err(RuntimeError::UnexpectedArguments(1, args.len())); 53 - } 54 - 55 - let mut args = args.to_vec(); 56 - 57 - let mut val = args.remove(0); 58 - 59 - for a in args { 60 - val = val + a; 61 - } 62 - 63 - Ok(val) 64 - }; 65 - 66 - pub const SUB: NativeFunc = |_, args| { 67 - if args.len() == 0 { 68 - return Err(RuntimeError::UnexpectedArguments(1, args.len())); 69 - } 70 - 71 - let mut args = args.to_vec(); 72 - let mut val = args.remove(0); 73 - 74 - for a in args { 75 - val = val - a; 76 - } 77 - 78 - Ok(val) 79 - }; 80 - 81 - pub const MUL: NativeFunc = |_, args| { 82 - if args.len() == 0 { 83 - return Err(RuntimeError::UnexpectedArguments(1, args.len())); 84 - } 85 - 86 - let mut args = args.to_vec(); 87 - 88 - let mut val = args.remove(0); 89 - 90 - for a in args { 91 - val = val * a; 92 - } 93 - 94 - Ok(val) 95 - }; 96 - 97 - pub const DIV: NativeFunc = |_, args| { 98 - if args.len() == 0 { 99 - return Err(RuntimeError::UnexpectedArguments(1, args.len())); 100 - } 101 - 102 - let mut args = args.to_vec(); 103 - 104 - let mut val = args.remove(0); 105 - 106 - for a in args { 107 - val = val / a; 108 - } 109 - 110 - Ok(val) 111 - }; 112 - 113 - pub const EQ: NativeFunc = |_, args| { 114 - if args.len() != 2 { 115 - return Err(RuntimeError::UnexpectedArguments(2, args.len())); 116 - } 117 - 118 - Ok(Value::Bool(args.get(0).unwrap() == args.get(1).unwrap())) 119 - }; 120 - 121 - pub const NOT: NativeFunc = |_, args| { 122 - if args.len() != 1 { 123 - return Err(RuntimeError::UnexpectedArguments(1, args.len())); 124 - } 125 - 126 - Ok(Value::Bool(!args.get(0).unwrap().is_truthy())) 127 - }; 128 - 129 - pub const AND: NativeFunc = |_, args| { 130 - if args.len() != 2 { 131 - return Err(RuntimeError::UnexpectedArguments(2, args.len())); 132 - } 133 - 134 - let b1 = args.get(0).unwrap().is_truthy(); 135 - let b2 = args.get(1).unwrap().is_truthy(); 136 - 137 - Ok(Value::Bool(b1 && b2)) 138 - }; 139 - 140 - pub const OR: NativeFunc = |_, args| { 141 - if args.len() != 2 { 142 - return Err(RuntimeError::UnexpectedArguments(2, args.len())); 143 - } 144 - 145 - let b1 = args.get(0).unwrap().is_truthy(); 146 - let b2 = args.get(1).unwrap().is_truthy(); 147 - 148 - Ok(Value::Bool(b1 || b2)) 149 - }; 150 - 151 - pub const GT: NativeFunc = |_, args| { 152 - if args.len() != 2 { 153 - return Err(RuntimeError::UnexpectedArguments(2, args.len())); 154 - } 155 - 156 - Ok(Value::Bool(args.get(0).unwrap() > args.get(1).unwrap())) 157 - }; 158 - 159 - pub const LE: NativeFunc = |_, args| { 160 - if args.len() != 2 { 161 - return Err(RuntimeError::UnexpectedArguments(2, args.len())); 162 - } 163 - 164 - Ok(Value::Bool(args.get(0).unwrap() < args.get(1).unwrap())) 165 - }; 166 - 167 - pub const GTE: NativeFunc = |_, args| { 168 - if args.len() != 2 { 169 - return Err(RuntimeError::UnexpectedArguments(2, args.len())); 170 - } 171 - 172 - Ok(Value::Bool(args.get(0).unwrap() >= args.get(1).unwrap())) 173 - }; 174 - 175 - pub const LEE: NativeFunc = |_, args| { 176 - if args.len() != 2 { 177 - return Err(RuntimeError::UnexpectedArguments(2, args.len())); 178 - } 179 - 180 - Ok(Value::Bool(args.get(0).unwrap() <= args.get(1).unwrap())) 181 - }; 182 - 183 - pub const NEG: NativeFunc = |_, args| { 184 - if args.len() != 1 { 185 - return Err(RuntimeError::UnexpectedArguments(1, args.len())); 186 - } 187 - 188 - let Value::Number(num) = args.get(0).unwrap() else { 189 - return Err(RuntimeError::InvalidArgumentType(1, ValueType::Number)); 190 - }; 191 - 192 - Ok(Value::Number(-num)) 193 - }; 194 - 195 - pub const GENSYM: NativeFunc = |_, args| { 196 - let mut rng = rand::rng(); 197 - let id = rng.random_range(100000..=999999); 198 - 199 - if args.len() != 1 { 200 - Ok(Value::Symbol(format!("{id}"))) 201 - } else { 202 - let Some(Value::String(template)) = args.get(0) else { 203 - return Err(RuntimeError::InvalidArgumentType(0, ValueType::String)); 204 - }; 205 - 206 - Ok(Value::Symbol(format!("{template}-{id}"))) 207 - } 208 - }; 209 - 210 - pub const MAP: NativeFunc = |env, args| { 211 - if args.len() != 2 { 212 - return Err(RuntimeError::UnexpectedArguments(2, args.len())); 213 - } 214 - let mut args = args.to_vec(); 215 - let mut newlist = vec![]; 216 - 217 - let Value::List(list) = args.remove(0) else { 218 - return Err(RuntimeError::InvalidArgumentType(0, ValueType::List)); 219 - }; 220 - 221 - let func = args.remove(0); 222 - if !func.is_function() { 223 - return Err(RuntimeError::InvalidArgumentType(1, ValueType::Func)); 224 - } 225 - 226 - for v in list { 227 - let nv = match func { 228 - Value::Func(ref f) => { 229 - if f.0.len() != 1 { 230 - continue; 231 - } 232 - 233 - let child = env.create_child(); 234 - child.write().set(f.0[0].clone(), v); 235 - 236 - f.call(child)? 237 - }, 238 - Value::NativeFunc(f) => { 239 - f(env.clone(), &[v])? 240 - } 241 - _ => unreachable!() 242 - }; 243 - 244 - newlist.push(nv); 245 - } 246 - 247 - Ok(Value::List(newlist)) 248 - }; 249 - 250 - pub const SORT: NativeFunc = |env, args| { 251 - if args.len() != 2 { 252 - return Err(RuntimeError::UnexpectedArguments(2, args.len())); 253 - } 254 - let mut args = args.to_vec(); 255 - 256 - let Value::List(mut list) = args.remove(0) else { 257 - return Err(RuntimeError::InvalidArgumentType(0, ValueType::List)); 258 - }; 259 - 260 - let func = args.remove(0); 261 - if !func.is_function() { 262 - return Err(RuntimeError::InvalidArgumentType(1, ValueType::Func)); 263 - } 264 - 265 - list.sort_by(move |x, y| { 266 - let nv = match func { 267 - Value::Func(ref f) => { 268 - if f.0.len() == 2 { 269 - let child = env.create_child(); 270 - child.write().set(f.0[0].clone(), x.clone()); 271 - child.write().set(f.0[1].clone(), y.clone()); 272 - 273 - f.call(child).unwrap_or(Value::Nil) 274 - } else { 275 - Value::Nil 276 - } 277 - }, 278 - Value::NativeFunc(f) => { 279 - f(env.clone(), &[x.clone(), y.clone()]).unwrap_or(Value::Nil) 280 - } 281 - _ => unreachable!() 282 - }.is_truthy(); 283 - 284 - if nv { 285 - std::cmp::Ordering::Greater 286 - } else { 287 - std::cmp::Ordering::Less 288 - } 289 - }); 290 - 291 - Ok(Value::List(list)) 292 - };
-178
src/stdlib/macros.rs
··· 1 - use super::{NativeMacro, RuntimeError, Value, ValueType}; 2 - 3 - pub const PROGN: NativeMacro = |_, ast| Ok(ast); 4 - 5 - pub const IF: NativeMacro = |env, ast| { 6 - if ast.len() != 3 { 7 - return Err(RuntimeError::UnexpectedArguments(3, ast.len())); 8 - } 9 - let mut ast = ast.into_iter(); 10 - 11 - let b = env.eval_expr(ast.next().unwrap())?.is_truthy(); 12 - let lth = ast.next().unwrap(); 13 - let rth = ast.next().unwrap(); 14 - 15 - if b { Ok(vec![lth]) } else { Ok(vec![rth]) } 16 - 17 - // Ok(vec![]) 18 - }; 19 - 20 - pub const WHILE: NativeMacro = |env, mut ast| { 21 - if ast.len() == 0 { 22 - return Err(RuntimeError::UnexpectedArguments(1, ast.len())); 23 - } 24 - 25 - let val = ast.remove(0); 26 - 27 - while env.eval_expr(val.clone())?.is_truthy() { 28 - env.eval(ast.to_vec())?; 29 - } 30 - 31 - Ok(vec![]) 32 - }; 33 - 34 - pub const DEFUN: NativeMacro = |env, mut ast| { 35 - if ast.len() < 2 { 36 - return Err(RuntimeError::UnexpectedArguments(2, ast.len())); 37 - } 38 - 39 - let Value::Symbol(sym) = ast.remove(0) else { 40 - return Err(RuntimeError::InvalidArgumentType(0, ValueType::Symbol)); 41 - }; 42 - 43 - let Value::List(arglist) = ast.remove(0) else { 44 - return Err(RuntimeError::InvalidArgumentType(1, ValueType::List)); 45 - }; 46 - 47 - let mut args = vec![]; 48 - 49 - for arg in arglist { 50 - let Value::Symbol(val) = arg else { 51 - return Err(RuntimeError::TypeError( 52 - "argument 1 of `defun` should be list of symbols".to_owned(), 53 - )); 54 - }; 55 - 56 - args.push(val); 57 - } 58 - 59 - env.write().set(sym, Value::Func(crate::Func(args, ast))); 60 - 61 - Ok(vec![]) 62 - }; 63 - 64 - pub const LAMBDA: NativeMacro = |_, mut ast| { 65 - if ast.len() < 1 { 66 - return Err(RuntimeError::UnexpectedArguments(1, ast.len())); 67 - } 68 - 69 - let Value::List(arglist) = ast.remove(0) else { 70 - return Err(RuntimeError::InvalidArgumentType(0, ValueType::List)); 71 - }; 72 - 73 - let mut args = vec![]; 74 - 75 - for arg in arglist { 76 - let Value::Symbol(val) = arg else { 77 - return Err(RuntimeError::TypeError( 78 - "argument 0 of `lambda` should be list of symbols".to_owned(), 79 - )); 80 - }; 81 - 82 - args.push(val); 83 - } 84 - 85 - Ok(vec![Value::Func(crate::Func(args, ast))]) 86 - }; 87 - 88 - pub const DEFMACRO: NativeMacro = |env, ast| { 89 - _ = (env, ast); 90 - Ok(vec![]) 91 - }; 92 - 93 - pub const WHEN: NativeMacro = |env, ast| { 94 - if ast.len() < 1 { 95 - return Err(RuntimeError::UnexpectedArguments(1, ast.len())); 96 - } 97 - let mut ast = ast.into_iter(); 98 - let b = env.eval_expr(ast.next().unwrap())?.is_truthy(); 99 - 100 - if b { 101 - let ast = ast.collect::<Vec<_>>(); 102 - Ok(ast) 103 - } else { 104 - Ok(vec![]) 105 - } 106 - }; 107 - 108 - pub const UNLESS: NativeMacro = |env, ast| { 109 - if ast.len() < 1 { 110 - return Err(RuntimeError::UnexpectedArguments(1, ast.len())); 111 - } 112 - let mut ast = ast.into_iter(); 113 - let b = env.eval_expr(ast.next().unwrap())?.is_truthy(); 114 - 115 - if !b { 116 - let ast = ast.collect::<Vec<_>>(); 117 - Ok(ast) 118 - } else { 119 - Ok(vec![]) 120 - } 121 - }; 122 - 123 - pub const LET: NativeMacro = |env, mut ast| { 124 - const ERRMSG: &str = "argument 0 of `let` should be list of variable bindings"; 125 - let child = env.create_child(); 126 - 127 - if ast.len() < 1 { 128 - return Err(RuntimeError::UnexpectedArguments(1, ast.len())); 129 - } 130 - 131 - let Value::List(varlist) = ast.remove(0) else { 132 - return Err(RuntimeError::InvalidArgumentType(0, ValueType::List)); 133 - }; 134 - 135 - for def in varlist { 136 - let Value::List(mut def) = def else { 137 - return Err(RuntimeError::TypeError(ERRMSG.to_owned())); 138 - }; 139 - 140 - if def.len() != 2 { 141 - return Err(RuntimeError::TypeError(ERRMSG.to_owned())); 142 - } 143 - 144 - let Value::Symbol(sym) = def.remove(0) else { 145 - return Err(RuntimeError::TypeError(ERRMSG.to_owned())); 146 - }; 147 - 148 - let val = def.remove(0); 149 - child.write().set(sym, val); 150 - } 151 - 152 - Ok(vec![child.eval(ast)?]) 153 - }; 154 - 155 - pub const DOLIST: NativeMacro = |env, mut ast| { 156 - if ast.len() < 2 { 157 - return Err(RuntimeError::UnexpectedArguments(2, ast.len())); 158 - } 159 - 160 - let child = env.create_child(); 161 - 162 - let Value::Symbol(def) = ast.remove(0) else { 163 - return Err(RuntimeError::InvalidArgumentType(0, ValueType::Symbol)); 164 - }; 165 - 166 - let Value::List(list) = env.eval_expr(ast.remove(0))? else { 167 - return Err(RuntimeError::InvalidArgumentType(1, ValueType::List)); 168 - }; 169 - 170 - let mut new_list = vec![]; 171 - 172 - for elem in list { 173 - child.write().set(&def, elem); 174 - new_list.push(child.eval(ast.clone())?); 175 - } 176 - 177 - Ok(vec![Value::Quoted(Box::new(Value::List(new_list)))]) 178 - };
-52
src/stdlib/mod.rs
··· 1 - use crate::{ 2 - NativeFunc, NativeMacro, Value, ValueType, 3 - env::{Environment, RuntimeError}, 4 - }; 5 - 6 - mod funcs; 7 - mod macros; 8 - 9 - /// Load the standard library into an [`Environment`] 10 - pub fn load_std(env: Environment) { 11 - { 12 - let mut mut_env = env.write(); 13 - mut_env.set("#t", Value::Bool(true)); 14 - mut_env.set("#f", Value::Bool(false)); 15 - mut_env.set("nil", Value::Nil); 16 - 17 - mut_env.set("type", Value::NativeFunc(funcs::TYPE)); 18 - mut_env.set("dbg", Value::NativeFunc(funcs::DEBUG)); 19 - mut_env.set("list", Value::NativeFunc(funcs::LIST)); 20 - mut_env.set("set", Value::NativeFunc(funcs::SET)); 21 - mut_env.set("add", Value::NativeFunc(funcs::ADD)); 22 - mut_env.set("sub", Value::NativeFunc(funcs::SUB)); 23 - mut_env.set("mul", Value::NativeFunc(funcs::MUL)); 24 - mut_env.set("div", Value::NativeFunc(funcs::DIV)); 25 - mut_env.set("eq", Value::NativeFunc(funcs::EQ)); 26 - mut_env.set("not", Value::NativeFunc(funcs::NOT)); 27 - mut_env.set("and", Value::NativeFunc(funcs::AND)); 28 - mut_env.set("or", Value::NativeFunc(funcs::OR)); 29 - mut_env.set(">", Value::NativeFunc(funcs::GT)); 30 - mut_env.set("<", Value::NativeFunc(funcs::LE)); 31 - mut_env.set(">=", Value::NativeFunc(funcs::GTE)); 32 - mut_env.set("<=", Value::NativeFunc(funcs::LEE)); 33 - mut_env.set("neg", Value::NativeFunc(funcs::NEG)); 34 - mut_env.set("gensym", Value::NativeFunc(funcs::GENSYM)); 35 - mut_env.set("map", Value::NativeFunc(funcs::MAP)); 36 - mut_env.set("sort", Value::NativeFunc(funcs::SORT)); 37 - 38 - mut_env.set("progn", Value::NativeMacro(macros::PROGN)); 39 - mut_env.set("if", Value::NativeMacro(macros::IF)); 40 - mut_env.set("while", Value::NativeMacro(macros::WHILE)); 41 - mut_env.set("defun", Value::NativeMacro(macros::DEFUN)); 42 - mut_env.set("lambda", Value::NativeMacro(macros::LAMBDA)); 43 - mut_env.set("defmacro", Value::NativeMacro(macros::DEFMACRO)); 44 - mut_env.set("when", Value::NativeMacro(macros::WHEN)); 45 - mut_env.set("unless", Value::NativeMacro(macros::UNLESS)); 46 - mut_env.set("let", Value::NativeMacro(macros::LET)); 47 - mut_env.set("dolist", Value::NativeMacro(macros::DOLIST)); 48 - } 49 - 50 - env.eval(crate::prelude::parse(include_str!("./std.zexa")).unwrap()) 51 - .unwrap(); 52 - }
-20
src/stdlib/std.zexa
··· 1 - ;; -*- mode: lisp -*- 2 - 3 - (set '*pi* 3.1415926535897932) 4 - (set '*tau* (mul *PI* 2)) 5 - (set '*phi* 1.618033988749894) 6 - (set '*e* 2.71828182845904523) 7 - 8 - (set '*zexa-version* "0.1.0") ; TODO: move definition to rust source code so we can use env!() macro 9 - 10 - (defun truthy? (x) 11 - (if x #t #f)) 12 - 13 - (defun xor (x y) 14 - (and (or x y) (not (eq x y)))) 15 - 16 - (defun max (x y) 17 - (if (> x y) x y)) 18 - 19 - (defun min (x y) 20 - (if (< x y) x y))
-5
src/test/test.zexa
··· 1 - ;; -*- mode: lisp -*- 2 - 3 - 4 - (greet "World") 5 - (greet "Mars")
-24
src/test/test2.zexa
··· 1 - ;; -*- mode: lisp -*- 2 - 3 - (dbg 4 - (type 32) 5 - (type #t) 6 - (type nil) 7 - (type :my_atom) 8 - (type dbg) 9 - (type '(1 2 3)) 10 - (add 3 4) 11 - (div 5 2)) 12 - 13 - (dbg (add 3 5 9 0 1 4 8 4 3)) 14 - (dbg (mul 1 2 3 4 5 6 7 8 9)) 15 - 16 - (dbg 'quoted_symbol) 17 - (dbg '(1 2 3 symbol (type 3n))) 18 - (dbg (list 1 2 3 (type 3))) 19 - 20 - (set 'x 434378) 21 - (dbg x) 22 - 23 - (set 'y "hello world") 24 - (dbg y)
-14
src/test/test3.zexa
··· 1 - ;; -*- mode: lisp -*- 2 - (defun square (x) 3 - (mul x x)) 4 - 5 - (dbg (square 5)) 6 - 7 - (defun circ (r) 8 - (mul 2 *PI* r)) 9 - 10 - (dbg (circ 4)) 11 - (dbg (circ 5)) 12 - 13 - 14 - (dbg *pi* *tau* *phi* *e*)
+242
src/types.zig
··· 1 + const std = @import("std"); 2 + 3 + const Allocator = std.mem.Allocator; 4 + const Arena = std.heap.ArenaAllocator; 5 + 6 + pub const Scope = struct { 7 + const Self = @This(); 8 + 9 + pub const VarMap = std.StringHashMap(*Value); 10 + 11 + allocator: Allocator, 12 + arena: Arena, 13 + variables: std.StringHashMap(*Value), 14 + parent: ?*Scope = null, 15 + 16 + pub fn init(allocator: Allocator) Self { 17 + return Self{ 18 + .allocator = allocator, 19 + .arena = Arena.init(allocator), 20 + .variables = VarMap.init(allocator), 21 + }; 22 + } 23 + 24 + pub fn deinit(self: *Self) void { 25 + self.variables.deinit(); 26 + self.arena.deinit(); 27 + } 28 + 29 + pub fn branch(self: *Self) Scope { 30 + var s = Scope.init(self.allocator); 31 + s.setParent(self); 32 + return s; 33 + } 34 + 35 + pub fn arenaAllocator(self: *Self) Allocator { 36 + return self.arena.allocator(); 37 + } 38 + 39 + pub fn setParent(self: *Self, parent: *Self) void { 40 + self.parent = parent; 41 + } 42 + 43 + pub fn createString(self: *Self, str: []const u8) ![]const u8 { 44 + const out = try self.arena.allocator().alloc(u8, str.len); 45 + @memcpy(out, str); 46 + return out; 47 + } 48 + 49 + pub fn insert(self: *Self, key: []const u8, value: *Value) !void { 50 + try self.variables.put(key, value); 51 + } 52 + 53 + pub fn get(self: *Self, key: []const u8) ?*Value { 54 + if (self.variables.get(key)) |v| { 55 + return v; 56 + } else if (self.parent) |p| { 57 + return p.get(key); 58 + } 59 + 60 + return null; 61 + } 62 + }; 63 + 64 + pub const Symbol = []const u8; 65 + pub const Number = f64; 66 + pub const NativeFunc = *const fn (scope: *Scope, args: []*Value) anyerror!*Value; 67 + pub const NativeMacro = void; 68 + 69 + pub const ValueType = enum { 70 + Nil, 71 + Bool, 72 + Sym, 73 + Num, 74 + Str, 75 + Quote, 76 + NativeFunc, 77 + Cons, 78 + }; 79 + 80 + pub const Value = union(enum) { 81 + const Self = @This(); 82 + 83 + pub const Atom = union(enum) { 84 + nil, 85 + bool: bool, 86 + sym: Symbol, 87 + num: Number, 88 + str: []const u8, 89 + quote: *Self, 90 + native_func: NativeFunc, 91 + }; 92 + pub const Cons = struct { car: *Value, cdr: *Value }; 93 + 94 + atom: Atom, 95 + cons: Cons, 96 + 97 + pub fn initNil(scope: *Scope) !*Self { 98 + const atom = try scope.arenaAllocator().create(Self); 99 + atom.* = Self{ .atom = .nil }; 100 + 101 + return atom; 102 + } 103 + 104 + pub fn initFrom(scope: *Scope, value: Self) !*Self { 105 + const val = try Self.initNil(scope); 106 + val.* = value; 107 + return val; 108 + } 109 + 110 + pub fn initFromAny(scope: *Scope, value: anytype) !*Self { 111 + return switch (@TypeOf(value)) { 112 + void => Self.initNil(scope), 113 + comptime_int, comptime_float, f32, f64 => Self.initFrom(scope, .{ 114 + .atom = .{ .num = @as(f64, value) }, 115 + }), 116 + i32, i64, u32, u64 => Self.initFrom(scope, .{ 117 + .atom = .{ .num = @floatFromInt(value) }, 118 + }), 119 + bool => Self.initFrom(scope, .{ 120 + .atom = .{ .bool = value }, 121 + }), 122 + else => error.InvalidType, 123 + }; 124 + } 125 + 126 + pub fn initString(scope: *Scope, str: []const u8) !*Self { 127 + const atom = try Self.initNil(scope); 128 + const nstr = try scope.createString(str); 129 + atom.* = Self{ .atom = .{ .str = nstr } }; 130 + return atom; 131 + } 132 + 133 + pub fn initSymbol(scope: *Scope, sym: []const u8) !*Self { 134 + const atom = try Self.initNil(scope); 135 + const nsym = try scope.createString(sym); 136 + atom.* = Self{ .atom = .{ .sym = nsym } }; 137 + return atom; 138 + } 139 + 140 + pub fn initCons(scope: *Scope, car: *Value, cdr: *Value) !*Self { 141 + const cons = try Self.initNil(scope); 142 + cons.* = Value{ 143 + .cons = .{ 144 + .car = car, 145 + .cdr = cdr, 146 + }, 147 + }; 148 + return cons; 149 + } 150 + 151 + pub fn initNativeFunc(scope: *Scope, func: NativeFunc) !*Self { 152 + return Self.initFrom(scope, .{ 153 + .atom = .{ .native_func = func }, 154 + }); 155 + } 156 + 157 + pub fn initList(scope: *Scope, values: []const *Value) !*Self { 158 + var cons = try Value.initCons(scope, try Value.initNil(scope), try Value.initNil(scope)); 159 + 160 + if (values.len == 0) { 161 + return cons; 162 + } 163 + cons.cons.car = values[0]; 164 + 165 + const ptr = cons; 166 + var rest = values[1..]; 167 + while (rest.len != 0) { 168 + std.debug.print("hm?\n", .{}); 169 + const ncons = try Value.initCons(scope, rest[0], try Value.initNil(scope)); 170 + 171 + cons.cons.cdr = ncons; 172 + cons = ncons; 173 + 174 + rest = rest[1..]; 175 + } 176 + 177 + return ptr; 178 + } 179 + 180 + pub fn isNil(self: *const Self) bool { 181 + return switch (self.*) { 182 + .atom => |atom| switch (atom) { 183 + .nil => true, 184 + else => false, 185 + }, 186 + .cons => |cons| cons.car.isNil(), 187 + }; 188 + } 189 + 190 + pub fn toSlice(self: *Self, scope: *Scope) ![]*Value { 191 + var list = try std.ArrayList(*Value).initCapacity(scope.allocator, 10); 192 + try self.toSliceInner(scope, &list); 193 + const slice = try list.toOwnedSlice(scope.allocator); 194 + defer scope.allocator.free(slice); 195 + 196 + const nslice = try scope.arenaAllocator().alloc(*Value, slice.len); 197 + @memcpy(nslice, slice); 198 + 199 + return nslice; 200 + } 201 + 202 + fn toSliceInner(self: *Self, scope: *Scope, list: *std.ArrayList(*Value)) !void { 203 + switch (self.*) { 204 + .atom => |atom| switch (atom) { 205 + .nil => {}, 206 + else => try list.append(scope.allocator, self), 207 + }, 208 + .cons => |cons| { 209 + try list.append(scope.allocator, cons.car); 210 + try cons.cdr.toSliceInner(scope, list); 211 + }, 212 + } 213 + } 214 + 215 + pub fn append(self: *Self, scope: *Scope, other: *Self) !void { 216 + switch (self.*) { 217 + .cons => |*cons| { 218 + if (cons.cdr.isNil()) { 219 + cons.cdr = try Value.initCons(scope, other, try Value.initNil(scope)); 220 + } else { 221 + try cons.cdr.append(scope, other); 222 + } 223 + }, 224 + else => {}, 225 + } 226 + } 227 + 228 + pub fn getType(self: *const Self) ValueType { 229 + return switch (self.*) { 230 + .atom => |atom| switch (atom) { 231 + .nil => ValueType.Nil, 232 + .bool => ValueType.Bool, 233 + .num => ValueType.Num, 234 + .str => ValueType.Str, 235 + .sym => ValueType.Sym, 236 + .quote => ValueType.Quote, 237 + .native_func => ValueType.NativeFunc, 238 + }, 239 + .cons => ValueType.Cons, 240 + }; 241 + } 242 + };
+1
test/test1.zexa
··· 1 +