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 interactive playground.
- 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.
- 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.