Veeyu Programming Language and Libraries

Veeyu is a general-purpose functional and object-oriented programming language most influenced by Lisp family and Python. It provides lambda functions with lexical scope, runtime polymorphism, well designed modern object protocol that supports metaclasses, macro facilities and homoiconicity.

The minimal goal of Veeyu is to provide an extensible homoiconic language without S-expressions. It was influenced by Dylan, Io, Python and Lisp mostly.

This document specifies Veeyu’s small syntax, semantics and runtime libraries plus some test codes. It’s okay to treat this document as the specification of Veeyu.

You can find its source code from the Git repository:

git clone git://github.com/veeyu/veeyu.git

You can check it from the web also: https://github.com/veeyu/veeyu

Syntax

Veeyu has a simple syntax. There are only few keywords of punctuations like =, :=, . and parentheses (and no keyword if keywords mean roman words). All types of forms are expressions that are homoiconic. Its syntax is slightly less minimal than Lisp, but still enough simple.

Veeyu syntax consists of several types of forms. All forms are expressions; that is, all forms return some value. (That’s why there’s no explicit return statement in Veeyu unlike other programming languages.)

Programs

A Veeyu program is composed of zero or more forms. A semicolon character (;) or a line break is used for a boundary between forms.

<source-code>    ::= [ <shebang-line> ] <program>
<shebang-line>   ::= "#!" { <any character> - <newline> } <newline>
<program>        ::= { <form-separator> }
                     { <form> <form-separator> { <form-separator> } }
                     { <form-separator> }
<form-separator> ::= ";" | <newline>

A program has to be a Unicode string, not a byte string. Typically it is stored in a file, and the program reader i.e. parser reads it from the file. But because files store byte strings, not Unicode strings, so the program reader treats files as UTF–8 string by default. And program readers may implement following optional advantages:

  • Detects the BOM (Byte Order Mark) from the beginning of the source code.
  • Detects the -e/--encoding option from the shebang line.
  • Character encoding auto-detection by some heuristics like Mozilla universal character encoding detection.

For example, an implementation may guess that the following Veeyu program is encoded by EUC-KR.

#!/usr/bin/env veeyu -eeuc-kr
write-line!: "안녕, 比喩!"

A program can start with shebang line, the #! syntax used in scripts to indicate an interpreter for execution in Unix, and then its first shebang line is just ignored. It is not a general comment in Veeyu, but just a character sequence ignored only in the beginning of the program. So, for example, the following program causes <name-error>, because #!/usr/bin/env is parsed to a symbol which is undefined.

"""The first line is not a shebang."""
#!/usr/bin/env veeyu -eascii

In order to use a symbol that starts with #! in the beginning of program, keep the first line empty or insert a meaningless shebang line.

#!/usr/bin/env veeyu
"""Shebang-line test."""
#!symbol := 123

The above example defines #!symbol, is 123.

As above examples showed, an implementation may provide several options through shebang line. For example, if an implementation is a compiler, it may have a -r/--restrict option or a -e/--extension for bootstrapping.

$!/usr/bin/env veeyu --restrict=eval,typeinfer --extension=partialclass
require: partial := veeyu.ext.partialclass

partial.extend!(<attribute-name>,
                +apply: method (environment: <object>) {
                  environment.+get-attribute(self)
                })

partial.extend!(<attribute>,
                +apply: method (environment: <object>) {
                  self.receiver(environment).+get-attribute(self.attribute)
                })

partial.extend!(<quote>,
                +apply: method (environment: <object>) {
                  self.form(environment)
                })

partial.subclass!(<form>, <function>)

Forms

There are several types of forms:

  • Symbols e.g. apple, <fruit>
  • Attributes e.g. apple.color
  • Quotes e.g. :apple, :(eat(apple))
  • Number literals e.g. 123, 3.14
  • String literals e.g. 'Avishai Cohen', "Structure in Emotion"
  • Calls e.g. eat(apple, with: fork)
  • Indices e.g. [1, 2, 3, 4], [x * 3, x: 1 ~ 100, x +isa? <odd-number>]
  • Definitions e.g. pi := 3.14, a = a + 1
  • Blocks e.g. { eat(apple); eat(apple, with: fork) }

Read further for details.

<form> ::= <symbol> | <attribute> | <quote>
         | <number-literal> | <string-literal>
         | <call> | <index> | <definition> | <block>

Symbols

