{"id":15574606,"url":"https://github.com/tjvr/nefarious","last_synced_at":"2025-08-31T01:34:27.696Z","repository":{"id":145681440,"uuid":"67864894","full_name":"tjvr/nefarious","owner":"tjvr","description":"my Nefarious Scheme","archived":false,"fork":false,"pushed_at":"2017-06-30T15:39:39.000Z","size":296,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-09T17:31:39.224Z","etag":null,"topics":["programming-language","rpython"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tjvr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"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":"2016-09-10T10:25:22.000Z","updated_at":"2020-01-03T23:25:44.000Z","dependencies_parsed_at":"2023-04-25T00:03:11.000Z","dependency_job_id":null,"html_url":"https://github.com/tjvr/nefarious","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/tjvr/nefarious","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tjvr%2Fnefarious","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tjvr%2Fnefarious/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tjvr%2Fnefarious/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tjvr%2Fnefarious/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tjvr","download_url":"https://codeload.github.com/tjvr/nefarious/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tjvr%2Fnefarious/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272930001,"owners_count":25017057,"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","status":"online","status_checked_at":"2025-08-30T02:00:09.474Z","response_time":77,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["programming-language","rpython"],"created_at":"2024-10-02T18:20:01.826Z","updated_at":"2025-08-31T01:34:27.654Z","avatar_url":"https://github.com/tjvr.png","language":"Python","readme":"_Nefarious Scheme_.\n===================\n\nA programming language with:\n\n* **mutable syntax**.\n* an efficient yet dynamic parser.\n* function _syntax_ rather than function names.\n* equivalence between types and CFG non-terminals.\n* lexical scope.\n* CFG rule priority: newest takes precedence [so shadowing works!].\n* an incremental hybrid GC.\n* ~~a fast tracing JIT bytecode VM (based on PyPy).~~ [not yet—compilers are hard!]\n\nWritten in RPython; compiles to native code (via C), using the [RPython\ntoolchain](https://rpython.rtfd.io/). But it can also run on top of a standard\nPython interpreter (albeit slower).\n\n**_Work in progress._**\n\nOverview\n--------\n\nNefarious is a text-based programming language. It has mutable syntax: the language grammar can be extend at runtime.\n\nThe idea is to do away with DSLs and operator overloading and so on, and just have fully general function syntax.\n\nHere's a quick (and poorly chosen) example:\n\n\tdefine Int:a + Int:b { return (INT_ADD a b) }\n\tdefine Int:a - Int:b { return (INT_SUB a b) }\n\tdefine if Bool:test then Block:tv else Block:fv { ... }\n\n\tdefine fib Int:n {\n\t\tif n \u003c 2 then { return 1 } else { return fib (n - 1) + fib (n - 2) }\n\t}\n\nIt has a very simple tokenisation stage: it separates out newlines, whitespace, individual punctuation characters, and strings of digits; anything that's left tokenises as a WORD.\n\nI use a sophisticated Earley parser; this allows me to be flexible and extend the grammar during parsing.\n\nWhen a variable declaration is encountered, eg:\n```\n\tlet x = 42\n```\nthe parser adds a new production `Int -\u003e x` to the grammar.\n\nBlocks `{ }` have their own scope. When we enter a block, we save the current grammar onto a stack; upon exiting the block we pop its rules. In this way the parser gives us lexical scope and variable shadowing for free.\n\nFunctions are defined not with *names*, but with a list of *symbols*. (This gets converted into a CFG rule.) eg:\n```\n    define fib Int:n { ... }\n```\n\nThe function `fib _` has one argument slot, named `n`, of type `Int`.\n\nUpon entering the function's body, the parser pushes its arguments onto the stack; like we did variables.\n\nAfter parsing the entire body, the function is type-checked, and a new rule added to the grammar; in this case `Int -\u003e 'fib' Int`.\n\nIn this way, the parser builds up a Scheme-like AST for the whole program file.\n\nJust like Scheme, we could support macros which are evaluated at compile-time (after parse-time).\n\nTo make all this manageable, we enforce an equivalence between non-terminals (in the CFG) and types (in the language's type system). So the LHS of a production is always its type: Int/Bool/Text/whatever. There are special types for Line and Block and Program.\n\nThis is done to help resolve ambiguity; there's no point accepting parses that won't type-check, when there are other parses that will.\n\nAlthough moving type-checking into the parser may turn out to be horrible to use in practice!\n\nThe other tool for resolving ambiguity is ordered choice; if two different productions result in the same non-terminal, the one defined most recently always wins. (This is why shadowing works.)\n\nThere's some extra magic to handle parametric types/rules — eg `T -\u003e if Bool then T else T`, or `List T -\u003e T ',' T` [Except for left-recursive parametrics, eg. T -\u003e T, which turns out to be iffy.]\n\nThis is all then compiled to bytecode for a custom VM. My plan is for the \"core\" language to just define rules for emitting the bytecodes; defining labels \u0026 jumps; and handling functions and name bindings; and then everything else can be implemented in the language itself, including control flow and all the built-in syntax.\n\nThe idea, after all, was to do away with DSLs! I imagine there would be standard \"preambles\" which define a nice language to work with. Maybe even specialised ones for different\ndomains (science, math)?\n\nI've omitted a few details (eg. upvars, optional whitespace), but this overview is too long as it is!\n\nThere are a range of fun extensions to the language and/or compiler: I could add an optimising compiler to the VM, and do flow analysis/SSA. Implementing closures properly could be fun. And the language would rather benefit from unevaluated argument types: `define while (Uneval Bool):test do Block:body`?\n\n\n\nInstall\n-------\n\n**Ubuntu**: you'll need the following before `make` will work (of course, you might have\nthem already):\n\n    sudo apt-get install build-essential git unzip python\n\nFor making the JIT (`make nfsj`), you'll need to run:\n\n    sudo apt-get install libffi-dev pkg-config\n\n\u003cs\u003eInstalling `pypy` is recommended (builds might be faster).\u003c/s\u003e\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftjvr%2Fnefarious","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftjvr%2Fnefarious","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftjvr%2Fnefarious/lists"}