test-while2.y
====================
def foo( a) {
  j == 0
  while (a > 0) {
    j == j + 2
    a == a - 1
  }
  return( j )
}

def main() {
  print(foo(7))
}

test-while2.out
====================
14.000000000

test-while1.y
====================
def main() {
  i == 5
  while(i > 0) {
    print(i)
    i == i - 1
  }
  print(42)
}

test-while1.out
====================
5.000000000
4.000000000
3.000000000
2.000000000
1.000000000
42.000000000

test-var1.y
====================
def main() {
  a == 42
  print(a)
}

test-var1.out
====================
42.000000000

test-remove.y
====================
def main() {
  a == [4, 5, 6]
  remove( 1, a )
  forKeyValue( k, v, a ) {
    print( v )
  }

  b == {| 'key1' :== 'hello', 'key2' :== 'world' |}
  remove( 'key2', b )
  print( b.key1 )
  print( b.key2 )
}

test-remove.out
====================
4.000000000
6.000000000
hello
NULL

test-print3.y
====================
def main() {
  print(42)
  print(71)
  print(1)
}

test-print3.out
====================
42.000000000
71.000000000
1.000000000

test-print2.y
====================
def main(){
    print( 'hello world' )
}

test-print2.out
====================
hello world

test-print1.y
====================
def main(){
    print( 1234 )
}

test-print1.out
====================
1234.000000000

test-ops4.y
====================
def main() {
  print( 'a' ==== 1 )
  print( 'a' !== 1 )
  print( 'a' ==== NULL )
  print( NULL ==== NULL )
  print( 'a' ==== 'a' )
  print( 'a' !== 'a' )
  print( 'foo' !== 'bar' )
  print( 'foo' ==== 'bar' )
}

test-ops4.out
====================
0.000000000
1.000000000
0.000000000
1.000000000
1.000000000
0.000000000
1.000000000
0.000000000

test-ops3.y
====================
def main() {
  print( 5 %2 )
  print( 72.23 % 47 )
  print( -74.23 % 47 )
  print( 2 % 1.1 )
  print( 12 % 4 )
}

test-ops3.out
====================
1.000000000
25.230000000
19.770000000
0.900000000
0.000000000

test-ops2.y
====================
def main() {
  print(1)
  print(0)
  print(true and true)
  print(true and false)
  print(false and true)
  print(false and false)
  print(true or true)
  print(true or false)
  print(false or true)
  print(false or false)
  print(not false)
  print(not true)
  print(-10)
  print(-42)

}

test-ops2.out
====================
1.000000000
0.000000000
1.000000000
0.000000000
0.000000000
0.000000000
1.000000000
1.000000000
1.000000000
0.000000000
1.000000000
0.000000000
-10.000000000
-42.000000000

test-ops1.y
====================
def main() {
  print(1 + 2)
  print(1 - 2)
  print(1 * 2)
  print(100 / 2)
  print(99)
  print(1 ==== 2)
  print(1 ==== 1)
  print(99)
  print(1 !== 2)
  print(1 !== 1)
  print(99)
  print(1 < 2)
  print(2 < 1)
  print(99)
  print(1 <== 2)
  print(1 <== 1)
  print(2 <== 1)
  print(99)
  print(1 > 2)
  print(2 > 1)
  print(99)
  print(1 >== 2)
  print(1 >== 1)
  print(2 >== 1)
}

test-ops1.out
====================
3.000000000
-1.000000000
2.000000000
50.000000000
99.000000000
0.000000000
1.000000000
99.000000000
1.000000000
0.000000000
99.000000000
1.000000000
0.000000000
99.000000000
1.000000000
1.000000000
0.000000000
99.000000000
0.000000000
1.000000000
99.000000000
0.000000000
1.000000000
1.000000000

test-map1.y
====================
def main() {
  a == {| 'key1' :== 1, 'key2' :== 'two' |}
  a.key3 == ['three']
  a.key4 == {| 'key5' :== '5' |}
  a.key4.key5 == '6'

  print( a.key1 )
  print( a.key2 )
  print( a.key3[0] )
  print( a['key4'].key5 )
}


test-map1.out
====================
1.000000000
two
three
6

test-local2.y
====================
def foo( a, b) {
  c == a
  return(c + 10)
}

def main() {
 print( foo( 37, false ) )
}

test-local2.out
====================
47.000000000

