Overview
Expreva is a small programming language based on arithmetic and algebra.
Its grammar and concepts are influenced by functional, list-processing, and scripting languages. It aims to be a modular, extensible language and cross-platform virtual machine.
Expreva is an exploration to design a suitable medium for end-user programming, for example: in a spreadsheet formula; for data transport or query protocol; and creation of dynamic hypertext documents and interactive textbooks.
The source code is compiled to a JSON-serializable format, suitable for transfer over HTTP, WebSocket, or inter-process communication.
The goal is to stay beginner-friendly, and simple enough to implement on a range of platforms.
Currently there is a TypeScript implementation that runs in the web browser and on Node.js servers; and one that runs on PHP. An eventual plan is to compile to WebAssembly.
Getting Started
Click on an expression and see its result on the left side of the page.
Example: 1 + 2 + 3
Try typing some numbers in the expression box to see the result change.
Language Reference
Table of Contents
Symbol
The basic building block of an expression is a symbol.
A symbol is made of one or more of the following characters.
! " # $ % & ' ( ) * + , - . / : ;< = > ? @ [ \ ] ^ _ ` { | } ~ 0 12 3 4 5 6 7 8 9 A B C D E F G H IJ K L M N O P Q R S T U V W X Y Za b c d e f g h i j k l m n o p qr s t u v w x y z
You can also use characters from any language, like あいうえお
.
Symbols are separated by a white space or new line.
A symbol can be one of the following types:
Number
Example: 42
2.5
Boolean
There are two kinds of boolean symbols: true
and false
.
Operator
An operator works with one or more expressions, and returns a value.
Operator | Description | Example |
---|---|---|
+ | Add | 1 + 2 |
- | Subtract | 3 - 4 |
* | Multiply | 5 * 6 |
/ | Divide | 7 / 8 |
^ | Exponentiation | 9 ^ 10 |
= | Assignment | x = 12 |
Comparison
These operators compare two expressions and return a boolean value.
Operator | Description | Example |
---|---|---|
== | Equal | 1 + 2 == 3 |
!= | Not equal | 1 + 2 != 3 |
> | Greater than | 3 * 3 > 3 + 3 |
< | Less than | 1 + 1 < 2 |
>= | Greater than or equal | 2 * 2 >= 2 + 2 |
<= | Less than or equal | 3 + 3 <= 2 + 3 |
&& | And | 2 == 2 && 3 == 3 |
|| | Or | 2 != 2 || 3 != 3 |
Group
The open and close parentheses ()
group expressions together.
This is used to control the order of operations.
See the difference between (1 + 2) * 3
and 1 + (2 * 3)
.
Statement
A statement is an expression that is not operating on any other expression.
In the following, there are three statements.
x = 2y = x * 3z = y * y * 4
The result of multiple statements is the value of the last statement.
Statements are separated by a white space or new line.
The exception is if a line starts or ends with an operator that connects to another expression.
1+2
Such cases are rare, but if needed, use the punctuation ;
to end a statement.
1;+2
Conditional
Use the operators ?
and :
to create a conditional expression.
It is used to control the flow of opearations based on a condition.
Such an expression has 3 parts.
- Condition that evaluates to true or false
- True branch to evaluate when true
- False branch to evaluate when false
4 * 8 == 32 ? 'Yes' : 'No'
Comment
A comment is any text you want to write that is not evaluated.
It's useful for including extra information, for example, to explain how an expression works.
Use //
to comment the rest of the line.
1 + 1 // Hello!
Create a comment block spanning multiple lines using /*
and */
.
/* Here is a comment. */
String
A string is some text created with the punctuation '
called a single quote.
Example: 'hi'
When you click on the example, you see that the result does not include the punctuations.
'
is an operator that returns what's between them, called the value of the string.
Escape character
To include '
itself in the string, use another punctuation \
before it.
'It\'s a beautiful day in the neighborhood.'
\
is called a backslash. It is used to escape the character after it, making it a string instead of a punctuation.
Variable
A variable is a name that points to another symbol.
The name has one or more characters, alphabets and numbers only. It must start with an alphabet.
Example: distance
When you click on the above example, you see the result is empty. This is because the variable doesn't have any value yet.
To make a variable point to a symbol, use the =
operator. This is called assigning a value.
distance = 50
The result of variable assignment is the value itself.
Now, when you evaluate the variable distance
, it will return its value.
A variable name cannot have a space in it. Use the underscore _
to separate words.
total_distance = 100
Function
A function takes an input, evaluates an expression, and returns an output.
Define
Use the operator =>
to define a function.
x => x + 1
A function without a name is called an anonymous function.
Assign it to a variable to give the function a name.
Usually a function name starts with a verb, because it performs an action.
add_one = x => x + 1
This is useful if you plan to use it more than once.
add_one(3) + add_one(4)
Arguments
The left part of a function definition is a list of inputs, called arguments.
Use ()
to pass arguments, separated by a comma.
(x, y) => x + y
Here, x
and y
will be passed as inputs when the function is called.
Each argument is assigned to a variable of that name, in the order given.
The argument list can be empty if the function doesn't need input.
() => 123
If there's only one argument, the ()
is not necessary.
x => x * x
Argument Defaults
The assignment operator =
can be used to provide initial values for missing function arguments.
f = (x = 1, y = 2) => x * yf(3)
Call
Call a function with ()
, optionally with a list of arguments.
say_love = (x, y) => 'I love '+x+' and '+y+'!' say_love('apples', 'bananas')
Use ()
to call an anonymous function immediately after creating.
(x => x + 1)(2)
Apply
Another way to call a function is to apply an expression to it.
Use the operator ->
after an expression to call a function with it as the first argument.
square = x => x * x (3 + 3)->square
Notice how the applied function doesn't need ()
after it.
This is equivalent to writing square(3 + 3)
.
The apply operator ->
is like a pipeline, passing the result of an expression to the next function.
It can make the flow of values easier to follow when chaining together multiple functions.
square = x => x * xdouble = x => x * 2triple = x => x * 3 3->square->double->triple
You can see that the initial value is squared, doubled, then tripled.
Compare to the following way of calling functions, where you must think "backwards" to visualize the flow of operations.
triple(double(square(3)))
You can mix the two styles to organize an expression.
square(3)->double->triple
Using functions
A function can be passed as an argument to another function.
[ 1, 2, 3 ]->map(x => x + 1)
Or after an apply operator.
1 -> x => x + 1
A function can return another function.
(x => y => x + y)(5)(6)
List
To create a list of items, use the open and close square brackets []
.
Use a comma ,
to separate each item.
[ 1, 2, 3 ]
A list can have any kind of item, including a function, the result of an expression, or another list.
[ true, 2 * 3 + 1, f = x => x * x, f(12), [ 'apples', 'oranges' ]]
List Item
To get an item from a list, use a period .
after it, and the index of the item.
An index is a number for the position of an item, counting from zero.
First, let's create a list and put it in a variable.
colors = [ 'red', 'green', 'blue' ]
Then get items by their index.
colors.0
colors.1
colors.(1 + 1)
The last example shows the index can be given as an expression.
You can get an item from any expression that returns a list.
get_letters = () => ['a', 'b', 'c']get_letters().1
Item of Item
If a list item is a list (or an object), you can combine multiple .
operators.
tic_tac_toe = [ [ 'o', '.', '.' ], [ '.', 'x', '.' ], [ 'o', 'x', 'o' ]] tic_tac_toe.1.1
Assign list item
a = [ 0, 0 ]a.1 = 1a
List Functions
There are a number of built-in functions for working with a list.
Use the operator ->
after a list to call these functions.
[ 1, 2, 3 ]->pop
You can also call them with ()
by passing a list as the first argument.
pop([ 4, 5, 6 ])
Notice that some functions, for example search
, will return another function to be called with more arguments.
size
size
returns the number of items in a list.
['red', 'green', 'blue']->size
search
search
looks for an item in a list, and returns its position index.
['red', 'green', 'blue']->search('blue')
['red', 'green', 'blue']->search('purple')
If it can't find the item, it will return -1
.
join
join
puts two lists together and returns a new list.
['red', 'green', 'blue']->join(['white', 'black'])
If given a string, it's used as a separator to combine all items into a string.
['red', 'green', 'blue']->join(' and ')
push
push
adds one or more items to the end of a list, and returns the list itself.
['white']->push('purple', 'pink')
pop
pop
removes an item from the end of a list, and returns the item.
[1, 2, 3]->pop
insert
insert
adds one or more items to a list at a specified index, and returns the list.
[0, 1, 2, 3]->insert(2, 'Here is index 2')
slice
slice
gets a section of a list and returns a new list with those items.
It takes two arguments: start index and end index.
[1, 2, 3, 4 ,5]->slice(2, 4)
If you don't pass an end index, it will get from start index to the end of the list.
[1, 2, 3, 4 ,5]->slice(2)
If the start index is negative, it will get from the end of the list.
[1, 2, 3, 4 ,5]->slice(-2)
map
map
calls a given function with each item in the list, and returns a new list with what the function returned.
['red', 'green', 'blue']->map( (item, index) => (index + 1)+'. '+item)
It passes two arguments to the function, the item and its index.
filter
filter
calls a given function with each item in the list: if the function returns true
, it keeps the item. At the end, it returns a new list with those items.
[1, 2, 3, 4, 5]->filter( (item, index) => item >= 3)
It passes two arguments to the function, the item and its index.
reduce
reduce
takes a list and adds up a total of some type, such as a number, string, or list.
[1, 2, 3, 4, 5]->reduce( (total, item) => total = total + item, 0)
reduce
takes two arguments:
- A function
- An initial value to use, called an accumulator.
In the above example, the accumulator starts with the value of zero.
For each item in the list, the given function is called with the accumulator and the item. It's expected to return a new value for the accumulator. At the end, you get the final value.
Object
An object is a kind of list where the items are in pairs, called a key and a value.
It is sometimes called a dictionary, because you "look up" a value by its key.
To create an object, use the open and close curly brackets {}
.
{ type: 'dog', color: 'red'}
Key-value pair
Use a colon :
between key and value.
{ key: 'value' }
Use a comma ,
to separate key-value pairs.
{ x: 1, y: 2, z: 3 }
Key as string
If a key has a space in it, pass it as a string.
{ 'key with space': 1 }
Dynamic key and value
The key and value can be an expression.
x = 'total'{ (x): 1 + 2}
Notice that ()
is used to set the key to the value of the variable x
.
Variable as key and value
For setting a variable's name as key and its value to an object, you can skip the :
.
key = 'value'{ key }
Value
To get a value, use the operator .
and the name of key after an object.
{ x: 1, y: 2, z: 3 }.x
To use a dynamic key, wrap it in ()
.
key = 'z'{ x: 1, y: 2, z: 3 }.(key)
If the value is an object (or a list), you can combine multiple .
operators.
{ parent: { child: 'here!' }}.parent.child
Assign value to key
a = { b: {}}a.b.c = 'hi'a
Object Functions
There are a number of built-in functions for working with an object.
Use the operator ->
after an object to call these functions.
{ a: 1, b: 2 }->keys
You can also call them with ()
by passing an object as the first argument.
keys({ c: 3, d: 4 })
size
size
returns the number of keys in an object.
{ x: 1, y: 2, z: 3 }->size
keys
keys
returns the keys in an object as a list.
{ x: 1, y: 2, z: 3 }->keys
set
set
assigns a key and its value to an object, and returns the object.
{ x: 1, y: 2, z: 3 }->set('a', 0)
If you pass an object instead of a key, it will set all keys and their values.
{ x: 1, y: 2, z: 3 }->set({ a: -1, b: -2 })
unset
unset
removes a key and its value from an object, and returns the object.
{ x: 1, y: 2, z: 3 }->unset('x')->unset('y')
Advanced Operators
Compound Assignment
There are shortcuts for assigning a new value to a variable, based on its existing value.
Let's say we start with x = 0
. Click on it for the examples below.
Compound Assignment | Example | Equivalent |
---|---|---|
++ | x++ | x = x + 1 |
-- | x-- | x = x - 1 |
+= | x += 2 | x = x + 2 |
-= | x -= 2 | x = x - 2 |
*= | x *= 2 | x = x * 2 |
/= | x /= 2 | x = x / 2 |
Spread operator
The spread operator ...
is used to assign a list of values from a variable or expression.
List
It can spread values into an list.
x = [ 1, 2, 3 ] [ 0, ...x, 4 ]
Object
With objects, it spreads key-value pairs.
x = { c: 3 }{ a: 1, b: 2, ...x}
If the same key exists, it will be overwritten with a new value.
x = { c: 3 }y = { c: 4 }{ a: 1, b: 2, ...x, ...y}
Function arguments
When used in a function argument, it gathers a list of values into a variable.
f = (x, ...y) => y f(1, 2, 3)