Symbols are used for identifiers. A symbol can be most of words e.g. value, <abstract-class>, +, ==. However, it’s not there is no constraint for symbols.

  • Cannot be = or :=. Because these are treated as definition operators.

  • Cannot include any whitespace characters e.g. like this.

  • Cannot include period character (.) e.g. like.this. Because these are treated as attributes.

  • Cannot consist of only digits even if a hyphen character (-) leads e.g. 123, -123. Because these are treated as number literals.

  • Cannot include colon character (:) e.g. :like-this, like-this:. Because symbols with a leading colon are treated as symbol quotes, and symbols with a trailing colon are treated as function/macro calls.

  • Cannot include any of parentheses, square brackets or curly brackets e.g. like(this), like[this], like{this}. Because these are treated as function/macro calls, indices or blocks.

  • Cannot include commas (,) e.g. like,this. Because commas are already reserved for separation of arguments in a function/macro call.

  • Cannot include semicolon characters (;) e.g. like;this. Because semicolons are already reserved together with new line characters for separation of statements.

  • Cannot include single quotes (') or double quotes (") e.g. like-this', like"this". Because these quotation marks are already reserved for string literals.

Though there are above many constraints, practically it is not a problem and symbols are expressive enough. For example, you can append a trailing question mark (?) into names of predicate functions like is-okay?.

Symbols can include underscore characters (_) like other programming languages, but Veeyu prefer instead hyphen characters (-) for separation of words according Lisp tradition.

<symbol>   ::= ( <sym-char> - ( <digit> | "=" ) ) { <sym-char> }
             | "=" <sym-char> { <sym-char> }
<sym-char> ::= <any charactr> -
               ( <whitespace> | ":" | "." | "," | ";" | "(" | ")" |
                 "[" | "]" | "{" | "}" | '"' | "'" )

Attributes

Every value (object) has some attributes. We can say that physically every object is just a key-value storage (where keys are surely attribute names) which remembers its class. And there’s a syntax to access to it.

a-value.an-attribute

Attribute syntax is like the above code: the first receiver form (a-value in the example) comes, a middle period character (.) follows, and the trailling attribute name (an-attribute in the example) ends. If whitespaces close to the middle period character present, they are ignored.

a-value . an-attribute
a-value. an-attribute
a-value .an-attribute

New line characters follows the middle period character are acceptable.

a-value.
an-attribute

Attribute name can be either a symbol, an index or a block.

a-value.symbol-attribute
a-value.[index-attribute]
a-value.{ block-attribute }

Middle period character can be omitted if the attribute name is an index or a block.

a-value[index-attribute]
a-value { block-attribute }

Attribute access is internally a call of +get-attribute method. For example, the following three forms:

receiver.symbol-attribute
receiver[index-attribute]
receiver { block-attribute }

and following three forms:

receiver.+get-attribute(:symbol-attribute)
receiver.+get-attribute(:([index-attribute]))
receiver.+get-attribute(:({ block-attribute }))

share the same behavitor.

<attribute>      ::= <form> "." <attribute-name>
                   | <form> ( <index> | <block> )
<attribute-name> ::= <symbol> | <index> | <block>

Quotes

Quotes are similar to Lisp’s quotes. A leading colon character and trailing parentheses that wrap a form are quote forms. They are evaluated as form objects.

:(form)
:(1)
:(complex(form))
:identifier

Parentheses can be omitted when a quoted form is an symbol.

<quote> ::= ":(" <form> ")"
          | ":" <symbol>

Number Literals

Number literals represents <integer> and <float> instances like 123 and 3.14. It includes a minus sign, because Veeyu has no unary operator. (That’s why symbols cannot be decimal string even a hyphen leads like -123.) But there’s no plus sign for number literals.

ExampleType it means
0<natural-number>
123<positive-integer>
-123<negative-integer>
3.14<positive-float>
-3.14<negative-float>
123.0<positive-float>
-123.0<negative-float>
3.14e-10<positive-float>

Number literals accept decimal numbers only. Hexadecimal or octal numbers can be represented by string literals with prefix characters.

<number-literal>   ::= <integer-literal> | <float-literal>
<integer-literal>  ::= [ "-" ] <digit> { <digit> }
<float-literal>    ::= <integer-literal> "." <digit> { <digit> }
                     | <exponent-literal>
<exponent-literal> ::= <integer-literal> [ "." <digit> { <digit> } ]
                       [ "e" | "E" ] [ "+" | "-" ] <digit> { <digit> }

String Literals

The main purpose of string literals is to represent string values by hardcoding in source codes. There are four types of string literals:

TypesSingle-quotedDouble-quoted
Singleline'str'"str"
Multiline'''str'''"""str"""

There are special escaping sequences for double-quoted strings: most of C-style escape sequences.

Escape sequenceMeaning (Unicode code point)
\\Backslash (\, U+005C)
\'Single quote (', U+0027)
\"Double quote (", U+0022)
\aASCII Bell (BEL, U+0007)
\bASCII Backspace (BS, U+0008)
\fASCII Formfeed (FF, U+000C)
\nASCII Linefeed (LF, U+000A)
\rASCII Carriage Return (CR, U+000D)
\tASCII Horizontal Tab (TAB, U+0009)
\vASCII Vertical Tab (VT, U+000B)
\x??Character with hexadecimal code point (U+00??)
\u????Character with hexadecimal code point (U+????)
\U????????Character with hexadecimal code point (U-????????)

Single-quoted strings can be named as raw string also; escape sequences described above are interpreted just literally in single-quoted strings.

It can also have a prefix character is a case-sensitive roman character i.e. [A-Za-z] in a regular expression, so it can be used for representing another types of values.

Prefix characterMeaningExample
bBinary numberb'101010'
cCharacterc'*'
xHexadecimal numberx'2a'
wWhitespace-separated listw'life universe everything'

The type of an evaluated string literal can be vary depending on its prefix character, but its type is invariable in the same prefix character. For example, string literals with the prefix character c are evaluated as a <character> object.

Any other prefix characters not described in the above table of prefix characters can be user-defined or extended by the specific implementation but defining a prefix character is not preferred because of forward compatibility.

How to define an operation of prefix character is just to define +literal-x-type and +literal-x function in the environment where x is a prefix character to define its operation.

+literal-r-type := regex.<pattern>
+literal-r := regex.compile

For example, the above code defines a prefix character r, then a form r'^[a-z]' will be evaluated to an instance of regex.<pattern> class, that is a return value of a call regex.compile('[^a-z]'). Evaluating a string literal with undefined prefix character cause a <literal-error>, a subclass of <syntax-error>.

If a return value of a call the function +literal-x is not an instance of +literal-x-type (or its subtype), it raises a <type-error>.

<string-literal>          ::= [ <string-literal-prefix> ]
                              <string-literal-body>
<string-literal-prefix>   ::= <alpha>
<string-literal-body>     ::= <string-literal-doublequote-body>
                            | <string-literal-doublequote-body>
<string-literal-dq-body>  ::= '"' { <string-item> } '"'
                          ::  <string-literal-quote> ::= '"'
<string-literal-sq-body>  ::=  "'" { <string-item> } "'"
                          ::  <string-literal-quote> ::= "'"
<string-literal-tdq-body> ::=  '"""' { <string-item> } '"""'
                          ::  <string-literal-quote> ::= <no character>
<string-literal-tsq-body> ::=  "'''" { <string-item> } "'''"
                          ::  <string-literal-quote> ::= <no character>
<string-literal-quote>    ::= '"' | "'"
<string-item>             ::= <string-character> | <string-escape-sequence>
<string-character>        ::= <any character> - "\" - <string-literal-quote>
<string-escape-sequence>  ::= "\" <any character>

Calls

The call, the calling form is either a function application, a macro expansion or a fexpr call. It takes zero or more arguments wrapped with parentheses, typically, in the case of normal calling form.

There are three types of calling forms.

normal calling form

A traditional C-style calling form e.g. function(arguments), function(). It can takes positional arguments and named arguments both.

