| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
RPython is a statically typed, interpreted language with Python-inspired syntax. Unlike Python, it uses explicit end delimiters instead of indentation and requires type annotations on function signatures. The entire toolchain—lexer, parser, type checker, interpreter, and standard library—is implemented in Rust.
Tip: View README.md in Raw mode on GitHub to copy code snippets without HTML rendering.
RPython was created as a teaching tool for undergraduate courses on programming language implementation. The codebase demonstrates:
The language surface resembles Python to lower the barrier for students, while the explicit block delimiters and mandatory type annotations expose concepts often hidden in dynamic languages.
val pi = 3.14159;
var counter = 0;
counter = counter + 1;
Note: RPython does not support comments in source code. The examples in this README omit comments for accuracy.
| Type | Example |
|---|---|
| Integer | 42, -7 |
| Real | 3.14, 0.0 |
| String | "hello", "line\nbreak" |
| Boolean | True, False |
| List | [1, 2, 3] |
| Tuple | (1, "a", True) |
| Category | Operators |
|---|---|
| Arithmetic | +, -, *, / |
| Equality | ==, != |
| Ordering | <, >, <=, >= |
| Logical | and, or, not |
Note: Equality operators support numbers, strings, and booleans. Ordering operators are currently limited to numbers.
RPython uses explicit, static types for function parameters and return values. Variables infer their type from the initializer expression.
if score >= 90:
grade = "A";
elif score >= 80:
grade = "B";
else:
grade = "C";
end
A single end closes the entire if-chain. The elif and else keywords introduce new branches without requiring separate end markers.
var i = 0;
while i < 5:
var _ = print_line(to_string(i));
i = i + 1;
end;
for x in [1, 2, 3]:
var _ = print_line(to_string(x));
end;
Functions require type annotations for parameters and return type.
def factorial(n: Int) -> Int:
if n <= 1:
return 1;
else:
return n * factorial(n - 1);
end;
end;
val result = factorial(5);
asserttrue(result == 120, "5! should be 120");
Syntax note: Block statements (if, while, for, def) require a semicolon after the closing end when followed by additional statements at the same level.
Anonymous functions can be assigned to variables or passed as arguments.
def apply(f: fn(Int, Int) -> Int, a: Int, b: Int) -> Int:
return f(a, b);
end;
val sum = apply(lambda (a: Int, b: Int) -> Int: return a + b end, 2, 3);
Current limitation: Lambdas are supported as first-class function values (especially when passed as arguments to functions expecting a fn(...) -> ... type), but calling a lambda via a variable name is not fully supported yet in all contexts. Prefer def for named functions, or pass lambdas directly as arguments.
Metabuiltins are functions implemented in Rust and exposed to user code. They handle I/O, type conversions, and common operations.
| Function | Description |
|---|---|
| input() | Read a line from stdin. Returns a String. |
| input(prompt) | Print prompt, then read a line from stdin. |
| input_int() | Read and parse an integer from stdin. |
| input_int(prompt) | Print prompt, then read and parse an integer. |
| input_real() | Read and parse a real number from stdin. |
| input_real(prompt) | Print prompt, then read and parse a real number. |
| print(value) | Print value without trailing newline. |
| print_line(value) | Print value followed by a newline. |
| Function | Description |
|---|---|
| to_string(value) | Convert any value to its string representation. |
| to_string_fixed(value, places) | Format a number with fixed decimal places. |
| to_int(value) | Convert a string or real to an integer. |
| to_real(value) | Convert a string or integer to a real. |
| Function | Description |
|---|---|
| str_concat(left, right) | Concatenate two strings. |
| join(values: List[String], sep) | Join a list of strings with a separator. |
| len(value) | Return the length of a string, list, or tuple. |
| Function | Description |
|---|---|
| tuple_get(value, index) | Return the element at index from a tuple (or an error string on invalid input). |
| Function | Description |
|---|---|
| open(path, "r") | Read and return the contents of path. |
| open(path, "w", content) | Write content to path, overwriting existing content. |
| open(path, "a", content) | Append content to path. |
RPython provides two monadic types for representing optional or fallible values: Maybe[T] and Result[Ok, Err].
Note: Just(value), Nothing, Ok(value), and Err(error) are supported as expression syntax.
ADTs can be declared with multiple constructors. Pattern matching is not yet implemented; values are constructed and passed around opaquely.
Current limitation: ADT declarations are parsed as types but cannot yet be declared as top-level statements. The syntax shown below is the planned syntax; it is not yet functional.
data Shape:
| Circle Int
| Rectangle Int Int
end
val c = Circle(5);
val r = Rectangle(3, 4);
Inline test definitions allow embedding unit tests directly in source files.
test addition_works():
val result = 2 + 2;
asserttrue(result == 4, "2 + 2 should be 4");
end
Assertions:
| Function | Description |
|---|---|
| assert(cond, msg) | Fail with msg if cond is false. |
| asserttrue(cond, msg) | Same as assert. |
| assertfalse(cond, msg) | Fail if cond is true. |
| asserteq(a, b, msg) | Fail if a != b. |
| assertneq(a, b, msg) | Fail if a == b. |
src/ ├── ir/ # AST definitions (expressions, statements, types) ├── parser/ # nom-based parsers for expressions, statements, types ├── type_checker/ # Static type checking for expressions and statements ├── interpreter/ # Tree-walking interpreter and test runner ├── stdlib/ # Metabuiltins table and implementations ├── pretty_print/ # AST → readable source formatter ├── environment/ # Scoped symbol tables (variables, functions, types) └── main.rs # Entry point (currently test-driven)
The pretty_print module converts parsed AST nodes back into readable RPython source code. It is primarily used for:
The pretty printer is not invoked during normal program execution. It is available via the prelude module for programmatic use:
use r_python::prelude::{pretty, ToDoc};
// pretty(80, &statement.to_doc()) → formatted StringOptional feature flags enable performance instrumentation:
# Timing metrics
cargo run --features pp-timing --example pp_timing
# Profile counters
cargo run --features pp-profile --example pp_bench# Clone the repository
git clone https://github.com/UnBCIC-TP2/r-python.git
cd r-python
# Build the project
cargo build
# Run all tests
cargo test
# Run tests with output (useful for debugging)
cargo test -- --nocaptureThe test suite currently includes 270+ unit tests covering the parser, type checker, interpreter, and standard library.
RPython includes a CLI to execute .rpy files directly:
# Run a program
cargo run -- path/to/program.rpy
# Or build first, then run the binary
cargo build --release
./target/release/r-python path/to/program.rpyThe interpreter reads from stdin and writes to stdout, making it suitable for automated judging systems like beecrowd.
Contributions are welcome! Please read the contribution guides before submitting issues or pull requests:
| Back | FazBrowse Home | New Git URL |