]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani-tests.mdc
oceani: free variables as soon as they go out of scope.
[ocean] / csrc / oceani-tests.mdc
index 102c957b0b4e459327e1418aa1f7e4b33ba3dde8..dccfb2a47bc2bdb50f7f3a39e7c3adf09ccf1b01 100644 (file)
@@ -38,8 +38,10 @@ arguments separated from the name by commas.  For each test, there is a section
 
        tests:: oceani_test_suite
        oceani_test_suite: oceani coverage_oceani
 
        tests:: oceani_test_suite
        oceani_test_suite: oceani coverage_oceani
-               @./parsergen --report --LR1 --tag Parser oceani.mdc | grep " - no conflicts" > /dev/null || \
-                   { echo "Grammar container conflicts, please review" ; exit 1; }
+               @echo -n Checking grammar ...
+               @./parsergen --report --LALR --tag Parser oceani.mdc | grep " - no conflicts" > /dev/null || \
+                   { echo "Grammar contains conflicts, please review" ; exit 1; }
+               @echo ok
                @rm -rf coverage; mkdir -p coverage
                @cp *.gcno coverage
                @for T in $(oceani_tests); do \
                @rm -rf coverage; mkdir -p coverage
                @cp *.gcno coverage
                @for T in $(oceani_tests); do \
@@ -52,9 +54,16 @@ arguments separated from the name by commas.  For each test, there is a section
                    echo -n "printing.. "; \
                    echo '``````' > .tmp.code1; echo '``````' > .tmp.code2 ;\
                    ./oceani --noexec --print --section "test: $$t" oceani-tests.mdc >> .tmp.code1; \
                    echo -n "printing.. "; \
                    echo '``````' > .tmp.code1; echo '``````' > .tmp.code2 ;\
                    ./oceani --noexec --print --section "test: $$t" oceani-tests.mdc >> .tmp.code1; \
-                   ./oceani --noexec --print .tmp.code1 >> .tmp.code2 ;\
+                   ./oceani --noexec --print .tmp.code1 >> .tmp.code2 || exit 1;\
                    if ! cmp -s .tmp.code1 .tmp.code2; then \
                       echo " Failed"; diff -u .tmp.code1 .tmp.code2; exit 1 ; fi ; \
                    if ! cmp -s .tmp.code1 .tmp.code2; then \
                       echo " Failed"; diff -u .tmp.code1 .tmp.code2; exit 1 ; fi ; \
+                   echo -n "extra-newlines.. "; \
+                   sed -e 'i\
+                   ' .tmp.code1 > .tmp.code1a; \
+                   echo '``````' > .tmp.code2a ;\
+                   ./oceani --noexec --print .tmp.code1a >> .tmp.code2a || exit 1;\
+                   if ! cmp -s .tmp.code1 .tmp.code2a; then \
+                      echo " Failed"; diff -u .tmp.code1 .tmp.code2a; exit 1; fi ; \
                    echo -n "exec-after-print.. "; \
                    ./oceani .tmp.code1 $${1+"$$@"} > .tmp.have ; \
                    if ! cmp -s .tmp.want .tmp.have; then \
                    echo -n "exec-after-print.. "; \
                    ./oceani .tmp.code1 $${1+"$$@"} > .tmp.have ; \
                    if ! cmp -s .tmp.want .tmp.have; then \
@@ -66,15 +75,16 @@ arguments separated from the name by commas.  For each test, there is a section
 
                ## test code
 
 
                ## test code
 
+               @for i in coverage/#*.gcda; do mv $$i coverage/$${i##*#}; done
                @gcov -o coverage oceani.mdc > /dev/null 2> /dev/null
                @gcov -o coverage oceani.mdc > /dev/null 2> /dev/null
