{"id":24178126,"url":"https://github.com/wixette/isb","last_synced_at":"2026-03-12T14:39:13.462Z","repository":{"id":45596318,"uuid":"339436987","full_name":"wixette/isb","owner":"wixette","description":"Interactive Small Basic (ISB) - Simple scripting language to be embedded in Unity games or shell environments.","archived":false,"fork":false,"pushed_at":"2023-01-30T07:08:28.000Z","size":4429,"stargazers_count":22,"open_issues_count":7,"forks_count":2,"subscribers_count":4,"default_branch":"main","last_synced_at":"2023-03-07T00:04:53.742Z","etag":null,"topics":["basic-lang","shell-scripting","unity-scripting"],"latest_commit_sha":null,"homepage":"https://www.nuget.org/packages/ISB/","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wixette.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}},"created_at":"2021-02-16T15:09:24.000Z","updated_at":"2023-01-30T08:03:58.000Z","dependencies_parsed_at":"2023-02-16T05:01:16.393Z","dependency_job_id":null,"html_url":"https://github.com/wixette/isb","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wixette%2Fisb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wixette%2Fisb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wixette%2Fisb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wixette%2Fisb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wixette","download_url":"https://codeload.github.com/wixette/isb/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233694810,"owners_count":18715506,"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":["basic-lang","shell-scripting","unity-scripting"],"created_at":"2025-01-13T04:45:28.866Z","updated_at":"2025-09-20T23:32:47.317Z","avatar_url":"https://github.com/wixette.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Interactive Small Basic (ISB)\n\n[Interactive Small Basic (ISB)](https://github.com/wixette/isb) is a simple\nscripting language derived from [Microsoft Small Basic](https://github.com/sb).\n\n## Background\n\nISB is a light-weight solution to mainly support the following scenarios:\n\n* As an in-game scripting language, to be embedded in Unity games.\n* As a shell scripting language, to provide a command-line interface where\n  simple code can be executed to control the host system.\n\nISB is implemented in C# as the original Microsoft Small Basic does.\n\n## ISB Programming Language\n\nMicrosoft maintains a [comprehensive introduction of Small\nBasic](https://smallbasic-publicwebsite.azurewebsites.net/tutorials/chapter1).\nIt's recommended to read it first if you are not familiar with at least one\nBASIC dialects.\n\nInteractive Small Basic (ISB) has a couple of language and API differences\ncompared with Microsoft Small Basic (MSB). I highlighted and described those\nfeatures and APIs in the [Quick Intro: ISB Programming\nLanguage](./isb_quick_intro.md) doc.\n\n## Build and Test\n\nBuild and test from source code:\n\n```shell\ncd csharp\n\ndotnet build\n\ndotnet test\n```\n\n## ISB Interactive Shell\n\nRun the interactive shell of ISB:\n\n```shell\n$ dotnet run -p ISB.Shell\nISB.Shell ...\nCopyright (C) ...\n\nType \"quit\" to exit, \"list\" to show the code, \"clear\" to clear the code, \"help\" to list available libraries.\n] print(\"Hello, World!\")\nHello, World!\n]\n] For i = 1 To 10\n\u003e   Print(Math.Log10(i))\n\u003e EndFor\n0\n0.301029995663981\n0.477121254719662\n0.602059991327962\n0.698970004336019\n0.778151250383644\n0.845098040014257\n0.903089986991944\n0.954242509439325\n1\n] quit\n$\n```\n\nThe shell can also be run as a command-line compiler and executor of ISB:\n\n```shell\n$ dotnet run -p ISB.Shell -- --help\nISB.Shell ...\nCopyright (C) ...\n\n  -i, --input      BASIC file (*.bas) to run/compile, or ISB assembly file (*.asm) to run. If not set, the interactive\n                   shell mode will start.\n\n  -c, --compile    Compile BASIC code to ISB assembly, without running it.\n\n  -o, --output     Output file path when --compile is set. If not set, the output assembly will be written to stdout.\n\n  --help           Display this help screen.\n\n  --version        Display version information.\n```\n\nFor example, print the fibonacci sequence with the sample code:\n\n```shell\ndotnet run -p ISB.Shell -- -i ../examples/fibonacci.bas\n```\n\n## Embed ISB in .Net Projects\n\nTo reference to the ISB DLL module from your .Net project, it's recommended to\nimport ISB via NuGet (Of course, you can also copy the source code or the\nDLL of ISB to your project manually).\n\nISB is released as a NuGet package at\n[https://www.nuget.org/packages/isb](https://www.nuget.org/packages/isb).\n\nIn your .Net project, add the NuGet package of ISB:\n\n```shell\ndotnet add package ISB\n```\n\nNow you are ready to create an instance of the ISB engine to compile and run\nBASIC code. For example, here is a C# program that runs ISB:\n\n```CSharp\nusing System.Collections.Generic;\nusing ISB.Runtime;\nusing ISB.Utilities;\n\nnamespace test\n{\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            var engine = new Engine(\"test\");\n            string code = \"print(\\\"Hello, World!\\\")\";\n            engine.Compile(code, true);\n            if (engine.HasError)\n            {\n                ReportErrors(engine.ErrorInfo.Contents);\n                return;\n            }\n            engine.Run(true);\n            if (engine.HasError)\n            {\n                ReportErrors(engine.ErrorInfo.Contents);\n                return;\n            }\n        }\n\n        private static void ReportErrors(IReadOnlyList\u003cDiagnostic\u003e diagnostics)\n        {\n            foreach (var diagnostic in diagnostics)\n            {\n                System.Console.WriteLine(diagnostic.ToDisplayString());\n            }\n        }\n    }\n}\n```\n\n## Unity In-Game Scripting\n\nA main use scenario of ISB is Unity in-game scripting.\n\nThe [Unity integration demos](./unity_integration_demos/) show how ISB can be\nembedded in Unity projects to enable users to control game object via BASIC\ncode.\n\nBelow are some quick descriptions of the\n[AddGameObject](./unity_integration_demos/AddGameObjects/) demo.\n\n### Prepare the Unity project\n\nInitiate the scene and the game objects in Unity. Typically, we need a\nmulti-line input field to type BASIC code in, and a button to trigger the\nexecution.\n\n![Unity Demo 1](screenshots/01.png)\n\n### Import the ISB assembly\n\nOption 1: import ISB via NuGet\n\n[NuGetForUnity](https://github.com/GlitchEnzo/NuGetForUnity) is a unity package\nthat helps manage NuGet dependencies. You can install\n[NuGetForUnity](https://github.com/GlitchEnzo/NuGetForUnity) first then use it\nto install the ISB NuGet package. Check its documentations for more details.\n\nOption 2: import ISB Dll directly\n\nBuild the ISB dll from source code and copy the ISB assembly\n`ISB/bin/Debug/netstandard2.0/ISB.dll` to your Unity project's `Assets/Plugins`\nor `Assets/Script` dir.\n\n### Define a BASIC library to control game objects\n\nCreate `Game.cs` under `Asserts/Scripts`. The class defined in `Game.cs` will be\nregistered as an ISB external library.\n\n```CSharp\nusing ISB.Runtime;\nusing ISB.Utilities;\nusing UnityEngine;\nusing UnityEngine.Scripting;\n\n[Preserve]\npublic class Game\n{\n    [Doc(\"Example lib function to access Unity objects.\")]\n    [Preserve]\n    public void AddBall(NumberValue x, NumberValue y, NumberValue z)\n    {\n        GameObject prefab = Resources.Load\u003cGameObject\u003e(\"Prefabs/Sphere\");\n        if (prefab != null)\n        {\n            Object.Instantiate(prefab,\n                new Vector3((float)x.ToNumber(), (float)y.ToNumber(), (float)z.ToNumber()),\n                Quaternion.identity);\n        }\n        else\n        {\n            Debug.Log(\"Failed to load prefab.\");\n        }\n    }\n}\n```\n\nThe lib function `AddBall` simply loads the sphere prefab and instantiates a\nclone object then places it at the location specified by the function's\narguments. In-game BASIC code can then invoke `AddBall(x, y, z)` to put balls\nonto the scene.\n\nNote that the attribute `[Preserve]` is used to preventing Unity from stripping\nthe library code. See Unity's [Managed code\nstripping](https://docs.unity3d.com/Manual/ManagedCodeStripping.html) for more\ndetails.\n\n### Run the ISB engine in Game\n\nNow in the button handler code, an ISB engine can be set up to compile and run\nBASIC code.\n\n```CSharp\npublic class GameManager : MonoBehaviour\n{\n    public Button RunButton;\n    public InputField CodeInput;\n\n    void Start()\n    {\n        RunButton.onClick.AddListener(OnRun);\n    }\n\n    public void OnRun()\n    {\n        string code = CodeInput.text;\n        Engine engine = new Engine(\"UnityDemo\", new Type[] { typeof(Game) });\n        if (engine.Compile(code, true) \u0026\u0026 engine.Run(true))\n        {\n            if (engine.StackCount \u003e 0)\n            {\n                string ret = engine.StackTop.ToDisplayString();\n                Debug.Log(ret);\n            }\n        }\n        else\n        {\n            foreach (var content in engine.ErrorInfo.Contents)\n            {\n                Debug.Log(content.ToDisplayString());\n            }\n        }\n    }\n}\n```\n\nThe code `Engine engine = new Engine(\"Unity\", new Type[] { typeof(Game) });`\nregisters the class `Game` into the ISB engine.\n\nThe button click event handler reads BASIC code from the input field then\ncompiles and runs it with the ISB engine. Error messages got from the ISB engine\nwill be reported to Unity's `Debug.Log`.\n\n### Run the Unity project\n\nStart the Unity game. Type the following BASIC code in the input field:\n\n```BASIC\nFor x = -3 To 3\n  For z = -3 To 3\n     Game.AddBall(x, 5, z)\n  EndFor\nEndFor\n```\n\nClick the \"Run\" button.\n\n49 bouncing balls will be put onto the main scene. Enjoy them!\n\n![Unity Demo 2](screenshots/02.png)\n\n![Unity Demo 3](screenshots/03.gif)\n\n### Run BASIC code as Unity Coroutine\n\nTo prevent an execution of BASIC code from blocking Unity's animation loop, the\nISB engine also provides an interface to run BASIC code as a [Unity\ncoroutine](https://docs.unity3d.com/Manual/Coroutines.html).\n\nHere is the coroutine version of the button's click handler:\n\n```CSharp\n    public void OnRun()\n    {\n        string code = Code.text;\n        DebugInfo.text = \"\";\n        Engine engine = new Engine(\"UnityDemo\", new Type[] { typeof(Game) });\n        if (!engine.Compile(code, true))\n        {\n            ReportErrors(engine);\n            return;\n        }\n        // Runs the program in a Unity coroutine.\n        Action\u003cbool\u003e doneCallback = (isSuccess) =\u003e\n        {\n            if (!isSuccess)\n            {\n                ReportErrors(engine);\n            }\n            else if (engine.StackCount \u003e 0)\n            {\n                string ret = engine.StackTop.ToDisplayString();\n                PrintDebugInfo(ret);\n            }\n        };\n        // Prevents the scripting engine from being stuck in an infinite loop.\n        int maxInstructionsToExecute = 1000000;\n        Func\u003cint, bool\u003e stepCallback =\n            (counter) =\u003e counter \u003e= maxInstructionsToExecute ? false : true;\n        StartCoroutine(engine.RunAsCoroutine(doneCallback, stepCallback));\n    }\n```\n\nA `doneCallback` can be passed in to receive the final execution state.\n\nThe code also uses a `stepCallback` to check if the BASIC code has\ntime-consuming logic such as infinite loops. The execution will be canceled if\nthe it exceeds a large number of IR instructions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwixette%2Fisb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwixette%2Fisb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwixette%2Fisb/lists"}