simple calling form

A calling form using only beginning colon character instead of wrapping parentheses pair e.g. function: arguments. There is a limit that named arguments cannot be applied for simple calling forms and it must one or more positional arguments.

binary operator form

A binary operator-style calling form e.g. receiver attribute argument. There is a limit that only one (and not zero) positional argument can be applied for binary operator form and its function is an attribute form.

The mostly used calling form is a normal calling form. Because it can replace any other two types of calling forms.

The purpose of a simple calling form is a typography of C block-style macro, fexpr or higher-order functions:

[1, 2, 3, 4].for-each!: \(el) {
  io.*stdout*.write(el)
}

All of binary operator forms can be replaced by any other calling forms. So, every calling form of the next code has the same behavior:

receiver method argument
receiver.method: argument
receiver.method(argument)

The purpose of a binary operator form is a typography of binary operator-style methods as its name. For example, sum two integers can operated with the instance method + of the <integer> class like 12.+(34), it usually is represented like the following code:

12 + 34

All of simple calling forms can be replaced by normal calling forms:

function: argument
function(argument)

Calling a function with no arguments or some named arguments can be represented by normal calling form only:

function()
function(a: 1)
function(a, b: 2)
function(a: 1, b: 2)
Calling form typeAccepted arguments typesMinimum–maximum arguments
Normal calling formPositional, Named0–(no maximum limit)
Simple calling formPositional1–(no maximum limit)
Binary operator formPositional1–1

It is not every object can be called. There are <callable> objects like functions, macros, fexprs and classes. <callable> type has a method named +call, and it can say that calling forms are aliases of invoking a method +call.

Therefore, every form of the following code shares the same behavior:

f(x)
f.+call(x)
f.+call.+call(x)
f.+call.+call.+call(x)

Because all of +call attributes (in <callable> objects) have to be a <callable> object also. Recursive invoking +call method can be stopped when a +call attribute and its receiver are the same object.

Calling an object that is not <callable> causes a <call-error>, a subtype of <type-error>.

Any trial of definition of call causes a <call-definition-error>, a subtype of <call-error> and <definition-error> unless +define macro is redefined by user.

<call>                  ::= <form> "(" <argument-list> ")"
                          | <form> ":" <unnamed-argument-list>
                          | <binary-operator>
<binary-operator>       ::= <form> <symbol> <form>

Indices

An index is an argument list wrapped with square brackets. Its purpose is to style accessor methods of data structures typographically similar to subscript indexing e.g. map[:key].

It is a syntactic sugar for a call +index macro (or fexpr), assumed already defined. For example, the following two forms share the same behavior:

[1, 2, 3, 4]
+index (1, 2, 3, 4)

In short, an index form:

[argument-list]

is an alias of:

+index (argument-list)

And of course, an index form with no arguments:

[]

is an alias of:

+index ()

Index can be an attribute name also. In this case, it finds +index macro (or fexpr) in the same receiver.

For example, two forms of the following code have the same behavior:

list.[1]
list.+index (1)

In short, a following form:

receiver.[argument-list]

is an alias of:

receiver.+index (argument-list)

And a middle period character (.) can be omitted when an index is an attribute name:

receiver[argument-list]

The best examples of typographical use of indices are list comprehensions and random access for <sequence>s.

[x * 3, x: 1 ~ 100, x +isa? <odd-number>]
list[123]

Environments or receivers that invoke indices have to be an instance of <indexable>. If it’s not, it raises a <index-error>, a subtype of <type-error>.

Unless +define macro is redefined by user, the following two forms are equivalent:

receiver[index] := value
receiver.+define-index (index, value, local: true)

In the same manner, setf definition form:

receiver[index] = value

is the same as:

receiver.+define-index (index, value, local: false)

provided the receiver is an <index-definable> object. If not, it raises <index-definition-error>, a subtype of <index-error> and <definition-error>.

Note that a value +define-index method returns is just ignored and an index definition form returns its rvalue, evaluated. So if we have to explain about index definitions exactly, f(r[i] := v()) is equivalent to _v := v(); r.+define-index (i, _v, local: true); f(_v) (but the name _v is never exposed, is used only for explanation).

<index> ::= "[" <argument-list> "]"

Definitions

A definition is either a call to a user-defined defining macro (or fexpr), or a call to a built-in defining macro. In any case, it is a just syntactic sugar for a call +define macro, assumed already defined.

For example, following two lines have the same behavior:

minhee-hong := <person>()
+define (minhee-hong, <person>(), local: true)

Following code is the same:

greet(name: <string>) = "Hi, " ++ name
+define (greet(name: <string>), "Hi, " ++ name, local: false)

In short, a := local definition form (:=, also called as let definition):

(lvalue-form) := (rvalue-form)

is an alias of:

+define ((lvalue-form), (rvalue-form), local: true)

In the same manner, a setf definition form (=, also called as assignment):

(lvalue-from) = (rvalue-from)

is an alias of:

+define ((lvalue-form), (rvalue-form), local: false)

There’s +define defined in the root class <object>, a built-in defining macro. So typically a definition makes a binding in the environment by default.

<definition> ::= <form> ( ":=" | "=" ) <form>

Blocks

The main purpose of blocks is to style macros/fexprs typographically to make programmers to guess that forms in the block are not evaluated immediately. It takes a program that contains zero or more forms.

It is a syntactic sugar for a call +block macro (or fexpr), assumed already defined.

{ msg := "log: " ++ $0
  io.*stdout*.write(msg) }

For example, the above code and the following code share the same behavior:

+block (msg := "log: " ++ $0,
        io.*stdout*.write(msg))

In short, a block form:

{ form-1; form-2; form-3; form-n }

is an alias of:

+block (form-1, form-2, form-3, form-n)

And of course, an empty block form:

{}

is an alias of:

+block ()

Block can be an attribute name also. In this case, it finds +block macro (or fexpr) in the same receiver.

For example, following forms of two lines have the same behavior:

\(a, b).{ a + b }
\(a, b).+block (a + b)

In short, a following form:

receiver.{ forms }

is an alias of:

receiver.+block (forms)

And a middle period character (.) can be omitted when a block is an attribute name:

receiver { forms }