-               @mv *.gcov coverage ; [ -f .gcov ] && mv .gcov coverage
+               @mv *.gcov coverage ; [ -f .gcov ] && mv .gcov coverage || true
                @ awk '/NOTEST/ { next } /^ *[1-9]/ {ran+=1} /^ *###/ {skip+=1} \
                    END {printf "coverage: %6.2f%%\n", ran * 100 / (ran + skip); \
                @ awk '/NOTEST/ { next } /^ *[1-9]/ {ran+=1} /^ *###/ {skip+=1} \
                    END {printf "coverage: %6.2f%%\n", ran * 100 / (ran + skip); \
-                        if (ran < (ran + skip) *0.93) exit(1) }' \
+                        if (ran < (ran + skip) *0.959) exit(1) }' \
                        coverage/oceani.mdc.gcov
                @rm -f .tmp*
 
                        coverage/oceani.mdc.gcov
                @rm -f .tmp*
 
-               @for T in $(oceani_tests); do \
+               @[ -n "$$SKIP_VALGRIND" ] || for T in $(oceani_tests); do \
                    echo -n "Valgrind $$T.. "; \
                    i="$$IFS"; IFS=,; set $$T; IFS="$$i"; t=$$1; shift; \
                    if ! valgrind --error-exitcode=1 --log-file=.tmp.valg ./oceani --section "test: $$t" oceani-tests.mdc $${1+"$$@"} \
                    echo -n "Valgrind $$T.. "; \
                    i="$$IFS"; IFS=,; set $$T; IFS="$$i"; t=$$1; shift; \
                    if ! valgrind --error-exitcode=1 --log-file=.tmp.valg ./oceani --section "test: $$t" oceani-tests.mdc $${1+"$$@"} \
@@ -98,10 +108,11 @@ calculations on them.
 ###### test list
        oceani_tests += "valvar"
 
 ###### test list
        oceani_tests += "valvar"
 
-
 ###### test: valvar
 
 ###### test: valvar
 
-       program:
+       func main
+               argv:[argc::]string
+       do
                a := 23; b:=12 ; b1 := -b
                print a, b, a+b, a-b, a*b, a/b, a%b
                print a<b, a<=b, a>b, a>=b, a<a, a==b, a==a
                a := 23; b:=12 ; b1 := -b
                print a, b, a+b, a-b, a*b, a/b, a%b
                print a<b, a<=b, a>b, a>=b, a<a, a==b, a==a
@@ -115,6 +126,13 @@ calculations on them.
 
                aconst :: string = "unchanging"
 
 
                aconst :: string = "unchanging"
 
+               // Check wrapping
+               print
+                 a + b
+                 + (a*2)
+                 + b1
+                 + b
+
 ###### output: valvar
 
        23 12 35 11 276 1.91667 11
 ###### output: valvar
 
        23 12 35 11 276 1.91667 11
@@ -122,6 +140,7 @@ calculations on them.
        23 12 12 -23 -12 12
        False True True False False False
        This is a string  field theory This is a string field theory
        23 12 12 -23 -12 12
        False True True False False False
        This is a string  field theory This is a string field theory
+       81
 
 Next we change the value of variables
 
 
 Next we change the value of variables
 
@@ -130,7 +149,7 @@ Next we change the value of variables
 
 ###### test: setvar
 
 
 ###### test: setvar
 
-       program:
+       func main()
                a := 4
                a = a * a
                a = (a + a) * (a + a)
                a := 4
                a = a * a
                a = (a + a) * (a + a)
@@ -146,14 +165,14 @@ Now some contants
        oceani_tests += "consts"
 
 ###### test: consts
        oceani_tests += "consts"
 
 ###### test: consts
-       const:
-               pi ::= 3.1415926
+       const
+               pi ::= 3.141 592 653
                four ::= 2 + 2 ; five ::= 10/2
        const pie ::= "I like Pie";
                cake ::= "The cake is"
                  ++ " a lie"
 
                four ::= 2 + 2 ; five ::= 10/2
        const pie ::= "I like Pie";
                cake ::= "The cake is"
                  ++ " a lie"
 
