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:
- The basic structure of the language is C-style, with
{
and}
to separate code blocks, and imperative constructs such asif
,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 (likefn add1(x) -> x + 1
) or blocks (likefn my_print(x) { print(x) }
).- Functions can be used in expressions, too, as anonymous functions by omitting the name, i.e.
let x = fn() -> 3
. They can be followed by either->
or{
when used in expressions.
- Functions can be used in expressions, too, as anonymous functions by omitting the name, i.e.
- A few basic types:
nil
: The absence of a value, and the default value for all declared uninitialized variablesbool
: A boolean, which can be eithertrue
or `falseint
: A 63-bit signed integercomplex
: A 64-bit signed integral complex number. Declared with thei
orj
suffix, i.e.1 + 3i
str
: A UTF-8 stringfunction
: The type of all functions
- Along with some basic library collections:
list
: 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
: Alist
variant which behaves elementwise with all basic operators.
- And user definable named tuple types, with the
struct
keyword. - Expressions should be familiar from most imperative programming languages, as should be operator precedence.
- Operators on their own are functions, so
(+)
is a two argument function which adds values. /
is floor division, and%
a modulo operator (same as Python)- The
.
operator is actually a low precedence function composition operator:a . b . c
is equivalent toc(b(a))
, and it can be chained in a functional style. - Short-circuiting
and
andor
use the keywords from Python.
- Operators on their own are functions, so
- Most functions (that aren't variadic) can be partially evaluated (like Haskell):
(+ 3)
is a function which takes one argument and adds three. - The language is almost completely newline independent, and whitespace only used to delimit tokens. There are a few edge cases where whitespace (or semicolons) is required between expressions to reduce ambiguity.
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?
forValueResult
, and is fairly critical to code clarity and avoiding overhead ofResult<ValuePtr, ErrorPtr>
variant_count
: Used for the automatic implementation ofNativeFunction::total()
, rather than supplying a constant.
Cordy has several optional features, which provide functionality, debugging, or verification:
- (Default)
rational
: This enables usage of therational
,imag
, andnumer
native functions, and the creation and usage ofrational
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 everypop
andpush
.
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.