The best example of typographical use of blocks is a lambda syntax.

\(a, b) { a + b }

Environments or receivers that invoke blocks have to be an instance of <block-callable>. If it’s not, it raises a <block-error>, a subtype of <type-error>.

Any trial of definition of block or block attribute causes a <block-definition-error>, a subtype of <block-error> and <definition-error> unless +define macro is redefined by user.

Under the hood, a form receiver { forms } actually becomes compiled to:

receiver.+get-attribute(:({ forms }))

Because { forms } is an attribute name in this case. And then, default +get-attribute method defined in <object> raises a <block-error> when its name argument is a <block>. Instead, <block-callable> overrides +get-attribute method to call +block method.

<block>          ::= "{" <program> "}"

Argument lists

Argument lists are mini syntax used inside calls or indices. Arguments are separated by comma characters (,). A trailing comma after all arguments is also allowed, but usually omitted.

There are two argument types:

Positional argument (unnamed argument)

Passed by its position.

Named argument (keyword argument)

Passed by its name. There is a preceding name symbol with a trailing colon (:) that separates an argument name and its value for each named argument e.g. name: value.

There is a defined rule of argument passing for function applications and most macro expansions (but except fexpr calls).

  • Passes named arguments to the parameters that have a matched name.
  • Passes positional arguments to their matched position in the parameter list excluding already matched named parameters.

For example, assume that there’s a defined function f:

f := \(a, b, c, d) { [a, b, c, d] }

Then four applications of the following code share the same return value [1, 2, 3, 4]:

f(1, 2, 3, 4)
f(a: 1, b: 2, c: 3, d: 4)
f(d: 4, c: 3, 1, 2)
f(2, a: 1, d: 4, 3)

But rarely, fexprs can have a their different rule of arguments passing. For a representative instance, list comprehensions are not a specific syntax of Veeyu, but implemented by a fexpr aware to its exact argument positions and names.

<argument-list>         ::= [ <argument> { "," <argument> } [ "," ] ]
<unnamed-argument-list> ::= [ <form> { "," <form> } [ "," ] ]
<argument>              ::= [ <symbol> ":" ] <form>

Runtime Library

Runtime library defined this section is core of Veeyu. All names are defined under veeyu module, imported automatically.

Glossary

abstract class

An instance of <abstract-class>; cannot be instantiated directly and would be subclassed.

class

An instance of <class>.

instance of <c>

An object that has <c> as its +class property.

kind of <t>

An object that satisfies <t>.is-type?(object) returns true i.e. object.isa?(<t>) returns true.

method

A property, an instance of <method>.

type

An instance of <type>.

union type

An instance of <union-type>.

intersection type

An instance of <intersection-type>.

Control Structures

macro \

Actually there’s no special syntax for defining functions. Instead, Veeyu provides \ macro defined in the standard runtime library. You can define functions like the following code:

factorial := \(integer) {
  (integer > 1) then (factorial(integer - 1) * integer, 1)
}

It supports lexical scoping as well.

adder := \(number) {
  \(delta) {
    number = number + delta
  }
}

The number variable is not a local variable of the inner function, but the outer function (adder).

>>> a := adder(1); a(1)
==> 2
>>> a(2)
==> 4
>>> b := adder(1); b(1)
==> 2

Note that = operator is used instead of :=. When := is used, number always becomes defined again as local variable.

>>> adder2 := \(number) {
...   \(delta) { number := number + delta }
... }
==> \(number) { ... }
>>> c := adder2(1); c(1)
==> 2
>>> c(1)
==> 2
>>> c(2)
==> 3

macro assert

The assert macro is a way to insert debugging assertions into a program.

a := 1
b := 2
assert (b == (a + 1))

The above code becomes compiled into (with debug mode):

a := 1
b := 2
(b == (a + 1)).then(<assert-error>().rise!(), nil)

It takes an optional second argument, the message string of <assert-error>, also.

assert (b == (a + 1), "b must be a + 1")

The above code is compiled to (with debug mode):

(b == (a + 1)).then(<assert-error("b must be a + 1").rise!(), nil)

The assert macro is ignored when debug mode is turned off. Every assert call is compiled into empty expression. So, the efficiency of compiled program without debug mode is equivalent to the same program without assert calls.

Basic Types

class <boolean>, a subclass of <function>

<boolean> is the type of the values false and true for logical operations. There are only two instances of <boolean> class: the true and the false. And it cannot be subclassed.

attribute not

Logical complement. The negated logical value.

The true when the boolean value is the false, otherwise the false.

The below code is its reference implementation:

true.not := false
false.not := true
method +apply returns <object>

Returns a given true-value when this is the true, and returns a given false-value when this is th false.

true-value

A value that is going to be returned when the boolean value is the true.

false-value

A value that is going to be returned when the boolean value is the false.

The below code is its reference implementation:

true.+apply := \(true-value, false-value) {
  true-value
}

false.+apply := \(true-value, false-value) {
  false-value
}
macro then returns <object>

Evaluates true-value and returns its evaluation result if this boolean value is the true. (false-value is not evaluated in this case.)

Evaluates false-value and returns its evaluation result if this boolean value is the false. (true-value is not evaluated in this case.)

The key difference between this and +apply (of <boolean>) is that the former evaluates only one of its arguments, but but latter evaluates all of its arguments.

true-value

A value that is going to be returned when the boolean value is the true.

false-value

A value that is going to be returned when the boolean value is the false.

The following code is the reference implementation:

true.then := macro (true-value, false-value) {
  true-value(environment)
}

false.then := macro (true-value, false-value) {
  false-value(environment)
}
macro and returns <boolean>

Logical conjunction.

Always returns the false without any evaluation of the operand when this boolean value is the false, otherwise evaluates the operand then tests truth value of its evaluation result.

Returns the false if the evaluation result of the given operand is considered false.

Returns the true when this boolean value and the evaluation result of the operand are both considered true.

operand
A value to be tested for truth value.

The below code is its reference implementation:

true.and := macro (operand) {
  <boolean>(operand(environment))
}

false.and := macro (operand) {
  false
}
macro or returns <boolean>

Logical disjunction.

Always returns the true with no evaluation of the given operand when this boolean value is the true, otherwise evaluates the operand then tests truth value of its evaluation result.