-       program:
+       func main()
                print "Hello World, what lovely oceans you have!"
                print "are there", five, "?"
                print pi, pie, "but", cake
                print "Hello World, what lovely oceans you have!"
                print "are there", five, "?"
                print pi, pie, "but", cake
@@ -170,19 +189,32 @@ Test merging of variables from multiple cases
 
 ###### test: varmerge
 
 
 ###### test: varmerge
 
-       program:
+       func main()
                for i:=0; then i=i+1; while i < 5:
                for i:=0; then i=i+1; while i < 5:
-                       switch i
+                       switch i:
+                               case 0: num:="zero"
+                               case 1: scratch:=42; num:="one"
+                               case 2: num:="two"
+                               case 3: num:="three"
+                               else    num:="many"
+                       print num,", ",
+               print
+
+               for i:=0; then i=i+1; while i < 5:
+                       switch i:
                                case 0: num:="zero"
                                case 1: num:="one"
                                case 2: num:="two"
                                case 3: num:="three"
                                case 0: num:="zero"
                                case 1: num:="one"
                                case 2: num:="two"
                                case 3: num:="three"
-                               else:   num:="many"
+                               else    num:="many"
+                       // re-declare a CondScope variable
+                       num := i*i
                        print num,", ",
                print
 
 ###### output: varmerge
        zero , one , two , three , many , 
                        print num,", ",
                print
 
 ###### output: varmerge
        zero , one , two , three , many , 
+       0 , 1 , 4 , 9 , 16 , 
 
 ## Conditions and Loops
 
 
 ## Conditions and Loops
 
@@ -193,11 +225,11 @@ Now we need to test if/else and some different loops
 
 ###### test: cond_loop
 
 
 ###### test: cond_loop
 
-       program:
+       func main()
                a := 4
                if a < 5:
                        print "Success"
                a := 4
                if a < 5:
                        print "Success"
-               else:
+               else
                        print "Failure"
                for b:=1; then b=b+b; while b < 100:
                        print '', b,
                        print "Failure"
                for b:=1; then b=b+b; while b < 100:
                        print '', b,
@@ -205,12 +237,12 @@ Now we need to test if/else and some different loops
                // Newtons method for square root of 2
                target ::= 2
                guess := target
                // Newtons method for square root of 2
                target ::= 2
                guess := target
-               for:
+               for
                        count: number = 0
                        count: number = 0
-               while:
+               while
                        current := guess * guess
                        use +(current - target) > 0.000000001
                        current := guess * guess
                        use +(current - target) > 0.000000001
-               do:
+               do
                        guess = (guess + (target / guess) ) / 2
                        print count, guess
                        count = count + 1
                        guess = (guess + (target / guess) ) / 2
                        print count, guess
                        count = count + 1
@@ -219,13 +251,30 @@ Now we need to test if/else and some different loops
                for j:=0; then j = j+3 ; while j < 10:
                        if j != 0 and then 20 / j > 3:
                                print "20 /", j," =", 20 / j
                for j:=0; then j = j+3 ; while j < 10:
                        if j != 0 and then 20 / j > 3:
                                print "20 /", j," =", 20 / j
-                       else:
+                       else
                                print "I won't calculate 20 /", j
                pi ::= 3.1415926535897
                if 355/113 == pi or else +(pi - 355/113) < 0.001:
                        print "Close enough"
                print "lower" if 355/113 < pi else "higher"
 
                                print "I won't calculate 20 /", j
                pi ::= 3.1415926535897
                if 355/113 == pi or else +(pi - 355/113) < 0.001:
                        print "Close enough"
                print "lower" if 355/113 < pi else "higher"
 
+               if pi > 3 then print "pi exceeds three"; else print "need more pie"
+               if (pi < 3) { print "not enough pi" } else { print "pi sufficient" }
+               for { i := 0; sum := 0 }
+               then { i = i+1 }
+               while i <= 10:
+                       sum = sum + i
+               else
+                       pass
+                       print "sum 1..10 is", sum
+               if
+                       PI1 := 22/7
+                       use PI1 < pi
+               then
+                       print "Smaller"
+               else
+                       print 'larger'
+
 ###### output: cond_loop
        Success
         1 2 4 8 16 32 64
 ###### output: cond_loop
        Success
         1 2 4 8 16 32 64
