jester v0.2.3
jester
The idea is to create beginner-friendly, forgiving language with solid theoretical underpinnings. So you could start with a simple program like this:
import! canvas
pen #red
moveto 10, 10
lineto 30, 30
lineto 10, 30
lineto 10, 10And progress to this:
import! fun
doubler = map .{ _ * 2 }, ?
summer = reduce .{ l,r| l + r }, 0, ?
sum_of_doubles = summer . doubler
print sum_of_doubles([1,2,3,4,5])Jester supports concurrency:
def get(url) {
-- perform HTTP GET of url
-- return string
}
t1 = spawn get "http://google.com"
t2 = spawn get "http://yahoo.com"
t3 = spawn get "http://cuil.com"
google = wait t1
yahoo = wait t2
cuil = wait t3The initial implementation is a register-based virtual machine running in Javascript. Bypassing the JS call-stack in the interpreter allows us to implement Go-style async concurrency written in a blocking style, but without crazy syntax tree transformations that you see in compile-to-JS languages.
I've outlined the eventual syntax below, very little of this is implemented yet.
TODO
- document import/export syntax
Notes
Stuff I might add
- generic
forloop - necessary? - object system - any point?
- comprehension syntax
- pattern matching
- switch/case
- do we need null/undefined/nil/none etc?
- multiple return values/assignment
- splat operator
- kwargs
- matrices?
- rational numbers?
- channels
There's a bit of punctuation still available for future work:
@, :, {..} delimited blocks
UTF-8 equivalents will be supported as appropriate.
Syntax Overview
Comments
-- this is a commentLiterals
5
5_000_000
1.23
0b1100
0xff33
true
false
"string"
#ff0000 -- RGB color
#ff00007f -- RGBA color
#red -- named colorVariable assignment
a = 10
foo = "hello jello"Operator list
Unary
!a
~aBinary
a + b
a - b
a * b
a / b
a ** b
a << b
a >> b
a % b
a & b
a | b
a ^ b
a < b
a <= b
a == b
a > b
a >= b
a . bArrays
Literal
[]
[1, 2, 3]Access
a = [1, 2, 3]
a[0]
a[1] = 100Dictionaries
Literal
{ foo = 10, bar = 20 }Access
a = { k1 = 10, k2 = 20 }
a.k1
a["key1"]
a.k1 = 30
a["key2"] = 40Vectors
2D and 3D vector literals are supported:
origin2d = <0,0>
origin3d = <0,0,0>Supported operators for vectors: *, /, +, -, ..
Function Definition
No arguments:
def foo {
}With arguments:
def foo(a, b, c) {
}With optional arguments:
def foo(a, b = 10, c = 20) {
}As in Ruby, method names may end in ? or !:
def available? {
false
}
def create_instance! {
-- do mojo
}Functions defined with def are immutable and preclude any other assignment to that simple in the same scope.
Return is implicit but explicit returns are also allowed:
def foo {
10
}
def bar {
return 20
}Calling functions
foo(a, b, c)Parens are optional:
foo a, b, cLone identifier is a function invocation iff ident bound to function (this may require a runtime check):
fooColors
Constructors:
#(r, g, b)
#(r, g, b, a)
#("string")Control constructs
While:
while exp {
}A loop is like while but there's an implicit yield at the end of the loop body:
loop while exp {
}Convenient shorthand for loop while true:
loop {
}If/else:
if exp {
} else if exp {
} else {
}Iterate over array/dictionary values:
foreach (ix in subject) {
}Iterate over array/dictionary keys/values:
foreach (key, ix in subject) {
}Globals
$ is a globally accessible dictionary.
$.foo = 10
print $.fooDynamic lookups work of course:
a = "foo"
print $["foo"]A shorthand syntax is also available:
$foo
print $fooConcurrency
Spawn invocation of function foo in a new green thread:
task = spawn foo(a, b, c)Wait for task to complete:
wait taskYield to the scheduler:
yieldDebugging
Call the trace function, if defined:
trace(trace always evaluates to true)
Lambda syntax
Anonymous functions are created thusly:
doubler = .{ x| x * 2 }In instances where there is only a single parameter, _ is implied:
doubler = .{ _ * 2 }Partial Application
Functions may be partially applied; ? denotes placeholder:
doubler = map .{ s | s * 2 }, ?
print doubler([1,2,3])
-- => [2,4,6]Function composition
Functions may also be composed:
f = .{ _ * 2 }
g = .{ _ + 5 }
-- whitespace is significant here; f.g would be a property lookup
f_of_g = f . g
print f_of_g(10)
-- => 30