Returns the true if the evaluation result of the given operand is considered true.

Returns the false when this boolean value and the evaluation result of the operand are both considered false.

operand
A value to be tested for truth value.

The below code is its reference implementation:

true.or := macro (operand) {
  true
}

false.or := macro (operand) {
  <boolean>(operand(environment))
}
method and? returns <boolean>

Logical conjunction with applicative order.

Always returns the false when this boolean value is the false. Otherwise, returns operand.

The key difference between this and macro and (of <boolean>) is that the former always evaluates operand, but the latter evaluates operand only when this boolean value is true.

operand
A value to be tested for truth value.

The below code is its reference implementation:

true.and? := \(operand) {
    operand
}

false.and? := \(operand) {
    false
}
method or? returns <boolean>

Logical disjunction with applicative order.

Always returns the true when this boolean value is the true. Otherwise, returns operand.

The key difference between this and macro or (of <boolean>) is that the former always evaluates operand, but the latter evaluates operand only when this boolean value is false.

operand
A value to be tested for truth value.

The below code is its reference implementation:

true.or? := \(operand) {
    true
}

false.or? := \(operand) {
    operand
}

abstract class <number>

It is an abstract root class for several number types e.g. <complex>, <real>, <rational>, <integral>.

abstract class <complex>, a subclas of <number>

Complex numbers have a real and imaginary part, which are each a <real> number.

abstract method + returns <complex>

Adds this number and operand and then returns the result of addition. This operation has to be commutative and associative.

operand (<complex>)
The second operand of addition.
abstract method - returns <complex>

Subtracts subtrahend from this number and returns the result it has.

subtrahend (<complex>)
The subtrahed of subtraction operation.
abstract method * returns <complex>

Multiplies this number by operand and then returns the result of multiplication. This operation has to be commutative, associative and distributive.

operand (<complex>)
The second operand of multiplication.
abstract method \ returns <complex>

Divides this number into divisor and then returns its quotient.

divisor (<complex>)
The divisor operand of division operation.
abstract property real is a <real>

The real part of this complex number.

abstract property imaginary is a <real>

The imaginary part of this complex number.

abstract method conjugate returns <complex>

Returns the conjugation.

abstract class <real>, a subclass of <complex>

A real number value.

method ceil returns <integer>

Returns the ceiling of this number, the smallest integer greater than or equal to this number.

method floor returns <integer>

Returns the floor of this number, the largest integer less than or equal to this number.

class <string>, a subclass of <sequence>

It is a data structure for storing and manipulating a string. Implementations can choose the right algorithms for their jobs e.g. ropes or ordinary array-based strings.

It has to be immutable and doesn’t have any operations that manipulate string itself in-place. We recommend to implement this as rope for such reason.

method replace returns <string>

Returns a new <string> of it with all occurrences of substring old replaced by new.

old (<string>)

The old string to be replaced by new.

new (<string>)

The new string to replace with old.

method trim-first returns <string>

Returns a new <string> of it with leading whitespace characters removed.

method trim-last returns <string>

Returns a new <string> of it with trailing whitespace characters removed.

method trim returns <string>

Returns a new <string> of it with trailing and trailing whitespace characters removed.

Object Protocol

Veeyu has modern and powerful object-oriented runtime type facilities: metaclasses, multiple inheritance (using C3 linearization) and multimethods.

abstract class <object>

The <object> is the root of the class hierarchy. Every class has <object> as a superclass at least. All objects implement the methods of this class.

By default, every object is immutable; their attributes cannot be changed after instantiated once.

class method +make returns <object>

Creates a new instance of the class with attributes that are given by keyword arguments. And returns a created new instance.

Variable keyword arguments
Attributes of the instance to be created.

For example, <object>(a: 1, b: 2) calls the following code internally:

<object>.+make(a: 1, b: 2)
property +class

The <class> instance what class the object has instantiated from.

ExampleEvaluated value
"str".+class<string>
c'a'.+class<character>
:sym.+class<identifier>
:(a.b).+class<attribute>
method +isa? returns <boolean>

Returns true when the object is a kind of a given type. It exactly equals to type.is-type?(object) when type is a <type> instance and object is the object.

type (<type>)
A type object to check.
property +hash

The integer that equals for equal objects even if objects have identically different references. This number has a enough precision in instances of the same class. There’s no defined exact rule to generate this number and it depends on implementation details. By default, its value equals to the instance’s +id value, but it can be overridden on subclasses.

This property is used for finding the equality of an object.

method +get-attribute returns <object>

Returns a value of the attribute name.

name (<attribute-name>)
A name of the attribute to get.

For example, two variables named hash and hash2 in the following code have the same value:

hash  := an-object.+get-attribute(:+hash)
hash2 := an-object.+hash
macro && returns <object>

Returns this value when it is considered false in boolean context without any evaluation of operand.

Otherwise, evaluates operand and then returns its evaluation result.

operand
A value to be tested for truth value.
macro || returns <object>

Returns this value when it is considered true in boolean context with no evaluation of operand.

Otherwise, evaluates operand and then returns its evaluation result.

operand
A value to be tested for truth value.

abstract class <type>

The abstract base class for Veeyu’s runtime type system. It makes the type protocol of Veeyu extensible by user.

abstract method is-type? returns <boolean>

It is a method for implementing +isa? method of an every object. Returns true when a given object is a kind of the type.

object
An object to check.
method | returns <union-type>

Returns the type which represents the disjunction of given operand types respectively.

<integer-or-string> := <integer> | <string>
operand (<type>)
The type to make <union-type> with.
method & returns <intersection-type>

Returns the type which represents the conjunction of given operand types respectively.

<mutable-enumerable> := <mutable-object> & <enumerable>
operand (<type>)
The type to make <intersection-type> with.

class <union-type>, a subclass of <type>, <type-set>

The type which represents the disjunction of types in the set respectively.

<integer-or-string> := <union-type>(<integer>, <string>)

class <intersection-type>, a subclass of <type>, <type-set>

The type which represents the conjunction of types in the set respectively.

<mutable-enumerable> := <intersection-type>(<mutable-object>, <enumerable>)

class <predicate-type>, a subclass of <type>

