A general-purpose programming language coming to life through a custom one-pass compiler and a stack-based virtual machine.
👉️ The language is currently being developed, but the implemented features can be seen in Milestones. This README is also in development.
Try out Thusly in the WASM-based interactive playground directly in the browser.
- General-purpose
- Interpreted
- Dynamically typed
- Imperative
- Garbage collected
The development of both the language and the surrounding documentation is currently on-going, but the following is a subset of the language:
Whitespace:
Whitespace is semantically insignificant except for newline characters on non-blank lines.
To read more about the architectural design, implementation details, and follow along walk-throughs of examples of tokenization, parsing, compilation, evaluation, and execution, see design/implementation.
- The terminals in the initial grammar can be identified from user input via a multi-line file or single-line REPL input and then tokenized.
- Arithmetic expressions using
number
(double) can be evaluated.- Addition (
+
) - Subtraction (
-
) - Multiplication (
*
) - Division (
/
) - Modulo (
mod
) - Unary negation (
-
) - Precedence altering (
()
)
- Addition (
- Comparison expressions using
number
can be evaluated.- Greater than (
>
) - Greater than or equal to (
>=
) - Less than (
<
) - Less than or equal to (
<=
)
- Greater than (
- Equality and logical negation expressions using
number
,boolean
,text
(string), andnone
can be evaluated.- Equal to (
=
) - Not equal to (
!=
) - Logical not (
not
)
- Equal to (
- Concatenation of
text
literals using+
can be evaluated.
- Temporary
@out
statement can be executed. - Global and local variables can be defined and used.
- Declaration and initialization (
var <name> : <expression>
) - Assignment expression (
<name> : <expression>
)
- Declaration and initialization (
- Variables adhere to lexical scope.
- Standalone block
block <statements> end
- Standalone block
- Logical operators can be evaluated.
- Conjunction (
and
) - Disjunction (
or
)
- Conjunction (
- Control flow statements can be executed.
-
Selection
-
if
-
elseif
-
else
if <condition> <statements> elseif <condition> <statements> else <statements> end
-
-
Loops
- Bounded (
foreach
)
foreach <name> in <start>..<end> step <change> <statements> end
Example 1
// `<change>` expression is implicitly 1 foreach value in 0..10 @out value end
Example 2
var a: 0 var b: 10 var c: 2 foreach value in a..b step c @out value end
- Unbounded (
while
)
while <condition> { <change> } <statements> end
Example
// `{ <change> }` expression is optional var i: 0 while i < 10 {i +: 1} @out i end
- Bounded (
-
- Augmented assignment expressions can be evaluated.
- Addition and assignment (
+:
) - Subtraction and assignment (
-:
) - Multiplication and assignment (
*:
) - Division and assignment (
/:
) - Modulo and assignment (
mod:
)
- Addition and assignment (
- Range comparison expression can be evaluated (
<value> in <min>..<max>
) - TODO (more milestones will be added here)
- A Thusly VM can run and execute code in the browser via an interactive playground.
- Functions can be defined and invoked.
- Closures are supported.
- Functions are first-class citizens.
- TODO (more milestones will be added here)
This section is for briefly demonstrating implemented functionality thus far and expected behavior when running your code.
By inputting code from either a file or via the REPL, the VM will interpret it and output the result if an @out
statement is used.
Table 1: Valid user input (expressions)
Example input | Expected output | Expected precedence parsing |
---|---|---|
1 + 2 * 3 / 4 |
2.5 | 1 + ((2 * 3) / 4) |
(1 + 2) * 3 / 4 |
2.25 | ((1 + 2) * 3) / 4 |
1 + -2 - -3 |
2 | (1 + (-2)) - (-3) |
1 > 2 = 3 > 4 |
true | (1 > 2) = (3 > 4) |
false != not(1 + 2 >= 3) |
false | false != (not((1 + 2) >= 3)) |
"he" + "llo" = "hello" |
true | ("he" + "llo") = "hello" |
"keep " + "on " + "coding" |
keep on coding | ("keep " + "on ") + "coding" |
false and false or true |
true | (false and false) or true |
true or true and false |
true | true or (true and false) |
Table 2: Valid user input (statements)
Example input | Expected output |
---|---|
var first: "Jane" var last: "Doe" var full: first + " " + last @out full |
Jane Doe |
var x: 1 var y: 2 var z: x: y @out x @out z |
2 2 |
var x: "global" @out x block x: "changed global" var x: "local" @out x end @out x |
global local changed global |
var x: 0 if x < 5 @out "in if" else @out "in else" end |
in if |
foreach value in 0..2 @out value end |
0 1 2 |
var a: 0 var b: 2 var c: 0.5 foreach value in a..b step c @out value end |
0 0.5 1 1.5 2 |
var x: 0 while x < 4 {x +: 1} @out x end |
0 1 2 3 |
Table 3: Invalid user input
Example input | Error type | Expected error reason |
---|---|---|
"one" + 2 |
Runtime | + operates on number only or text only |
"one" < 2 |
Runtime | < operates on number only |
!true |
Comptime | ! is only allowed in != (use not ) |
x: 1 |
Comptime | x has not been declared |
var x: 1 1 + x: 2 |
Comptime | 1 + x is an invalid assignment target( + has higher precedence than : ) |
- A C compiler (e.g. Clang or GCC)
- CMake version 3.20 or later
Run the below command to make Thusly come to life. It will create a top-level bin
directory where the configured and compiled project will be located along with the executable binary cthusly
.
./build.sh
If permission is denied, first add executable permission to the build script by running:
chmod +x build.sh
.
Once you have built the project you can go ahead and feed it some code to interpret thusly (..get it?):
Usage example:
$ ./bin/cthusly --help
Usage: ./bin/cthusly [options] [path]
The REPL (interactive prompt) starts if no [path] is provided
-h, --help Show usage
-d, --debug Enable all debug flags below
-dcomp, --debug-comp Show compiler output (bytecode)
-dexec, --debug-exec Show VM execution trace
Flags:
Currently, only 1 flag may be provided.
Interpret code from a file:
./bin/cthusly path/to/your/file
Start the REPL (interactive prompt):
./bin/cthusly
Exit REPL:
Press
Cmd + D
(Mac) orCtrl + D
(Windows).
Example:
$ ./bin/cthusly
> @out "he" + "llo" = "hello"
true
> @out (1 + 2) * 3 / 4
2.25
>
Enable/disable debug:
For the debug flags to have an effect, the following macro in src/common.h need to be defined.
- DEBUG_MODE
You may comment or uncomment it to disable or enable support for the flags (then rebuild the project).
This software is licensed under the terms of the MIT license.