Library / SDK
StepfenShawn/Cantonese avatar
StepfenShawn/Cantonese

Cantonese: a programming language whose keywords are Cantonese

粤语編程語言.The Cantonese programming language.

1,195 stars48 forksRustMIT

At a glance

What is it?
A compiler written in Rust that exposes a Python package, where variables are introduced, values are returned and loops are run, all in Cantonese, with Python and Rust libraries callable from the same source. The author describes most of the compiler as code written during his high school years, and invites contributions on exactly that basis.
Who is it for?
Cantonese suits a developer who wants to study how a natural language can be a programming language's surface syntax, or who wants a toy project to read end to end, since the compiler, the grammar, the examples and the documentation are all in the repository. It does not suit a production project, because the author himself describes the compiler's code quality as poor, and because a language whose keywords are Cantonese is unusable by a team without Cantonese speakers.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 30 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the project is, and who wrote it

Cantonese is a programming language in which you talk to the computer in Cantonese. The README's introduction says it plainly: in this language the computer can understand the Cantonese you write, so you can use Cantonese to operate on, or in the author's phrasing abuse, the computer.

The project is by Stepfen Shawn, the licence is MIT, the primary language in the repository metadata is Rust, and the package is on PyPI as `Cantonese` at version 1.0.12 with the console script `cantonese`. The repository is not archived, the last push was on 2026-09-23, and there are no GitHub releases, so the PyPI version is the version history.

The authorship note is the most human thing in the README, and it is worth quoting because it sets the expectation. The author says most of the compiler was developed during his high school years, that the code is like that, and that it is still the same now, and he welcomes Cantonese speakers and programming enthusiasts to discuss and contribute together.

That single sentence tells you what kind of project this is. It is a compiler written by a teenager and maintained by the same person, and it is presented as an invitation rather than as a product.

The language also handles script conversion. The Cargo manifest includes `zhconv`, a Chinese conversion crate, and the README states that all keywords can be written in traditional characters, or a mix of simplified and traditional.

The documentation situation is worth knowing before you start. The main README is in Cantonese, with an English version at `README-en.md`, and there is a five minute introduction to the language linked from the README, plus a community site.

How the compiler is put together

The build is a Rust crate with Python bindings, and the two halves are separated in the manifest in a way that explains the whole design.

The `Cargo.toml` declares a package named `cantonese_rs` at version 0.1.0, edition 2024, with a library that is built as both a `cdylib` and an `rlib`. The `python` feature is what enables the `pyo3/extension-module` binding, and the `full` feature turns on the `python` feature, so the extension module and the complete language are the same binary.

The Python side is built with maturin. The `pyproject.toml` requires maturin 1.0 or newer as the build backend, points maturin at the Cargo manifest, and sets the Python source directory to `python` and the module name to `cantonese_rs._core`.

The dependency list is short. `pyo3` at 0.29.2 with the `abi3-py38` feature, `thiserror` for error types, `unicode-width` and `unicode-xid` for identifier handling, and `zhconv` for the script conversion.

The `abi3-py38` feature is the one that matters operationally. It means the extension module uses the stable ABI, so a single built wheel works across Python versions from 3.8 up, which is why the package can claim support for 3.8 through 3.12 from one build.

The repository layout matches this split. There is `src/` for the Rust compiler, `grammar/` for the language definition, `python/` for the Python package sources, `examples/` with subdirectories for basic, functional, games, leetcode, algorithms, macros, machine learning, numerical, sql, web and app examples, a `doc/` directory, and `tests/` with a `test.py` at the top level. The `Cargo.lock` and the `pyproject.toml` are both committed, so the Rust and Python build sides are pinned independently.

The language surface, from assignment to functions

The README walks through the language feature by feature, and the mapping from Rust to Cantonese is close enough that the source reads as Rust with the keywords translated.

Assignment introduces a variable, and the block form assigns several at once. The hello world is a print statement:

