{"id":22954747,"url":"https://github.com/cl4cnam/funcsug","last_synced_at":"2025-08-13T02:31:59.866Z","repository":{"id":40296835,"uuid":"453142468","full_name":"cl4cnam/funcSug","owner":"cl4cnam","description":"Program like the event loop doesn't exist! FuncSug is a language that simplifies programming the reaction to events in browser. It aims to make more linear code in line with async/await and structured concurrency.","archived":false,"fork":false,"pushed_at":"2025-06-04T17:27:43.000Z","size":2878,"stargazers_count":9,"open_issues_count":6,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-04T22:42:15.112Z","etag":null,"topics":["async-await","await-event","browser","easy-programming","event-loop","gui-programming","logical-parallelism","programmer-friendly","programming-language","structured-concurrency","user-event","user-interaction"],"latest_commit_sha":null,"homepage":"https://github.com/cl4cnam/funcSug/wiki","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cl4cnam.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,"zenodo":null}},"created_at":"2022-01-28T16:40:41.000Z","updated_at":"2025-06-04T17:27:45.000Z","dependencies_parsed_at":"2024-02-07T18:31:41.679Z","dependency_job_id":"eef02fc3-4dd7-4be4-a006-971648fa06bf","html_url":"https://github.com/cl4cnam/funcSug","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cl4cnam/funcSug","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cl4cnam%2FfuncSug","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cl4cnam%2FfuncSug/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cl4cnam%2FfuncSug/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cl4cnam%2FfuncSug/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cl4cnam","download_url":"https://codeload.github.com/cl4cnam/funcSug/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cl4cnam%2FfuncSug/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270167210,"owners_count":24538734,"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-13T02:00:09.904Z","response_time":66,"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":["async-await","await-event","browser","easy-programming","event-loop","gui-programming","logical-parallelism","programmer-friendly","programming-language","structured-concurrency","user-event","user-interaction"],"created_at":"2024-12-14T16:19:26.593Z","updated_at":"2025-08-13T02:31:59.818Z","avatar_url":"https://github.com/cl4cnam.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![header](https://github.com/user-attachments/assets/72744a48-d5d6-4058-88ca-19d39ac5059a)\n\n[Try it in the Playground](https://cl4cnam.github.io/try_FuncSug/?example=drinkingCow)\n\n# **FuncSug: User-interaction programming made easy**\n\nFuncSug is an experimental scripting language that aims to simplify GUI programming in browser, as a complement to JavaScript.\nThe convenience is that FuncSug allows you to write code in an order that is more consistent with the execution order.\nIt enables a more linear code in line with [async/await](https://en.wikipedia.org/wiki/Async/await) and [structured concurrency](https://en.wikipedia.org/wiki/Structured_concurrency). It replaces event-driven code structures with easy-to-use seemingly parallel syntaxes (without using OS threads). It allows you to program like the event loop doesn't exist.\n- No more asynchronous calls\n- Reactions to events can be expressed in ways other than event-action links\n- Reactions to events are allowed to be long\n\n[**Tutorials**](https://github.com/cl4cnam/funcSug/wiki/Tutorials) - [**Online Playground**](https://cl4cnam.github.io/try_FuncSug) - [**Getting started**](https://github.com/cl4cnam/funcSug#instructions-for-use) - [**Examples**](https://github.com/cl4cnam/funcSug#get-a-taste-of-the-language) - [**REPL**](https://cl4cnam.github.io/FuncSugREPL/replPy.html)\n\nThe main goal of FuncSug might be painted as follows:\n\n![presenta2_b](https://github.com/user-attachments/assets/26d6d28d-30ae-4ab1-948d-f0e9365cbb93)\n## A few samples\n\n### Play multiple sounds at the same time\n\n```gdscript\nparallel ||\n\tplaySoundFile('sound1.mp3')\n||\n\tplaySoundFile('sound2.mp3')\n||\n\tplaySoundFile('sound3.mp3')\n```\n[Try it in the Playground](https://cl4cnam.github.io/try_FuncSug/?example=soundParallel)\n\n### Play multiple sounds one at a time\n\n```gdscript\nplaySoundFile('sound1.mp3')\nplaySoundFile('sound2.mp3')\nplaySoundFile('sound3.mp3')\n```\n[Try it in the Playground](https://cl4cnam.github.io/try_FuncSug/?example=soundSequence)\n\n### Timeouts\n\n```gdscript\ndisplayNewMessage('What is ...?')\nparallel exitAfter 1 finished ||\n\tvar theAnswer := awaitHumanText()\n||\n\twaitSeconds(15)\n```\n\n### A simple choice\n\n```gdscript\ndisplayNewMessage('\u003cbutton id=\"A\"\u003eI choose A\u003c/button\u003e \u003cbutton id=\"B\"\u003eI choose B\u003c/button\u003e')\n\nparallel(select 1) ||\n||=================\n\tawaitClickBeep('#A')\n...---\n\tdisplayNewMessage(\"You've chosen A\")\n||================\n\tawaitClickBeep('#B')\n...---\n\tdisplayNewMessage(\"You've chosen B\")\n```\n[Try it in the Playground](https://cl4cnam.github.io/try_FuncSug/?example=simpleChoice)\n### A less simple choice\n\n```gdscript\ndisplayNewMessage(`\n\t\u003cbutton id=\"A\"\u003eI choose A\u003c/button\u003e\n\t\u003cbutton id=\"B\"\u003eI choose B\u003c/button\u003e\n`)\n\nparallel(select 1) ||\n||=================\n\tawaitClickBeep('#A')\n\tdisplayNewMessage('\u003cbutton id=\"Aconfirmed\"\u003eYes, I choose A\u003c/button\u003e')\n\tawaitClickBeep('#Aconfirmed')\n...---\n\tdisplayNewMessage(\"You've chosen A\")\n||================\n\tawaitClickBeep('#B')\n...---\n\tdisplayNewMessage(\"You've chosen B\")\n||================\n\twaitSeconds(5)\n...---\n\tdisplayNewMessage(\"You've hesitated\")\n```\n[Try it in the Playground](https://cl4cnam.github.io/try_FuncSug/?example=lessSimpleChoice)\n## Why\n\nMany people ask why GUI programming is so difficult. Some of common difficulties come from event-driven programming problems.\nThat's why, with FuncSug, programmers do NOT have to follow the event-driven programming paradigm. For example, you no longer use \"addEventListener\" and so no longer have the corresponding problems.\n\n## How\n\nFuncSug suppresses **event-driven programming** problems: **callback hell** and **state management**.\n\n**Advantages:**\n- It avoids *callback hell* (You don't need callback any more).\n- Your code follows the order of execution so you avoid spaghetti code and debug more easily.\n- It solves the [state management](https://en.wikipedia.org/wiki/State_management) problem (It **eliminates** the need to manage **all the combinations** of component states).\n- It easily manages task cancellations (including task timeouts).\n- It can detect a change in the value of a variable and react accordingly.\n- It's deterministic.\n- (You can also include JavaScript snippets, pass FuncSug variables to it and get back JavaScript return).\n\n**by means of**:\n- explicit **logical parallelism**,\n- block cancellations,\n- and \"`await` event\" instructions.\n\nPlease, let me know what you think ([Github discussions](https://github.com/cl4cnam/funcSug/discussions), [Mastodon](https://piaille.fr/@cli345)).\u003cbr\u003e\nI'd be happy to read your opinion and answer your questions.\n\n![solve2_c2](https://github.com/cl4cnam/funcSug/assets/40176886/78b1eea5-cb49-4666-b9a7-bec64973c2e0)\n\n## Compare\nThese two codes do the same thing (on mobile, please scroll right to see the FuncSug code):\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth align=\"center\"\u003eJavaScript/DOM\u003c/th\u003e\n\u003cth align=\"center\"\u003eFuncSug\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```javascript\nlet numberOfClick\nfunction $(id) {\n   return document.getElementById(id)\n}\nfunction launch() {\n   $('launch').removeEventListener('click', launch)\n   setTimeout(\n      ()=\u003e{\n         $('clickZone')\n         .removeEventListener('click', clickZone)\n         console.log(\"Good job! See you soon!\")\n      },\n      30000\n   )\n   numberOfClick = 0\n   $('clickZone')\n   .addEventListener('click', clickZone)\n}\nlet timeoutID\nfunction clickZone() {\n   if (numberOfClick == 0) {\n      timeoutID = setTimeout(\n         ()=\u003e{\n            if (numberOfClick \u003c 3) {\n               numberOfClick = 0\n               console.log(\"Non-triple click\")\n            }\n         },\n         2000\n      )\n   }\n   numberOfClick += 1\n   if (numberOfClick == 3) {\n      numberOfClick = 0\n      console.log(\"Triple click\")\n      clearTimeout(timeoutID)\n   }\n}\n$('launch').addEventListener('click', launch)\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```python\nawaitClickBeep('#launch')\nparallel exitAfter 1 finished ||\n   waitSeconds(30)\n||\n   while true:\n      awaitClickBeep('#clickZone')\n      parallel exitAfter 1 finished ||\n         awaitClickBeep('#clickZone')\n         awaitClickBeep('#clickZone')\n         print(\"Triple click\")\n      ||\n         waitSeconds(2)\n         print(\"Non-triple click\")\nprint(\"Good job! See you soon!\")\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nIf you copy and paste, replace each three initial spaces by one tabulation (Github markdown doesn't allow to change tabulation size in this context).\n\n## Get a taste of the language\nHave a look at:\n- ['Memory' code](https://github.com/cl4cnam/Memory/blob/main/memory.fg)\nor [play now](https://cl4cnam.github.io/Memory/memory.html).\n- ['Memory2' code](https://github.com/cl4cnam/Memory2/blob/main/memory.fg)\nor [play now](https://cl4cnam.github.io/Memory2/memory.html).\n- ['Hypertext fiction' code](https://github.com/cl4cnam/hypertextFictionExample/blob/main/hypertextFictionExample.fg)\nor [play now](https://cl4cnam.github.io/hypertextFictionExample/hypertextFictionExample.html).\n- [the 'Make Gems' code](https://github.com/cl4cnam/make_gems/blob/main/makegemPhaserPy.fg)\nor [play now](https://cl4cnam.github.io/make_gems/makegemPhaserPy.html).\n- ['Guess the Number' code](https://github.com/cl4cnam/Guess_the_number/blob/main/guessTheNumberPy.fg)\nor [play now](https://cl4cnam.github.io/Guess_the_number/guessTheNumberPy.html).\n- ['Mini Sweet' code](https://github.com/cl4cnam/miniSweet/blob/main/miniSweetPy.fg)\nor [play now](https://cl4cnam.github.io/miniSweet/miniSweetPy.html).\n- ['Aquarium' code](https://github.com/cl4cnam/aquarium/blob/main/aquariumPy.fg)\nor [play now](https://cl4cnam.github.io/aquarium/aquariumPy.html).\n\nLook at the **global structure of the code**: One cannot follow this structure in usual programming language.\n\nLet's take, for example, [the 'Make Gems' code](https://github.com/cl4cnam/make_gems/blob/main/makegemPhaserPy.fg):\n\nIn this language, there is no need to build a ball object, just call a function ```lifeOfBall```.\nYou just run multiple ```lifeOfBall```, ```birthOfGem``` and a ```lifeOfPaddle``` in parallel.\nThese functions do not build objects: they are just like any classical function.\n\u003cbr\u003e\nIn the body of ```lifeOfPaddle```, just code the various behaviors of the ball in parallel.\n\nIn ['Guess the Number'](https://github.com/cl4cnam/Guess_the_number/blob/main/guessTheNumber.fg), ```gameCourse``` is just a function. The line just after the call of ```gameCourse``` is executed only when the player has found the number, that is only when ```gameCourse``` has returned, just like any classical function call.\n\nYou can also [use FuncSug online playground](https://cl4cnam.github.io/try_FuncSug) or [test snippets of it](https://cl4cnam.github.io/FuncSugREPL/replPy.html).\n\n## Concurrent way\n![logo](https://github.com/cl4cnam/funcSug/assets/40176886/2d4c08b3-6f96-4acd-b993-b9bbe0df6b91)\n\nFuncSug uses the \"**concurrent way**\" or more exactly the \"**logically parallel way**\". That is, it introduces explicit concurrency where no concurrency seems present or mandatory. The concurrency is reputed to be very difficult. However, amazingly, many cases (in particular concurrency of waits) are simpler with explicit concurrency!\n\nWith this style, you can program (as you program for the console) without users losing the multiple possibilities of interaction (Indeed, this style suppresses the *inversion of control* of the callback style of event-driven programming).\n\nThis \"**concurrent way**\" is expressed thanks to additional control flow instructions (beyond `if`, `while`, `for`,...):\n- `parallel` / `parallel exitAfter ... finished` / `parallel(select ...)` / `parallel(for ... in ...)`,\n- `select`,\n- `spawn`,\n- `whileTrue_dependsOn` / `whileTrueAwaitFrame_js` / `whileTrueAwaitDom_js`,\n- `repeat`,\n- `sequence`,\n- ...\n\nand with new modifiers (beyond `break`, `return`): `restart`, `pause`, `resume`.\n\nThat enables a better **structure of code** (that is, a more natural and more readable structure).\n\nIf you're curious, you can read the [the 'Memory' code](https://github.com/cl4cnam/Memory2/blob/main/memory.fg)\nor [try it](https://cl4cnam.github.io/Memory2/memory.html) or read this [post](https://trio.discourse.group/t/structured-concurrency-for-gui-programming-without-concurrency/488).\n\nIt's loosely based on [SugarCubes](https://github.com/LordManta/SugarCubesJS) by Jean-Ferdy Susini which is a derivative of [Esterel](https://en.wikipedia.org/wiki/Esterel) by Gérard Berry. It adheres to \"[structured concurrency](https://en.wikipedia.org/wiki/Structured_concurrency)\" principles. It doesn't use OS threads. It doesn't aim to improve speed of execution.\n\n\u003e [!NOTE]\n\u003e **Goal**: facilitating **GUI programming** (in fact, the interactivity aspect)\u003cbr\u003e\n\u003e **Non-goals**: improving speed of execution, safety, facilitating data structuration, object management, mutability, types\n\n## Instructions for use\n\nIn your ```myProgram.html```, in the end of the body element, include the lines:\n```\n  \u003cscript src=\"https://cdn.jsdelivr.net/gh/cl4cnam/funcSug/libStd.fg\" type=\"application/funcsug\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/gh/cl4cnam/funcSug/libDOM.fg\" type=\"application/funcsug\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/gh/cl4cnam/funcSug/libDOMSVG.fg\" type=\"application/funcsug\"\u003e\u003c/script\u003e\n  \u003cscript src=\"myProgram.fg\" type=\"application/funcsug\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/gh/cl4cnam/funcSug/parser.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/gh/cl4cnam/funcSug/parserPy.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/gh/cl4cnam/funcSug/interpreter.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/gh/cl4cnam/funcSug/DOMloader.js\"\u003e\u003c/script\u003e\n```\nWrite your code in the file ```myProgram.fg```.\n\n### Specific case: With phaser_ce\n\nIn your ```myProgram.html```, in the end of the body element, include the lines:\n```\n  \u003cscript src=\"https://cdn.jsdelivr.net/gh/photonstorm/phaser-ce/build/phaser.min.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/gh/cl4cnam/funcSug/libStd.fg\" type=\"application/funcsug\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/gh/cl4cnam/funcSug/libDOM.fg\" type=\"application/funcsug\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/gh/cl4cnam/funcSug/libPhaser.fg\" type=\"application/funcsug\"\u003e\u003c/script\u003e\n  \u003cscript src=\"myProgram.fg\" type=\"application/funcsug\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/gh/cl4cnam/funcSug/parser.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/gh/cl4cnam/funcSug/parserPy.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/gh/cl4cnam/funcSug/interpreter.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/gh/cl4cnam/funcSug/DOMloader.js\"\u003e\u003c/script\u003e\n```\nWrite your code in the file ```myProgram.fg```.\n\n## Some features\n\n### Parallel construct\n\u003e Beware that this is just a logical parallelism.\n\nYou can write\n```\nparallel ||\n\t\u003cparallelBranch1\u003e\n||\n\t\u003cparallelBranch2\u003e\n```\nto execute ```parallelBranch1``` and ```parallelBranch2``` concurrently.\n\nYou can also:\n- add a branch dynamically,\n- select parallel branch(es) according to event(s).\n\n### Interruptible block\nYou can interrupt (`break`), pause (`pause`), resume (`resume`) or restart (`restart`) a block. For example:\n```\nparallel ||\n\t@myBlock\n\t\u003cinstruction1\u003e\n\t\u003cinstruction2\u003e\n||\n\tbreak myBlock\n```\n### Reaction to a change of a variable\nYou can react to a change of a variable, for example, like this:\n```\nwhile true:\n\tawaitBeep myVariable\n\t\u003cwhatToDoInThisCase\u003e\n```\n\n## Syntax elements\n\nThe syntax is very similar to that of Python.\n\nAfter the colon ```:``` of some blocks, you can add ``` @label ``` just after the function name to label the expression (This is useful for the ```break``` instruction).\nThis 'label' must be a declared variable.\n\n## A few instructions/expressions (loose description)\n\n```print(value)``` writes ```value``` onto the console.\n\n```var variableName``` declares a new local variable.\n\n```variableName := value``` assigns  ```value``` to ```variableName```.\n\n```variableName += value``` increments  ```variableName``` by ```value``` (also for `-`,`*`,`/` operators).\n\n```true``` and ```false``` returns the boolean value 'true' and 'false' respectively.\n\n```value1 + value2``` returns the sum/concatenation of the two values (also for `-`,`*`,`/`,`mod`).\n\n```value1 \u003c value2``` returns the truth value of ```value1 \u003c value2``` (also for `\u003c=`,`=`,`/=`, `and`, `or`).\n\n```randomIntBetween(value1, value2)``` returns a random integer between ```value1``` and ```value2```.\n\n```if```, ```while```, ```def``` acts as usual in Python.\n\n```break label``` interrupts the execution of the expression labelled by ```label```.\n### Sequence\n```\nseq:\n\texpression1\n\t...\n\texpressionN\n```\nor\n```\nsequence:\n\texpression1\n\t...\n\texpressionN\n```\nexecutes the expressions in sequence and returns the value of the last (in a context of a `parallel:` block).\nIn all other contexts,\n```\nexpression1\n...\nexpressionN\n```\nexecutes the expressions in sequence and returns the value of the last.\n### Parallel\n```\npar:\n\texpression1\n\t...\n\texpressionN\n```\n```\nparallel:\n\texpression1\n\t...\n\texpressionN\n```\n```\nparallel ||\n\texpression1\n||\n\t...\n||\n\texpressionN\n```\nexecutes the expressions in parallel.\n### Last Will\n```\nonBreak:\n\texpression\n```\nexecutes ```expression``` if the preceding expression is interrupted.\n### Embedded JavaScript\n```\njs (variable1, ..., variableN):\n\tjavascriptSnippet\n```\nexecutes the JavaScript code ```javascriptSnippet``` (in which ```variable1 ... variableN``` can be used).\n### Other\n```displayNewMessageIn(text cssSelector)``` displays a new message ```text``` into the DOM element identified by ```cssSelector```.\n\n```displayNewMessageIn(text cssSelector/cssClass)``` displays a new message ```text``` into the DOM element identified by ```cssSelector``` and assigns ```cssClass``` to it.\n\n```awaitNewHumanNumberIn(cssSelector)``` awaits a number from user in the DOM element identified by ```cssSelector```.\n\n```awaitClickBeep(cssSelector)``` awaits a click from user in the DOM element identified by ```cssSelector```.\n\n## Contributing\n\nPull requests are welcome.\n\nIf you want to make big change, please open an [issue](https://github.com/cl4cnam/funcSug/issues) first to discuss it.\n\nYou can just post your thoughts into [discussions](https://github.com/cl4cnam/funcSug/discussions) tab too.\n\nExamples of contributions: Tutorials, optimization, translations, fixing bugs, ...\n\n## Various\n\nThis language has [syntax highlighting for Geany](https://github.com/cl4cnam/funcSug/tree/main/tools/forGeany); otherwise, with Geany, if you choose that of zephir (or nsis, powershell, ruby), it can be pleasant.\n\nThe file ```parserPy.js``` has been generated online from the file ```funcSugPy.peggyjs``` on the site https://peggyjs.org/online.html with \"parser variable\" set to \"pegPy\".\n\nFor now, this implementation consists just in a quick and dirty (and very slow) interpreter but it works enough to be assessed.\n\nWork in progress.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcl4cnam%2Ffuncsug","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcl4cnam%2Ffuncsug","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcl4cnam%2Ffuncsug/lists"}