@@ -240,6 +289,10 @@ Now we need to test if/else and some different loops
        I won't calculate 20 / 9
        Close enough
        higher
        I won't calculate 20 / 9
        Close enough
        higher
+       pi exceeds three
+       pi sufficient
+       sum 1..10 is 55
+       larger
 
 ## Say Hello
 
 
 ## Say Hello
 
@@ -247,19 +300,22 @@ The demonstration code presented in the interpreted is suitable for the test sui
 Here I break it into two parts, keeping the array code separate.
 
 ###### test list
 Here I break it into two parts, keeping the array code separate.
 
 ###### test list
-       oceani_tests += "sayhello,55,33"
-       oceani_tests += "sayhello,12,60"
+       oceani_tests += "sayhello,55,33,hello,True"
+       oceani_tests += "sayhello,12,60,there,False"
 
 ###### test: sayhello
 
 
 ###### test: sayhello
 
-       program A B:
+       func main(av:[ac::number]string)
+               A := $av[1]; B := $av[2]
+               astr := av[3]
+               bbool := av[ac-1] == "True"
                print "Hello World, what lovely oceans you have!"
                /* When a variable is defined in both branches of an 'if',
                 * and used afterwards, the variables are merged.
                 */
                if A > B:
                        bigger := "yes"
                print "Hello World, what lovely oceans you have!"
                /* When a variable is defined in both branches of an 'if',
                 * and used afterwards, the variables are merged.
                 */
                if A > B:
                        bigger := "yes"
-               else:
+               else
                        bigger := "no"
                print "Is", A, "bigger than", B,"? ", bigger
                /* If a variable is not used after the 'if', no
                        bigger := "no"
                print "Is", A, "bigger than", B,"? ", bigger
                /* If a variable is not used after the 'if', no
@@ -268,26 +324,27 @@ Here I break it into two parts, keeping the array code separate.
                if A > B * 2:
                        double:string = "yes"
                        print A, "is more than twice", B, "?", double
                if A > B * 2:
                        double:string = "yes"
                        print A, "is more than twice", B, "?", double
-               else:
+               else
                        double := B*2
                        print "double", B, "is", double
 
                a : number
                a = A;
                b:number = B
                        double := B*2
                        print "double", B, "is", double
 
                a : number
                a = A;
                b:number = B
+               print "still", bigger // check for regression in scoping
                if a > 0 and b > 0:
                        while a != b:
                                if a < b:
                                        b = b - a
                if a > 0 and b > 0:
                        while a != b:
                                if a < b:
                                        b = b - a
-                               else:
+                               else
                                        a = a - b
                        print "GCD of", A, "and", B,"is", a
                else if a <= 0:
                        print a, "is not positive, cannot calculate GCD"
                                        a = a - b
                        print "GCD of", A, "and", B,"is", a
                else if a <= 0:
                        print a, "is not positive, cannot calculate GCD"
-               else:
+               else
                        print b, "is not positive, cannot calculate GCD"
 
                        print b, "is not positive, cannot calculate GCD"
 
-               for:
+               for
                        togo := 10
                        f1 := 1; f2 := 1
                        print "Fibonacci:", f1,f2,
                        togo := 10
                        f1 := 1; f2 := 1
                        print "Fibonacci:", f1,f2,
@@ -299,50 +356,60 @@ Here I break it into two parts, keeping the array code separate.
                        f2 = f3
                print ""
 
                        f2 = f3
                print ""
 
+               if bbool:
+                       print astr ++ " was the str"
+               else
+                       print "I found the str over " ++ astr
+
                /* Binary search... */
                /* Binary search... */
