{"id":20710450,"url":"https://github.com/saltysystems/gdminus","last_synced_at":"2025-04-23T06:01:40.425Z","repository":{"id":113777880,"uuid":"494689879","full_name":"saltysystems/gdminus","owner":"saltysystems","description":"A scripting language for sharing code between Erlang and Godot.","archived":false,"fork":false,"pushed_at":"2024-05-01T00:48:29.000Z","size":84,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-29T22:31:27.541Z","etag":null,"topics":["erlang","gdscript","godot","programming-language"],"latest_commit_sha":null,"homepage":"","language":"Erlang","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/saltysystems.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-05-21T05:30:09.000Z","updated_at":"2024-05-01T00:48:32.000Z","dependencies_parsed_at":null,"dependency_job_id":"7164c302-8e09-4cfd-814b-5fda2716efcd","html_url":"https://github.com/saltysystems/gdminus","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saltysystems%2Fgdminus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saltysystems%2Fgdminus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saltysystems%2Fgdminus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saltysystems%2Fgdminus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/saltysystems","download_url":"https://codeload.github.com/saltysystems/gdminus/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250379787,"owners_count":21420841,"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":["erlang","gdscript","godot","programming-language"],"created_at":"2024-11-17T02:12:00.477Z","updated_at":"2025-04-23T06:01:39.700Z","avatar_url":"https://github.com/saltysystems.png","language":"Erlang","funding_links":[],"categories":[],"sub_categories":[],"readme":"gdminus\n=====\n\nWhat and why?\n---\n\ngdminus is an implementation of [GDScript](https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_basics.html)\nfor Erlang, allowing Erlang applications to share code with\n[Godot](https://godotengine.org/). \n\ngdminus is a component of a larger system, Overworld, that aims to be an \nErlang-powered server framework for building scalable multiplayer games.\n\nThere may also be some generally useful snippets in this codebase for anyone \nwanting to build a whitespace-significant language that runs on the BEAM. \n\nScope and Plans\n-----\nThe intent is to implement a strict subset of GDScript that facilitates\ncommunication between Erlang-based game servers and Godot-based clients. \n\ngdminus will probably not implement keywords supporting coroutines, signals, or\nnetworking RPC. These include `yield`, `signal`, `remote`, `master`, `puppet`,\nand so on.\n\ngdminus does not currently support classes, but may in the future if they are not too onerous to implement.\n\nCurrent State\n-----\nA working lexer, parser and tree-walking interpreter have been developed that\nsupport a generous subset of the language including:\n  * Arithmetic expressions and Boolean comparison operators.\n  * If/Else statements\n  * While/For statements with `break` and `continue`\n  * Match statements\n  * Functions, including a number of built-in functions. See e.g. `examples/fib.gd` or `examples/math.gd` \n  * Dictionaries and arrays\n\nThe lexer has been implemented using [leex](https://github.com/rvirding/leex)\nand the parser is implemented via [yecc](https://erlang.org/doc/man/yecc.html).\nThe interpreter takes a great deal of inspiration from\n[Luerl](https://github.com/rvirding/luerl) as well as [Crafting\nInterpreters](https://craftinginterpreters.com/).\n\nPerformance\n-----\ngdminus is easily 10x slower than Godot for many applications. In fact, gdminus\nwill probably never be as fast as Godot's built-in GDScript virtual machine.\nThis is due to inherent slowness in using a treewalking interpreter, overheads\nincurred by implementing a procedural and mutable language in the BEAM, and\ngeneral programmer inefficiency :)\n\nCalculating the first 25 numbers in the Fibonacci sequence using the recursive\nimplementation yields:\n\nImplementation             | Time\n-------------------------- | ----- \nGodot                      | 88ms  \ngdminus (OTP/24 with JIT)  | 673ms \ngdminus (OTP/22)           | 713ms \n\n(on an i7-7600U with absolutely no performance optimizations)\n\n\nKnown Caveats\n-----\nThere have been no efforts to date to ensure gdminus rigorously follows\nGDScript semantics, nor have any of the re-implementations of various built-in\nfunctions been verified for correctness. Caution is advised around floating\npoint math especially.\n\nThe implementation is decidedly uncouth for Erlang code for any number of\nreasons. The author is rather unhappy with abusing the process dictionary to\nhold state in the lexer and interpreter.\n\nBuild / Test \n-----\n```\n    $ rebar3 shell\n    1\u003e gdminus_test:regenerate().\n    2\u003e c(gdminus_scan).\n    3\u003e c(gdminus_parse).\n    4\u003e gdminus_int:file(\"examples/minimal.gdm\")\n```\n    \nExamples\n-----\n\n### Fibonacci\nCalculate the first 25 [Fibonacci numbers](https://en.wikipedia.org/wiki/Fibonacci_number):\n```\nfunc fib(n):\n    if n \u003c 2:\n        return 1\n    else:\n        return fib(n-1) + fib(n-2)\n\nfunc time():\n    return OS.get_ticks_msec()\n\nvar start = time()\nprint(fib(25))\nvar end = time()\nprint(\"Time: \" + str(end - start) + \"ms\")\n```\n\ngdminus will return a 3-tuple to the shell in the format\n`{Stdout,Stderr,FinalState}`. Standard out and standard error are represented\nas lists with each new line representing a list item. The final state contains\nthe user-defined function table plus any variables defined and so on.\n```\n1\u003e gdminus_int:file(\"examples/fib.gdm\").\n{[121393,\"Time: 1395ms\"],\n [],\n {state,0,0,\n  #{0 =\u003e\n     {env,\n      #{\"fib\" =\u003e\n         {[{name,1,\"n\"}],\n          [{'if',\n            {'\u003c',{name,2,\"n\"},{number,2,2}},\n            [{return,{number,3,1}}]},\n           {else,\n            [{return,\n              {'+',\n               {func_call,{name,5,\"fib\"},[{'-',{name,...},{...}}]},\n               {func_call,{name,5,\"fib\"},[{'-',{...},...}]}}}]}]},\n        \"time\" =\u003e\n         {[],\n          [{return,\n            {func_call,\n             {{name,8,\"OS\"},{string,8,\"get_ticks_msec\"}},\n             []}}]}},\n      #{\"end\" =\u003e 1629431927532,\"start\" =\u003e 1629431926137}}},\n  #{},[]}}\n```\n\n### Custom functions\ngdminus allows an application to add custom functions to the function table. Here we add an application function, `erf(float)` (representing the [Error function](https://en.wikipedia.org/wiki/Error_function)), callable from gdminus:\n```\n1\u003e  gdminus_int:init().\nok\n2\u003e F1 = fun([X]) -\u003e math:erf(X) end.\n#Fun\u003cerl_eval.44.40011524\u003e\n3\u003e gdminus_int:insert_function(\"erf\", F1).\nok\n4\u003e gdminus_int:do(\"print(erf(0.42))\").\n{[0.4474676184260253],\n [],\n  {state,0,0,#{},#{},\n          #{\"erf\" =\u003e #Fun\u003cerl_eval.44.40011524\u003e},\n                  []}}\n```\n\ngdminus functions created this way must return a value. \n\ngdminus will first evaluate locally defined functions, application functions (such as erf/1 in this example), and finally builtin functions (a subset of canonical gdscript functions).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaltysystems%2Fgdminus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsaltysystems%2Fgdminus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaltysystems%2Fgdminus/lists"}