Introduction

Dekoration is a programming language which has functional feature.
Dekoration has features as follows.

  • first class functions and anonymous functions

  • first class continuations

  • tail recursion optimization

  • LISP like macros

  • message passing mechanism

  • User defineable infix operators

  • Syntax sugar which can describe control flow like C

Install

Node.js

If you want to use CLI, you add -g option.

npm install dekoration

How to use

CLI

To start REPL, you type the command shown as follows.

$ dekoration

Syntax Reference

Lexical syntax

Tokens of Dekoration consist of symbols, numbers and boolean values.

Symbols

The character except shown as follows can use as a symbol.

. , : ; ( ) { } [ ]

If these characters appears in string of symbol, the symbol will be delimited because these characters indicate infix operator.

+ - *  / $ ^ ! # % & @ < >

The stirng of these characters can use as infix operator.

+ - *  / ^ ! % & @ < >

A symbol with `(backquote) will recognize a symbol with all characters which can use as a symbol.
A symbol with '(single quote) will recognize a quoted symbol.
A symbol which surrounded by "(double quote) will recognize a quoted symbol (string).

Avaliable tokens are shown as follows.

Table 1. Avaiable token
Token Symbol

symbol

symbol

++

++

`string=

string=

'string=

q(`string=)

"This is a string"

quoted This is a string

Numbers

Dekoration can use double precision floating numbers.

Boolean values

Dekoration can use Boolean values represented by true or false.

Lists

Lists are described shown as follows.

header(element, ...)

The list shown above is equivalent with this list.

#[header, element, ...]

Delimiter of elements can use ,(comma), ;(semicolon) and ⇒.

List of element surrounded by { …​ } can add the list.
Below list is

if(a) { b; c }

equivalent with below list.

if(a, begin(b, c))

Elements in { …​ } must be delimited by ;(semicolon).

You can add the extra list which follows { …​ }. Below list is

if(a) { b; c } elseif(c) { d }

equivalent with below list.

if(a, begin(b, c), elseif(c, begin(d)))

Reference to variable

A unquoted String is a reference of variable.

function call

add(1, 2)

You can call a function by an array of which function name or an object to apply specifies by first element and arguments specify by rest element.
To get an element of an array, object or string, the array is specified the object and the index is specified by then arguments.

Quote

q(#[1, 2, 3])

The list started by "q" is the quoted object.

Blocks

begin(add(1, 2), add(3, 4))

Last value of the expression will be return value.

Functions

lambda(x, y, begin(add(x, y)))
lambda(x, y) { add(x, y) }
lambdar(x, y; r; begin(add(x, y, r(0))))
lambdar(x, y; r) { add(x, y, r(0)) }

To get the rest argument, you apply use lambdar special form.

Condition

if(eqv(x, 0); 1, 2)
if(eqv(x, 0)) { 1 } else { 2 }
if(eqv(x, 0)) { 1 } elseif(eqv(x, 1)) { 2 } else { 3 }

Evaluates clause of second argument if the value of first argument is not false, or third argument if the value is false.
Else clause is optional.
elseif is equivalent with if, and else if equivalent with else.

Variable definition

x:1

Binds a value to the variable by infix : operator.

Define functions

function(func; x, y, begin(add(x, y)))
function(func; x, y) { add(x, y) }
functionr(func; x, y; r; begin(add(x, y, r(0))))
functionr(func; x, y; r) { add(x, y, r(0)) }

First argument specifies function name to be defined.
To get the rest argument, you apply use lambdar special form.

Setting value to variable

x:=1

Sets a value to the variable by infix := operator.
The variable must be bound.

Local varaible definition

let(
  x => 1,
  y => 2;
  add(x, y));
let(
  x => 1,
  y => 2) {
    add(x, y)
}

Loop (named let)

loop(sum;
  x => 10,
  y => 0;
  if(eqv(x, 0), y, sum(x - 1, x + y))
)
loop(sum;
  x => 10,
  y => 0
) {
  if(eqv(x, 0)) {
    y
  } else {
    sum(x - 1, x + y)
  }
}

Local function definition

letrec(
  sum => lambda(x, y; if(eqv(x, 0), y, sum(x - 1, x + y));
  sum(10, 0)
)
letrec(
  sum => lambda(x, y) {
    if(eqv(x, 0)) {
      y
    } else {
      sum(x - 1, x + y)
    }
  }
) {
  sum(10, 0)
}

Quasiquote

qq(obj1(string), obj2(obj3(uq(add(1, 2)), uqs(#[1, 2]))))

Quasiquote is almost the same as quoting, an array surrounded by uq is evaluated.

delay

delay(x + y)

Evaluates code given property of delay lazily.
The delayed code can be evaluated by force.
The evaluated result by executing force is memorized. The result of code shown as follows will be 765.

> x:765
> promise:delay(x)
> force(promise)
765
> x:=961
> force(promise)
961

Macro

defmacro(aMacro; a, b; add(a, b))
defmacro(aMacro; a, b) {
  add(a, b)
}
defmacror(aMacro; a, b; r; add(a, b, r(0)))
defmacror(aMacro; a, b; r) {
  add(a, b, r(0))
}

and

and(1, 2, 3)
1 && 2

The last element of the given array is acquired if all values of the array are not false.
False is acquired if at least one value is false.
True is acquited if the array is empty.

or

or(false, 2, 3)
false || 2

The first non-false value is acquired if at least one value is not false.
False is acquired if all values is false or the array is empty.

Message Passing

message(
  a => 765,
  b => 346
)

Tiny object-oriented programming can be realized by this mechanism.

while

while(i < 5, begin(p(i), i++))
while(i < 5) {
  p(i);
  i++
}

for

for(i, 0, i < 5, i++, p(i))
for(i => 0; i < 5; i++) {
  p(i)
}

Operators

Predefied Dekoration operators and its priority shows as follows.

Table 2. Operators
Priority Operator Associativity Description

2700

++(Postfix)

-

increment

--(Postfix)

-

decrement

2600

++(Prefix)

-

increment

--(Prefix)

-

decrement

+(Unary)

Right to left

-

-(Unary)

Right to left

Negate the sign

!

Right to left

Logical NOT

2400

*

Left to right

Multiplication

/

Left to right

Division

2300

+

Left to right

Addition

-

Left to right

Subtraction

2100

<

Left to right

Compare numbers

>

Left to right

Compare numbers

Left to right

Compare numbers

>=

Left to right

Compare numbers

2000

=

Left to right

Compare numbers

!=

Left to right

Compare numbers

===

Left to right

Equivalent of values (eqv)

!==

Left to right

Not equivalent of values (negation of eqv)

1600

&&

Left to right

Logical AND

1500

||

Left to right

Logical OR

1300

:

-

Binds to the variable

:=

-

Sets to the variable

Operator definition

Operators can define by op special form.
Operator must be combined to function or special form.

op(2350, yfx, `+++)

