{"id":13496725,"url":"https://github.com/stackotter/galah","last_synced_at":"2026-03-07T23:32:00.480Z","repository":{"id":219202622,"uuid":"747684958","full_name":"stackotter/galah","owner":"stackotter","description":"A scripting language with the goal of being lightweight and embeddable in Swift applications.","archived":false,"fork":false,"pushed_at":"2025-01-21T22:57:04.000Z","size":6138,"stargazers_count":9,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-07-18T06:15:33.401Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://stackotter.github.io/galah/","language":"Swift","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/stackotter.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":["stackotter"]}},"created_at":"2024-01-24T12:45:40.000Z","updated_at":"2025-03-26T03:56:17.000Z","dependencies_parsed_at":"2025-07-18T04:49:27.320Z","dependency_job_id":"58022cb1-7fa8-4a7c-8d94-2ce15d1ddc9b","html_url":"https://github.com/stackotter/galah","commit_stats":null,"previous_names":["stackotter/galah"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/stackotter/galah","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackotter%2Fgalah","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackotter%2Fgalah/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackotter%2Fgalah/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackotter%2Fgalah/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stackotter","download_url":"https://codeload.github.com/stackotter/galah/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackotter%2Fgalah/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30237329,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T23:24:20.706Z","status":"ssl_error","status_checked_at":"2026-03-07T23:21:10.486Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":[],"created_at":"2024-07-31T19:01:58.031Z","updated_at":"2026-03-07T23:32:00.423Z","avatar_url":"https://github.com/stackotter.png","language":"Swift","funding_links":["https://github.com/sponsors/stackotter"],"categories":["Swift"],"sub_categories":[],"readme":"## galah\n\nA scripting language with the goal of being lightweight and embeddable in Swift applications.\n\n### Trying it out\n\n#### Online playground\n\nThe [Galah playground](https://stackotter.github.io/galah) uses WASM to run a Galah interpreter\nin your browser! Visit it in a modern browser to try out Galah without the need to install it\nlocally.\n\n#### Building locally\n\nThe following commands build the interpreter's CLI from source and run the `sample.galah` file\nincluded in this repository,\n\n```sh\ngit clone https://github.com/stackotter/galah\ncd galah\nswift run galah ./sample.galah\n```\n\n### Syntax (WIP, mostly not implemented yet)\n\nThis syntax is all bound to change! Nothing is set in stone, and even the style of the language\nisn't completely decided yet.\n\nThe following example program is strongly typed but relies heavily on type inference instead of\ntype annotations. Still not sure whether omitting return type annotations is a good idea or not.\nWith good enough LSP support it should be fine, but LSPs won't always be that useful when using\nuser-provided built-in functions etc (there's a limit to how much the LSP can know without some\nsort of interface file).\n\n```swift\nstruct Citizen {\n    let name: Str\n    let age: Int\n\n    // `name` is inferred to be of type `Str`.\n    init(name) {\n        self.name = name\n        self.age = 0\n    }\n\n    fn randomName() -\u003e Str {\n        [\"Steve Apple\", \"John Smith\"].randomChoice()\n    }\n\n    // Return type is inferred as `(Str, Optional\u003cStr\u003e)`\n    fn parsedName(self) {\n        let parts = self.name.split(\" \", maxSplits: 1)\n        return (parts[0], parts.last)\n    }\n\n    // We could infer that it throws for the user, but that might not be a good idea. Note that\n    // this method definitely shouldn't throw in any sane software, this is just an example.\n    fn incrementAge(mut self) throws {\n        self.age += 1\n        if self.age \u003e 100 || Int.random(0, 80) == 0 {\n            throw \"Citizen died\"\n        }\n    }\n}\n\nfn main() {\n    let stackotter = Citizen(\"stackotter\")\n    for _ in 0..\u003c80 {\n        do {\n            try stackotter.incrementAge()\n        } catch {\n            eprint(\"stackotter died at {stackotter.age}\")\n            exit(1)\n        }\n    }\n\n    print(\"stackotter is {stackotter.age}\")\n    let (first, last) = stackotter.parsedName()\n    print(\"stackotter's first name is {first} and his last name is \\(last ?? \"unknown\")\")\n}\n```\n\nHere's the same program but written in Python as a comparison,\n\n```python\nfrom typing import Optional\n\nclass Citizen:\n    name: Str\n    age: Int\n\n    def init(self, name: str, age: int):\n        self.name = name\n        self.age = age\n\n    @classmethod\n    def randomName(cls) -\u003e str {\n        return [\"Steve Apple\", \"John Smith\"].randomChoice()\n\n    def parsedName(self) -\u003e (str, Optional[str]):\n        let parts = self.name.split(\" \", 1)\n        return (parts[0], parts[1] if len(parts) == 2 else None)\n\n    def incrementAge(self):\n        self.age += 1\n        if self.age \u003e 100 or random.randrange(0, 80) == 0:\n            raise Exception(\"Citizen died\")\n\nif __name__ == \"__main__\":\n    stackotter = Citizen(\"stackotter\")\n    for _ in range(80):\n        try:\n            try stackotter.incrementAge()\n        catch Exception:\n            print(\"stackotter died at {stackotter.age}\")\n            exit(1)\n\n    print(f\"stackotter is {stackotter.age}\")\n    first, last = stackotter.parsedName()\n    print(f\"stackotter's first name is {first} and his last name is \\(last ?? 'unknown')\")\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstackotter%2Fgalah","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstackotter%2Fgalah","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstackotter%2Fgalah/lists"}