-               for:
+               for
                        lo:= 0; hi := 100
                        target := 77
                        lo:= 0; hi := 100
                        target := 77
-               while:
+               while
                        mid := (lo + hi) / 2
                        if mid == target:
                                use Found
                        if mid < target:
                                lo = mid
                        mid := (lo + hi) / 2
                        if mid == target:
                                use Found
                        if mid < target:
                                lo = mid
-                       else:
+                       else
                                hi = mid
                        if hi - lo < 1:
                                hi = mid
                        if hi - lo < 1:
+                               lo = mid
                                use GiveUp
                        use True
                                use GiveUp
                        use True
-               do: pass
+               do pass
                case Found:
                        print "Yay, I found", target
                case GiveUp:
                case Found:
                        print "Yay, I found", target
                case GiveUp:
-                       print "Closest I found was", mid
+                       print "Closest I found was", lo
 
 
-###### output: sayhello,55,33
+###### output: sayhello,55,33,hello,True
        Hello World, what lovely oceans you have!
        Is 55 bigger than 33 ?  yes
        double 33 is 66
        Hello World, what lovely oceans you have!
        Is 55 bigger than 33 ?  yes
        double 33 is 66
+       still yes
        GCD of 55 and 33 is 11
        Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
        GCD of 55 and 33 is 11
        Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
+       hello was the str
        Closest I found was 77.3438
 
        Closest I found was 77.3438
 
-###### output: sayhello,12,60
+###### output: sayhello,12,60,there,False
        Hello World, what lovely oceans you have!
        Is 12 bigger than 60 ?  no
        double 60 is 120
        Hello World, what lovely oceans you have!
        Is 12 bigger than 60 ?  no
        double 60 is 120
+       still no
        GCD of 12 and 60 is 12
        Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
        GCD of 12 and 60 is 12
        Fibonacci: 1 1 2 3 5 8 13 21 34 55 89 144
+       I found the str over there
        Closest I found was 77.3438
 
 ###### test list
        oceani_tests += "insert_sort"
 ###### test: insert_sort
        Closest I found was 77.3438
 
 ###### test list
        oceani_tests += "insert_sort"
 ###### test: insert_sort
-       program:
+       func main()
                size::=55
                list:[size]number
                size::=55
                list:[size]number
-               list[0] = 1234
+               list[0] = 1_234
                for i:=1; then i = i + 1; while i < size:
                        n := list[i-1] * list[i-1]
                        list[i] = (n / 100) % 10000
                for i:=1; then i = i + 1; while i < size:
                        n := list[i-1] * list[i-1]
                        list[i] = (n / 100) % 10000
@@ -485,7 +552,7 @@ ad-hoc things array related.
 
 ###### test: arrays
 
 
 ###### test: arrays
 
-       program:
+       func main()
                bools:[5]Boolean
                strings:[4]string
 
                bools:[5]Boolean
                strings:[4]string
 
@@ -493,11 +560,58 @@ ad-hoc things array related.
                bools[1] = strings[2] <= "there"
 
                for i:=0; then i=i+1; while i<5:
                bools[1] = strings[2] <= "there"
 
                for i:=0; then i=i+1; while i<5:
-                       print '', bools[i],
+                       j ::= i
+                       ra:[j]number
+                       ra[i-1] = i*i
+                       ra[6] = 42 // mustn't crash
+                       print '', bools[i], ra[j-1],
                print
 
 ###### output: arrays
                print
 
 ###### output: arrays
