Programming language that elves use


Keywords
javascript, sugar, syntax, syntax sugar, elvish
License
QPL-1.0
Install
npm install elfu@0.0.40

Documentation

screenshot

#Elfu - hosti lammen

Elfu is highly experimental symbolic language. UNICODE contains thousands and thousands of symbols, why not use them?

  • Elfu stands for elvish functional language or elvish numeric gongfu.
  • Elfu in elvish is called hosti lammen, or computing language.
  • Elfu is Javascript compatible, you mix Javascript and Elfu in Elfu file.
  • Elfu file extension is .yy (this is elvish)
  • Elfu is written in Javascript itself.
  • To type symbols we use TAB completion feature of the editor.
  • Most of symbols are just replaced with their Javascript counterparts.
  • Some symbols are parsed in a special way, like or .
  • Editors known to be Elfu-friendly are Sublime Text, Geany, Deodar.
  • If your computer does not show all symbols, there is a font file [elfu.ttf][100].
  • Elfu only uses Unicode standard symbols.
  • Elfu is mostly reversable, in other words you can convert .yy->.js and .js->.yy. Mostly.
  • Read this document in better font here. [100]: http://exebook.github.io/fonts/elfu.ttf

Contents

/* TODO: ∼◬ String.fromCharCode() - auto arg ꘉ bind - auto arg - mini functions f = ➮ a + b ⦙ ロ f(2, 3)

*/

#Screenshot Here is how Elfu looks in author's editor:

screenshot

#Syntax


#####function definition

  • typed as fu|TAB.

  • Elfu translator will replace with function.

  • you can avoid (, ) and , in argument declaration.

  • if you omit any arguments, arguments a b c are default.

  • use ➮f(){} or ➮{} syntax to declare an anomymous function without arguments.

  • ➮ {} is a lambda with default arguments a, b, c.

  • ➮ a + b ; becomes ((➮ { $a+b }).bind(this)) - aka "arrow function"

  • anonymous function with arguments a,b: ➮ - a b {}

 compare (a, b) { console.log(a == b) }
 compare a b { console.log(a == b) }
 compare { console.log(a == b) }
[1,2,3].forEach( { console.log(a) })
n = 2
a  [1,2,3,4,5]   a > n ; // 'this' is bound to a caller
 a // prints [3,4,5]
Math.sum =  - x y {
	$ x+y
}

return statement $
  • $ is replaced with return.
 four { $ 2 + 2 }

while and for statements and
  • is replaced with while.
  • is replaced with for.
  • typed as wh|TAB, fo|TAB.
  • parens () can be avoided if you have braces {}
 (true) step()
 (var i = 0; i < 3; i++) step()

break and continue statements @
  • @ is replaced with break.
  • is replaced with continue.
 (true) {
	step()
	if (again()) 
	if (finished()) @
}
n  5
 n > 0 { // parens, ( and ) are not needed
	 n--
}

