{"id":20007118,"url":"https://github.com/valkmjolnir/nasal-interpreter","last_synced_at":"2025-05-04T18:33:42.675Z","repository":{"id":39381783,"uuid":"198687231","full_name":"ValKmjolnir/Nasal-Interpreter","owner":"ValKmjolnir","description":"Modern efficient runtime for Nasal: using stack-based direct-threading virtual machine.","archived":false,"fork":false,"pushed_at":"2024-04-11T16:10:56.000Z","size":9532,"stargazers_count":49,"open_issues_count":0,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-04-14T15:34:21.958Z","etag":null,"topics":["bytecode-interpreter","compiler-principles","flightgear","interpreter","language","linux","macos","nasal","programming-language","script-language","scripting-language","windows"],"latest_commit_sha":null,"homepage":"https://www.fgprc.org.cn/nasal_interpreter.html","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ValKmjolnir.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}},"created_at":"2019-07-24T18:11:58.000Z","updated_at":"2024-04-15T17:30:51.843Z","dependencies_parsed_at":"2023-12-24T09:24:37.729Z","dependency_job_id":"c220bf19-a554-4611-9728-a86f34330083","html_url":"https://github.com/ValKmjolnir/Nasal-Interpreter","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ValKmjolnir%2FNasal-Interpreter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ValKmjolnir%2FNasal-Interpreter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ValKmjolnir%2FNasal-Interpreter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ValKmjolnir%2FNasal-Interpreter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ValKmjolnir","download_url":"https://codeload.github.com/ValKmjolnir/Nasal-Interpreter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252382727,"owners_count":21739209,"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":["bytecode-interpreter","compiler-principles","flightgear","interpreter","language","linux","macos","nasal","programming-language","script-language","scripting-language","windows"],"created_at":"2024-11-13T06:14:45.909Z","updated_at":"2025-05-04T18:33:42.651Z","avatar_url":"https://github.com/ValKmjolnir.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# \u003cimg src=\"./doc/svg/nasal_transparent.svg\" height=\"40px\"/\u003e __Nasal - Modern Interpreter__\n\n\u003cimg src=\"./doc/pic/header.png\" style=\"width:600px\"\u003e\u003c/img\u003e\n\n![GitHub release(latest by date)](https://img.shields.io/github/v/release/ValKmjolnir/Nasal-Interpreter?style=flat-square\u0026logo=github)\n[![license](https://img.shields.io/badge/license-GPLv2-green?style=flat-square\u0026logo=github)](./LICENSE)\n![downloads](https://img.shields.io/github/downloads/ValKmjolnir/Nasal-Interpreter/total.svg?style=flat-square\u0026logo=github)\n[![C/C++ CI](https://github.com/ValKmjolnir/Nasal-Interpreter/actions/workflows/c-cpp.yml/badge.svg)](https://github.com/ValKmjolnir/Nasal-Interpreter/actions/workflows/c-cpp.yml)\n[![Test CI](https://github.com/ValKmjolnir/Nasal-Interpreter/actions/workflows/test.yml/badge.svg)](https://github.com/ValKmjolnir/Nasal-Interpreter/actions/workflows/test.yml)\n\n\u003e This document is also available in: [__中文__](./doc/README_zh.md) | [__English__](./README.md)\n\n## __Contents__\n\n* [__Introduction__](#introduction)\n* [__Download__](#download)\n* [__Compile__](#compile)\n* [__Usage__](#how-to-use)\n* [__Tutorial__](./doc/tutorial.md)\n* [__Release Notes__](./doc/dev.md#release-notes)\n* [__Development History__](./doc/dev.md)\n* [__Benchmark__](./doc/benchmark.md)\n* [__Difference__](#difference-between-andys-and-this-interpreter)\n* [__Trace Back Info__](#trace-back-info)\n* [__Debugger__](#debugger)\n* [__REPL__](#repl)\n* [__Web Interface__](#web-interface)\n\n__Contact us if having great ideas to share!__\n\n* __lhk101lhk101@qq.com__ (ValKmjolnir)\n\n* __sidi.liang@gmail.com__ (Sidi)\n\n## __Introduction__\n\n![star](https://img.shields.io/github/stars/ValKmjolnir/Nasal-Interpreter?style=flat-square\u0026logo=github)\n![fork](https://img.shields.io/github/forks/ValKmjolnir/Nasal-Interpreter?style=flat-square\u0026logo=github)\n![issue](https://img.shields.io/github/issues/ValKmjolnir/Nasal-Interpreter?style=flat-square\u0026logo=github)\n![pr](https://img.shields.io/github/issues-pr/ValKmjolnir/Nasal-Interpreter?style=flat-square\u0026logo=github)\n\n[Nasal](http://wiki.flightgear.org/Nasal_scripting_language)\nis an ECMAscript-like language used in [FlightGear](https://www.flightgear.org/).\nThe designer is [Andy Ross](https://github.com/andyross).\nThis interpreter is rewritten by [ValKmjolnir](https://github.com/ValKmjolnir) using `C++`(`-std=c++17`).\nWe really appreciate that Andy created this amazing programming language: [Andy Ross's nasal interpreter](https://github.com/andyross/nasal).\n\nOld version of this project uses __MIT license__ (2019/7 ~ 2021/5/4 ~ 2023/5). Now it uses __GPL v2 license__ (since 2023/6).\n\n### __Why writing this Nasal interpreter?__\n\n2019 summer,\nmembers in [FGPRC](https://www.fgprc.org/) told me that it is hard to debug with nasal-console in Flightgear,\nespecially when checking syntax errors.\nSo i wrote a new interpreter to help checking syntax error and runtime error.\n\nI wrote the lexer, parser and\nbytecode virtual machine to help checking errors.\nWe found it much easier to debug.\n\nYou could also use this language to write some\ninteresting programs and run them without the lib of Flightgear.\nYou could add your own modules to make\nthe interpreter a useful tool in your own projects.\n\n## __Download__\n\nNightly build could be found here.\nWindows nightly build is not supported yet,\nplease wait or just compile it by yourself, a Cmake file is given for Visual Studio to compile this project easily:\n\n* [MacOS-nightly-build](https://github.com/ValKmjolnir/Nasal-Interpreter/releases/tag/next_macOS)\n* [Linux-nightly-build](https://github.com/ValKmjolnir/Nasal-Interpreter/releases/tag/next_linux_x86_64)\n* [Windows-nightly-build](#download) [WIP]\n\n## __Compile__\n\n![g++](https://img.shields.io/badge/GNU-g++-A42E2B?style=flat-square\u0026logo=GNU) ![clang++](https://img.shields.io/badge/LLVM-clang++-262D3A?style=flat-square\u0026logo=LLVM) ![vs](https://img.shields.io/badge/Visual_Studio-MSVC-5C2D91?style=flat-square\u0026logo=visualstudio)\n\nDownload the latest source of the interpreter and build it! It's quite easy to build, what you need are only two things: C++ compiler and the `make`. There is no third-party library used in this project.\n\n### __Windows (MinGW-w64)__\n\nMake sure thread model is `posix thread model`, otherwise no thread library exists.\n\n\u003e mkdir build;\n\u003e mingw32-make nasal.exe -j4\n\n### __Windows (Visual Studio)__\n\nThere is a [__CMakelists.txt__](./CMakeLists.txt) to create project. Recently we find how to build it with command line tools: [__Build Nasal-Interpreter on Windows__](./doc/windows-build.md).\n\n### __Linux / macOS / Unix__\n\n![linux](https://img.shields.io/badge/GNU-Linux-green?style=flat-square\u0026logo=GNU) ![macOS](https://img.shields.io/badge/Apple%20Inc.-MacOS-green?style=flat-square\u0026logo=apple)\n\n\u003e make -j\n\nYou could choose which compiler you want to use:\n\n\u003e make nasal CXX=... -j\n\n## __How to Use__\n\n![usage](./doc/gif/help.gif)\n\nIf your system is `Windows` and you want to output unicode, you could write this in nasal code:\n\n```javascript\nif (os.platform()==\"windows\") {\n    system(\"chcp 65001\");\n}\n```\n\nOr use `std.runtime.windows.set_utf8_output()`:\n\n```javascript\nuse std.runtime;\n\nruntime.windows.set_utf8_output();\n```\n\n## __Difference Between Andy's and This Interpreter__\n\n![error](./doc/gif/error.gif)\n\n\u003cdetails\u003e\u003csummary\u003eMust use `var` to define variables\u003c/summary\u003e\n\nThis interpreter uses more strict syntax to make sure it is easier for you to program and debug.\nAnd flightgear's nasal interpreter also has the same rule.\nSo do not use variable without using `var` to declare it.\n\nIn Andy's interpreter:\n\n```javascript\nforeach(i; [0, 1, 2, 3])\n    print(i)\n```\n\nThis program can run normally.\nBut take a look at the iterator `i`,\nit is defined in foreach without using keyword `var`.\nI think this design will make programmers feeling confused that they maybe hard to find the `i` is defined here.\nWithout `var`, they may think this `i` is defined anywhere else.\n\nSo in this interpreter i use a more strict syntax to force users to use `var` to define iterator of forindex and foreach.\nIf you forget to add the keyword `var`, you will get this:\n\n```javascript\ncode: undefined symbol \"i\"\n --\u003e test.nas:1:9\n  |\n1 | foreach(i; [0, 1, 2, 3])\n  |         ^ undefined symbol \"i\"\n\ncode: undefined symbol \"i\"\n --\u003e test.nas:2:11\n  |\n2 |     print(i)\n  |           ^ undefined symbol \"i\"\n```\n\n\u003c/details\u003e\n\n## __Trace Back Info__\n\n![stackoverflow](./doc/gif/stackoverflow.gif)\n\nWhen interpreter crashes,\nit will print trace back information:\n\n\u003cdetails\u003e\u003csummary\u003eNative function `die`\u003c/summary\u003e\n\nFunction `die` is used to throw error and crash immediately.\n\n```javascript\nfunc() {\n    println(\"hello\");\n    die(\"error occurred this line\");\n    return;\n}();\n```\n\n```javascript\nhello\n[vm] error: error occurred this line\n[vm] error: error occurred in native function\n\ncall trace (main)\n  call func@0x557513935710() {entry: 0x850}\n\ntrace back (main)\n  0x000547     4c 00 00 16     callb   0x16 \u003c__die@0x557512441780\u003e(std/lib.nas:150)\n  0x000856     4a 00 00 01     callfv  0x1(a.nas:3)\n  0x00085a     4a 00 00 00     callfv  0x0(a.nas:5)\n\nstack (0x5575138e8c40, limit 10, total 14)\n  0x00000d    | null |\n  0x00000c    | pc   | 0x856\n  0x00000b    | addr | 0x5575138e8c50\n  0x00000a    | nil  |\n  0x000009    | nil  |\n  0x000008    | str  | \u003c0x5575138d9190\u003e error occurred t...\n  0x000007    | nil  |\n  0x000006    | func | \u003c0x5575139356f0\u003e entry:0x850\n  0x000005    | pc   | 0x85a\n  0x000004    | addr | 0x0\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eStack overflow\u003c/summary\u003e\n\nHere is an example of stack overflow:\n\n```javascript\nfunc(f) {\n    return f(f);\n}(\n    func(f) {\n        f(f);\n    }\n)();\n```\n\n```javascript\n[vm] error: stack overflow\n\ncall trace (main)\n  call func@0x564106058620(f) {entry: 0x859}\n   --\u003e 583 same call(s)\n  call func@0x5641060586c0(f) {entry: 0x851}\n\ntrace back (main)\n  0x000859     45 00 00 01     calll   0x1(a.nas:5)\n  0x00085b     4a 00 00 01     callfv  0x1(a.nas:5)\n  0x00085b     582 same call(s)\n  0x000853     4a 00 00 01     callfv  0x1(a.nas:2)\n  0x00085f     4a 00 00 01     callfv  0x1(a.nas:3)\n\nstack (0x56410600be00, limit 10, total 4096)\n  0x000fff    | func | \u003c0x564106058600\u003e entry:0x859\n  0x000ffe    | pc   | 0x85b\n  0x000ffd    | addr | 0x56410601bd20\n  0x000ffc    | nil  |\n  0x000ffb    | nil  |\n  0x000ffa    | func | \u003c0x564106058600\u003e entry:0x859\n  0x000ff9    | nil  |\n  0x000ff8    | func | \u003c0x564106058600\u003e entry:0x859\n  0x000ff7    | pc   | 0x85b\n  0x000ff6    | addr | 0x56410601bcb0\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eNormal vm error crash info\u003c/summary\u003e\n\nError will be thrown if there's a fatal error when executing:\n\n```javascript\nfunc() {\n    return 0;\n}()[1];\n```\n\n```javascript\n[vm] error: must call a vector/hash/string but get number\n\ntrace back (main)\n  0x000854     47 00 00 00     callv   0x0(a.nas:3)\n\nstack (0x564993f462b0, limit 10, total 1)\n  0x000000    | num  | 0\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eDetailed crash info\u003c/summary\u003e\n\nUse command __`-d`__ or __`--detail`__ the trace back info will show more details:\n\n```javascript\nhello\n[vm] error: error occurred this line\n[vm] error: error occurred in native function\n\ncall trace (main)\n  call func@0x55dcb5b8fbf0() {entry: 0x850}\n\ntrace back (main)\n  0x000547     4c 00 00 16     callb   0x16 \u003c__die@0x55dcb3c41780\u003e(std/lib.nas:150)\n  0x000856     4a 00 00 01     callfv  0x1(a.nas:3)\n  0x00085a     4a 00 00 00     callfv  0x0(a.nas:5)\n\nstack (0x55dcb5b43120, limit 10, total 14)\n  0x00000d    | null |\n  0x00000c    | pc   | 0x856\n  0x00000b    | addr | 0x55dcb5b43130\n  0x00000a    | nil  |\n  0x000009    | nil  |\n  0x000008    | str  | \u003c0x55dcb5b33670\u003e error occurred t...\n  0x000007    | nil  |\n  0x000006    | func | \u003c0x55dcb5b8fbd0\u003e entry:0x850\n  0x000005    | pc   | 0x85a\n  0x000004    | addr | 0x0\n\nregisters (main)\n  [pc    ]    | pc   | 0x547\n  [global]    | addr | 0x55dcb5b53130\n  [local ]    | addr | 0x55dcb5b43190\n  [memr  ]    | addr | 0x0\n  [canary]    | addr | 0x55dcb5b53110\n  [top   ]    | addr | 0x55dcb5b431f0\n  [funcr ]    | func | \u003c0x55dcb5b65620\u003e entry:0x547\n  [upval ]    | nil  |\n\nglobal (0x55dcb5b53130)\n  0x000000    | nmspc| \u003c0x55dcb5b33780\u003e namespace [95 val]\n  0x000001    | vec  | \u003c0x55dcb5b64c20\u003e [0 val]\n  ...\n  0x00005e    | func | \u003c0x55dcb5b8fc70\u003e entry:0x846\n\nlocal (0x55dcb5b43190 \u003c+7\u003e)\n  0x000000    | nil  |\n  0x000001    | str  | \u003c0x55dcb5b33670\u003e error occurred t...\n  0x000002    | nil  |\n```\n\n\u003c/details\u003e\n\n## __Debugger__\n\n![dbg](./doc/gif/dbg.gif)\n\nWe added a debugger in `v8.0`.\nUse command `./nasal -dbg xxx.nas` to use the debugger,\nand the debugger will print this:\n\n\u003cdetails\u003e\u003csummary\u003eClick to unfold\u003c/summary\u003e\n\n```javascript\nsource code:\n--\u003e var fib = func(x) {\n        if (x\u003c2) return x;\n        return fib(x-1)+fib(x-2);\n    }\n    for(var i=0;i\u003c31;i+=1)\n        print(fib(i),'\\n');\n\n\nnext bytecode:\n    0x0003a8    07:00 00 00 00 00 00 00 00     pnil    0x0 (std/lib.nas:413)\n    0x0003a9    56:00 00 00 00 00 00 00 00     ret     0x0 (std/lib.nas:413)\n    0x0003aa    03:00 00 00 00 00 00 00 56     loadg   0x56 (std/lib.nas:413)\n--\u003e 0x0003ab    0b:00 00 00 00 00 00 03 af     newf    0x3af (test/fib.nas:1)\n    0x0003ac    02:00 00 00 00 00 00 00 03     intl    0x3 (test/fib.nas:1)\n    0x0003ad    0d:00 00 00 00 00 00 00 22     para    0x22 (x) (test/fib.nas:1)\n    0x0003ae    3e:00 00 00 00 00 00 03 be     jmp     0x3be (test/fib.nas:1)\n    0x0003af    45:00 00 00 00 00 00 00 01     calll   0x1 (test/fib.nas:2)\n\nvm stack (0x7fca7e9f1010, limit 16, total 0)\n\u003e\u003e\n```\n\n\u003c/details\u003e\n\nIf want help, input `h` to get help.\n\nWhen running the debugger, you could see what is on stack.\nThis will help you debugging or learning how the vm works:\n\n\u003cdetails\u003e\u003csummary\u003eClick to unfold\u003c/summary\u003e\n\n```javascript\nsource code:\n    var fib = func(x) {\n--\u003e     if (x\u003c2) return x;\n        return fib(x-1)+fib(x-2);\n    }\n    for(var i=0;i\u003c31;i+=1)\n        print(fib(i),'\\n');\n\n\nnext bytecode:\n    0x0003a8    07:00 00 00 00 00 00 00 00     pnil    0x0 (std/lib.nas:413)\n    0x0003a9    56:00 00 00 00 00 00 00 00     ret     0x0 (std/lib.nas:413)\n    0x0003aa    03:00 00 00 00 00 00 00 56     loadg   0x56 (std/lib.nas:413)\n    0x0003ab    0b:00 00 00 00 00 00 03 af     newf    0x3af (test/fib.nas:1)\n    0x0003ac    02:00 00 00 00 00 00 00 03     intl    0x3 (test/fib.nas:1)\n    0x0003ad    0d:00 00 00 00 00 00 00 22     para    0x22 (x) (test/fib.nas:1)\n    0x0003ae    3e:00 00 00 00 00 00 03 be     jmp     0x3be (test/fib.nas:1)\n--\u003e 0x0003af    45:00 00 00 00 00 00 00 01     calll   0x1 (test/fib.nas:2)\n\nvm stack (0x7fca7e9f1010, limit 16, total 8)\n  0x000007    | pc   | 0x3c7\n  0x000006    | addr | 0x0\n  0x000005    | nil  |\n  0x000004    | nil  |\n  0x000003    | num  | 0\n  0x000002    | nil  |\n  0x000001    | nil  |\n  0x000000    | func | \u003c0x5573f66ef5f0\u003e func(elems...) {..}\n\u003e\u003e\n```\n\n\u003c/details\u003e\n\n## REPL\n\nWe added experimental repl interpreter in v11.0.\nUse this command to use the repl interpreter:\n\n\u003e nasal -r\n\nThen enjoy!\n\n```bash\n[nasal-repl] Initializating enviroment...\n[nasal-repl] Initialization complete.\n\nNasal REPL interpreter version 11.0 (Oct  7 2023 17:28:31)\n.h, .help   | show help\n.e, .exit   | quit the REPL\n.q, .quit   | quit the REPL\n.c, .clear  | clear the screen\n.s, .source | show source code\n\n\u003e\u003e\u003e\n```\n\nTry import `std/json.nas`~\n\n```bash\n[nasal-repl] Initializating enviroment...\n[nasal-repl] Initialization complete.\n\nNasal REPL interpreter version 11.1 (Nov  1 2023 23:37:30)\n.h, .help   | show help\n.e, .exit   | quit the REPL\n.q, .quit   | quit the REPL\n.c, .clear  | clear the screen\n.s, .source | show source code\n\n\u003e\u003e\u003e use std.json;\n{stringify:func(..) {..},parse:func(..) {..}}\n\n\u003e\u003e\u003e\n```\n\n## __Web Interface__\n\nA web-based interface is now available for trying out Nasal code directly in your browser. It includes both a code editor and an interactive REPL (WIP).\n\n### Web Code Editor\n- Syntax highlighting using CodeMirror\n- Error highlighting and formatting\n- Example programs\n- Execution time display option\n- Configurable execution time limits\n- Notice: The security of the online interpreter is not well tested, please use it with sandbox mechanism or other security measures.\n\n### Web REPL\n- ** IMPORTANT: The time limit in REPL is not correctly implemented yet. Thus this REPL web binding is not considered finished. Do not use it in production before it's fixed. **\n- Interactive command-line style interface in browser\n- Multi-line input support with proper prompts (`\u003e\u003e\u003e` and `...`)\n- Command history navigation\n- Error handling with formatted error messages\n- Example snippets for quick testing\n\n### Running the Web Interface\n\n1. Build the Nasal shared library:\n```bash\ncmake -DBUILD_SHARED_LIBS=ON .\nmake nasal-web\n```\n\n2. Set up and run the web application:\n\nFor the code editor:\n```bash\ncd nasal-web-app\nnpm install\nnode server.js\n```\nVisit `http://127.0.0.1:3000/`\n\nFor the REPL:\n```bash\ncd nasal-web-app\nnpm install\nnode server_repl.js\n```\nVisit `http://127.0.0.1:3001/repl.html`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvalkmjolnir%2Fnasal-interpreter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvalkmjolnir%2Fnasal-interpreter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvalkmjolnir%2Fnasal-interpreter/lists"}