-        False True False False False
+        False 0 True 1 False 4 False 9 False 16
+
+## Structures
+
+Time to test if structure declarations and accesses work correctly.
+
+###### test list
+       oceani_tests += structs
+
+###### test: structs
+
+       const three ::= 3
+       struct foo
+               size:[three]number
+               name:string
+               active:Boolean = True
+
+       struct baz { a:number; b:Boolean; }
+
+       func main
+       do
+               info:[4]foo
+
+               for i:=0; then i=i+1; while i < 4:
+                       switch i
+                       case 2: nm:= "peter"
+                       case 0: nm:= "bob"
+                       case 1: nm:= "jane"
+                       else    nm:= "janine"
+
+                       info[i].name = nm
+                       info[i].size[0] = i*i
+                       if nm != "jane":
+                               info[i].active = False
+
+               for i:=0; then i=i+1; while i < 4:
+                       print info[i].name, info[i].active, info[i].size[0]
+
+###### output: structs
+
+       bob False 0
+       jane True 1
+       peter False 4
+       janine False 9
 
 ## Test code with syntax errors
 
 
 ## Test code with syntax errors
 
@@ -535,15 +649,14 @@ separate file first, then run from there.
 
 ###### test: syn1
 
 
 ###### test: syn1
 
-       program:
+       func main()
                if then else while do
 
 ###### output: syn1
                if then else while do
 
 ###### output: syn1
-       .tmp.code:3:11: error: unhandled parse error: then
-       oceani: no program found.
+       .tmp.code:3:11: Syntax error in statement: then
 
 ###### test: tokerr
 
 ###### test: tokerr
-       program:
+       func main()
                a := 1i  // imaginary numbers aren't understood
                b:[2i]number // array sizes are handled separately
                c:[3.14159]Boolean // array sizes must be integers
                a := 1i  // imaginary numbers aren't understood
                b:[2i]number // array sizes are handled separately
                c:[3.14159]Boolean // array sizes must be integers
@@ -593,7 +706,7 @@ various places that `type_err()` are called.
 
 ###### test: type_err1
 
 
 ###### test: type_err1
 
-       program:
+       func main()
                print "hello" ++ 5, 5 ++ "hello"
 
                b ::= 3
                print "hello" ++ 5, 5 ++ "hello"
 
                b ::= 3
@@ -613,7 +726,7 @@ various places that `type_err()` are called.
 
 ###### test: type_err2
 
 
 ###### test: type_err2
 
-       program:
+       func main()
                a := 1
                a := 2
                a ::= 3
                a := 1
                a := 2
                a ::= 3
@@ -634,7 +747,11 @@ various places that `type_err()` are called.
 
 ###### test: type_err3
 
 
 ###### test: type_err3
 
-       program:
+       struct foo
+               a: number
+               b:string = "hello"
+
+       func main()
                c := "hello"
                c = c + 1
                c = "hello" ++ (True and False)
                c := "hello"
                c = c + 1
                c = "hello" ++ (True and False)
@@ -642,11 +759,11 @@ various places that `type_err()` are called.
                print 45 + ( "Hello" ++ "there")
                c[5] = 1
 
                print 45 + ( "Hello" ++ "there")
                c[5] = 1
 
-               while:
+               while
                        use 1
                        use True
                        use "Hello"
                        use 1
                        use True
                        use "Hello"
-               do:
+               do
                        print
                case 1: print "one"
                case "Hello": print "Hello"
                        print
                case 1: print "one"
                case "Hello": print "Hello"
@@ -659,78 +776,108 @@ various places that `type_err()` are called.
                a4[1] = True
                c = a2[3]
 
                a4[1] = True
                c = a2[3]
 
+               bar:foo
+               foo.c = 43
+               print c.foo
+               print bar.c
+               print bar.b + 42
+               
+
+               // trigger 'labels not permitted' error message
+               while 1 if True else False:
+                       print
+               case 2: print "two"
+
 ###### output: type_err3
 ###### output: type_err3