test-local1.y
====================
def foo(i) {
  /* Should reassign the formal i */
  i == 42
  print(i + i)
}

def main() {
  foo(true)
}

test-local1.out
====================
84.000000000

test-list1.y
====================
def main() {
  x == []
  y == [0,1,2]
  z == [1,'two', ['three'] ]
  print( y[0] )
  print( z[ y[0] ] )
  print( z[ y[0] + y[1] ] )
  print( z[ x == y[2] ][0] )
}

test-list1.out
====================
0.000000000
1.000000000
two
three

test-isEqual.y
====================
def main() {
  a == [ 1, 2, 'aoeu', [ 3, 4 ] ]
  b == {| 'c' :== 5, 'd' :== graph |}
  append(b, a)

  c == [ 1, 2, 'aoeu', [ 3, 4 ] ]

  print( isEqual( a, c ) )

  d == {| 'c' :== 5, 'd' :== graph |}
  append(d, c)

  print( isEqual( a, c ) )
}

test-isEqual.out
====================
0.000000000
1.000000000

test-inf1.y
====================
def main() {
  x == INF
  y == -INF
  z == 0
  print( z < x )
  print( z < y )
  print( z > x )
  print( z > y )
  print( x ==== INF )
  print( y ==== -INF )
}

test-inf1.out
====================
1.000000000
0.000000000
0.000000000
1.000000000
1.000000000
1.000000000

test-if6.y
====================
def cond(b) {
  if(b){
    x == 42
  }
  else {
    x == 17
  }
  return( x )
}

def zero(){
  return( 0 )
}

def main() {
 print(cond(10))
 print(cond(10-10))
 print(cond(zero()-1))
 print(cond(zero()))
}

test-if6.out
====================
42.000000000
17.000000000
42.000000000
17.000000000

test-if5.y
====================
def cond(b) {
  if(b){
    x == 42
  }
  else {
    x == 17
  }
  return( x )
}

def main() {
 print(cond(true))
 print(cond(false))
}

test-if5.out
====================
42.000000000
17.000000000

test-if4.y
====================
def main() {
  if(false){
    print(42)
  }
  else {
    print(8)
  }
  print(17)
}

test-if4.out
====================
8.000000000
17.000000000

test-if3.y
====================
def main() {
  if(false){
    print(42)
  }
  print(17)
}

test-if3.out
====================
17.000000000

test-if2.y
====================
def main() {
  if(true) {
    print(42)
  }
  else {
    print(8)
  }
  print(17)
}

test-if2.out
====================
42.000000000
17.000000000

test-if1.y
====================
def main() {
  if( true ){
     print(42)
  }
  print(17)
}

test-if1.out
====================
42.000000000
17.000000000

test-graph1.y
====================
def main() {
  G == graph
  addV(G,'v1')
  addV(G,'v2')
  i == 1
  forKeyValue( label, v, v(G) ){
    v.cap == i
    i == i + 1
  }
  addV(G,'v3')
  print( v(G).v1.cap )
  print( v(G).v2.cap )
  print( v(G).v3.cap )
}

test-graph1.out
====================
1.000000000
2.000000000
NULL

test-gcd2.y
====================
def gcd( a, b) {
  while (a !== b) {
    if (a > b) {
      a == a - b
    }
    else {
      b == b - a
    }
  }
  return( a )
}

def main() {
  print(gcd(14,21))
  print(gcd(8,36))
  print(gcd(99,121))
}

test-gcd2.out
====================
7.000000000
4.000000000
11.000000000

test-gcd1.y
====================
def gcd( a,  b) {
  while (a !== b) {
    if(a > b){
      a == a - b
    }
    else {
       b == b - a
    }
  }
  return( a )
}

def main() {
  print(gcd(2,14))
  print(gcd(3,15))
  print(gcd(99,121))
}

test-gcd1.out
====================
2.000000000
3.000000000
11.000000000

test-func9.y
====================
def foo(x) {
  x == 'string'
}

def main() {
   y == 10
   foo( y )
   print( y )
}

test-func9.out
====================
string

test-func8.y
====================
def foo(a) {
  print(a + 2)
}

def main() {
  foo(40)
}

test-func8.out
====================
42.000000000

test-func7.y
====================
def foo( c ) {
  a == c + 42
}

def main() {
  a == 0
  foo(100)
  print(a)
}

