{"id":16674154,"url":"https://github.com/gravatalonga/ninja","last_synced_at":"2025-10-11T07:37:33.288Z","repository":{"id":37263660,"uuid":"504090331","full_name":"gravataLonga/ninja","owner":"gravataLonga","description":"Ninja Programming Language - General Scripting Language inspired in PHP and Javascript. ","archived":false,"fork":false,"pushed_at":"2023-08-11T20:07:57.000Z","size":55414,"stargazers_count":3,"open_issues_count":12,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-23T22:12:18.407Z","etag":null,"topics":["golang","pratt-parser","programming-language"],"latest_commit_sha":null,"homepage":"https://ninja.jonathan.pt","language":"Go","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/gravataLonga.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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},"funding":{"github":["gravataLonga"]}},"created_at":"2022-06-16T09:19:53.000Z","updated_at":"2024-08-01T09:48:38.000Z","dependencies_parsed_at":"2024-06-19T16:22:26.213Z","dependency_job_id":"7d39e831-df2d-43b2-aebe-b78d55f59791","html_url":"https://github.com/gravataLonga/ninja","commit_stats":null,"previous_names":[],"tags_count":39,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gravataLonga%2Fninja","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gravataLonga%2Fninja/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gravataLonga%2Fninja/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gravataLonga%2Fninja/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gravataLonga","download_url":"https://codeload.github.com/gravataLonga/ninja/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248104101,"owners_count":21048282,"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":["golang","pratt-parser","programming-language"],"created_at":"2024-10-12T12:29:28.444Z","updated_at":"2025-10-11T07:37:28.247Z","avatar_url":"https://github.com/gravataLonga.png","language":"Go","funding_links":["https://github.com/sponsors/gravataLonga"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\n![ninja programming language](./ninja.svg)\n\n\u003c/p\u003e\n\n[![Testing](https://github.com/gravataLonga/ninja/actions/workflows/main.yml/badge.svg)](https://github.com/gravataLonga/ninja/actions/workflows/main.yml)  \n\n# Install  \n\n## Homebrew  \n\n```sh\nbrew tap gravatalonga/ninja-lang\nbrew install ninja-lang\n```  \n\n## YUM / RPM  \n\nTo enable, add the following file `/etc/yum.repos.d/ninja.repo`:\n\n```sh\n[ninja]\nname=Ninja Programming Language\nbaseurl=https://yum.fury.io/gravatalonga/\nenabled=1\ngpgcheck=0\n```  \n\nCheck if correctly created  \n\n```\nyum --disablerepo=* --enablerepo=ninja list available\n```  \n\nTo install you only need run following command:  \n\n```\nyum install ninja-lang  \n```  \n\n## APT    \n\nTo configure apt access, create a following file `/etc/apt/sources.list.d/ninja.list` with content of :  \n\n```  \ndeb [trusted=yes] https://apt.fury.io/gravatalonga/ /\n```  \n\nOr use this one line command:  \n\n```\necho \"deb [trusted=yes] https://apt.fury.io/gravatalonga/ /\" \u003e /etc/apt/sources.list.d/ninja.list\n```  \n\nand them you can install  \n\n```\nsudo apt install ninja-lang\n```\n\n## Manual Download    \n\nDownload from [github](https://github.com/gravataLonga/ninja/releases)  \n\n## Manual Installation  \n\n```sh  \ngit clone https://github.com/gravataLonga/ninja\ncd ninja\ngo build -o ninja-lang\n```  \n\n# Documentation  \n\nFor more detail about language, you can check [here](https://ninja.jonathan.pt) (Still working in progress).  \n\n# Demo  \n\nResolved [katas](https://github.com/gravataLonga/ninja-lang-katas) from this [website](https://adventofcode.com/2015)  \n\n# Syntax  \n\n## Variable  \n\n`var \u003cidentifier\u003e = \u003cexpression\u003e;`  \n\nExamples  \n\n```\nvar a = 1;\nvar a1 = \"Name\";\nvar b = 2.0;\nvar c = a + 1;\nvar d = a + b;\nvar e = ++a;\nvar f = function () {};\nvar g = [1, 2, 3, \"hello\", function() {}];\nvar h = {\"me\":\"Jonathan Fontes\",\"age\":1,\"likes\":[\"php\",\"golang\",\"ninja\"]}\nvar i = a \u003c b;\nvar j = true;\nvar k = !j;\nvar l = if (a) { \"yes\" } else { \"no\" };  \n\ng[0] = 10;\ng[4] = \"new value\"; // it will append to array.  \nh[\"other\"] = true;\n\"ola\"[0] // print o  \n```  \n\nIt's possible to reassign variable for example:  \n\n```\nvar a = 1;\na = a + 1;  \nputs(a);  \n```\n\n## Data Types Availables  \n\n```\n /**\n  * Booleans\n  */\n \n true;\n false;\n\n /**\n  * Integer\n  */\n \n 1;\n 20000;\n \n /**\n  * Floats\n  */\n  \n 100.20;\n 5.20;\n \n /**\n  * Scientific Notation  \n  */\n  \n  1e3;\n  2e-3;\n  \n  /**\n   * Hexadecimal Number  \n   */ \n  \n  0x00F\n  0xf\n  0x10C\n  \n /**\n  * Strings\n  */\n   \n \"hello\"\n \"\\u006E\\u0069\\u006E\\u006A\\u0061\" // ninja in unicode chars  \n \"\\n\\r\\t\\b\\f\" // special caracters is also supported\n   \n /**\n  * Array\n  */\n    \n [1, \"a\", true, function() {}]\n    \n /**\n  * Hash    \n  */\n     \n {\"key\":\"value\",\"arr\":[],\"other\":{}}  \n \n /**\n  * Functions  \n  */\n  \n  function () {}()\n  var a = function () {}; a();\n  function a() { }; a();\n  function (a) { return function() { return a; }}(10)();  \n  function (a, b = 1) { return a + b; };  \n  \n  \n    \n```  \n\n## Comments  \n\n`// \u003c...\u003e` or `/* \u003c...\u003e */`  \n\nComments can start with double slash `//` ou multiple lines with `\\* *\\`  \n\n## Functions  \n\n`var \u003cidentifier\u003e = function (\u003cidentifierarguments\u003e?) { \u003cstatements\u003e }`  \n`function \u003cidentifier\u003e (\u003cidentifierarguments\u003e?) { \u003cstatements\u003e }`\n\nFunctions is where power of language reside, it's a first-citizen function, which mean it can accept function as arguments\nor returning function. We got two ways declaring functions, literal or block.  \n\n```\nfunction say(name) {\n    puts(\"Hello: \" + name);\n}\n```\n\nOr  \n\n```\nvar say = function(name) {\n    puts(\"Hello: \" + name);\n}\n```  \n\nThey are exactly same, but this is illegal:  \n\n```\nvar say = function say(name) {\n    puts(\"Hello: \" + name);  \n}\n```  \n\nWe also could declare default values for parameters  \n\n```\nfunction add (a, b = 20) {\n    return a + b;\n}\n\nadd(10);\nadd(10, 30);\n```\n\n### Builtin Functions  \nThere are several builtin functions that you can use:  \n\n1. **puts** - print at console  \n2. **len** - get length of object  \n3. **first** - get first item of array  \n4. **last** - get last item of array  \n5. **rest** - get items after first one  \n6. **push** - add item to array  \n7. **exit** - exit program  \n8. **args** - get arguments passed to ninja programs  \n9. **rand** - get random number from 0 to 1 float point  \n10. **time** - return Unix time, the number of seconds elapsed  \n\n```\nvar a = [1, 2, 3, 4];\nputs(len(a)); // print 4\n\nputs(len(\"Hello!\")); // print 5  \n```\n\n```\nvar a = [1, 2, 3, 4];\nputs(first(a)); // print 1\n```\n\n```\nputs(\"Hello World\"); // print in screen  \n```\n\n```\nvar a = [1, 2, 3, 4];\nputs(last(a)); // print 4\n```  \n\n```\nvar a = [1, 2, 3, 4];\nputs(rest(a)); // print [2, 3, 4]; (all but not first)  \n```\n\n```\nvar a = [1, 2, 3, 4];\nputs(push(a, 5)); // print [1, 2, 3, 4, 5];\n```\n\n## Import  \n\nYou can import another ninja files, it will act like `require file.php` in php language.  \n\n```\nimport \"testing.ninja\";  \nvar lib = import \"mylib.ninja\"; // return function() {};  \n```  \n\n## Operators \u0026\u0026 Logics Operators  \n\n`\u003cexpression\u003e \u003coperator\u003e \u003cexpression\u003e`  \n\nLogic's Operators  \n```\n10 \u003c 10;    // FALSE\n10 \u003e 10;    // FALSE\n10 == 10;   // TRUE\n10 != 10;   // FALSE\n10 \u003c= 10;   // TRUE\n10 \u003e= 10;   // TRUE\n10 \u0026\u0026 10;   // TRUE\n10 || 10;   // TRUE\n!10;        // FALSE\n!!10;       // TRUE  \n\n```  \n\n\u003e **Note**: a value is considered truthy when a value is not nil or not false.  \n\n`\u003cexpression\u003e? \u003coperator\u003e \u003cexpression\u003e`  \nArithmetics Operators  \n\n```  \n1 + 1;      // SUM\n1 - 1;      // SUBTRACT\n1 / 1;      // DIVIDER\n1 * 1;      // MULTIPLE\n4 % 2;      // MOD\n10 ** 0;    // POW\n10 \u0026 2;     // AND Bitwise operator\n10 | 2;     // OR Bitwise operator \n10 ^ 2;     // XOR Bitwise operator \n10 \u003c\u003c 2;    // Shift left (multiply each step)\n10 \u003e\u003e 2;    // Shift right (divide each step)\n++1;        // First increment and then return incremented value  \n--1;        // First decrement and then return decremented value  \n1++;        // First return value and then increment value\n1--;        // First return value and then decrement value  \n```  \n\n## Data Structures  \n\n### Array  \n\n`var \u003cidentifier\u003e = [\u003cexpressions\u003e...]`  \n\n```\nvar a = [1 + 1, 2, 4, function() {}, [\"a\", \"b\"]];  \n```  \n\n\n#### Delete index\n\n```\ndelete a[0];  \n```  \n\nIt will keep the order  \n\n#### Add Key\n\n```\na[5] = \"hello\";  \npush(a, \"anotherKey\"); \n\n// push by empty braces\na[] = 6;  \n```  \n\n\n\n### Hash  \n\n`var \u003cidentifier\u003e = {\u003cexpression\u003e:\u003cexpression\u003e,....}`\n\n```\nvar a = {\"key\":\"hello\",\"key\" + \"key\":\"hello2\", \"other\":[\"nice\", \"other\"], 2: true};  \n```  \n\n#### Delete Key    \n\n```\ndelete a[\"key\"];\n```  \n\n#### Add Key  \n\n```\na[\"testing\"] = \"hello\";  \n```  \n\n### Enum  \n\n```\nenum STATUS {\n    case OK: true;\n    case NOK: false;\n}\n\nenum RESPONSE {\n    case OK: 200;\n    case NOT_FOUND: 404;\n    case ERR_MSG: \"There are some errors\"\n    case TIME: 32.2 + 43.3;\n    case TEST: if (true) { 0 } else { 1 };\n}\n```  \n\n\nthen you can use his values:  \n\n```\nputs(STATUS::OK);  \n```\n\n## Conditions  \n\n\n### If / ElseIf / Else \n`if (\u003ccondition\u003e) { \u003cconsequence\u003e } elseif (\u003ccondition1\u003e) { \u003cconsequence1\u003e } else { \u003calternative\u003e }`  \n\n#### Simple If Condition  \n```  \nif (true) {\n    puts(\"Hello\");\n}\n```  \n\n#### If / Else \n\n```  \nif (true) {\n    puts(\"Hello\");\n} else {\n    puts(\"Nope\");\n}\n```   \n\n#### If / ElseIf / Else   \n\n```  \nif (true) {\n    puts(\"Hello\");\n} elseif (1 \u003e 2) {\n    puts(\"1 is greater than 2\");\n} else {\n    puts(\"Nope\");\n}\n```   \n\nWe can omit else condition  \n\n```  \nif (true) {\n    puts(\"Hello\");\n} elseif (1 \u003e 2) {\n    puts(\"1 is greater than 2\");\n}\n\nif (true) {\n    puts(\"Hello\");\n}  \n```   \n\n### Ternary  \n\n`\u003ccondition\u003e ? \u003cconsequence\u003e : \u003calternative\u003e`  \n\n\n```\ntrue ? 10 : 20\n```  \n\n\n### Elvis Operator  \n\n`\u003cexpression\u003e ?: \u003cexpression\u003e`  \n\n```\nvar a = \"hello\";\nvar b = a ?: \"world\";  \n```  \n\n## Loop  \n\n`for (\u003cinitial\u003e?;\u003ccondition\u003e?;\u003citeration\u003e?) { \u003cstatements\u003e }`  \n\n\u003e **Note** initial, condition and iteration is optional, you can omit   \n\n```\nvar i = 0;\nfor(;i\u003c=3;++i) {\n    puts(i);\n}\n\nvar a = [1, 2, 3];\nfor(var i = 0; i \u003c= len(a)-1; ++i) {\n    puts(a[i]);\n}\n\nfor(var i = 0; i \u003c= len(a)-1; i = i + 1) {\n    puts(a[i]);\n}\n\nfor(;;) {\n    break;\n}\n```  \n\n# Object Call  \n\nWe support object call in any of data type.  \n\n## String  \n\nHere a full of list of support object call for string:  \n\n```\n\"hello\".type();                             // \"STRING\"\n\"hello\".length();                           // 5\n\"a,b,c\".split(\",\");                         // [\"a\", \"b\", \"c\"];\n\"hello world\".replace(\"world\", \"ninja\");    // \"hello ninja\"\n\"hello world\".contain(\"hello\");             // TRUE\n\"hello world\".index(\"Hello\");               // 0\n\"hello world\".upper();                      // \"HELLO WORLD\"\n\"HELLO WORLD\".lower();                      // \"hello world\"\n\" hello world \".trim();                     // \"hello world\"\n\"1\".int();                                  // 1\n\"1.1\".float();                              // 1.1 \n```  \n\n## Integer  \n\n```\n1.type();               // \"INTEGER\"\n1.string();             // \"1\"\n1.float();              // 1.0\nvar a = -1; a.abs();    // 1.0\n```  \n\n## Float  \n\n```\n1.0.type();             // \"FLOAT\"\n1.0.string();           // \"1.0\"  \nvar a = -1.0; a.abs();  // 1.0\n1.5.round();            // 2.0  \n```  \n\n## Boolean  \n\n```\ntrue.type();     // \"BOOLEAN\"  \n```  \n\n\n## Array   \n\n```\n[1, 2, 3].type();            // \"ARRAY\"\n[1, 2, 3].length();          // 3\n[1, 2, 3].joint(\",\");        // \"1,2,3\"\n[1, 2, 3].push(4);           // return null, but underlie value of array was change to [1, 2, 3, 4]  \n[1, 2, 3].pop();             // return 3 and underlie value of array was change to [1, 2] \n[1, 2, 3].shift();           // return 1 and underlie value of array was change to [2, 3]  \n[1, 2, 3].slice(1);          // copy array with following elements [2, 3] \n[1, 2, 3].slice(1, 1);       // copy array with following elements [2] \n```\n\n## Hash     \n\n```\n{\"a\":1,\"b\":2}.type();           // \"HASH\"\n{\"a\":1,\"b\":2}.keys();           // [\"a\", \"b\"];\n{\"a\":1,\"b\":2}.values();         // [1, 2];\n{\"a\":1,\"b\":2}.merge({\"c\":3});   // {\"a\":1,\"b\":2,\"c\":3}\n{\"a\":1,\"b\":2}.has(\"a\");         // true\n```  \n\n\u003e **Note:** Order of keys isn't preserved.  \n\n## Keywords  \n\n```\nvar true false function return if\nelse for import delete break enum case\n```  \n\n## Extending Ninja Programming Language  \n\nYou can extending ninja by creating a custom plugins, create an file for example:  \n\n```\npackage main\n\nimport . \"github.com/gravataLonga/ninja/object\"\n\nfunc Hello(args ...Object) Object {\n\treturn \u0026String{Value: \"Hello World!\"}\n}\n\nfunc main() {\n\tpanic(\"this is a plugin\")\n}\n\n```  \n\nThen, compile as plugin:   \n\n```\ngo build -buildmode=plugin -o hello.so hello.go  \n```  \n\nAfter this you can import and called it in your ninja programs, like so:\n\n```\nvar plugin = plugin(\"hello\"); // don't need \".so\" extension  \nputs(plugin.hello());  // it will print \"Hello World!\"  \n```  \n\n## Lexical Scooping  \n\n[Inspiration](https://craftinginterpreters.com/resolving-and-binding.html)  \n\n\u003e To “resolve” a variable usage, we only need to calculate how many “hops” away the declared variable will be in the \n\u003e environment chain. The interesting question is when to do this calculation—or, put differently, where in our \n\u003e interpreter’s implementation do we stuff the code for it?  \n\n## A variable resolution pass  \n\n\u003e After the parser produces the syntax tree, but before the interpreter starts executing it, we’ll do a single walk over \n\u003e the tree to resolve all of the variables it contains. Additional passes between parsing and execution are common. \n\u003e If \u003cname-of-programming-language\u003e had static types, we could slide a type checker in there. Optimizations are often implemented in separate \n\u003e passes like this too. Basically, any work that doesn't rely on state that’s only available at runtime can be done \n\u003e in this way.  \n\nWhen binding a variable we need to know how depth we are in rabbit hole.  \n\n## Examples  \n\n1. Check tests  \n2. Check resolved [katas](https://github.com/gravataLonga/ninja-lang-katas)  \n\n\n## Tests  \n\n```\ngo test -v -race ./...  \n```\n\n## Profiling \u0026\u0026 Performance\n\n### Where CPU resources spend more time\nCreate svg graph:  \n[interpreter result](https://github.com/google/pprof/blob/main/doc/README.md#interpreting-the-callgraph)\n```\ngo test -bench=. -cpuprofile cpu.prof  \ngo tool pprof -svg cpu.prof \u003e cpu.svg  \n```  \n\n### Cores\n\n```\ngo test -bench=. -trace trace.out  \ngo tool trace trace.out\n```  \n\n### Test Race Condition\n\n```  \ngo test -race\n```  \n\n# References  \n\n - Structure and Interpretation of Computer Programs, Second Edition  \n - Engineering a Compiler, Second Edi- tion. Morgan Kaufmann.  \n - Parsing Techniques. A Practical Guide.. Ellis Horwood Limited.  \n - Modern Compiler Design, Second Edition. Springer  \n - The Elements Of Computing Systems. MIT Press.  \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgravatalonga%2Fninja","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgravatalonga%2Fninja","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgravatalonga%2Fninja/lists"}