-       .tmp.code:4:12: error: expected number but variable 'c' is string
-       .tmp.code:3:8: info: this is where 'c' was set to string
-       .tmp.code:4:12: error: Arithmetic returns number but string expected
-       .tmp.code:3:8: info: variable 'c' was set as string here.
-       .tmp.code:5:24: error: Boolean operation found where string expected
-       .tmp.code:6:12: error: Comparison returns Boolean but string expected
-       .tmp.code:3:8: info: variable 'c' was set as string here.
-       .tmp.code:7:21: error: Concat returns string but number expected
-       .tmp.code:8:8: error: string cannot be indexed
-       .tmp.code:8:8: error: string cannot be indexed
-       .tmp.code:17:13: error: expected number found string
-       .tmp.code:13:16: error: expected number, found string
-       .tmp.code:20:8: error: cannot assign value of type [5]number
-       .tmp.code:21:13: error: expected [5]number but variable 'a3' is [10]number
-       .tmp.code:19:36: info: this is where 'a3' was set to [10]number
-       .tmp.code:21:8: error: cannot assign value of type [5]number
-       .tmp.code:22:13: error: expected [5]number but variable 'a4' is [5]string
-       .tmp.code:19:51: info: this is where 'a4' was set to [5]string
-       .tmp.code:22:8: error: cannot assign value of type [5]number
-       .tmp.code:23:16: error: expected number found string
-       .tmp.code:24:16: error: expected string found Boolean
-       .tmp.code:25:12: error: have number but need string
-       .tmp.code:3:8: info: variable 'c' was set as string here.
+       .tmp.code:8:12: error: expected number but variable 'c' is string
+       .tmp.code:7:8: info: this is where 'c' was set to string
+       .tmp.code:8:12: error: Arithmetic returns number but string expected
+       .tmp.code:7:8: info: variable 'c' was set as string here.
+       .tmp.code:9:24: error: Boolean operation found where string expected
+       .tmp.code:10:12: error: Comparison returns Boolean but string expected
+       .tmp.code:7:8: info: variable 'c' was set as string here.
+       .tmp.code:11:21: error: Concat returns string but number expected
+       .tmp.code:12:8: error: string cannot be indexed
+       .tmp.code:12:8: error: string cannot be indexed
+       .tmp.code:21:13: error: expected number found string
+       .tmp.code:17:16: error: expected number, found string
+       .tmp.code:24:8: error: cannot assign value of type [5]number
+       .tmp.code:25:13: error: expected [5]number but variable 'a3' is [10]number
+       .tmp.code:23:36: info: this is where 'a3' was set to [10]number
+       .tmp.code:25:8: error: cannot assign value of type [5]number
+       .tmp.code:26:13: error: expected [5]number but variable 'a4' is [5]string
+       .tmp.code:23:51: info: this is where 'a4' was set to [5]string
+       .tmp.code:26:8: error: cannot assign value of type [5]number
+       .tmp.code:27:16: error: expected number found string
+       .tmp.code:28:16: error: expected string found Boolean
+       .tmp.code:29:12: error: have number but need string
+       .tmp.code:7:8: info: variable 'c' was set as string here.
+       .tmp.code:32:8: error: variable used but not declared: foo
+       .tmp.code:32:8: error: field reference attempted on none, not a struct
+       .tmp.code:32:16: error: expected none found number
+       .tmp.code:33:14: error: field reference attempted on string, not a struct
+       .tmp.code:34:14: error: cannot find requested field in foo
+       .tmp.code:35:17: error: have string but need number
+       .tmp.code:39:29: error: expected number (labels not permitted) found Boolean
        oceani: type error in program - not running.
 
 ###### test: type_err4
        oceani: type error in program - not running.
 
 ###### test: type_err4
-       program:
+       func main()
                a:=1; b=2; c::=3
                print a, b, c
 
 ###### output: type_err4
                a:=1; b=2; c::=3
                print a, b, c
 
 ###### output: type_err4
-       .tmp.code:3:14: error: expected *unknown*type* (labels not permitted) but variable 'b' is label
-       .tmp.code:3:14: info: this is where 'b' was set to label
-       .tmp.code:3:16: error: expected label found number
-       .tmp.code:3:14: info: variable 'b' was set as label here.
-       .tmp.code:4:17: error: expected *unknown*type* (labels not permitted) but variable 'b' is label
-       .tmp.code:3:14: info: this is where 'b' was set to label
+       .tmp.code:3:14: error: variable used but not declared: b
+       .tmp.code:3:16: error: expected none found number
+       .tmp.code:3:14: info: variable 'b' was set as none here.
        oceani: type error in program - not running.
 
 ###### test list
        oceani: type error in program - not running.
 
 ###### test list