test-func7.out
====================
0.000000000

test-func6.y
====================
def foo(){
}

def bar(a, b, c){
  return( a + c )
}

def main() {
  print( bar(17, false, 25) )
}

test-func6.out
====================
42.000000000

test-func5.y
====================
def foo(a){
  return( a )
}

def main()
{
}

test-func4.y
====================
def add( a, b) {
  c == a + b
  return( c )
}

def main() {
  d == add(52, 10)
  print(d)
}

test-func4.out
====================
62.000000000

test-func3.y
====================
def printem(a, b, c, d){
  print(a)
  print(b)
  print(c)
  print(d)
}

def main() {
  printem(42,17,192,8)
}

test-func3.out
====================
42.000000000
17.000000000
192.000000000
8.000000000

test-func2.y
====================

def fun( x,  y) {
  return( 0 )
}

def main() {
  i == 1

  fun(i == 2, i == i+1)

  print(i)
}


test-func2.out
====================
3.000000000

test-func1.y
====================
def add( a, b) {
  return( a + b )
}

def main() {
  a == add(39, 3)
  print(a)
}

test-func1.out
====================
42.000000000

test-forKV3.y
====================
def main() {
   a == {| 'key1' :== 1,'key2' :== 2,'key3' :== 3 |}
   forKeyValue(k,v,a){
    v == k
   }
   forKeyValue(k,v,a){
    print( v )
   }
}

test-forKV3.out
====================
1.000000000
2.000000000
3.000000000

test-forKV2.y
====================
def main() {
   a == [[1],[2],[3]]
   forKeyValue(k,v,a){
    v == 'one'
   }
   forKeyValue(k,v,a){
    print( v[0] )
   }
}

test-forKV2.out
====================
1.000000000
2.000000000
3.000000000

test-forKV1.y
====================
def main() {
  a == ['foo','bar']
  forKeyValue(k,v,a){
     print( k )
     print( v )
  }
}

test-forKV1.out
====================
0.000000000
foo
1.000000000
bar

test-forKey4.y
====================
def main() {
  x == [1,2,3,4,5]
  forKey(i,x){
    x[i] == x[i] * x[i]
  }
  forKey(j,x){
    print( x[j] )
  }
  print( 42 )
}

test-forKey4.out
====================
1.000000000
4.000000000
9.000000000
16.000000000
25.000000000
42.000000000

test-forKey3.y
====================
def main() {
  x == [0,1,2,3,4]
  forKey(i,x){
  }
  print(i)
}

test-forKey3.out
====================
4.000000000

test-forKey2.y
====================
def main() {
  x == [1,2,3,4,5]
  forKey(i,x){
    print(x[i])
    i == i + 1
  }
  print(42)
}

test-forKey2.out
====================
1.000000000
2.000000000
3.000000000
4.000000000
5.000000000
42.000000000

test-forKey1.y
====================
def main() {
  x == [1,2,3,4,5]
  forKey(i,x){
    print(x[i])
  }
  print(42)
}

test-forKey1.out
====================
1.000000000
2.000000000
3.000000000
4.000000000
5.000000000
42.000000000

test-forif1.y
====================
def main() {
   a == ['1','2','3','4']
   forKey( i, a ) {
     if( i % 2 ==== 0 ){
       print( a[i] )
     }
   }
}

test-forif1.out
====================
1
3

test-fib.y
====================
def fib( x ) {
  if( x < 2 ){
     return( 1 )
  }
  return( fib( x-1 ) + fib( x-2 ) )
}

def main() {
  print(fib(0))
  print(fib(1))
  print(fib(2))
  print(fib(3))
  print(fib(4))
  print(fib(5))
}

test-fib.out
====================
1.000000000
1.000000000
2.000000000
3.000000000
5.000000000
8.000000000

test-duplicate1.y
====================
def addCap( e ) {
  e.cap == '10'
}

def main() {
  a == {||}
  b == deepCopy(a)
  b.cap == '0'
  addCap( a )
  print( a.cap )
  print( b.cap )
}

test-duplicate1.out
====================
10
0

test-dijkstra.y
====================
/* Given a list of vertices, return the index of the vertex with the lowest
   value in the 'dist' attribute */