It adapts a predicate function to <type> interface.

<odd-number> := <predicate-type>: \(value: <integer>) {
  value.rem(2) == 1
}
predicate (<function>)
The predicate function which takes a value and returns a <boolean> result.

class <abstract-class>, a subclass of <type>

The class for abstract classes. Its every instance cannot create new instances of that.

method is-type? returns <boolean>

Returns true when object.+class is this class or a subclass of this class.

object
An object to check.
method subclass returns <class>

Makes a subclass the (abstract) class, and then returns the made subclass.

Variable keyword arguments
Attributes of the class to be defined.

class <class>, a subclass of <abstract-class>, <function>

The construct that is used as a template to create instances of that class. Classes are values as well, and these are instance of <class> class. So creating a class is just making an instance of <class>:

<point> := <class>(x: <integer>,
                   y: <integer>)

In the above example, <point> class has two attributes: x and y. In order to instantiate a class, just call it:

p := <point>(x: 10, y: 15)

Every <abstract-class> object has the subclass method for inheritance:

<point3d> := <point>.subclass(z: <integer>)
p3d := <point3d>(p, z: 20)
Variable keyword arguments
Attributes of the class to be defined.

There’s a more flexible way to define attributes and methods as well:

<point> := <class> {
  +make := class-method (x: <integer>, y: <integer>) {
    super.+make(x: x, y: y)
  }

  is-aligned-horizontally? := method (point: <point>) {
    self.y == point.y
  }

  is-aligned-vertically? := method (point: <point>) {
    self.x == point.x
  }
}
method +apply returns <object>

Creates a new instance of this class and returns it. Exactly it is a just proxy method to +make user-defined per-instance method: all arguments of this method are transparently passed to +make method and a value +make method application returns is returned straight.

abstract class <descriptor>

Every class (including abstract classes) has their own prototype, and its instance finds an attribute from itself to prototype of its class.

When the attribute dispatcher (+get-attribute) found an attribute value from prototype of the class and it is a <descriptor>, one more procedure has injected: .

abstract method get returns <object>

Called to get the attribute of the receiver.

receiver
The receiver object of the attribute.

abstract class <mutable-object>

Veeyu objects are immutable and stateless by default, but it is a special class for stateful objects. Subclassing <mutable-object> makes attributes of instances able to be changed.

method +initialize! returns <nil>

The constructor method of nondeterministic version that is called after a instance has instantiated.

A returned value of this method is just ignored silently.

property +id

The identical but arbitrary integer for the same reference’s object. This value is unique for respective objects. This specification doesn’t define any detail approach to generate this number and it’s just implementation details. The typical way is to use memory addresses of objects.

This property is used for finding the identity of an object.

abstract class <mutable-descriptor>, a subclass of <descriptor>

Descriptor interface for <mutable-object>. It defines two more abstract methods in addition to abstract method get of abstract class <descriptor> for defining and undefining an attribute.

abstract method define returns <object>

Call to define the attribute on the receiver as the value.

receiver

The receiver object of the attribute.

value

The new attribute value to set.

abstract method undefine

Called to undefine the attribute on the receiver.

receiver
The receiver object of the attribute.

Forms

Veeyu is a homoiconic language like Lisp. Therefore it has to provide classes for representing its codes. There are several types of forms in Veeyu. Form classes are straight model classes of them. An instance of these classes can be created with a quote syntax also, not only by these constructors.

macro quote returns <form>

Quotes a given form.

What it does basically is equivalent to a quote syntax, but the main difference is a form interpolation. In this macro, ~ symbol is interpreted as an unquote to interpolate a form. For example,

f := :y
quote(x + ~f + x.~f)

is evaluated to:

:(x + y + x.y)

In order to escape ~ to express ~ as just a symbol, not an unquote, use ~~ instead. In the same manner, in order to express ~~, use ~~~. For example,

f := :x
quote(f + ~f + ~~f + ~~~f + ~~~~f)

is evaluated to:

:(f + x + ~f + ~~f + ~~~f)
form
A form to be quoted.

abstract class <node>

The abstract base class of AST nodes e.g. <form>, <symbol>, <program>.

abstract class <form>, a subclass of <function>, <node>

Every form class is its subclass.

method quote returns <quote>

Returns an instance of <quote>, of this form.

method +apply returns <object>

Evaluates this form in the environment then returns its evaluation result.

environment
An environment object.
method replace returns <form>

Replaces all forms that equals to old of in the entire form tree with new form, then returns its resulted form.

For example,

:(a + b + (c - d)).replace(:c, :k)

returns:

:(a + b + (k - d))

There’s no limit of form type, so:

:(a + b + (c - d(e - f) * g)).replace(:(d(e - f)), :h)

returns:

:(a + b + (c - h * g))

By default, it doesn’t find old forms in the quoted forms. For example,

:(a + :(b + c)).replace(:b, :d)

returns just:

:(a + :(b + c))

Because there’s b, but it is quoted. In order to dig quoted forms also, turn the including-quote option on.

:(a + :(b + c)).replace(:b, :d, includng-quote: true)

will return the form you expected:

:(a + :(d + c))
old (<form>, <function>)

A form to be replaced by new form.

new (<form>, <function>)

A form to replace old forms.

including-quote (<boolean>)

Whether it digs <quote> forms also. Default is false.

class <quote>, a subclass of <form>

class method +make returns <quote>

Returns a <quote> instance that quotes the form. It is the same as form.quote().

form (<form>)
A form to be quoted.
property form

The quoted <form> instance.

abstract class <attribute-name>, a subclass of <form>

The abstract base class of forms that can be used as <attribute> forms’ name such as <symbol>, <index> or <block>.

class <symbol>, a subclass of <attribute-name>

Symbol forms.

>>> :hello.+class
<symbol>
class method +make returns <symbol>

Gets a symbol.

symbol (<symbol> | <string>)
A symbol or symbol name string. If the given string is invalid, it raises <type-error>.

class <index>, a subclass of <attribute-name>

Index forms.

>>> :([123]).+class
<index>

class <block>, a subclass of <attribute-name>

Block forms.

>>> :({ block! }).+class
<block>
class method +make returns <block>

Creates a <block> form.

