Dynamically Typed Scripting Language
MIT License
Cordy is a dynamically typed, interpreted, semi-functional / semi-procedural language. It is designed as a quick-to-write, simple-yet-feature-full, scripting language for solving puzzles and other fun things as an alternative to Python.
An online Cordy REPL can be found here, using the cordy-web
subproject targeting Web Assembly. Language support and syntax highlighting is available via a VS Code Extension.
This language is inspired by parts from Python, Rust, Haskell, Java, and JavaScript. It is also heavily inspired by the Crafting Interpreters book. A basic rundown of the syntax:
{
and }
to separate code blocks, and imperative constructs such as if
, else
, while
, etc.let x
is used to declare a variable. fn foo(x, y, z)
declares a function. Functions can either be followed be expressions (like fn add1(x) -> x + 1
) or blocks (like fn my_print(x) { print(x) }
).
let x = fn() -> 3
. They can be followed by either ->
or {
when used in expressions.nil
: The absence of a value, and the default value for all declared uninitialized variablesbool
: A boolean, which can be either true
or `falseint
: A 63-bit signed integercomplex
: A 64-bit signed integral complex number. Declared with the i
or j
suffix, i.e. 1 + 3i
str
: A UTF-8 stringfunction
: The type of all functionslist
: A ring buffer with O(1) index, pop/push front and back.set
: A collection with unique elements and O(1) contains
checks, along with insertion-order iteration.dict
: A mapping from keys to values with O(1) lookups, along with insertion-order iteration.heap
: A min-heap.vector
: A list
variant which behaves elementwise with all basic operators.struct
keyword.(+)
is a two argument function which adds values./
is floor division, and %
a modulo operator (same as Python).
operator is actually a low precedence function composition operator: a . b . c
is equivalent to c(b(a))
, and it can be chained in a functional style.and
and or
use the keywords from Python.(+ 3)
is a function which takes one argument and adds three.Below is a solution to Advent of Code 2022 Day 1 Part 1, written in a functional style:
read_text "input.txt"
. split "\n\n"
. map(fn(g) -> g . split "\n" . map int . sum)
. max
. print
Or the same solution, written in a different style, with the same language:
let inp = read_text("input.txt")
let answer = 0
for group in inp.split("\n\n") {
let elf = 0
for weight in group.split("\n") {
elf += int(weight)
}
answer max= elf
}
print(answer)
For a more comprehensive documentation, see the language documentation or the standard library.
Build with Rust (nightly), cargo build --release
, and invoke the cordy
executable at /target/release/cordy
. With --help
, this prints the following message:
$ cordy [options] <file> [program arguments...]
When invoked with no arguments, this will open a REPL for the Cordy language (exit with 'exit' or Ctrl-C)
Options:
-h --help : Show this message, then exit.
-v --version : Print the version, then exit.
-d --disassembly : Dump the disassembly view. Does nothing in REPL mode.
-o --optimize : Enables compiler optimizations and transformations.
--no-line-numbers : In disassembly view, omits the leading '0001' style line numbers
This project requires a rust nightly toolchain due to use of two unstable features:
try_trait_v2
: Used for the implementation of ?
for ValueResult
, and is fairly critical to code clarity and avoiding overhead of Result<ValuePtr, ErrorPtr>
variant_count
: Used for the automatic implementation of NativeFunction::total()
, rather than supplying a constant.Cordy has several optional features, which provide functionality, debugging, or verification:
rational
: This enables usage of the rational
, imag
, and numer
native functions, and the creation and usage of rational
values in Cordy.This feature requires the rug
and gmp-mpfr-sys
crates, which rely on the GMP
library, built from source. This, notably, cannot be cross-compiled to WASM, and requires additional setup (Windows). It also requires a nightly-gnu
toolchain (as opposed to the default msvc
on Windows):
$ rustup install nightly-gnu
$ rustup default nightly-gnu
Attempting to use any of the above functions on a version of Cordy built without this feature will raise a PlatformError
.
Debug features can be available, which provide trace output, primarily intended for use during debugging tests:
trace_parser
traces the parser execution, logging tokens accepted, pushed, and rules entered.trace_interpreter
traces the virtual machine execution, logging instructions, and key events such as function invocations.trace_stack
traces the virtual machine's stack after every pop
and push
.Verification features can be enabled to run a much wider suite of possible test cases:
verify_parser
causes every compilation to compile every prefix of the input first. This does not check the output (and the vast majority of these will result in expected compile errors anyway), but instead this is intended to catch pathological cases where the parser error handling does not function correctly and hangs, or crashes.