Deor
A language for all, transpiled to Rust, as simple as Python, as procedural as Fortran
Learn more by reading the Documentation
Getting Started is the place to go to get up and running.
Pi Calculator Sample
for readability
# Imports must be declared at the top of a file but are global, this means
# imports can all be imported in main or from an imports.deor file imported by main
# this follows the old C-methodology you must be careful about naming root level items
import "lib/convert.deor"
import "lib/string.deor"
import "lib/math.deor"
# This may look strange, it is a substitution for all T replaces with PiChunk, the main
# use of this is setting types for the import, a way of passing a generic
import "lib/tasks.deor" where T = PiChunk
# structs are data, no methods can be attached to the data; Deor is strongly procedural
struct PiChunk
int min
int max
float value
# These are validator types that wrap Rust's Option, they return valid (or not valid) if they are
# set to a value that matches the predicate, this is the only way to have a "null/undefined" in Deor
type SmallPositive(int value)
value > 0 and value <= 32
type LargePositive(int value)
value > 0 and value <= 100_000
# Shapes are the equivalent to generics in other languages, Deor believes in strong human
# readability so we use shapes (not <>) for lists and generic function definitions. piChunkList
# here is actually redundant (the tasks import has this shape that is defined with T-substitution):
# which brings us to another important point: Deor will simply drop root level items that are clones
shape piChunkList = func of PiChunk to PiChunk
# Macros are ways you can insert code (as seen below with macro_run) as part of the transpiler,
# it is as if you had written it that way. Consts can't be global, so this is a useful pattern.
macro use_print_consts
const string SEPARATOR = "): "
const string NONE = ""
# Because Deor clones all items by default, iteration in loops clones arguments to functions
# (which is a problem for a list or large struct), while not true here, macros for organization
# in for loops are not a bad option as many performance issues come from looping over function calls
macro leibniz_iteration
# As will allow the compiler to determine the type for you and initialize that variable in one go
is_even as (iter % 2 is 0)
decimal_iter as c_int_to_float(iter)
denom as 1.0 + decimal_iter * 2
if is_even
value = value + 1.0 / denom
else
value = value - 1.0 / denom
# Functions and variables are C style in definition {type} {name}
fn PiChunk compute_pi_chunk(PiChunk chunk)
# There is no dot-notation in Deor, con/de(struction) is used to keep variable names consistent
(min, max) in chunk
# In addition to using as, you can also spell out types, this is recommended as a best practice
# if the type of the value is not acutely obvious from what is being assigned to it
float value = perform_liebniz_computation(min, max)
# Here we are using a 'with' this clones the struct and replaces the matching field
PiChunk chunk_with_value = chunk with (value)
return chunk_with_value
fn float perform_liebniz_computation(int start_iter, int end_iter)
float value = 0.0
# Loops use ranges like other languages such as Python these can be used in various ways, here it
# is going from a start to end value. Note: end is reserved in Deor as a keyword and can't be used
for iter in range(start_iter, end_iter)
macro_run leibniz_iteration
return value
# Although still well under the limit, functions have a strict limit of three parameters, if passing
# more, you must use a struct. Again: the focus here is human readability
fn piChunkList build_chunk(int max_iterations, int iterations_per_thread)
# While a list can be assigned literally with [value1,value2] it can't be assigned a [], this
# is because, once again, Deor focuses on readability. As a result, you must assign empty instead
piChunkList list_of_chunks = empty
float value = 0.0
current as 0
for if current < max_iterations
current = current + iterations_per_thread
int max = current
if max > max_iterations
max = max_iterations
min as current - iterations_per_thread
PiChunk chunk = (min, max, value)
list_of_chunks at end = move chunk
return list_of_chunks
fn int ask_for_threads()
macro_run use_print_consts
const int DEFAULT = 8
for if true
# You will notice that prompt is not passed literally, the reason why is Deor as part of the
# "Human-Readability" philosophy: use named-variables for functions with more than 1 argument
prompt as s_join(["How many thread-tasks would you like to run? (default ", c_int_to_string(DEFAULT)])
print(prompt, SEPARATOR)
# Inputs split on spacing to provide arguments, first is the first arg, second the second and so on.
# There is also a input_string and input_list that gives the full string and argument list.
(first) in input()
# Libs are included with Deor that wrap rust blocks allowing raw access to rust features, these
# libs are prefixed with a letter, here it is the convert lib c_ to not pollute the global space
# When assigned SmallPositive is validated against its predicate you saw earlier
SmallPositive input_value = c_string_to_int(first)
if first is NONE
return DEFAULT
# Here the is valid checks that SmallPositive predicate; an 'avow' unwraps the primitive if valid
# If we are wrong with avow it will crash -- hence the strong wording 'avow'.
else if input_value is valid
return avow input_value
else
# Print can take a string or any other primitive, even a literal string if it is 1 argument
print("Incorrect entry, must be >0 and the max is 32")
fn int ask_for_iterations()
macro_run use_print_consts
const int DEFAULT = 10
# Something not mentioned yet is that there is no `while`; for = loop, so "for if" = while
for if true
prompt as "How many MILLIONS of iterations do you want to run? (default 10 xMILLION"
print(prompt, SEPARATOR)
(first) in input()
LargePositive iterations = c_string_to_int(first)
if first is NONE
return DEFAULT
else if iterations is valid
return avow iterations
else
print("Incorrect entry, must be >0 and the max is 100000 (in MILLIONS)")
# Deor is picky about case as it is key to readability: consts are SCREAMING_SNAKE, primitives are one
# word lowercase, shapes are camelCase, structs and enums PascalCase, functions/variables snake_case.
# The idea is logic uses snake_case and structure uses Pascal or camelCase.
fn float total_final_results(piChunkList results)
float net_value = 0.0
# Here the for loop will iterate over every item in the list
for res in results
(min, max, value) in res
net_value = net_value + value
return net_value
fn void main()
# Deor supports _ separators for readability in numbers, they can be put anywhere and are dropped
const float MILLIONS = 1_000_000.0
const float LIEBNIZ_COEFFICIENT = 4
threads as ask_for_threads()
float_threads as c_int_to_float(threads)
iterations as ask_for_iterations()
float_iterations as c_int_to_float(iterations) * MILLIONS
iterations_per_thread as m_floor(float_iterations/float_threads)
total_iterations as iterations_per_thread * threads
print("Performing " + c_int_to_string(total_iterations) + " iterations")
# Multithreading makes use of a task system, a wrapped rust library that exposes these features
# It is very basic in use and requires a list of the substituted value (T-sub you saw earlier)
TaskPool pool = t_pool_make()
list_of_chunks as build_chunk(total_iterations, iterations_per_thread)
# When complete, it will output that same list-type as a result when all threads finish
piChunkList results = t_pi_chunk_run_all(pool, list_of_chunks, compute_pi_chunk)
net_value as total_final_results(move results)
float pi_value = LIEBNIZ_COEFFICIENT * net_value
print(s_join(["Pi was calculated to be: ", c_float_to_string(pi_value)]))