program (<sequence> of <form>)
A program which consists of forms.
property program is a <program>

The program that the block contains.

class <attribute>, a subclass of <form>

class method +make returns <attribute>

Creates an <attribute> form object.

>>> <attribute>(:receiver, :attribute)
:(receiver.attribute)
>>> <attribute>(:receiver, :([123]))
:(receiver[123])
>>> <attribute>(:receiver, :({ block! }))
:(receiver { block! })
receiver (<form>)

The receiver form.

attribute (<attribute-name>)

The attribute name.

property receiver is a <form>

The form that is thae receiver of the message.

property attribute is a <attribute-name>

The attribute name.

class <program>, a subclass of <node>, <sequence>

A list of forms.

class method +make returns <program>

Creates a <program> node.

forms (<sequence> of <form>)
A list of forms.

Exceptions

Veeyu provides exception handling mechanism and basic hierarchy of exceptions and errors.

abstract class <signal>

The abstract base class for all built-in exceptions.

method rise! returns <nil>

Terminates current running function call and raises itself up to call stack until it has caught.

class <exception>, a subclass of <signal>

All exceptions subclass this class except <signal>s to control language.

class <error>, a subclass of <exception>

All errorss subclass this class.

class <return>, a subclass of <signal>

In Veeyu internals, value returning of function is implemented by raising <return> signal exception with a value to return. For example,

f := \() {
  <return>(value: 123).rise!()
}

val := f()

is equivalent to the following code:

f := \() {
  return (123)
}

val := f()

In other words, in the local environment of function body, return function is implemented like:

return := \(value) {
  <return>(value).rise!()
}
class method +make returns <return>

Creates a <return> instance with the value to return.

value
A object to return.
attribute value

The value a function returns.

function raise

Just raises an exception. It is equivalent to exception.rise!() except it also takes any subclass of <signal> instead of instance of <signal>. Therefore, the following two lines have the same behavior:

raise: <exception>()
raise (<exception>)

Its return value is so meaningless that it’s undefined.

exception (<signal>)
An exception object.

Data Structures

Veeyu contains several common data structures like strings, hash maps. You can find test codes for them in the directory /runtime/tests/data-structures/.

abstract class <container>

It is a type abstracts the most common concepts of data structures: contains? and add. Every instance of <container> have to satisfy that c.add(e) contains? e where c is an instance of <container> and e is an instance of a type c accepts as its element. It assumes that the container is immutable by default.

abstract method contains? returns <boolean>

Returns true only when the container contains an element. This method is deterministic.

element
An element object to test whether the container has.
method add returns <container>

Returns a new <container> instance contains the element. This method is deterministic and never manipulates the container itself.

element
An element object to be contained.

abstract class <enumerable>, a subclass of <container>

It is a type abstracts the common concepts of traversable <container>s: first, rest and concatenation(++).

abstract property null

A <boolean> value whether the container is empty. It is false if it has any one or more elements. Otherwise, it is true.

abstract property first

The first element of the enumerable container. This property is deterministic. It is nil when the container is empty.

abstract property rest

A <enumerable> container that contains all elements of the original container except its first element.

method ++ returns <enumerable>

Returns a new <enumerable> instance concatenates a container after the original container.

container (<enumerable>)
An enumerable sequence to be appended.
method fold returns <object>

Aggregates values in the enumerable container then returns the aggregated value. The order of values to be aggregated is not deterministic. For instance, this method can be run in parallel internally, for efficiency. Therefore, binary-operation should satisfy that binary-operation(v1, v2) == binary-operation(v2, v1) (commutative law) and binary-operation(v1, binary-operation(v2, v3)) == binary-operation(binary-operation(v1, v2), v3) (associativity).

If you look for the similar method that guarantee the left-to-right order of operations, find fold-left method of the <sequence> class.

For example, the following code calculates the sum of l, assumed that it is an <enumerable> and contains integers only:

l.fold(\(a, b) { a + b }, 0)

For another simpler example, the following code calculates the cardinality of l, assumed <enumerable>:

l.fold(\(a, b) { a + 1 }, 0)
binary-operation (<function>)

A function which takes two arguments. It should satisfy commutative law and associativity both.

identity

An identity element for the binary-operation. If the enumerable container is empty, this method returns the identity as it is.

The following code is the reference implementation:

method (binary-operation: <function> taking 2, identity) {
  empty := nil +is? self.rest
  empty.then(identity,
             binary-operation(identity,
                              self.rest.fold(binary-operation, self.first)))
}
method is-all?

Tests whether its all elements are true. It optionally takes an argument map as well.

map (<function>)
A predicate function that takes an element and returns a <boolean> value. Default is <boolean>.

The next code is the reference implementation:

method (map(<function> taking 1) := <boolean>) {
  self.null.then(true,
                 map(self.first) and self.rest.is-all?(map))
}
method is-any?

Tests whether one or more elements are true. It optionally takes an argument map as well.

map (<function>)
A predicate function that takes an element and returns a <boolean> value. Default is <boolean>.

The next code is the reference implementation:

method (map(<function> taking 1) := <boolean>) {
  self.null.then(false,
                 map(self.first) or self.rest.is-any?(map))
}
method each!

A non-deterministic method that iterates through its elements and apply each element to do! function.

do! (<function>)
A function that takes one argument and maybe non-deterministic.

The next code is the reference implementation:

method (do!: <function> taking 1) {
  empty := nil +is? self.rest
  empty({},
        { do!(self.first)
          self.rest.for-each!(do!) })()
}

abstract class <sequence>, a subclass of <enumerable>,

<indexable>

It is a type abstracts the common concepts of randomly accessible sequential <container>s.

method fold-left returns <object>

This method does an operation similar to the fold method of <enumerable> class, but it guarantee that its elements are joined from left to right. Therefore, the binary-operation have not to satisfy commutative law or associativity either.

For exmaple, the next code returns 85:

"""It calculates `100 - 1 - 2 - 3 - 4 - 5`."""
[1, 2, 3, 4, 5].fold(\(a, b) { a - b }, 100)
binary-operation (<function>)

A function which takes two arguments.

identity

An left identity element for the binary-operation. If the enumerable container is empty, this method returns the identity as it is.

The following code is the reference implementation:

