├── .github └── workflows │ ├── all-debug-compile-only.yml │ └── run-tests.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── build.zig ├── build.zig.zon ├── examples ├── basicWorldTest.self ├── fibonacci.self └── httpServer.self ├── objects ├── actor.self ├── array.self ├── basicTraits.self ├── block.self ├── booleans.self ├── collection.self ├── collector.self ├── defaultBehavior.self ├── everything.self ├── file.self ├── globals.self ├── hashMap.self ├── hashSet.self ├── hashTable.self ├── integer.self ├── list.self ├── os.self ├── scheduler.self ├── sortKey.self ├── string.self ├── testing.self └── vector.self ├── repl.self ├── scripts └── enable-all-debug-flags.sh ├── src ├── debug.zig ├── language.zig ├── language │ ├── ASTPrinter.zig │ ├── Diagnostics.zig │ ├── Location.zig │ ├── LocationRange.zig │ ├── Parser.zig │ ├── Range.zig │ ├── Script.zig │ ├── Token.zig │ ├── Tokenizer.zig │ ├── ast.zig │ ├── ast_copy_visitor.zig │ └── grammar.zig ├── main.zig ├── runtime.zig ├── runtime │ ├── Activation.zig │ ├── Actor.zig │ ├── ByteArray.zig │ ├── Heap.zig │ ├── RuntimeError.zig │ ├── Selector.zig │ ├── SourceRange.zig │ ├── VirtualMachine.zig │ ├── base_object.zig │ ├── bytecode.zig │ ├── bytecode │ │ ├── AstGen.zig │ │ ├── CodeGen.zig │ │ ├── astcode.zig │ │ ├── astcode │ │ │ ├── Liveness.zig │ │ │ └── register_location.zig │ │ ├── block.zig │ │ ├── executable.zig │ │ ├── instruction.zig │ │ ├── lowcode.zig │ │ └── lowcode │ │ │ ├── RegisterFile.zig │ │ │ ├── RegisterPool.zig │ │ │ └── register_location.zig │ ├── context.zig │ ├── execution_result.zig │ ├── interpreter.zig │ ├── intrinsic_map.zig │ ├── map.zig │ ├── map_builder.zig │ ├── object.zig │ ├── object_bless.zig │ ├── object_lookup.zig │ ├── object_traversal.zig │ ├── objects │ │ ├── activation.zig │ │ ├── actor.zig │ │ ├── actor_proxy.zig │ │ ├── array.zig │ │ ├── block.zig │ │ ├── byte_array.zig │ │ ├── executable_map.zig │ │ ├── float.zig │ │ ├── intrinsic │ │ │ └── addrinfo.zig │ │ ├── managed.zig │ │ ├── method.zig │ │ └── slots.zig │ ├── primitives.zig │ ├── primitives │ │ ├── actor.zig │ │ ├── array.zig │ │ ├── basic.zig │ │ ├── byte_array.zig │ │ ├── number.zig │ │ ├── object.zig │ │ └── system_call.zig │ ├── slot.zig │ ├── stack.zig │ ├── stack_trace.zig │ ├── value.zig │ └── value_inspector.zig ├── utility │ ├── bounds_check.zig │ ├── error_set.zig │ ├── hash.zig │ ├── pointer.zig │ ├── ref_counted.zig │ ├── scoped_bits.zig │ ├── tracy.zig │ └── weak_ref.zig └── zigself.zig ├── tests ├── actor │ ├── actorSendMessage.self │ ├── actorSendObject.self │ ├── actorSpawn.self │ ├── actorSpawnAssignmentMessage.error.self │ ├── actorSpawnEntrypointUnset.error.self │ ├── actorSpawnInRegularActor.self │ ├── actorSpawnMessageNotMethod.error.self │ ├── actorSpawnNonUnaryMethod.error.self │ ├── actorSpawnRuntimeError.error.self │ ├── actorSpawnUnknownSelector.error.self │ ├── actorSpawnWithoutActorMode.error.self │ ├── genesisInActorMode.error.self │ └── genesisResult.self ├── addSlots │ └── basicAddSlots.self ├── array │ ├── arrayCopy.self │ └── arraySize.self ├── boolean │ ├── assert.error.self │ └── assertMsg.error.self ├── byte_array │ └── equal.self ├── collector │ ├── collectorDoubleDispatch.self │ ├── collectorEqual.self │ └── collectorSize.self ├── file │ ├── openFileAndRead.self │ └── openNonexistentPath.self ├── fixtures │ └── hello_world.txt ├── global_reachability │ ├── actorCannotModifyGloballyReachableObjectByAddSlots.error.self │ ├── actorCannotModifyGloballyReachableObjectByArrayPut.error.self │ └── actorCannotModifyGloballyReachableObjectByAssignment.error.self ├── harness.zig ├── hashTable │ ├── hashTableCollision.self │ ├── hashTableCopy.self │ ├── hashTableRemove.self │ └── hashTableReplaceExistingObject.self ├── integer │ ├── integerAsString.self │ └── integerOps.self ├── interpreter │ ├── activationObjectAsMethodReceiver.error.self │ ├── activationObjectInArgument.error.self │ ├── activationObjectReturn.error.self │ ├── blockWithTooManyArgs.error.self │ ├── blockWithTooManyAssignableSlots.error.self │ ├── inlineMethodCall.self │ ├── methodWithTooManyArgs.error.self │ └── methodWithTooManyAssignableSlots.error.self ├── primitives │ └── inspect.self.disabled ├── scheduler │ └── schedulerTest.self ├── sortKey │ └── basic.self ├── string │ ├── stringAsInteger.self │ ├── stringAt.self │ ├── stringAtPut.self │ ├── stringConcat.self │ ├── stringCopy.self │ ├── stringEqual.self │ ├── stringJoin.self │ ├── stringReverse.self │ ├── stringSplit.self │ └── stringSplitByDo.self └── vector │ ├── vectorAdd.self │ ├── vectorAt.self │ ├── vectorAtOutOfBounds.error.self │ ├── vectorAtPut.self │ ├── vectorAtPutOutOfBounds.error.self │ ├── vectorCopy.self │ ├── vectorRemove.self │ ├── vectorRemoveIfAbsent.self │ ├── vectorRemoveOutOfBounds.error.self │ └── vectorShrinkToFit.self └── zigself.bnf /.github/workflows/all-debug-compile-only.yml: -------------------------------------------------------------------------------- 1 | # A workflow that checks that the debug options haven't bitrotted. 2 | name: Compile with all debug options 3 | 4 | on: 5 | push: 6 | branches: [master] 7 | pull_request: 8 | branches: [master] 9 | 10 | workflow_dispatch: 11 | 12 | jobs: 13 | all-debug-compile-only: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: Setup Zig 20 | uses: mlugg/setup-zig@v1 21 | with: 22 | version: 0.15.0-dev.465+bb79c85cb 23 | 24 | - name: Enable all debug flags 25 | run: scripts/enable-all-debug-flags.sh 26 | 27 | - name: Compile the project 28 | run: zig build 29 | -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: Run zigSelf tests 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | workflow_dispatch: 10 | 11 | jobs: 12 | run-tests: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: Setup Zig 19 | uses: mlugg/setup-zig@v1 20 | with: 21 | version: 0.15.0-dev.465+bb79c85cb 22 | 23 | - name: Run tests 24 | run: zig build test --summary all 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .zig-cache/ 2 | zig-out/ 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # zigSelf Contribution Guidelines 2 | 3 | This document outlines how to contribute to zigSelf. 4 | 5 | ## Where to start 6 | 7 | To become familiar with the codebase, new contributors are encouraged to start 8 | with small fixes first. Issues marked with "good first issue" are usually easy 9 | fixes that other people just haven't gotten around to, and new contributors are 10 | recommended to start with them. 11 | 12 | ## Coding style 13 | 14 | Zig code follows standard Zig style. When contributing changes, make sure to run 15 | the changed files through `zig fmt`. Your editor probably has a method to do 16 | this automatically on save. 17 | 18 | Self code standards are currently not fully decided upon yet, but a general rule 19 | of thumb is listed below: 20 | 21 | - 4 spaces for indentation. No hard tabs. 22 | - All names must be `camelCase`. Keywords other than the first keyword must be 23 | `PascalCase` (enforced by the parser). 24 | - Primitive names must be `_PascalCase`. 25 | - Code itself can grow to more than 80 characters, but wrap comments at 80 26 | characters. 27 | - Comments have two different styles: 28 | 29 | - At the top of files, start a comment and follow it up with a newline for 30 | copyright information: 31 | 32 | ```zigself 33 | " 34 | Copyright (c) 20XX, John Doe 35 | 36 | SPDX-License-Identifier: GPL-3.0-only 37 | " 38 | ``` 39 | 40 | - Other comments such as documentation for functions should start the comment 41 | itself immediately after the comment start character, and each subsequent 42 | line should be indented one character after the comment start character: 43 | 44 | ```zigself 45 | "This is an example comment which demonstrates how to 46 | write your comments. Note that lines following the first 47 | comment line is indented one character further." 48 | ``` 49 | 50 | - Objects which are primarily slots objects should open the slot list 51 | immediately after the opening parentheses and should be listed on multiple 52 | lines: 53 | 54 | ```zigself 55 | foo = (| 56 | "..." 57 | |). 58 | ``` 59 | 60 | - Methods should prefer to keep all their slots on the same line. In case multiple lines are needed (i.e. for inline methods), the slot list closing pipe character should be one indent before the current indentation: 61 | 62 | ```zigself 63 | foo: arg Bar: anotherArg = (| 64 | someArg. 65 | someMethod = (| ... | 66 | ... 67 | ). 68 | | 69 | ... 70 | ). 71 | ``` 72 | 73 | - Parent slots should be listed first, and all other slots should follow. 74 | - The public interface of an object should be at the top, followed by the 75 | private implementation details (if any). See 76 | [`vector.self`](objects/vector.self) for an example. 77 | 78 | **TODO:** Add more details. 79 | 80 | ## Commit style 81 | 82 | Each commit title should describe the category of the change, i.e. `runtime:` or 83 | `objects:`. Commit title and description must not exceed 72 characters. The 84 | first word of the commit message after the category must be capitalized and must 85 | be an imperative verb (`fix`, `implement`, `update`, etc.). 86 | 87 | An example commit message: 88 | 89 | ```gitcommit 90 | runtime: Fix some VM problem 91 | 92 | The VM had an issue which was then fixed, blah blah blah. The commmit 93 | message was then wrapped at 72 characters. 94 | ``` 95 | 96 | Each commit must be atomic, i.e. all tests should pass and the REPL and other 97 | examples should run. This is to help with bisectability. 98 | 99 | ## Creating new issues 100 | 101 | When a bug is found, please create an issue for it (create a separate issue for 102 | each bug). However, feature requests from non-contributors are usually not 103 | accepted. If you want something to happen, you make it happen. :^) 104 | 105 | ## Language 106 | 107 | All zigSelf code and documentation uses American English in order to be 108 | accessible to as many people as possible. Please use proper spelling, grammar 109 | and punctuation in code, documentation and in commit messages. 110 | 111 | ## Opening a pull request 112 | 113 | When opening a pull request, please ensure that its scope is limited to the set 114 | of commits that you're making. Large PRs with many commits will be hard to 115 | review. 116 | 117 | Note however that commits that fix small issues that you come across while 118 | making your intended change is fine, but please split your yak shaves into 119 | relevantly-scoped PRs. :^) 120 | 121 | ## Applying pull request feedback 122 | 123 | After a contributor reviews your pull request and requests changes, please make 124 | any changes requested and update your commitset using git rebase and force-push. 125 | Please do not introduce fixup or merge commits (commits should stay atomic after 126 | you make your changes). If you feel like a requested change is not correct, 127 | respond to the appropriate review comment. After pushing a new set of commits, 128 | mark the requested changes that you have applied as resolved and re-request a 129 | review. 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## zigSelf 2 | 3 | [![Discord](https://img.shields.io/discord/983578577029181440?logo=discord&logoColor=white&logoWidth=20&labelColor=7289DA&label=Discord&color=119334&style=plastic)](https://discord.gg/HJ62kw6yvn) [![justforfunnoreally.dev badge](https://img.shields.io/badge/justforfunnoreally-dev-9ff)](https://justforfunnoreally.dev) 4 | 5 | An implementation of the Self programming language with an actor model. 6 | 7 | ## What is Self? 8 | 9 | [Self](https://selflanguage.org/) is a programming language designed in 1986 at 10 | Xerox PARC. It is an object-oriented programming language which uses 11 | _prototype-based inheritance_ as its basis and message-passing as its execution 12 | method. It is dynamically (but strongly) typed. 13 | 14 | Self uses an image-based approach for runtime. All the objects in the system 15 | are stored in a _Self world_ and turned into a _snapshot_ for saving. At 16 | runtime, objects can be interacted with, created and destroyed without losing 17 | state on other objects. 18 | 19 | ## What is zigSelf? 20 | 21 | zigSelf takes the good parts of Self (the global object hierarchy, the 22 | image-based workflow, the visual programming, behavior sharing with parent slots, 23 | ...), and leaves the bad parts behind (the ancient UI, cooperative scheduling, ...). 24 | It also introduces [an actor system inspired by Erlang](https://sin-ack.github.io/posts/zigself-actor/) 25 | to replace the cooperative scheduling of the previous version and to bring some 26 | structure to the system. 27 | 28 | zigSelf does not use the world provided with the original Self distribution, but 29 | instead has its own. It also has a few quality-of-life changes to the syntax 30 | that I've found to be useful, such as the `;` operator that allows for easier 31 | chaining of keyword messages. 32 | 33 | Currently, zigSelf doesn't have the visual programming environment nor the snapshot 34 | system, but they are planned. 35 | 36 | ## Build-time requirements 37 | 38 | You need the Zig compiler, preferably one built with the known-good version 39 | commit. You can find the source code, instructions for building, and more on the 40 | [Zig repository](https://github.com/ziglang/zig). 41 | 42 | Latest Zig version known to work is [0.15.0-dev.465+bb79c85cb](https://github.com/ziglang/zig/commit/bb79c85cb). 43 | Earlier and later versions may work but there are no guarantees. 44 | 45 | ## Building zigSelf 46 | 47 | 1. Clone the repository: `git clone https://github.com/sin-ack/zigself` 48 | 2. Run the code: `zig build run -- examples/fibonacci.self` 49 | 50 | That's it! If you want to build a release version, you can build one with 51 | `zig build -Doptimize=ReleaseFast` and the binary will be in `zig-out/bin/`. 52 | 53 | There is an (experimental) REPL that you can run with `zig build run -- repl.self`. 54 | 55 | ## Building for Wasm 56 | 57 | ZigSelf is able to run as a WebAssembly module via WASI. To build it, add the 58 | `wasm32-wasi` target when building: `zig build -Dtarget=wasm32-wasi` 59 | 60 | You can then run the resulting executable at `zig-out/bin/self.wasm` with 61 | [Wasmtime](https://github.com/bytecodealliance/wasmtime). Currently ZigSelf does 62 | not support loading Self code via stdin, so you will need to give it filesystem 63 | access like so: `wasmtime --mapdir=.::. zig-out/bin/self.wasm