-       oceani_failing_tests += type_err_const type_err_const1
+       oceani_failing_tests += type_err_const type_err_const1 missing_program
 
 ###### test: type_err_const
 
 ###### test: type_err_const
-       const:
+       const
                foo :: number = 45
                bar ::= "string" + 56
                foo :: number = 45
                bar ::= "string" + 56
-       const:
+       const
                bar ::= "baz"
                bar ::= "baz"
-       program:
+       func main()
                foo := 4
                print foo, bar
 
                foo := 4
                print foo, bar
 
+       // trigger duplicate-main error
+       func main()
+               foo := 6
+               print bar, foo
+
 ###### output: type_err_const
        .tmp.code:4:16: error: expected number found string
        .tmp.code:6:8: error: name already declared: bar
        .tmp.code:4:8: info: this is where 'bar' was first declared
        .tmp.code:8:8: error: variable 'foo' redeclared
        .tmp.code:3:8: info: this is where 'foo' was first declared
 ###### output: type_err_const
        .tmp.code:4:16: error: expected number found string
        .tmp.code:6:8: error: name already declared: bar
        .tmp.code:4:8: info: this is where 'bar' was first declared
        .tmp.code:8:8: error: variable 'foo' redeclared
        .tmp.code:3:8: info: this is where 'foo' was first declared
+       .tmp.code:13:8: error: variable 'foo' redeclared
+       .tmp.code:3:8: info: this is where 'foo' was first declared
+       .tmp.code:13:8: "main" defined a second time
 
 ###### test: type_err_const1
 
 ###### test: type_err_const1
-       const:
+       const
                foo : number = 45
                bar := "string"
                foo : number = 45
                bar := "string"
-       program:
+       func main()
                foo := 4
                print foo, bar
 
 ###### output: type_err_const1
                foo := 4
                print foo, bar
 
 ###### output: type_err_const1
-       .tmp.code:3:12: error: unhandled parse error: :
-       oceani: no program found.
+       .tmp.code:3:12: Syntax error in constant: :
+       .tmp.code:4:12: Syntax error in constant: :
+
+###### test: missing_program
+       const
+               foo::="bar"
 
 
+###### output: missing_program
+       oceani: no main function found.
 
 ## Test erroneous command line args
 
 
 ## Test erroneous command line args
 
@@ -754,7 +901,6 @@ command list possible.
            ./coverage_oceani $${1+"$$@"} > /dev/null 2>&1 ;\
        done || true
 
            ./coverage_oceani $${1+"$$@"} > /dev/null 2>&1 ;\
        done || true
 
-
 ###### test list
        oceani_special_tests += "cmd"
        oceani_special_tests += "cmd,-zyx"
 ###### test list
        oceani_special_tests += "cmd"
        oceani_special_tests += "cmd,-zyx"
@@ -767,7 +913,7 @@ command list possible.
 
 ###### output: cmd,-zyx
        ./oceani: invalid option -- 'z'
 
 ###### output: cmd,-zyx
        ./oceani: invalid option -- 'z'
-       Usage: oceani --trace --print --noexec --brackets--section=SectionName prog.ocn
+       Usage: oceani --trace --print --noexec --brackets --section=SectionName prog.ocn
 
 ###### output: cmd,nofile
        oceani: cannot open nofile
 
 ###### output: cmd,nofile
        oceani: cannot open nofile
@@ -777,4 +923,3 @@ command list possible.
 
 ###### output: cmd,--section,toast:nothing,oceani-tests.mdc
        oceani: cannot find section toast:nothing
 
 ###### output: cmd,--section,toast:nothing,oceani-tests.mdc
        oceani: cannot find section toast:nothing
-