method (binary-operation: <function> taking 2, identity) {
  empty := nil +is? self.rest
  empty.then(identity,
             binary-operation(identity,
                              self.rest.fold-left(binary-operation,
                                                  self.first)))
}

abstract class <map>, a subclass of <container>, <indexable>

It is a type abstracts the common concepts of maps, also called dictionaries, e.g. hash maps, associative arrays.

Module System

Veeyu provides facilities of modules, packages and namespaces to support modular programming.

Filesystem Layout

Similar to other popular programming languages like Java or Python, Veeyu’s module layout is designed in consideration of filesystem-based packaging. It’s slightly simple: the Veeyu file suffixed .vu becomes a module of the same name (a suffix .vu goes, of course).

For example, starman.vu becomes a module named just starman.

This rule should be implemented in most of, filesystem-based platform, but if the platform is not filesystem-based, an implementation can consider alternative layouts that is not based on filesystem.

macro require

require is a built-in macro that imports modules. Its syntax is:

require: module-name

The above imports a module named module-name. It takes one or more arguments and imports specified modules. For example, the following code imports two modules named datetime and regex:

require: datetime, regex

It’s possible to import only an attribute including submodules in a module. For example, the following code imports a module bytes.encodings, becomes named as just encodings, and an object io.*stdout*, also becomes named as just *stdout*:

require: bytes.encodings,
         io.*stdout*

So you can use bytes.encodings by the name encodings instead of bytes.encodings, and io.*stdout* also can be used by the name *stdout* in the same manner:

message := 'Hello modular programming!'
bytes := encodings.<utf-8>.encode(message)
*stdout*.write-line!(bytes)

Note that it defines no symbols like bytes or io — because its main purpose is to avoid namespace pollution.

Also you can name module to be imported by yourself — use definition form:

require: encs := bytes.encodings,
         stdout := io.*stdout*

function import returns <object>

import is a function lower than require (which can be implemented by using import function). It takes a module name (in <symbol>) then returns the imported module object.

For example:

require: bytes.encodings

The above code using require macro can be replaced with the above equivalent code using import function:

encodings := import(:(bytes.encodings))
module-name (<symbol>)
The name of the module to import.

Under the hood

Like other many things of Veeyu, modules also are first-class objects. Technically, each module is an instance of <module> class, so you can instantiate a module by hand:

hello := <module>()

Note that <module> is not a <mutable-object>, so you cannot define any functions or classes if it has instantiated once. In order to make a module to imply functions or classes you define, put an <environment> object, has functions and classes, when you initialize a <module>.

hello-env := <environment>()
with (hello-env) {
  greet := \(name) {
    'Hello ' ++ name
  }
}
hello := <module>(hello-env)

Then, use the module named hello.

>>> hello.greet('Hong Minhee')
==> 'Hong Minhee'

macro use-literal

Special-purpose importing macro. It makes the source able to use third party defined literals. For example:

use-literal: bytes (B)
example := B'byte string'

indicates the rest of the source code can use B-prefixed string literals like B'byte string'.

Under the hood, the above example code is equivalent to the following code:

require: io.bytes.+literal-B-type, io.bytes.+literal-B

You can use alternative prefix character also:

use-literal: bytes (B: o)
example := o'byte string'

Standard Libraries

Veeyu provides several standard libraries like input/output facilities, text processing tools, concurrent programming tools, network programming libraries, etc by default. It’s Veeyu’s “included batteries.”

module bytes — Byte Strings

It provides byte type and bidrectional codec interface between bytes and string.

literal B

This module defines prefix character B for byte string literal.

use-literal: bytes (B)
example := B'byte string'

Byte string literals are evaluated as a value kind of <sequence> of bytes.<byte>.

class bytes.<byte>

The byte character.

class bytes.<encoding>

It is an abstract base class for string—bytes codecs.

module bytes.encodings — Codecs

class bytes.encodings.<ascii>, a subclass of bytes.<encoding>

ASCII encoding implementation.

class bytes.encodings.<latin-1>, a subclass of bytes.<encoding>

ISO/IEC 8859–1, also known as Latin–1, encoding implementation.

class bytes.encodings.<utf-7>, a subclass of bytes.<encoding>

UTF–7 encoding implementation.

class bytes.encodings.<utf-8>, a subclass of bytes.<encoding>

UTF–8 encoding implementation.

class bytes.encodings.<utf-16>, a subclass of bytes.<encoding>

TODO

class bytes.encodings.<utf-16-be>, a subclass of

bytes.encodings.<utf-16>

TODO

class bytes.encodings.<utf-16-le>, a subclass of

bytes.encodings.<utf-16>

TODO

class bytes.encodings.<utf-32>, a subclass of bytes.<encoding>

TODO

class bytes.encodings.<utf-32-be>, a subclass of

bytes.encodings.<utf-32>

TODO

class bytes.encodings.<utf-32-le>, a subclass of

bytes.encodings.<utf-32>

TODO

module io — Input/Output Streams

To make programs useful, these have to interact with “outer world” e.g. users, other programs. This module abstracts generalized stream concept from channels for such communications.

abstract class io.<input-stream>, a subclass of

<mutable-object>

io.<input> is a basic interface class for input stream. It forces subclasses to implement instance methods read! and read-line!.

abstract method read! returns <sequence> of bytes.<byte>

Reads size bytes from the buffer and returns it. It returns an empty byte string when there’s no remaining bytes to read.

size (<unsigned-integer>)
The size of bytes to read.
abstract method read-line! returns <sqeuence> of bytes.<byte>

Reads a line from the buffer and returns it. The result includes trailing new line character(s) e.g. "\n", "\r\n". It returns an empty byte string when there’s no remaining bytes to read.

abstract class io.<output-stream>, a subclass of

<mutable-object>

io.<output-stream> is a basic interface class for ouput stream. It forces subclasses to implement an instance method write!.

abstract method write! returns <nil>

Writes given bytes to the buffer.

bytes (<sequence> of bytes.<byte>)
Bytes to write into the buffer.
method write-line! returns <nil>

Similar to write! method except it also writes trailing new line character and flush as well.

bytes (<sequence> of bytes.<byte>)
Bytes to write into the buffer.