rust
畀我睇下「"Hello World!"」點樣先?

The type of a variable is queried with a separate verb, and the output shown in the README is `<class 'int'>`.

Control flow is Rust-shaped. A loop has a start value and an end value, and the README notes that one keyword acts as a break and another as a continue. There is a `For` loop as an alternative, and conditionals use an if with an else, plus a `match` statement whose arms are written in the Rust style with a catch-all at the end.

Functions are declared with a name and parameters, and they can return a value. The README's example is a maximum function, and there is a functional programming form where an anonymous function is written as a pair of parameters and a body, with a call syntax that passes arguments after the function.

Two things are worth pulling out of that list. The first is that the language is a dialect rather than a new paradigm, which is why every example in the README maps onto something a Rust programmer would recognise. The second is that the README's own comments about the loop and the break keyword are phrased conversationally, in the register of the language, which is a deliberate choice and makes the documentation read like a tutorial rather than a specification.

Errors, assertions, and a runtime message that shows the source

The error handling section is where the language shows something that most toy languages do not.

Exceptions are raised with a dedicated statement, and the runtime output the README shows is detailed. The message includes the error type, a note that the error was detected at runtime, the file and line of the offending statement, a caret pointing at the source line, and a tip. The trace style is the Python one, with the filename and line number, which is a direct consequence of the implementation.

Assertions work the same way and produce the same shape of message with an `AssertionError` instead.

The exception handling block is a try, except and finally written in Cantonese, and the README's example catches a specific error type by name, `NameError`, in the except clause, and puts cleanup code in the finally clause.

The source pointer in the error output is the feature that makes the rest of the design work. A language whose keywords are translated from Rust would be very hard to debug from an error message that only said line 12, and a caret under the actual source line means the message is useful even to someone who does not read the language.

The README shows the runtime output for the raise example, the assertion example and the error handling example, each with the caret pointing at the relevant line, and the file paths in the output are the example files in the repository, which tells you the examples are executed rather than written out by hand.

Calling Python and Rust from the same file

The library interop is the feature that makes the language more than a syntax exercise.

Python modules are imported with a use statement, and the README shows importing a module's contents, a module, and a set of names from a module, including the standard library's `re` and `pandas`.

You can also call Python code defined inline, which the README shows by writing a Python function in the middle of a Cantonese program and then calling it.

And there is a macro route that does both at once. There is a `macros` module with `Py` and `Rust` macros, so you can define a Python function with a macro and call it, and then define a Rust function with a macro and call it. The README's note is that the macro approach is the way to call Python and Rust from the same program.

The point of that design is that the language is not sealed. Anything in the Python standard library or the Rust ecosystem is reachable, which means the language's own surface is the only thing that is small, and a program that needs a parser or a linear algebra routine does not have to wait for the language to grow.

The `examples/` directory is organised along these lines. There are `lib_sample` examples for calling libraries, `machine_learning/` and `numerical/` for the data work, `leetcode/` for algorithms, `functional/` for the functional style, `games/`, `macros/`, `sql/`, `basic/`, `web/` and `App/`.

Macros let you define your own syntax

The section the README calls the pocket magic is the macro system, and it is the most interesting part of the language design.

The explanation is that Cantonese introduces macros similar to those in Rust, so the language's syntax can be extended, and in simpler terms it works like a `match` statement, where matching extracts metavariables and substitutes them at compile time.

The README's first example defines a greeting macro with two arms, one taking a string and one taking nothing, and then calls it three ways, the third of which is an error because it does not match. That last line is the point: the macro is type checked at the call site, and a wrong call is a compile error rather than a runtime surprise.

The second example is the vector macro, which takes a repetition of expressions and builds a list, and it shows the empty case as well.

Then comes the demonstration that the point of the feature is that you can write a new piece of syntax. The README defines a calculator macro whose patterns are phrases in the form of asking to compute something with a left operand, an operator word and a right operand, and then calls it with an addition and a multiplication, showing the results.