First argument is priority, second is associativity and last is operator name.
The value of second argument is shown as follows.

Table 3. Associativity
Value Description

fx

Postfix non-assoative

fy

Postfix assoative

xf

Prefix non-assoative

yf

Prefix assoative

fxf

Infix non-assoative

yxf

Infix Left to right

fxy

Infix Right to left

Library Reference

Arithmetic Operations

Addition, Multiplication

add(1, 2, 3)
`+(1, 2, 3)
mul(1, 2, 3)
`*(1, 2, 3)

Adds or multiplys the arguments.

Subtraction, Division

sub(1, 2, 3)
`-(1, 2, 3)
div(1, 2, 3)
`/(1, 2, 3)

Subtracts or divides rest arguments from first arguments.

Division of Integer

quotient(13, 4)
remainder(13, 4)
modulo(13, 4)

"quotient" is the division of integer.
"remainder" and "modulo" returns the remainder of division.
The difference of "remainder" and "modulo" is as follows.

Table 4. The difference of remainder and modulo
First Second remainder modulo

13

4

1

1

-13

4

-1

3

13

-4

1

-3

-13

-4

-1

-1

Comparison

Equivalence

eqv(1, 2)

"eqv" returns true if the arguments are equal without considering data structure.

Numbers

=(1, 1, 1, 1)
!=(1, 5, 3, 4)
<(1, 2, 3, 4)
<=(1, 2, 2, 3)
>(4, 3, 2, 1)
>=(3, 2, 2, 1)