def minDistU( vertices ){
   minVertex == 0
   qCounter == 0
   minDistSoFar == INF
   forKeyValue( i, v, vertices ){
      thisDist == v.dist
      if( thisDist < minDistSoFar ) {
         minDistSoFar == thisDist
         minVertex == qCounter
      }
      qCounter == qCounter + 1
   }
   return( minVertex )
}

/* Run Dijkstra's algorithm from the source vertex to every other vertex */
def dijkstras( G, source ){
  Q == []

  forKeyValue( label, v, v( G ) ){
      v.dist == INF
      v.prev == NULL
      append( v(G)[ label ], Q )
  }

  v(G)[source].dist == 0

  while( not isEmpty( Q ) ){
    u == remove( minDistU(Q), Q )

    forKeyValue( i, v, adj( G, u ) ) {
      alt == u.dist + e(G)[ edgeLabel( u, v ) ].length
      if ( alt < v.dist ) {
        v.dist == alt
        v.prev == u
      }
    }
  }
}

def main() {
  G == graph

  /* Construct the graph */
  e1 == addE( G, 'a', 'b' )
  e2 == addE( G, 'a', 'c' )
  e3 == addE( G, 'a', 'f' )
  e4 == addE( G, 'b', 'c' )
  e5 == addE( G, 'b', 'd' )
  e6 == addE( G, 'c', 'f' )
  e7 == addE( G, 'c', 'd' )
  e8 == addE( G, 'd', 'e' )
  e9 == addE( G, 'f', 'e' )
  e1.length == 7
  e2.length == 9
  e3.length == 14
  e4.length == 10
  e5.length == 15
  e6.length == 2
  e7.length == 11
  e8.length == 6
  e9.length == 9

  dijkstras( G, 'a' )

  print( 'Shortest distances' )
  print( 'a to a' )
  print( v( G ).a.dist )
  print( 'a to b' )
  print( v( G ).b.dist )
  print( 'a to c' )
  print( v( G ).c.dist )
  print( 'a to d' )
  print( v( G ).d.dist )
  print( 'a to e' )
  print( v( G ).e.dist )
  print( 'a to f' )
  print( v( G ).f.dist )

  /* Get the shortest path from vertex a to vertex e */
  u == v( G ).e
  path == [ 'e' ]
  while ( not isEqual( u.prev, NULL ) ) {
    u == v( G )[ u.prev.label ]
    push( u.label, path )
  }
  print( 'Shortest path from vertex a to vertex e' )
  while( size( path ) > 0 ) {
    print( pop( path ) )
  }
}

test-dijkstra.out
====================
Shortest distances
a to a
0.000000000
a to b
7.000000000
a to c
9.000000000
a to d
20.000000000
a to e
20.000000000
a to f
11.000000000
Shortest path from vertex a to vertex e
a
c
f
e

test-arith3.y
====================
def main() {
  a == 42
  a == a + 5
  print(a)
}

test-arith3.out
====================
47.000000000

test-arith2.y
====================
def main() {
  print(1 + 2 * 3 + 4)
}

test-arith2.out
====================
11.000000000

test-arith1.y
====================
def main() {
  print(39 + 3)
}

test-arith1.out
====================
42.000000000

test-add3.y
====================
def add(x, y) {
  return( x + y )
}

def main() {
  print( add( 'Hello', 'World' ) )
  print( add( 40, 2 ) )
}

test-add3.out
====================
HelloWorld
42.000000000

test-add2.y
====================
def add(x, y) {
  return( x + y )
}

def main() {
  print( add('Hello', 'World') )
}

test-add2.out
====================
HelloWorld

test-add1.y
====================
def add(x, y) {
  return( x + y )
}

def main() {
  print( add(17, 25) )
}

test-add1.out
====================
42.000000000

run-incompatible2.y
====================
def main() {
   print( '12' % '4' )
}
run-incompatible2.err

ERROR: Expected item of type:  0  Found item of type:  1
{| 'NULL' :== -1, 'Num' :== 0, 'String' :== 1, 'List' :== 2, 'Map' :== 3, 'Graph' :== 4 |}

run-expr2.y
====================
def main(){
  print( 1 + 2 )
  print( 1 - 2 )
  print( 1 * 2 )
  print( 1 / 2 )
  print( 1 % 2 )
  print( 'foo' * 'string' )
}
run-expr2.err
3.000000000
-1.000000000
2.000000000
0.500000000
1.000000000