The pattern matching in that example uses literal types, so the operands have to be literals. That is a limitation of the demonstration rather than of the system, and it is the kind of thing a reader should test rather than assume.

There is a `macros/` example directory in the repository, and the language's use of Rust macros is what makes the implementation tractable, since the compiler is Rust and a macro is the natural way to add syntax to a Rust-based parser.

Where Cantonese is the wrong choice

The first wrong case is any production system. The author says the code is poor, and the implementation is a Rust crate of a few thousand lines with a hand-written grammar, a PyO3 binding and a Python package. That is fine for a language project and not fine for code whose output you depend on.

The second is a team without Cantonese speakers. The keywords are Cantonese, and while the README says the keywords can be written in traditional, simplified or a mix, the documentation, the examples and the error messages are Cantonese, so a team that does not read the language is reading a program in a language it does not know.

The third is a project that needs a maintained toolchain. There are no GitHub releases, the PyPI version is 1.0.12 while the Rust crate is 0.1.0, the two are versioned independently, and the last push was on 2026-09-23. Nothing tells you the two halves are compatible other than the fact that they are in the same repository.

The fourth is a project that wants a language with a specification. The README is a tutorial, and the language's semantics for edge cases, for integer overflow, for the interaction between the Cantonese keywords and the Rust ones they came from, are whatever the implementation happens to do.

The fifth is anyone expecting a working standard library. The README's own directory list ends with database programming marked as still in development, and the examples that exist, machine learning, LeetCode, games and numerical work, are demonstrations rather than a library surface.

What the project is genuinely good for is teaching. It is a complete compiler, a grammar, a Python package, an example suite and a documentation set in one repository, in a syntax that forces you to read every keyword carefully, which is an unusual and rather effective way to make a programming language memorable.

Editorial conclusion

Cantonese suits a developer who wants to study how a natural language can be a programming language's surface syntax, or who wants a toy project to read end to end, since the compiler, the grammar, the examples and the documentation are all in the repository. It does not suit a production project, because the author himself describes the compiler's code quality as poor, and because a language whose keywords are Cantonese is unusable by a team without Cantonese speakers. Before adopting it, read the five minute introduction linked from the README, note that the documentation is in Cantonese with an English README alongside it, and check the Python floor of 3.8 and the Rust edition 2024 toolchain before you start.

Frequently asked questions

How do I install the Cantonese language?

With `pip install Cantonese`. The package is on PyPI at version 1.0.12, requires Python 3.8 or newer, and installs a console script called `cantonese`. The compiler itself is a Rust crate, `cantonese_rs`, built with maturin using the stable ABI from Python 3.8.

What is the Cantonese programming language written in?

The compiler is written in Rust, in a crate named `cantonese_rs` at edition 2024, with a grammar directory, and it is exposed to Python through pyo3 as the `cantonese_rs._core` extension module. The author says most of the compiler was written during his high school years.

Can Cantonese programs call Python and Rust libraries?

Yes. Python modules are imported with a use statement, including the standard library and packages like pandas, and there is a macros module with `Py` and `Rust` macros for defining functions in either language and calling them from the same program.

Can you define new syntax in Cantonese with macros?

Yes. The README calls it the pocket magic and explains that macros work like a match statement, extracting metavariables and substituting them at compile time. Its examples define a greeting macro, a vector macro and a calculator macro that accepts phrase-shaped patterns for addition, subtraction, division and multiplication.

What do Cantonese runtime errors look like?

The README's examples show a message with the error type, a note that the error was detected at runtime, the file and line of the offending statement, a caret pointing at the source line, and a tip, which is the same trace style as Python and works because the implementation is built on it.

Official sources

  1. Issues
  2. License: MIT
  3. Project website
  4. README
  5. StepfenShawn/Cantonese on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/stepfenshawn-cantonese.svg)](https://hysenlabs.com/projects/stepfenshawn-cantonese)

Was this useful?