Returns true if the arguments are equal, not equal, monotonically increasing, monotonically nondecreasing, monotonically decreasing, or monotonically nonincreasing.

Strings

`string=("a", "a", "a")
`string!=("a", "c", b")
`string<("a", "aa", "b")
`string<=("a", "a", "b")
`string>("b", "aa", "a")
`string>=("b", "a", "a")

Returns true if the arguments are equal, not equal, monotonically increasing, monotonically nondecreasing, monotonically decreasing, or monotonically nonincreasing.
Strings are compared by lexicographic order.

Strings (Ignoring cases)

`stringci=("a", "A", "a")
`stringci!=("a", "C", b")
`stringci<("a", "Aa", "b")
`stringci<=("a", "A", "b")
`stringci>("b", "Aa", "a")
`stringci>=("b", "A", "a")

Compares the arguments with ignoring cases.

Logical

not(false)

Returns true if the argument is false, or false if the argument is not false.

Mathematical Functions

Trigonometric Functions

sin(0)
cos(0)
tan(0)

Inverted Trigonometric Functions

asin(0)
acos(0)
atan(1)

Returns NaN if the argument is out of range.

Exponential or Logarithmic Functions

exp(0)
log(1)

Returns NaN if the argument is out of range.

Power

expt(2, 3)

Ceiling or Floor Functions

floor(2.3)
ceiling(2.3)
truncate(2.3)
round(2.3)

Maximum or Minimum

max(1, 3, 4, 2)
min(1, 3, 4, 2)

Returns the largest or smallest value in the given arguments.

Type Predicates

numberp(2.5)
integerp(2)
booleanp(false)
arrayp(#[1])
functionp(lambda(1))

Returns true if the argument is number, integer, boolean value, null, array, object (including array) or function (including continuation) respectively.

Array Operation

Array Construction

list(1, 2, 3)

Constructs an array of the given arguments.

First element or rest elements of Array

first(#[1, 2, 3])
rest(#[1, 2, 3])

Returns first element or rest elements of the given array.

Setting Property

setprop(1, #[0, 1], 2)

Sets the value to the given object.

Concatenation

concat(#[1, 2, 3], #[4, 5, 6], #[7, 8, 9])

Concatenates the given arrays.

map of Array

arraymap(add, #[1, 2, 3], #[4, 5, 6], #[7, 8])

"arraymap" applies the first element to the each elements of the arrays.
In this example, it applies add(1, 4, 7) and add(2, 5, 8) and the result is #[12, 15].

String Operation

Concatenation of Strings

stringAppend("abc", "def", "ghi")

Concatenates the given strings.

Substring

substring("abcde", 1, 3)

Returns substring from the second argument (inclusive) to the third argument (exclusive).

Continuation

callcc(lambda(k, k(765)))

Calls the function with current continuation.

The result of below example will be 1111.

> s:false
> add(346, callcc(lambda(k) { s:k; 961 }))
> s(765)
1111

Others

Appling Function

apply(add, #[1, 2, 3])

Applies the arguments given by an array to the given function.

Executing delayed code (promise)

force(promise)

Executes delayed code (promise). The result is memorized.

Conversion from Number to String

numberToString(100, 16)

Converts first argument by radix given by second argument.
The radix must be between 2 to 36.
The radix is 10 if the radix is not given.

Conversion from String to Number

stringToInteger("100", 8)

Converts first argument by radix given by second argument.
The radix must be between 2 to 36.
The radix is 10 if the radix is not given.

Conversion from String to Number

stringToNumber("100.3")

Returns an array of the keys of the given object.

Length

length(#[1, 2, 3])
length("abc")

Returns the length of the given array or string.

Multiple Values

values(1, 2, lambda(1))

All elements of arrays must be dekoration representive values.
But elements of multiple values may be non dekoration representive values.

Output to Console

p("console output")

Outputs to console.

String Representation

toString(#[1, 2, 3])

Returns the string representation of the argument.

Error Report

error("Error occurred")

Reports an error and quit the program.