Skip to content

Latest commit

 

History

History
807 lines (528 loc) · 13.9 KB

ELVA.md

File metadata and controls

807 lines (528 loc) · 13.9 KB

elva language specification

Elva is a tiny LISP on Java. Everyone can write elva by learning only how to define functions and macros and how to call the Java APIs.

Why Elva?

The elva specification is very small and is independent of the complex traditions of Common Lisp and Scheme. Unlike Clojure, you don't have to keep up with the latest language evolution to maintain the programs. This is a great advantage for domain-specific issues.

Learn Elva

Everything you need to learn is written on this page. If you find a function or macro that you are not familiar with, you can always find the definition by following the source code dependencies.

Evaluation

A program is written as an atom or a list form. Atoms are all values that are not lists, e.g., a symbol, type, number, boolean, string, function, macro, and other Java objects. Unlike lists, they cannot be disassembled, so they are called atoms.

1919810 ;atom
"Hello" ;atom
(3 6 4) ;list

Elva evaluates these programs according to the following rules.

  • The value of an atom is the atom itself.
  • The value of a symbol is the variable value referenced by the symbol.
  • For lists, apply the operator at the first element to the subsequent list elements.

There are no exceptions.

Atom

Symbol

The following shows an example of defining and referencing the variable JR1ZTT.

(setq JR1ZTT 1420)
JR1ZTT ;1420

If there is no variable with the specified name, the symbol will be resolved as the name of the Java class.

(import java.lang.String)
String ;java.lang.String

Number

A number is an instance of Number, e.g., an int, long, float, double and BigDecimal. The entity of integer literal is an int, and all other numeric literals with a decimal point are BigDecimals.

1919810 ;int
364.364 ;BigDecimal

Boolean

A boolean literal is an instance of Boolean.

#t ;true
#f ;false

String

A string literal is an instance of String.

"Ramen Yatai"

Object

Any other atoms are instances of Object.

List

A list is a data structure in which multiple elements are arranged in order. A list is an instance of List.

'(1 2 3) ;a list whose contents are 1, 2, and 3

To create a list, use the list function.

(list 1 2 3)

To insert an element at the beginning of the list, use the cons function.

(cons 1 (list 2 3)) ;(1 2 3)

Use the car function to retrieve the first element of the list. Use the cdr function to get a partial list with the second and subsequent elements of the list.

(car (list 1 2 3)) ;1
(cdr (list 1 2 3)) ;(2 3)

The nth function is an efficient way to specify an index by number and retrieve the element at that position.

(nth 0 (list 1 14 5 14)) ;1
(nth 2 (list 1 14 5 14)) ;5

Note that Java arrays are handled as lists in elva.

Function

A function works as the C and Java programmers know. You can define some functions add and mul as follows.

(defun add (x y z) (+ x y z))
(defun mul (x y z) (* x y z))

These functions take three values as arguments and calculate the sum or product. To call these functions, write as follows.

(add 1 2 3) ;  6
(mul 3 6 9) ;162

Note that the function arguments are evaluated before calling the function. Therefore, you can specify the value of a function as an argument to another function as follows.

(add (mul 5 9 9) (mul 1 0 0) (mul 1 1 0)) ;405
(mul (add 5 9 9) (add 1 0 0) (add 1 1 0)) ; 46

The arguments are evaluated as follows. Keep this behavior in mind and compare it to the macro behavior described below.

(add 405 0 1) ;405
(mul  23 1 2) ; 46

To create an anonymous function, use the lambda form.

(lambda () (+ 1420 16005)) ;accepts no arguments and returns 17425
(lambda (x y z) (+ x y z)) ;accepts three arguments

These anonymous functions can be called in the same way as named functions.

((lambda (x y) (* x y)) 100 110) ;11000

In fact, the defun macro is syntactic sugar equivalent to the following expression.

(defmacro defun (name params body) (list 'setq name (list 'lambda params body)))

Macro

A macro is a function that transforms a macro call into another expression and evaluates the converted expression. The functions add and mul introduced above can be redefined as macros as follows.

(defmacro add (x y z) (list + x y z)) ;will expand x,y,z into the template (+ x y z)
(defmacro mul (x y z) (list * x y z)) ;will expand x,y,z into the template (* x y z)

And you can use them like functions.

(add (mul 5 9 9) (mul 1 0 0) (mul 1 1 0)) ;405
(mul (add 5 9 9) (add 1 0 0) (add 1 1 0)) ; 46

However, macros are not functions. First, the macro call is evaluated as follows:

(+ (mul 5 9 9) (mul 1 0 0) (mul 1 1 0)) ;405
(* (add 5 9 9) (add 1 0 0) (add 1 1 0)) ; 46

Great. By using the list function, both macros embed their arguments into the template without evaluating the arguments. The converted expression is then evaluated as follows.

(+ 405 0 0) ;405
(*  23 1 2) ; 26

Unlike functions, macros give you the freedom to decide whether to evaluate an argument or treat it as data without evaluating it. Macros are a good way to implement some syntax or domain-specific languages in LISP. To create an anonymous macro, use the syntax form.

(syntax () (+ 1420 16005)) ;accepts no arguments and returns 17425
(syntax (x y z) (+ x y z)) ;accepts three arguments

These anonymous macros can be called in the same way as named macros.

((syntax (x y) (* x y)) 100 110) ;11000

In fact, the defmacro macro is syntactic sugar equivalent to the following expression.

(defmacro defmacro (name params body) (list 'setq name (list 'syntax params body)))

Java APIs

To import a Java class, use the import function.

(import java.lang.String)

You can access the Java constructor by using the new function.

(new Integer int) ;Integer::new

To reference a Java method, use the method function.

