{"id":13806708,"url":"https://github.com/novika-lang/novika","last_synced_at":"2025-04-09T12:15:46.923Z","repository":{"id":37865704,"uuid":"500113681","full_name":"novika-lang/novika","owner":"novika-lang","description":"🪱 Novika is a free-form, moldable, interpreted programming language","archived":false,"fork":false,"pushed_at":"2025-02-05T21:31:44.000Z","size":11660,"stargazers_count":15,"open_issues_count":22,"forks_count":0,"subscribers_count":2,"default_branch":"rev10","last_synced_at":"2025-02-05T22:37:10.330Z","etag":null,"topics":["crystal","interpreter","language","novika","programming-language","repl"],"latest_commit_sha":null,"homepage":"https://novika-lang.github.io/","language":"Crystal","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/novika-lang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-06-05T14:02:34.000Z","updated_at":"2025-02-05T21:31:15.000Z","dependencies_parsed_at":"2024-05-02T20:11:56.917Z","dependency_job_id":null,"html_url":"https://github.com/novika-lang/novika","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/novika-lang%2Fnovika","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/novika-lang%2Fnovika/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/novika-lang%2Fnovika/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/novika-lang%2Fnovika/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/novika-lang","download_url":"https://codeload.github.com/novika-lang/novika/tar.gz/refs/heads/rev10","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248036057,"owners_count":21037093,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crystal","interpreter","language","novika","programming-language","repl"],"created_at":"2024-08-04T01:01:15.016Z","updated_at":"2025-04-09T12:15:46.837Z","avatar_url":"https://github.com/novika-lang.png","language":"Crystal","funding_links":[],"categories":["Implementations/Compilers"],"sub_categories":[],"readme":"# Novika\n\n[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://app.gitter.im/#/room/#novika-lang:gitter.im)\n\n\u003cimg src=\"img/logo.svg\" align=right\u003e\n\n\u003e A language that doesn't affect the way you think about programming, is not worth knowing.\n\u003e ­— Alan J. Perlis\n\nNovika is a free-form, moldable, interpreted programming language.\n\n---\n\n**Table of contents:**\n\n- [Introduction](#introduction)\n- [Examples](#examples)\n- [Installing Novika](#installing-novika)\n- [Building Novika from source](#building-novika-from-source)\n- [Running the examples](#running-the-examples)\n- [Playing with the REPL](#playing-with-the-repl)\n- [On blocks](#on-blocks)\n- [Want to learn more?](#want-to-learn-more)\n- [Trade-offs, or why is Novika so slow?](#trade-offs-or-why-is-novika-so-slow)\n- [Contributing and internals](#contributing-and-internals)\n- [Contributors](#contributors)\n\n---\n\n## Introduction\n\nFirst and foremost, **Novika is weird**. Why not, though, being inspired by Lisp, Forth, Factor, Self, Red/Rebol, Smalltalk, and so on — the weird kids on the block.\n\nNovika is like simulating a house of LEGO blocks vs. simulating a house of huge concrete blocks, wood, and all that. The latter\nis much easier computationally, while the former offers unlimited flexibility. You can build only so much from huge concrete blocks,\nwood, chairs, and whatnot. With LEGO, it's another story — an infinite amount of possibilities before you.\n\nSemantically, Novika is like Lisp *A* set in motion by Lisp *B* with the possibility of bidirectional communication and control — but with objects, stacks, and so, so much more!\n\nAnd the syntax of Novika? Well, there is no syntax. That is to say, almost no syntax. Syntactically, Novika lies somewhere between Lisp and Forth. And Forth — Forth has no syntax.\n\n## Examples\n\nA quine:\n\n```novika\n[ 'Some payload here perhaps?' ]\nthis\neach:\necho\n```\n\nHello World:\n\n```novika\n'Hello World' echo\n```\n\n---\n\nFactorial. Note that parentheses `()` are treated as whitespace in Novika. They also don't have to be matched.\n\n```novika\n(5 to: 1) product \"120\"\n```\n\n---\n\nFirst 100 Fizz buzz rounds:\n\n```novika\n1 to: 100 each: [\n  [ [ 15 /? ] 'FizzBuzz'\n    [  5 /? ] 'Buzz'\n    [  3 /? ] 'Fizz'\n  ] choose echo\n]\n```\n\n---\n\nSieve of Eratosthenes: prints prime numbers in `[2; 120]`.\n\n```novika\n2 to: 120 ||-\u003e [ $: n (stack without: [ n /? ]) asStack n ] each: echo\n```\n\n---\n\n[Zigzag problem](https://leetcode.com/problems/zigzag-conversion/) from LeetCode, with the examples as tests. Observe the boundary between terseness and readability.\n\n```novika\n\"\"\"\nNot the mathy one but the naive one, because programming is\nnot math thank goodness!\n\"\"\"\n\n[ dup 1 = =\u003e [ drop ^ ]\n\n  collect: '' dup 1 |to $: grid\n\n  0 $: col\n\n  [ grid |: |\u003e |atRightBound? asc desc sel ] $: desc\n  [ grid |: \u003c| |afterFirst? desc asc sel (col 1 + =: col) ] $: asc\n  desc @: action\n\n  [ $: char grid |: [ char ~ ] ] @: put\n\n  each: [ put action =: action ]\n\n  grid join\n] @: convert\n\n\ndescribe 'Zigzag Conversion' [\n  in leetcode\n\n  it should 'follow the happy path' [\n    'A' 1 convert 'A' assert=\n    'A' 3 convert 'A' assert=\n    'HELLOWORLD' 1 convert 'HELLOWORLD' assert=\n  ]\n\n  it should 'convert given 3 rows' [\n    'PAYPALISHIRING' 3 convert 'PAHNAPLSIIGYIR' assert=\n  ]\n\n  it should 'convert given 4 rows' [\n    'PAYPALISHIRING' 4 convert 'PINALSIGYAHRPI' assert=\n  ]\n]\n\nrunTestsInGroup: leetcode\n```\n\n### What about something a bit more elaborate?\n\n- A snake game [example](https://github.com/novika-lang/novika/blob/rev10/examples/snake.new.nk)\n- A simple [documentation viewer](https://github.com/novika-lang/novika/blob/rev10/examples/docuview.nk)\n- A [prompt](https://github.com/novika-lang/novika/blob/rev10/examples/lch-prompt.nk) that blinks in colors from the LCH color space\n- A TDD-d [observable](https://github.com/novika-lang/novika/blob/rev10/examples/observable.nk)\n- A [live REPL interface](https://github.com/novika-lang/novika/blob/rev10/examples/mathrepl.nk) to a DSL for infix math expressions\n\n## Installing Novika\n\nThe fastest way to get started with Novika is to download and unpack the latest [nightly build](https://github.com/novika-lang/nightly-builds/releases/latest).\nNovika [releases](https://github.com/novika-lang/novika/releases/latest) are as unstable as nightlies, if not more so, so don't worry :zany_face:\n\n1. If you don't want to do a system-wide install, simply use `bin/novika` *while in the directory of the nightly/release*.\n\n2. Otherwise, move the `env` folder to your user's home directory, and rename it to `.novika`. Optionally, add `bin/novika` to your PATH.\n\n## Building Novika from source\n\nYou will need to have [Crystal](https://crystal-lang.org/install/) installed.\n\n1. Clone this repository:\n\n```\ngit clone https://github.com/novika-lang/novika.git\n```\n\n2. Go there:\n\n```\ncd novika\n```\n\n### Windows\n\n```\nshards build --without-development --release --progress --no-debug\n```\n\n### Linux\n\n```\nshards build --without-development --release --progress --no-debug -Dnovika_console -Dpreview_mt\n```\n\n### What do the `-D`s mean?\n\n* `-Dnovika_console`: use [termbox2.cr](https://github.com/homonoidian/termbox2.cr) as the backend for capability *console*.  Otherwise, *console* won't be available. Since [termbox2](https://github.com/termbox/termbox2) doesn't support Windows, you have to drop the flag when compiling for/under it.\n\n### What's next?\n\nYou can optionally add `bin/novika` to PATH, and/or create a symbolic link for `env` called `.novika` in your user's home directory, like so:\n\n```\nln -s /path/to/novika/repo/env /home/\u003cyour-user\u003e/.novika\n```\n\nI'd recommend you to run the tests with `bin/novika tests`. If something seems wrong, [file an issue](https://github.com/novika-lang/novika/issues/new).\n\n## Running the examples\n\nTry to run one of the [examples](#examples). Some of them contain instructions on how you can run them. In general, you can use:\n\n```\nbin/novika path/to/example.nk\n```\n\nIf it's yelling at you in red that you need *console*, use:\n\n```\nbin/novika console path/to/example.nk\n```\n\n(unless you're on Windows; Novika on Windows doesn't support console yet)\n\n## Playing with the REPL\n\nTo run the REPL, use:\n\n```\nbin/novika repl\n```\n\nTo list all available words, use `la`:\n\n```\n\u003e\u003e\u003e la\n```\n\nTo see documentation for a particular word, use `help` followed by the word that you're interested in:\n\n```\n\u003e\u003e\u003e help toOrphan\n...\n\u003e\u003e\u003e help 123\ndecimal number 123\n\u003e\u003e\u003e help 'Who am I?'\nquote 'Who am I?'\n```\n\nTo get a string description of a thing's type, use `typedesc`:\n\n```\n\u003e\u003e\u003e 123 typedesc\n... 'decimal' ...\n\u003e\u003e\u003e ##foobar typedesc\n... 'quoted word' ...\n```\n\n\n## On blocks\n\nNovika is all about blocks! The name is pretty generic, and has little if any connection to \"blocks\" of mainstream programming languages.\n\n### Blocks are lists with a cursor\n\n\u003cimg src=\"img/blocks-are-lists-with-a-cursor.svg\" align=right width=512 /\u003e\n\nBlocks allow you to store different kinds of *forms* one after another. A form could be a number, a string, or even another block!\n\nIn this regard, a block is somewhat similar to a Python list or a Ruby array.\n\nMoreover, now taking the *cursor* into account, blocks seem a lot like text input fields but with *arbitrary constituents* rather than just characters.\n\nYou can move the cursor back and forth in a block. You can \"backspace\", insert, and so on, all this not only *empowering computation* but also *backed by computation*.\n\n\u003cbr clear=\"right\"/\u003e\n\n```novika\n\"\"\"\n'Cut' the block in half at the cursor using |slice.\n\"\"\"\n[ 1 2 3 4 | 5 6 7 8 ] |slice leaves: [ [ 1 2 3 4 | ] [ 5 6 7 8 | ]  ]\n\n\"\"\"\nRemember where the cursor is, then slide it forward and double\neach 'top' number. Finally, move the cursor back to where it was.\n\"\"\"\n[ 1 2 3 4 | 5 6 7 8 ] |~\u003e [ dup + ] leaves: [ [ 1 2 3 4 | 10 12 14 16 ] ]\n```\n\n### Blocks are dictionaries — and objects\n\n\u003cimg src=\"img/blocks-are-dictionaries.svg\" align=right width=512 /\u003e\n\nBlocks are dictionaries for themselves and for other blocks. The former is useful for *running* blocks, and the latter is useful for *connecting* blocks to each other — to form scopes, object hierarchies, and so on.\n\nAgain, you can imagine something like a Python dictionary or — even better — a JavaScript object.\n\nBlock dictionaries hold *entries*.\n\nWhen the key form is seen, looked up in the dictionary, and *opened*, *opener entries* (or *openers* for short) in turn *open* the value form (*open* is Novika-speak for \"run\", \"execute\", \"evaluate\").\n\nOn the other hand, *pusher* entries simply push their value form onto the stack.\n\n\u003cbr clear=\"right\"/\u003e\n\n```novika\n100 $: x\n200 $: y\nx y + echo  \"STDOUT: 300⏎\"\n\n[ ${ x y } this ] @: newPoint\n\n100 200 newPoint $: A\n300 400 newPoint $: B\n\nA echo \"STDOUT: [ ${ x y } this · ${y :: 200} ${x :: 100} ]⏎\"\nB echo \"STDOUT: [ ${ x y } this · ${y :: 400} ${x :: 300} ]⏎\"\n\nA.x A.y 2echo \"STDOUT: 100⏎200⏎\"\nB.x B.y 2echo \"STDOUT: 300⏎400⏎\"\n```\n\n\n### Blocks are stacks\n\nAs simple as that: blocks are also stacks, you just have to look at them differently.\n\nApplying operations immediately before (or even after!) the cursor enables brevity often associated with stack-oriented programming languages. You can also move the cursor — this allows to avoid `rot`s and other nasty Forth-isms. Here is how `rot` can be implemented in Novika:\n\n```novika\n[ \u003c| swap |\u003e swap ] @: rot\n```\n\nLet's execute `1 2 3 rot` step-by-step, as if we were a Novika interpreter.\n\n1. Stack: `[ | ]`, block: `[ | 1 2 3 rot ]`\n2. Push `1`, stack: `[ 1 | ]`, block: `[ 1 | 2 3 rot ]`\n3. Push `2`, stack: `[ 1 2 | ]`, block: `[ 1 2 | 3 rot ]`\n4. Push `3`, stack: `[ 1 2 3 | ]`, block: `[ 1 2 3 | rot ]`\n5. Open `rot` with stack: `[ 1 2 3 | ]`: *instantiate* (basically copy) the block `[ \u003c| swap |\u003e swap ]`, and move the cursor to the beginning like so: `[ | \u003c| swap |\u003e swap ]`\n6. Open `\u003c|`, stack: `[ 1 2 | 3 ]`, block: `[ \u003c| | swap |\u003e swap ]`\n7. Open `swap`, stack: `[ 2 1 | 3 ]`, block: `[ \u003c| swap | |\u003e swap ]`\n8. Open `|\u003e`, stack: `[ 2 1 3 | ]`, block: `[ \u003c| swap |\u003e | swap ]`\n9. Open `swap`, stack: `[ 2 3 1 | ]`, block: `[ \u003c| swap |\u003e swap | ]`\n10. Cursor for block `[ \u003c| swap |\u003e swap | ]` is at end, close it!\n11. Cursor for block `[ 1 2 3 rot | ]` is at end, close it!\n12. No more blocks to run!\n\nVoilá! It does rotate: `1 2 3 -- 2 3 1`.\n\n\u003cimg src=\"img/blocks-are-stacks.svg\"  width=1024 /\u003e\n\n### Blocks are vertices\n\n\u003cimg src=\"img/blocks-are-vertices.svg\" align=right width=512 /\u003e\n\nScoping, inheritance, and composition are all achieved through block relationships in Novika. There are two kinds of relationships: *is a friend of*, and *is **the** parent of*.\n\n- Blocks can have zero or one *parent*.\n- Blocks can have zero or more *friends*.\n\nBlocks can change their (and other blocks') relationships (i.e. edges) at runtime, thereby affecting how, which, and whose entries are looked up and opened.\n\nBlock relationships can be cyclic: already-queried blocks are simply skipped. For those interested, Novika entry lookup is a weird (mainly for historical reasons and for convenience) combination of DFS and BFS (I guess...) that roughly goes as follows:\n\n- *Is the parent of* relationships of block A are traversed;\n- A's friends are traversed;\n- The friends of A's parents are traversed.\n\nTogether they are known as *the first echelon* in Novika. Then *the second echelon* — parents, friends, and friends of parents of the first echelon — is explored. Novika lookup machinery (and machinery it is!) simply recurses on members of the second echelon; prior to that it queries each member for whatever it is interested in, and turns to recursion only when the query remains unanswered. In general, you can look at the numerous A\\* or Dijkstra pathfinding visualizations over at YouTube to see how such traversal might look like. Although the visualizations won't directly apply to Novika, they're still super helpful.\n\n\u003cbr clear=\"right\"/\u003e\n\n```novika\n[ 100 $: x ] obj $: definesX\n[ 200 $: y ] obj $: definesY\n\n\"\"\"\nEstablish a cyclic relationship (remember that parentheses are\ntreated as whitespace!)\n\"\"\"\n(definesX -- definesY -- definesX) drop\n\ndefinesX.x leaves: 100\ndefinesX.y leaves: 200\n\ndefinesY.x leaves: 100\ndefinesY.y leaves: 200\n```\n\n### Blocks are code\n\nWhen you're writing Novika, you're writing blocks. It's like when you're writing Lisp, you're writing lists.\n\nAll Novika code you saw or will see is a block — or, rather, is *in* a block. The toplevel block is the one that holds your whole code and doesn't need to be enclosed in `[]`s. You can think of it as of the \"file\" block, that is, the block which encloses an entire file of Novika source code *implicitly*.\n\n```novika\nthis echo  \"STDOUT: [ this echo · ${__path__ :: '/path/to/folder'} ${__file__ :: '/path/to/folder/file.nk'} ]\"\n```\n\n### Blocks are continuations\n\nA Novika continuation is a block that consists of two blocks: the stack block, and the code block, like so: `[ [ …code… ] [ …stack… ] ]`. Many words exist that create, add, remove, or modify continuation blocks and continuations. Most of them are so-called *builtins*, which are bits of runnable native code as seen from Novika. Here are some examples:\n\n- [hydrate](https://novika-lang.github.io/docs/hydrate), as in:\n\n  ```novika\n  [ 1 2 ] [ + echo ] hydrate  \"STDOUT: 3\"\n  ```\n\n- [open](https://novika-lang.github.io/docs/open) — this is an ancient (and often used) word from which the term *to open* came. What is described as *opening* is in reality a form of *hydration*, but for historical reasons *opening* is used anyway.\n\n  ```novika\n  4 [ dup + ] open echo  \"STDOUT: 8\"\n  ```\n\n- [do](https://novika-lang.github.io/docs/do) — opens a block with a new empty (isolated) stack:\n\n  ```novika\n  1 2 [ stack echo ] do  \"STDOUT: [ ]\"\n  ```\n\n- And more, see the [words documentation](https://novika-lang.github.io/docs) or env/core.\n\nStack blocks can be shared between two continuations (as in `open` or opener entries where the block you open shares the stack with the opener block). Code blocks can also be shared, but I have never needed this in practice so there's no word that does something like that in env/core.\n\nIn the code block, the cursor is kept immediately after the form that is being opened right now.\n\n- The current (active) continuation can be accessed using the word `cont`, as in:\n\n  ```novika\n  1 2 cont echo 3 4  \"STDOUT: [ [ 1 2 cont echo | 3 4 ] [ 1 2 ] ]\"\n  ```\n\n- The stack of the current continuation (dubbed the *active stack* or simply the stack) can be accessed using the word `stack`, as in:\n\n  ```novika\n  1 2 \u003c| stack echo |\u003e 3 4  \"STDOUT: [ 1 | 2 ]\"\n  ```\n\n- The code block of the current continuation (dubbed the *active block* or simply the block) can be accessed using the word `this`, as in:\n\n  ```novika\n  1 2 this echo 3 4  \"STDOUT: [ 1 2 this echo | 3 4 ]\"\n  ```\n\n- The code block of the previous continuation (and the one that will be *activated* when the current continuation finishes) can be accessed using the word `ahead`. This word is *crucial* for writing human-readable Novika, as in `1 to: 100 only: even? each: echo`:\n\n  ```novika\n  [ ahead echo ] @: sneakyPeaky\n\n  1 2 sneakyPeaky 3 4  \"STDOUT: [ 1 2 sneakyPeaky | 3 4 ]\"\n  ```\n\nFinally, the *continuations block* is a single large block that holds individual continuation blocks. The top continuation block is the one that is currently executed. Below is (roughly) what you'd get if you type `conts shallowCopy each: echo` in the REPL. Do not forget `shallowCopy`, or the language will gain consciousness — and this never ends well!!! :)\n\n```novika\n[ [ … REPL code … · ${__path__ :: '/path/to/novika/env'} ${__file__ :: '/path/to/novika/env/repl/repl.nk'} ${_pgRoot :: a block} @{startSession :: a block} ] [ ] ]\n[ [ … More REPL code … · ${error :: false} ${pgStack :: a block} @{runLine :: ( Q -- )} ] [ ] ]\n[ [ ahead thruBlock loop ] [ ] ]\n[ [ new $: iterBody iterBody createLoop $: nextLoop $: breakLoop @: startLoop iterBody #break breakLoop opens iterBody #next nextLoop opens startLoop · ${iterBody :: a block} ${nextLoop :: a block} ${breakLoop :: a block} @{startLoop :: a block} ] [ ] ]\n[ [ this =: breakTo orphan loopBody hydrate! ] [ ] ]\n[ [ orphan iterBody hydrate | repeat ] [ ] ]\n[ [ '\u003e\u003e\u003e ' readLine br: [ runLine ] [ 'Bye.' echo break ] ] [ ] ]\n[ [ ahead thruBlock ahead thruBlock br ] [ ] ]\n[ [ runLine ] [ ] ]\n[ [ … More REPL code … · ${line :: 'conts shallowCopy each: echo'} ${self :: ( Q -- )} ${durationMs :: 0} ${pgRootInstance :: a block} ${pgStackCopy :: a block} ] [ ] ]\n[ [ [ reportError #true =: error self resume ] @: __died__ [ pgStackCopy pgRootInstance line slurp hydrate! ] measure | =: durationMs · @{__died__ :: a block} ] [ ] ]\n[ [ monotonic $: t1 do | monotonic $: t2 t2 t1 - · ${t1 :: 35111923.17418} ] [ ] ]\n[ [ pgStackCopy pgRootInstance line slurp hydrate! ] [ ] ]\n[ [ conts shallowCopy each: echo ] [ 1 2 3 4 ] ]\n```\n\nDon't be scared, it's just a bunch of letters :)\n\n## Want to learn more?\n\n1. Explore files in `tests/` to see how various words can be used. Beware, however, that those are internal behavior tests — and most of the time, they aren't practical/particularly readable.\n2. Explore `help` messages of various words. Read word documentation [here](https://novika-lang.github.io/docs/).\n3. Explore files in `env/core`, the language's standard library.\n4. Explore the [Wiki](https://github.com/novika-lang/novika/wiki).\n\nI know there aren't a lot of materials here nor anywhere that'd teach you the language. On the fundamental stuff, the language is so weird I can't even remember how it all came to be. And in general I have so much to say that I just don't know where to begin. Hopefully, there will be more stuff here someday.\n\nExplore Novika as if it were an alien spaceship that accidentally fell on Earth, full of weird little yellow rotating yukoos. The aliens did not write on every button what it will do when you press it. And even if they did, what kind of language would they be using?!\n\n## Trade-offs, or why is Novika so slow?\n\nOf course, I had to make some trade-offs to achieve such a peculiar arrangement!\n\n### Negative performance\n\n*Wait, what?*\n\nSee, good compilers/interpreters live well in the positives. That is to say they remove irrelevant runtime. Bad compilers and “normal” interpreters live near zero, at the very least getting rid of the notion of parsing.\n\nAnd what about Novika? Novika is deep in the negatives. Novika *parses* at runtime. Yup, you’ve heard it right.\n\nWaging wars with FFI will give you performance, sure (that is, will move you closer to zero from the negative side!) But then, why not simply use C, Rust, Crystal, or any other fancy-schmancy programming language — especially if you're doing something *serious*?\n\n### Readability\n\n*It's up to you.*\n\nMaybe you want your code to look cryptic — so your friends think you’re a hacker or something. Novika will not stand in your way.\n\nBut wait, why is that? Why is Novika not *designed* to be readable? Isn't that popular nowadays?\n\nSee, in Novika, it is easy to make your code readable — even natural language-like. This ease, however, degrades performance. That is, enforcing style or syntax degrades performance. Even if Novika someday gets a JIT, writing natural-language-like code will still impose a performance penalty, however minuscule it will be. The choice between complete, high-level control over the language and the machinery involved vs. performance is up to you.\n\n### Big projects\n\n*Never.*\n\nI have no clue what big projects are, or what they need. There are enough smart people in this world already, and I'm certainly not one of them.\n\nI would say Novika is an interesting experiment and a great personal project. Perhaps the language will grow into something bigger a few years from now. Most likely, however, it'll die. Maintaining a general-purpose programming language in the 21st century is hard ­— there's just so much it must be able to do! After all, we are not drawing rectangles at the speed of a snail today, are we?\n\n## Contributing and internals\n\nFirst of all, thank you for even getting this far! Even if you didn't read the whole document, thank you. Seriously :)\n\n### Where do I start?\n\n1. First of all, the documentation for rev10 (i.e., this implementation) is available [here](https://novika-lang.github.io/novika/).\n2. Try exploring [capabilities](https://github.com/novika-lang/novika/tree/rev10/src/novika/capabilities) and their [implementations](https://github.com/novika-lang/novika/tree/rev10/src/novika/capabilities/impl). This is where native code words like `dup` and `appendEcho` are defined. This is also a nice *starting point* to find bugs, optimize, add new stuff, etc. It's also one of the places where you can find typos, lack of documentation, and even some TODOs.\n3. Try looking through the [interpreter code](https://github.com/novika-lang/novika/tree/rev10/src/novika) in general. I do have a compulsion to write comments, so most of the code is documented. How well documented is not for me to decide, but documented it is.\n4. If you're someone who knows something about optimization, your eyes will hurt! Believe me :)\n\n### What happens where?\n\nWhen you do your `bin/novika hello.nk`, here's *roughly* the order in which various components get invoked:\n\n1. [The command-line interface](https://github.com/novika-lang/novika/blob/rev10/src/cli.cr) frontend is what greets you (or doesn't) and sets everything up.\n2. [Resolver](https://github.com/novika-lang/novika/blob/rev10/src/novika/resolver.cr) knows where everything is on the disk.\n3. [Capability collection](https://github.com/novika-lang/novika/blob/rev10/src/novika/capability.cr) allows to control the capabilities of this particular invokation of the language/capabilities of the language overall. For example, this component is aware of you droping the `-Dnovika_console` flag.\n4. [Capability interfaces and implementations](https://github.com/novika-lang/novika/tree/rev10/src/novika/capabilities) describe and implement those capabilities.\n5. [Scissors](https://github.com/novika-lang/novika/blob/rev10/src/novika/scissors.cr) cut the contents of `hello.nk` (or any other blob of source code) into pieces called *unclassified forms*\n6. [Classifier](https://github.com/novika-lang/novika/blob/rev10/src/novika/classifier.cr) classifies them, and shoves the resulting [forms](https://github.com/novika-lang/novika/tree/rev10/src/novika/forms) into a *file block*.\n7. [Blocks](https://github.com/novika-lang/novika/blob/rev10/src/novika/forms/block.cr) are *the* most important forms in Novika.\n8. [Engine](https://github.com/novika-lang/novika/blob/rev10/src/novika/engine.cr) [runs](https://github.com/novika-lang/novika/blob/db440e7f8ba4342a9eaacf77f76b6c59bc49528f/src/novika/engine.cr#L307) file blocks and all blocks \"subordinate\" to them. **This is the entrypoint for code execution, and one of the cornerstones of Novika**.\n9. [Errors](https://github.com/novika-lang/novika/blob/rev10/src/novika/error.cr) happen. Or don't.\n\nNote that most of these components interact with each other, making this list pretty pointless \"for science\".\n\n### Implementing features as a capability (in Crystal) vs. in Novika\n\nTL; DR: The rule of thumb for me is if something requires awareness of the\nuser's OS or isn't portable/`ffi`-compatible, it should be implemented as a\ncapability (meaning in Crystal).\n\nFor instance, networking, reading/writing files, building paths -- all of this\nrequires awareness of the underlying OS, due to different syscalls, permission\njugglery, and other slash-vs-backslash kinds of issues.\n\nNovika is a high-level interface -- you won't believe it, a *language*! Whether\nthe underlying (\"discussed\") objects are from the native code \"reality\" or\nconstructed with the means of the language, is completely irrelevant to\nthe end user, nor to Novika the High-Level Interface.\n\nAgain, Novika is a slightly different way of thinking, sure, but certainly\nnot an operating system!\n\nNote that e.g. SDL is cross-platform provided you put the dynamic libraries\nfor it in the proper place. Moreover, `ffi` is a capability and is cross-platform.\nSo it's perfectly valid to use `ffi`, the only requirement being that the library\nyou're `ffi`-ing is cross-platform.\n\nNovika code is supposed to be run in a sandbox of sorts, like JavaScript in the\nbrowser. The gatekeeper of sorts is called the *resolver* (perhaps I should\nrename it to gatekeeper though 💩).\n\nInside the sandbox, there is no information about the OS. However, the resolver\ndoes have access to this information, so you can branch in your `.nk.app` or `.nk.lib`\nlike so: `[ windows, linux |  myWindowsFile, myLinuxFile ].nk`.\n\nNow, I know the sandbox is \"breachy\", but I can't do anything about it! The\nworld is a dangerous place, huh?\n\n### And the usual procedure\n\n1. Fork it (\u003chttps://github.com/novika-lang/novika/fork\u003e)\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create a new Pull Request\n\n## Contributors\n\n* [homonoidian](https://github.com/homonoidian) - creator and maintainer\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnovika-lang%2Fnovika","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnovika-lang%2Fnovika","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnovika-lang%2Fnovika/lists"}