each looping and
  • typed as ea|TAB.
  • compiles to for (var i = 0; i < obj.length; i++).
  • just type i ⬌ obj, it converts to the above.
  • (iterator) typed as it|TAB.
  • ► is similar to ⬌, but the 'i' is an array item rather than an index.
  • typed as fe|TAB.`
  • simply converts to .forEach.
var a = [1,2,3]
i  a { console.log(a[i]) }
a  [1,2,3]
i  a  aⁱ
a  [1,2,3]
i  a  i
// index still can be accessed with `_` + name, in this case `_i`.
The `i` will be replaced with `a[i]`. Operator `►` either requires `{}` or the expression must be on a single line. (Otherwise Elfu would need to use the full blown expression parser, which is beyond the scope of the current version).
A  [1,2,3,4]
A  ( {a ; })

console.log
  • typed as lo|TAB
  • is Chinese/Japanese character for mouth.
  • tired typing console.log hundreds times a day?
  • takes everything until the end of line or ; as arguments.
  • make sure you add ';' if your code continues on this line.
 'hello world!'
 'numbers are:', 1, 2, 3
if (true)  'here'
 compare {  a == b; }

Automatic + insertion. You can avoid + for brevity, because inside all string literals can be automatically glued to identifiers and some obvious expressions with '+'.

x  12345
a  [1,2,3]

 'x = ' x
ロ 'four means ' (2+2)
ロ 'a = ' a ' and length is ' a↥

Elfu allows you to mix with ${} style of strings.

a  5678
 `a = ${a}`

if, else, elseif ⌥ ⎇ ⥹
  • typed as if|TAB, el|TAB, ei|TAB.
  • is replaced with if.
  • is replaced with else.
  • is replaced with else if.
  • if the conditional statement is enclosed in {}, then () are optional
  • () are optional when the conditional statement starts with one of @, $, , , , , '∞', ';', '⌥'.
 (x == 1)  'GREAT'
 (x == 2)  'OK'
  'WRONG'

 x == 2 {  'x equals to two'}

var and def ∇ ∆ ≜
  • typed as va|TAB, de|TAB, df|TAB.
  • is replaced with var.
  • x ∆ is translated to var x =.
  • reads as is defined as or just define.
  • used to be delta, but in fact it is a simplified form of a math symbol -- definition or is defined as.
  • x ≜ y is replaced with if (typeof x == 'undefined') x = y.
x  100
 ( i = 0; i < x; i++)
a  1  b  'string'  c  {}  d  []
 countIt {
	a.count  0
	a.count++
}
state  {}
countIt(state)
countIt(state)
 state

stack operations
  • are typed as pu|TAB and po|TAB.
  • is for .push and is for .pop.
  • you can omit ( and ).
  • are typed as Pu|TAB and Po|TAB.
  • is for .shift and is for .unshift.
  • mnemonically shift() is pop() from the other side.
  • mnemonically unshift() is push() from the other side.
  • add ( and ) if you push an expression.
A  []
A  1
A  (2 + 2)
// A = [1, 4]
 A  ; // 4

superscript indexing Xⁱ
  • aⁱ translates to a[i].
  • a⁰ translates to a[0].
  • aⁱ⁰ translates to a[i][0].
  • typed as .i|TAB or .1|TAB.
  • super-script index can only be single character.
  • supported are all lowercase latin characters and digits 0-9.
  • do not try to use UPPERCASE characters.
  • do not try to use multicharacter variables like count.
A = [1,2,3]
i  A  Aⁱ
B = [[1,111],[2,222],[3,333]]
i  B  Bⁱ¹

this and undefined are
  • is translated to this..
  • is translated to this.
  • is translated to undefined.
  • typed as th|TAB.
  • typed as this|TAB.
  • typed as un|TAB.
 f {
	 (⚫name == )  'no name'
	  ⚫name
}
f()
⚫name = 'f1'
f.bind()()

comparison operators and
  • typed as eq|TAB and ne|TAB.
  • converts to ==.
  • converts to !=.
 (x  2)  'two'
 (x  2)  'not two'

clean and visible semicolon
  • since elfu code is so condensed, many expressions fit on the same line, to improve readability of such dense code, cleaner version of semicolon was introduced.
  • typed as sc|TAB.
  • and ; both can be used.
 2+2   3+3   4+4 ;  5+5

delete and new are and
  • typed as dl|TAB.
  • typed as new|TAB.
 f { ⚫name = 'f1' }
a   f
 'name =', a.name
⏀ a ⦙ a = ∅

length of an array or a string
  • typed as .le|TAB.
  • is translated to .length.
  • do not type '.' before , it is implied.
A  [1,2,3]
s  'hello'
 s↥, A↥
x  0
 (x < s↥) {    x++ }

require directive ≣
  • typed as re|TAB.
  • is replaced with require.
  • you can use ( and ) or avoid them.
fs   'fs'
spawn   ('child_process').spawn

#####Math functions

  • is typed as ra|TAB.
  • is converted to Math.random()
  • is typed as ro|TAB.
  • is converted to Math.round()
  • is typed as fl|TAB.
  • is converted to Math.floor()
  • and can omit ( and ) for simple expressions.
 (i  0  i < 20; i++)   ( * 1000000)
 a = 0.5
  a,  a

infinite loop
  • typed as in|TAB.
  • '∞' is replaced with while(true).
  • sometimes you just need an infinite loop.
  • or you need a loop whose logic is more complex than for or while.
	 step() // infinite
	x  0
	 {
		x +=  * 2
		 (x  5) @
		 (x  7) @
		 (x > 10) @
		 x
	}

time operations
  • is converted to setTimeout.
  • is converted to setInterval.
  • ⌿⌛ is converted to clearTimeout.
  • ⌿⌚ is converted to clearInterval.
  • is converted to (new Date().getTime()).
  • gives you millisecond tick.
  • is typed as st|TAB.
  • is typed as si|TAB.
  • is typed as tt|TAB (mnemonic: time tick).
  • ⌿⌛ is typed as ct|TAB.
  • ⌿⌚ is typed as ci|TAB.
 'please wait two seconds'
( { 'ready';}, 2000)
T    s  ''
 (s↥ < 1000000) s += 'a'
 'benchmark: ',  - T, 'ms'

node.js fs functions ,
  • is replaced with fs.readFileSync.
  • is replaced with fs.writeFileSync.
  • is typed fsrs|TAB.
  • is typed fsws|TAB.
  • you can omit ( and ) for ⛁ with a single argument.
fs   'fs'
A  'readme.txt'   '\n'
 A , 'lines loaded'

str serialization with .
  • is typed as sp|TAB.
  • is typed as jo|TAB.
  • is typed as ts|TAB.
  • is compiled as .split
  • is compiled as .join
  • you can omit ( and ) for simple expressions with , and .
  • is converted to .toString
// replace all occurences of "-" with "+"
 '1-2-3-4-5'  '-'  '+'
// same with ( and )
s  '-+'
ロ '1-2-3-4-5' ⌶ (s⁰) ⫴ (s¹)
x  123.456
 'length of string representation of number', x, 'is', x≂↥	
fs   'fs'
 'Readme contains: ' +  ('README.md')   '\n'  + ' lines'

booleans ⦿ and
  • ⦿ is replaced with true.
  • is replaced with false.
  • ⦿ is typed as tr|TAB.
  • is typed as fa|TAB.
	a  ⦿
	 (a) a = 
	b  { initialized:  }

last item of a string or an array
  • is typed as .la|TAB.
  • is typed as .lx|TAB.
  • is used to access the last item of an array or a string.
  • is compiled to [x.length - 1], so xꕉ becomes x[x.length - 1].
  • x↟ is compiled to (x.length - 1).
A  ['X','Y']
 appendAndReturnIndex { A  a  $ A↟ }
z  appendAndReturnIndex('Z')
 'inserted', Aᶻ, 'at:', z
A  ['hey', 'there', '.', '.', 'how', 'are', 'are', 'you', '.']
 removeDoubles {
	R  []
	i  a {
		 (aⁱ  Rꕉ) 
		R  (aⁱ)
	}
	$ R
}
 removeDoubles(A)  ' '
// hey there . how are you .

finding occurence in a string or array with ≀≀
  • is typed as io|TAB.
  • ≀≀ is typed as lio|TAB or io|TABio|TAB.
  • is replaced with .indexOf.
  • ≀≀ is replaced with .lastIndexOf.
  • ( and ) can be used or omited.
s  'hello world!'
  s  'world', s  ('o'), s ≀≀ 'o'
// 6 4 7

array utilities , string and character utilities
  • is typed as sl|TAB.
  • is typed as pl|TAB.
  • is typed as fi|TAB.
  • is typed as ma|TAB.
  • is typed as aa|TAB.
  • is typed as so|TAB.
  • is replaced with .slice.
  • is replaced with .splice.
  • is replaced with .filter.
  • is replaced with .map.
  • is replaced with .concat.
  • is replaced with .sort.
  • is typed as cc|TAB.
  • is typed as ca|TAB.
  • is typed as su|TAB.
  • is replaced with .charCodeAt.
  • is replaced with .charAt.
  • is replaced with .substr.
 numbersOnly { $ a  '' ꔬ (➮ { $ a◬(0) <= 57 }) }
ロ numbersOnly('a1b2c4d8q11')
// same as above. but sorted
 numbersOnly { $ a  '' ꔬ (➮ { $ a◬(0) <= 57 }) }
ロ numbersOnly('a1b2c4d8q11')❄ (➮ { $a - b })

symbolic variables
  • there are three types of symbolic variables.
  • the goal is to provide more condense, formula-like notation.
  • α γ β ... ζ are greek letters.
  • Javascript supports greek letters, no translation is needed.
  • Typing in greek: alf=α bet=β gam=γ del=δ eps=ε zet=ζ eta=η tet=θ iot=ι kap=κ lam=λ muu=μ nuu=ν xii=ξ pii=π roo=ρ sig=σ tau=τ ups=υ fii=φ chi=χ psi=ψ ome=ω.
 α = 10, δ = 5
α += δ
 'alfa plus delta is:', α
  • ... are encircled letters.
  • encircled letters are typed ooa|TAB, oob|TAB, ooz|TAB etc.
  • they are useful if you are out of latin letters.
  • internally they are represented as _oo_0 to _oo_26.
  = 0,  = 26
 , 
  • are tags or labels, they have special syntax.
  • is a label definition, ❶ 5 equals to ;var var0 = 5.
  • is a label reference, or usage, ロ ① will convert to console.log(var0).
 'hello'  'world'
 , 

is defined
  • is typed as id|TAB.
  • ⟑ <expr> is replaced with (typeof <expr> != undefined).
s  {x:123}
 (⟑s.x)  's.x is not undefined'

multi line strings

Elfu supports multi line strings enclosed with opening '''\n and closing '''.

console.log('''
   Hello, multi line
   strings world
''')

str ∆ '''
   Hello, multi line
   strings world'''
   

(GitHub markdown does highlight with red background for some reason.)


tuples
  • is typed as tu|TAB.
  • a,b ꔪ <expr> is replaced with tmp=<expr>;a=tmp[0],b=tmp[1].
 repl { $a.replace(b, c) }

 half {
	$[a, a/2]
}

A  {whole:, part:}

 A { whole, part  half(200) }

 a,b,c  [33,44,55]

 A,a,b,c
//{ whole: 200, part: 100 } 33 44 55

TODO: add support for simple name matching with ꔪ, like this:

obj  { a:1, b:2 }
b,a  obj
//b = obj['b'], a = obj['a']
 a, b
// 1, 2

object keys as an array with '⚷'
	obj  {a:1, b:2, c:3}
	  obj // ['a', 'b', 'c']

namespace utility with ➮| and ➮]

If your elfu source file has ➮] anywhere in it, then all top level declared functions of this file will be automatically exported to module.exports. If you use ➮|, the functions will be exported as global variables.

######main.yy

|
'lib'
 load {
	 'loaded...'
}

scan()

######lib.yy

 scan {
	load()
	 'processing...'
}

|
new syntax for branching with ]232
  • is typed as q|TAB or [|TAB.
  • is typed as w|TAB or ]|TAB.
  • is typed as e|TAB.
  • replace '❱' with ')', or '){' when the next token is on the same line.
  • replace '◇' with: a. '} else if(' if followed by the next non-space character '❰'; b. '} else {' if the next token is on the same line; c. 'else'. -- not possible, ◇ cannot be used with the oneliners.
  • replace '⁋' with '}'.
  • replace '❰' with 'if ('.

There is no if keyword or it's analog if you use this notation, the test condition is enclosed in and . The conditional statement is a one liner if it goes on the same line, otherwise end it with the . Same is true with else which is .

This syntax does not replace original JavaScript or original Elfu if else and , but coexist.

/*
	Nested conditional expressions.
	You cannot use ◇ with one-liners. But ◇ itself could have a oneliner expression.
*/

❰1❱
	❰2❱
		b = 3
	
		b = 4
	

	❰5❱
		b = 6
	
		b = 7
	
❰a  5 a = c
 b = 1

❰a == 5 b = 4

❰a == 5
	b = 4

	b = 6

❰a == 5 b = 4  b = 6

❰a == 5 b = 4  ❰a == 5 b = 6


❰a == 5 b = 4  ❰a == 5
	b = 6

You can combine syntaxes like this:

❰1❱
	{ 2 }
  { 3 }

...or like this:

❰1❱
	{ 2 }
else
	{ 3 }

#####String array literals

 [@ dormouse hare hatter]

// [ 'dormouse', 'hare', 'hatter']
extras
`__arrarr` - get the function arguments as an array.
`__elfuver` - return a string specifying current elfu version. This is read from `package.json`.

#Usage

  • install with npm, [sudo] npm i -g elfu.
  • yy <program> run the .yy program.
  • yyj program.yy convert program.yy to Javascript. Data is written to standart outout.
  • jyy program.js convert Javascript to Elfu.
  • require('elfu'); require('example.yy') you can require modules written in Elfu.

#Dotcall syntax

  • Elfu supports dotcall syntax.
  • dotcall is callback hell remedy.
  • read dotcall README for details.

#Feedback