(method 'length String) ;String.length()

Give arguments to call the constructor and method.

((method 'replaceAll String String String) "foobar" "r" "z") ;"foobaz"
((method 'replaceAll String String String) "foobar" "f" "b") ;"boobar"

For instance methods, the first argument must be the instance. This argument is not required when calling constructors or static methods. The second and subsequent arguments are passed to the constructor or method as their arguments. To reference a Java field, use the access function.

((access 'x Point) ((new Point int int) 123 321)) ;123
((access 'y Point) ((new Point int int) 123 321)) ;321

If you do not mind the processing efficiency, Java APIs can be referenced using the new!, method!, and access! functions.

((new! Integer) 123)
((method! 'replaceAll) "foobar" "r" "z")
((access! 'x Point) ((new! Point) 12 3))

Passing an elva list to a Java method will convert the list to a Java List. If the method requires an array, the list will be converted to an array.

Quotation

Quoting is an important feature that realizes LISP's powerful metaprogramming capabilities. The quote form controls when the expression is evaluated.

(quote (+ 1 2 3)) ;a list (+ 1 2 3)

The quote form accepts a single expression as an argument and returns it as is without evaluation. You can abbreviate the quote form as follows.

'(+ 1 2 3) ;is equivalent to (quote (+ 1 2 3))

There is another version of quoting, namely quasiquote.

`(+ 1 2 3)
(quasiquote (+ 1 2 3))

You can unquote some sub expressions in the quasi-quoted expression. These sub expressions are evaluated exceptionally. You can use the unquote function or a special symbol ` for this purpose.

`(+ 1 2 ,(+ 1 2)) ;(+ 1 2 3)

There is another version of unquoting, called unquote-splicing. This evaluates the unquoted sub expression as a list and then embeds the elements to the expression as a list.

`(+ 1 2 ,@(list 3 4 5)) ;(+ 1 2 3 4 5)

System Functions

absence

creates and returns a absence object.

(absence name code)

access

returns the field with the specified name.

(access 'name class)

access!

returns the field with the specified name.

(access! 'name)

+

performs addition and returns a real value.

(+ real1 *reals)

and

performs and operation and returns a bool value.

(and bool1 *bools)

array

returns an array type.

(array element-type)

assert

throws an error if the expression returns false.

(assert condition message)

block

evaluates the expressions inside a nested scope.

(block *expressions)

cadr

returns the second element of the specified list.

(cadr list)

car

returns the first element of the specified list.

(car list)

case

evaluates the expression specified by the key.

(case condition (key value)*)

catch

evaluates the expression and returns an error.

(catch expression)

cddr

returns the third and subsequent elements of the specified list.

(cddr list)

cdr

returns the second and subsequent elements of the specified list.

(cdr list)

cons

concatenates the specified value and list into a list.

(cons first second)

contest

creates and returns a contest object.

(contest name host mail link start-day final-day dead-line)

/

performs division and returns a real value.

(/ real1 *reals)

eq

performs identify test and returns a bool value.

(equal value1 value2)

equal

performs equality test and returns a bool value.

(equal value1 value2)

eval

evaluates the specified value.

(eval value)

format

formats a string using the specified arguments.

(format string *arguments)

>=

performs greater-equal operation and returns a bool value.

(>= real1 *reals)

>

performs greater operation and returns a bool value.

(> real1 *reals)

if

evaluates the first (or second) expression if true (or false).

(if condition first second)

import

imports the specified class.

(import class)

lambda

creates and returns an anonymous closure.

(lambda (parameters) body)

<=

performs less-equal operation and returns a bool value.

(<= real1 *reals)

length

returns the length of the list.

(length list)

let

creates a local variable and evaluates the expression.

(let variable value expression)

list

creates a list of elements as specified.

(list *elements)

load

loads the specified LISP file.

(load string)

<

performs less operation and returns a bool value.

(< real1 *reals)

member

tests if the list contains the specified value.

(member value list)

method

returns a method with the specified name.

(method 'name class *parameter-types)

method!

returns a method with the specified name.

(method! 'name [class])

mod

performs modulo and returns a real value.

(mod real1 *reals)

*

performs multiplication and returns a real value.

(* real1 *reals)

name

returns a qualified name in the specified namespace.

(name namespace local-name)

new

returns a constructor of the specified class.

(new class *parameter-types)

new!

returns a constructor of the specified class.

(new! class)

nil?

tests if the argument is nil or not.

(nil? argument)

not

performs not operation and returns a bool value.

(not bool)

nth

returns the n-th element of the list.

(nth index list)

null?

tests if the argument is null or not.

(null? argument)

or

performs or operation and returns a bool value.

(or bool1 *bools)

pattern

creates and returns a pattern object.

(pattern normalize transform cross-check)

print

evaluates the argument and print its value.

(print argument)

quasiquote

quotes the expression except for some unquoted sub-expressions.

(quasiquote expression)

quote

returns the expression without evaluation.

(quote expression)

remove-if

removes elements for which the specified function returns false.

(remove-if fun list)

section

takes four functions and returns a section object.

(section name code cities verify unique entity result)

set

creates a variable with the specified name and value.

(set name value)

-

performs subtraction and returns a real value.

(- real1 *reals)

subseq

returns a subsequence of the specified list.

(subseq list start end)

symbol

returns a symbol with the specified name.

(symbol name)

syntax

creates and returns an anonymous macro.

(syntax (parameters) body)

throw

throws an error with the specified message.

(throw string)

type

returns the type of the specified value.

(type value)

unquote-splicing

embeds the specified list elements into the outer expression.

(unquote-splicing list)

unquote

embeds the specified value into the outer expression.

(unquote value)

xor

performs exclusive-or operation and returns a bool value.

(xor bool1 bool2)