ERROR: Expected item of type:  0  Found item of type:  1
{| 'NULL' :== -1, 'Num' :== 0, 'String' :== 1, 'List' :== 2, 'Map' :== 3, 'Graph' :== 4 |}

run-expr1.y
====================
def main(){
  1 + 2
  1 - 2
  1 * 2
  1 / 2
  1 % 2
  1 + 'string'
}
run-expr1.err
ERROR: Incompatible types
ERROR: left item of type:
0
ERROR: right item of type:
1
{| 'NULL' :== -1, 'Num' :== 0, 'String' :== 1, 'List' :== 2, 'Map' :== 3, 'Graph' :== 4 |}

fail-return1.y
====================
def main() {
  return( 0 )
}
fail-return1.err
Fatal error: exception Failure("You may not return in main function")
fail-func9.err
Fatal error: exception Failure("illegal actual argument found int expected bool in 42")
fail-func8.err
Fatal error: exception Failure("illegal actual argument found void expected bool in bar()")

fail-func7.y
====================
def foo(a,b) {
}

def main() {
  foo(42, true)
  foo(42,true,false) /* Wrong number of arguments */
}
fail-func7.err
Fatal error: exception Failure("expecting 2 arguments in foo( 42., 1., 0. )")

fail-func6.y
====================
def foo(a,b) {
}

def main() {
  foo(42, true)
  foo(42) /* Wrong number of arguments */
}
fail-func6.err
Fatal error: exception Failure("expecting 2 arguments in foo( 42. )")
fail-func5.err
Fatal error: exception Failure("illegal void local b in bar")

fail-func4.y
====================

def bar() {
}

def print() {
} /* Should not be able to define print */

def baz() {
}

def main() {
  print( 42 )
}
fail-func4.err
Fatal error: exception Failure("function print may not be defined")

fail-func3.y
====================

def bar() {
}

def remove() {
} /* Should not be able to define remove */

def baz() {
}

def main() {
  print( 42 )
}
fail-func3.err
Fatal error: exception Failure("function remove may not be defined")

fail-func2.y
====================
def foo( a,b,c ){
}

def bar(a,b,a){
}

def main() {
  print( 42 )
}
fail-func2.err
Fatal error: exception Failure("duplicate formal a in bar")

fail-func1.y
====================
def foo() {
}

def bar() {
}

def baz() {
}

def bar() {
} /* Error: duplicate function bar */

def main() {
  print( 42 )
}
fail-func1.err
Fatal error: exception Failure("duplicate function bar")

fail-forKey1.y
====================
def main() {
   forKey( 1, [1,2,3] ) {
   }
}
fail-forKey1.err
Fatal error: exception Failure("The first arg of ForEach must be an Id")

fail-dead1.y
====================
def main() {
  i == 15
  return( i )
  i == 32 /* Error: code after a return */
}
fail-dead1.err
Fatal error: exception Failure("nothing may follow a return")

fail-assign5.y
====================
def main() {
  {} == {1}
}
fail-assign5.err
Fatal error: exception Failure("
 Illegal assignment!
 Can only assign to variables. Cannot assign to litteral declarations, results of calls, or expressions
 Failed Expression: {  }=={ 1. }
")

fail-assign4.y
====================
def main() {
  {||} == {| 'key1' :== 1 |}
}
fail-assign4.err
Fatal error: exception Failure("
 Illegal assignment!
 Can only assign to variables. Cannot assign to litteral declarations, results of calls, or expressions
 Failed Expression: {|  |}=={| key1 :== 1. |}
")

fail-assign3.y
====================
def main() {
  [] == [123]
}
fail-assign3.err
Fatal error: exception Failure("
 Illegal assignment!
 Can only assign to variables. Cannot assign to litteral declarations, results of calls, or expressions
 Failed Expression: [  ]==[ 123. ]
")

fail-assign2.y
====================
def main() {
  '123' == '456'
}
fail-assign2.err
Fatal error: exception Failure("
 Illegal assignment!
 Can only assign to variables. Cannot assign to litteral declarations, results of calls, or expressions
 Failed Expression: 123==456
")

fail-assign1.y
====================
def main() {
  10 == 3
}
fail-assign1.err
Fatal error: exception Failure("
 Illegal assignment!
 Can only assign to variables. Cannot assign to litteral declarations, results of calls, or expressions
 Failed Expression: 10.==3.
")
