]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani-tests.mdc
oceani: propagate_type should return the found type, not what it was compatible with
[ocean] / csrc / oceani-tests.mdc
index 881fee7229e7642869bca66b3cc79c9d808ad63d..1a36534abf4ba13b6079e4f80ecc22132ecc1b46 100644 (file)
@@ -35,6 +35,8 @@ arguments separated from the name by commas.  For each test, there is a section
 
        oceani_tests :=
        ## test list
 
        oceani_tests :=
        ## test list
+       oceani_valg_tests := $(oceani_tests)
+       ## combine test lists
 
        tests:: oceani_test_suite
        oceani_test_suite: oceani coverage_oceani
 
        tests:: oceani_test_suite
        oceani_test_suite: oceani coverage_oceani
@@ -78,17 +80,13 @@ arguments separated from the name by commas.  For each test, there is a section
                @for i in coverage/#*.gcda; do mv $$i coverage/$${i##*#}; done
                @gcov -o coverage oceani.mdc > /dev/null 2> /dev/null
                @mv *.gcov coverage ; [ -f .gcov ] && mv .gcov coverage || true
                @for i in coverage/#*.gcda; do mv $$i coverage/$${i##*#}; done
                @gcov -o coverage oceani.mdc > /dev/null 2> /dev/null
                @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); \
-                        if (ran < (ran + skip) *0.944) exit(1) }' \
-                       coverage/oceani.mdc.gcov
                @rm -f .tmp*
 
                @rm -f .tmp*
 
-               @[ -n "$$SKIP_VALGRIND" ] || for T in $(oceani_tests); do \
+               @[ -n "$$SKIP_VALGRIND" ] || for T in $(oceani_valg_tests); do \
                    echo -n "Valgrind $$T.. "; \
                    i="$$IFS"; IFS=,; set $$T; IFS="$$i"; t=$$1; shift; \
                    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+"$$@"} \
-                        > /dev/null 2>&1 ; then \
+                   if valgrind --error-exitcode=42 --log-file=.tmp.valg ./oceani --section "test: $$t" oceani-tests.mdc $${1+"$$@"} \
+                        > /dev/null 2>&1 ; [ $$? -eq 42 ] ; then \
                       echo "FAILED"; cat .tmp.valg; exit 1; fi ; \
                    if grep 'LEAK SUMMARY' .tmp.valg > /dev/null; then \
                       echo "valgrind found LEAKS"; cat .tmp.valg ; exit 1 ; fi; \
                       echo "FAILED"; cat .tmp.valg; exit 1; fi ; \
                    if grep 'LEAK SUMMARY' .tmp.valg > /dev/null; then \
                       echo "valgrind found LEAKS"; cat .tmp.valg ; exit 1 ; fi; \
@@ -96,6 +94,11 @@ arguments separated from the name by commas.  For each test, there is a section
                       echo "valgrind found memory in use at exit"; cat .tmp.valg ; exit 1 ; fi; \
                    echo " passed"; \
                done
                       echo "valgrind found memory in use at exit"; cat .tmp.valg ; exit 1 ; fi; \
                    echo " passed"; \
                done
+               ## valgrind test code
+               @[ -n "$$SKIP_COVERAGE_CHECK" ] || awk '/NOTEST/ { next } /^ *[1-9]/ {ran+=1} /^ *###/ {skip+=1} \
+                   END {printf "coverage: %6.2f%%\n", ran * 100 / (ran + skip); \
+                        if (ran < (ran + skip) *0.972) exit(1) }' \
+                       coverage/oceani.mdc.gcov
 
        coverage_oceani: oceani.c
                $(CC) $(CFLAGS) --coverage -fprofile-dir=coverage -o coverage_oceani oceani.c $(LDLIBS)
 
        coverage_oceani: oceani.c
                $(CC) $(CFLAGS) --coverage -fprofile-dir=coverage -o coverage_oceani oceani.c $(LDLIBS)
@@ -110,9 +113,7 @@ calculations on them.
 
 ###### test: valvar
 
 
 ###### test: valvar
 
-       func main
-               argv:[argc::]string
-       do
+       func main(argv:[argc::]string)
                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
@@ -133,14 +134,26 @@ calculations on them.
                  + b1
                  + b
 
                  + b1
                  + b
 
+               z:Boolean= True
+               w:Boolean = False
+               if ?z:
+                       print "w??z", w??z
+                       print "z??w", z??w
+                       print "z??False", z??False, "w??False", w??False
+               if ?w:
+                       print "Weird?"
+
 ###### output: valvar
 
 ###### output: valvar
 
-       23 12 35 11 276 1.91667 11
+       23 12 35 11 276 1.916666667 11
        False False True True False False True
        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
        False False True True False False True
        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
+       w??z True
+       z??w True
+       z??False True w??False False
 
 Next we change the value of variables
 
 
 Next we change the value of variables
 
@@ -157,7 +170,7 @@ Next we change the value of variables
                print a, a/a
 
 ###### output: setvar
                print a, a/a
 
 ###### output: setvar
-       1.07374e+09 1
+       1073741824 1
 
 Now some contants
 
 
 Now some contants
 
@@ -166,6 +179,7 @@ Now some contants
 
 ###### test: consts
        const
 
 ###### test: consts
        const
+               tau ::= pi * 2
                pi ::= 3.141 592 653
                four ::= 2 + 2 ; five ::= 10/2
        const pie ::= "I like Pie";
                pi ::= 3.141 592 653
                four ::= 2 + 2 ; five ::= 10/2
        const pie ::= "I like Pie";
@@ -175,12 +189,12 @@ Now some contants
        func main()
                print "Hello World, what lovely oceans you have!"
                print "are there", five, "?"
        func main()
                print "Hello World, what lovely oceans you have!"
                print "are there", five, "?"
-               print pi, pie, "but", cake
+               print pi, pie, "but", cake, "Tau is", tau
 
 ###### output: consts
        Hello World, what lovely oceans you have!
        are there 5 ?
 
 ###### output: consts
        Hello World, what lovely oceans you have!
        are there 5 ?
-       3.14159 I like Pie but The cake is a lie
+       3.141592653 I like Pie but The cake is a lie Tau is 6.283185306
 
 Test merging of variables from multiple cases
 
 
 Test merging of variables from multiple cases
 
@@ -193,7 +207,7 @@ Test merging of variables from multiple cases
                for i:=0; then i=i+1; while i < 5:
                        switch i:
                                case 0: num:="zero"
                for i:=0; then i=i+1; while i < 5:
                        switch i:
                                case 0: num:="zero"
-                               case 1: num:="one"
+                               case 1: scratch:=42; num:="one"
                                case 2: num:="two"
                                case 3: num:="three"
                                else    num:="many"
                                case 2: num:="two"
                                case 3: num:="three"
                                else    num:="many"
@@ -267,24 +281,32 @@ Now we need to test if/else and some different loops
                else
                        pass
                        print "sum 1..10 is", sum
                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
        0 1.5
 
 ###### output: cond_loop
        Success
         1 2 4 8 16 32 64
        0 1.5
-       1 1.41667
-       2 1.41422
-       3 1.41421
-       error is  -4.51095e-12
+       1 1.416666667
+       2 1.414215686
+       3 1.414213562
+       error is  -4.510950445e-12
        I won't calculate 20 / 0
        I won't calculate 20 / 0
-       20 / 3  = 6.66667
-       20 / 6  = 3.33333
+       20 / 3  = 6.666666667
+       20 / 6  = 3.333333333
        I won't calculate 20 / 9
        Close enough
        higher
        pi exceeds three
        pi sufficient
        sum 1..10 is 55
        I won't calculate 20 / 9
        Close enough
        higher
        pi exceeds three
        pi sufficient
        sum 1..10 is 55
+       larger
 
 ## Say Hello
 
 
 ## Say Hello
 
@@ -323,6 +345,7 @@ Here I break it into two parts, keeping the array code separate.
                a : number
                a = A;
                b:number = B
                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:
                if a > 0 and b > 0:
                        while a != b:
                                if a < b:
@@ -359,37 +382,40 @@ Here I break it into two parts, keeping the array code separate.
                while
                        mid := (lo + hi) / 2
                        if mid == target:
                while
                        mid := (lo + hi) / 2
                        if mid == target:
-                               use Found
+                               use .Found
                        if mid < target:
                                lo = mid
                        else
                                hi = mid
                        if hi - lo < 1:
                        if mid < target:
                                lo = mid
                        else
                                hi = mid
                        if hi - lo < 1:
-                               use GiveUp
+                               lo = mid
+                               use .GiveUp
                        use True
                do pass
                        use True
                do pass
-               case Found:
+               case .Found:
                        print "Yay, I found", target
                        print "Yay, I found", target
-               case GiveUp:
-                       print "Closest I found was", mid
+               case .GiveUp:
+                       print "Closest I found was", lo
 
 ###### output: sayhello,55,33,hello,True
        Hello World, what lovely oceans you have!
        Is 55 bigger than 33 ?  yes
        double 33 is 66
 
 ###### output: sayhello,55,33,hello,True
        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
        hello was the str
        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.34375
 
 ###### output: sayhello,12,60,there,False
        Hello World, what lovely oceans you have!
        Is 12 bigger than 60 ?  no
        double 60 is 120
 
 ###### output: sayhello,12,60,there,False
        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
        I found the str over there
        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
+       Closest I found was 77.34375
 
 ###### test list
        oceani_tests += "insert_sort"
 
 ###### test list
        oceani_tests += "insert_sort"
@@ -571,6 +597,7 @@ Time to test if structure declarations and accesses work correctly.
        struct foo
                size:[three]number
                name:string
        struct foo
                size:[three]number
                name:string
+               thing:baz
                active:Boolean = True
 
        struct baz { a:number; b:Boolean; }
                active:Boolean = True
 
        struct baz { a:number; b:Boolean; }
@@ -593,6 +620,7 @@ Time to test if structure declarations and accesses work correctly.
 
                for i:=0; then i=i+1; while i < 4:
                        print info[i].name, info[i].active, info[i].size[0]
 
                for i:=0; then i=i+1; while i < 4:
                        print info[i].name, info[i].active, info[i].size[0]
+               info[0].thing.b = True
 
 ###### output: structs
 
 
 ###### output: structs
 
@@ -601,6 +629,148 @@ Time to test if structure declarations and accesses work correctly.
        peter False 4
        janine False 9
 
        peter False 4
        janine False 9
 
+## Functions
+
+Test functions.  They don't return anything, so we need to get them to print
+
+###### test list
+       oceani_tests += functions func_ret_type
+
+###### test: functions
+
+       func test1
+               t: Boolean
+       do
+               if t:
+                       print "true"
+
+       func noarg
+       do
+               pass
+
+       func twoarg
+               a:number
+               b:string
+       do
+               while a > 0:
+                       print b
+                       a = a - 1
+
+       func test(n:number; s:string)
+               if n >= 1:
+                       print n,s,
+                       test(n-1, "."++s)
+               else
+                       print "done"
+
+       func to_polar
+               x:number; y:number
+       return
+               rho:number
+               theta:number
+       do
+               rho = x + y
+               theta = x - y
+
+       func main()
+               for i:=0; then i = i + 1; while i < 5:
+                       test(i, " ")
+               angular := to_polar(32, 23)
+               print angular.rho, angular.theta
+
+###### output: functions
+       done
+       1  done
+       2  1 . done
+       3  2 . 1 .. done
+       4  3 . 2 .. 1 ... done
+       55 9
+
+###### test: func_ret_type
+
+       func double(n:number):number
+               use n+n
+
+       func answer
+               prefix:string
+               suffix:string
+       return string
+       do
+               use prefix ++ suffix
+
+       func noarg_returns
+       return Boolean
+       do
+               use 22/7 == 3.14159
+
+       func main()
+               for j:=10; then j = j - 3; while j > -5:
+                       print answer("dou","ble"), j, "is", double(j)
+
+###### output: func_ret_type
+       double 10 is 20
+       double 7 is 14
+       double 4 is 8
+       double 1 is 2
+       double -2 is -4
+
+## References
+
+A simple linked list example
+
+###### test list
+       oceani_tests += "linked_list,one,two,three,four"
+
+###### test: linked_list
+
+       struct node
+               next: @node
+               this: string
+
+       func insert(list:@node; new:string):@node
+               p:=list
+               prev := @nil
+               while ?p and then p.this < new:
+                       prev = p
+                       p = p.next
+               if ?prev:
+                       prev.next = @new()
+                       prev.next.next = p
+                       prev.next.this = new
+               else
+                       list = @new()
+                       list.next = p
+                       list.this = new
+               use list
+
+       func printlist(list:@node)
+               while ?list:
+                       print list@.this
+                       list = list@.next
+
+       func freelist(list:@node)
+               if list != @nil:
+                       freelist(list.next)
+                       @free = list
+
+       func main(argv:[ac::]string)
+               list := insert(@nil, "@start")
+               list = insert(list, "~end")
+               for i:=1; then i=i+1; while i < ac:
+                       list = insert(list, argv[i])
+               list = insert(list, "Hello!")
+               printlist(list)
+               freelist(list)
+
+###### output: linked_list,one,two,three,four
+       @start
+       Hello!
+       four
+       one
+       three
+       two
+       ~end
+
 ## Test code with syntax errors
 
 Syntax errors aren't handled well yet - the result is almost always a
 ## Test code with syntax errors
 
 Syntax errors aren't handled well yet - the result is almost always a
@@ -631,6 +801,9 @@ separate file first, then run from there.
            ./coverage_oceani --section "test: $$t" oceani-tests.mdc > /dev/null 2>&1 ;\
        done || true
 
            ./coverage_oceani --section "test: $$t" oceani-tests.mdc > /dev/null 2>&1 ;\
        done || true
 
+###### combine test lists
+       oceani_valg_tests += $(oceani_failing_tests)
+
 ###### test list
        oceani_failing_tests := syn1
        oceani_failing_tests += tokerr
 ###### test list
        oceani_failing_tests := syn1
        oceani_failing_tests += tokerr
@@ -674,10 +847,10 @@ separate file first, then run from there.
                This is a multiline string
                With an unsupportable suffix
                """Aa
                This is a multiline string
                With an unsupportable suffix
                """Aa
-       .tmp.code:14:11: error: undefined type: unknown
        .tmp.code:15:12: error: name undeclared: unknowable
        .tmp.code:17:12: error: array size must be a constant: zzsize
        .tmp.code:20:12: error: unrecognised number: 00123
        .tmp.code:15:12: error: name undeclared: unknowable
        .tmp.code:17:12: error: array size must be a constant: zzsize
        .tmp.code:20:12: error: unrecognised number: 00123
+       .tmp.code:14:11: error: type used but not declared: unknown
 
 ## Tests for type errors
 
 
 ## Tests for type errors
 
@@ -690,7 +863,7 @@ These programs were generated by looking for the
 various places that `type_err()` are called.
 
 ###### test list
 various places that `type_err()` are called.
 
 ###### test list
-       oceani_failing_tests += type_err1 type_err2 type_err3 type_err4
+       oceani_failing_tests += type_err1 type_err2 type_err3 type_err4 type_err5 type_err6
 
 ###### test: type_err1
 
 
 ###### test: type_err1
 
@@ -701,15 +874,18 @@ various places that `type_err()` are called.
                b = b + 1
 
                if 3 * 4 and not True: print "Weird"
                b = b + 1
 
                if 3 * 4 and not True: print "Weird"
+               d:number = .fred
+               (d + b) = 12
 
 ###### output: type_err1
        .tmp.code:3:25: error: expected string found number
        .tmp.code:3:28: error: expected string found number
        .tmp.code:6:8: error: Cannot assign to a constant: b
        .tmp.code:5:8: info: name was defined as a constant here
 
 ###### output: type_err1
        .tmp.code:3:25: error: expected string found number
        .tmp.code:3:28: error: expected string found number
        .tmp.code:6:8: error: Cannot assign to a constant: b
        .tmp.code:5:8: info: name was defined as a constant here
-       .tmp.code:6:8: error: Cannot assign to a constant: b
-       .tmp.code:5:8: info: name was defined as a constant here
        .tmp.code:8:11: error: Arithmetic returns number but Boolean expected
        .tmp.code:8:11: error: Arithmetic returns number but Boolean expected
+       .tmp.code:9:20: error: expected number found label
+       .tmp.code:9:8: info: variable 'd' was set as number here.
+       .tmp.code:10:8: error: cannot assign to an rval
        oceani: type error in program - not running.
 
 ###### test: type_err2
        oceani: type error in program - not running.
 
 ###### test: type_err2
@@ -768,6 +944,12 @@ various places that `type_err()` are called.
                foo.c = 43
                print c.foo
                print bar.c
                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
        .tmp.code:8:12: error: expected number but variable 'c' is string
 
 ###### output: type_err3
        .tmp.code:8:12: error: expected number but variable 'c' is string
@@ -785,19 +967,23 @@ various places that `type_err()` are called.
        .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: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:23:8: info: variable 'a1' was set as [5]number here.
        .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: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:23:8: info: variable 'a1' was set as [5]number here.
        .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: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:8: error: field reference on none is not supported
        .tmp.code:32:16: error: expected none found number
        .tmp.code:32:16: error: expected none found number
-       .tmp.code:33:14: error: field reference attempted on string, not a struct
+       .tmp.code:33:14: error: field reference on string is not supported
        .tmp.code:34:14: error: cannot find requested field in foo
        .tmp.code:34:14: error: cannot find requested field in foo
+       .tmp.code:35:17: error: have string but need number
+       .tmp.code:38:29: error: expected number found Boolean
        oceani: type error in program - not running.
 
 ###### test: type_err4
        oceani: type error in program - not running.
 
 ###### test: type_err4
@@ -811,8 +997,38 @@ various places that `type_err()` are called.
        .tmp.code:3:14: info: variable 'b' was set as none here.
        oceani: type error in program - not running.
 
        .tmp.code:3:14: info: variable 'b' was set as none here.
        oceani: type error in program - not running.
 
+###### test: type_err5
+       struct foo
+               bar:baz
+               a:number
+       struct baz
+               bat:foo
+               b:string
+       struct foo
+               c:number
+
+###### output: type_err5
+       .tmp.code:8:7: error: type already declared: foo
+       .tmp.code:2:7: info: this is location of declartion: foo
+       .tmp.code:2:7: error: type has recursive definition: foo
+       .tmp.code:5:7: error: type has recursive definition: baz
+
+###### test: type_err6
+
+       func main()
+               a:= "hello"
+               if ?a:
+                       print "no"
+               print a ?? "there"
+
+###### output: type_err6
+       .tmp.code:4:12: error: '?' requires a testable value, not string
+       .tmp.code:6:14: error: "??" requires a testable value, not string
+       oceani: type error in program - not running.
+
+
 ###### test list
 ###### test list
-       oceani_failing_tests += type_err_const type_err_const1 missing_program
+       oceani_failing_tests += type_err_const type_err_const1 type_err_const2 missing_program bad_main
 
 ###### test: type_err_const
        const
 
 ###### test: type_err_const
        const
@@ -824,12 +1040,21 @@ various places that `type_err()` are called.
                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
 ###### 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: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:12:5: error: function 'main' redeclared
+       .tmp.code:7:5: info: this is where 'main' 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:4:16: error: expected number found string
 
 ###### test: type_err_const1
        const
 
 ###### test: type_err_const1
        const
@@ -843,6 +1068,15 @@ various places that `type_err()` are called.
        .tmp.code:3:12: Syntax error in constant: :
        .tmp.code:4:12: Syntax error in constant: :
 
        .tmp.code:3:12: Syntax error in constant: :
        .tmp.code:4:12: Syntax error in constant: :
 
+###### test: type_err_const2
+       const
+               four ::= two + two
+               two ::= four / 2
+       
+###### output: type_err_const2
+       .tmp.code:3:8: error: const four cannot be resolved.
+       .tmp.code:4:8: error: const two cannot be resolved.
+
 ###### test: missing_program
        const
                foo::="bar"
 ###### test: missing_program
        const
                foo::="bar"
@@ -850,6 +1084,139 @@ various places that `type_err()` are called.
 ###### output: missing_program
        oceani: no main function found.
 
 ###### output: missing_program
        oceani: no main function found.
 
+###### test: bad_main
+       func main(foo:string)
+               print foo
+
+###### output: bad_main
+       .tmp.code:2:10: error: expected []string but variable 'foo' is string
+       .tmp.code:2:10: info: this is where 'foo' was set to string
+       oceani: main has wrong type.
+
+Test for type errors with functions
+
+###### test list
+       oceani_failing_tests += func_err_args func_err_redeclare
+
+###### test: func_err_args
+
+       func test1(a:number; b:string; c:[3]Boolean)
+               print a, b, c[1]
+
+       func test2(a:number; b:string; c:[3]Boolean)
+               print a, b, c[1]
+
+       func test3()
+               # use undefined names
+               print a, z
+
+       func main()
+               truth:[3]Boolean
+               truth[1] = True
+               test1(1,"hello")
+               test1("hello",1)
+               test1(1, "two", truth)
+               test1(1, 2, truth)
+               test1(1, "lo", truth, 4)
+               print test(), test1(1,2,3)
+               if test1 == test2:
+                       pass
+
+       func test4(a:number):string
+               use a * a
+
+       func test5(a:number):string
+               print a
+
+       struct foo
+               a: number
+               b:string = "hello"
+
+       func test6(a:number):foo
+               b:foo
+               b.a = a
+               use b
+
+###### output: func_err_args
+       .tmp.code:34:5: error: function cannot return value of type foo
+       .tmp.code:28:8: error: expected string, found none
+       .tmp.code:25:8: error: expected string, found number
+       .tmp.code:15:14: error: insufficient arguments to function.
+       .tmp.code:16:14: error: expected number found string
+       .tmp.code:16:22: error: expected string found number
+       .tmp.code:16:14: error: insufficient arguments to function.
+       .tmp.code:18:17: error: expected string found number
+       .tmp.code:19:14: error: too many arguments to function.
+       .tmp.code:20:14: error: attempt to call a non-function.
+       .tmp.code:20:32: error: expected string found number
+       .tmp.code:20:28: error: insufficient arguments to function.
+       .tmp.code:21:20: error: expected "func test1" but variable 'test2' is "func test2"
+       .tmp.code:5:5: info: this is where 'test2' was set to "func test2"
+       .tmp.code:10:14: error: variable used but not declared: a
+       .tmp.code:10:17: error: variable used but not declared: z
+       oceani: type error in program - not running.
+
+###### test: func_err_redeclare
+
+       func test1(a:number; b:string; c:[3]Boolean)
+               print a, b, c[1]
+
+       func test1
+       do
+               pass
+
+       func test1
+               b:Boolean
+       do
+               pass
+
+###### output: func_err_redeclare
+       .tmp.code:5:5: error: function 'test1' redeclared
+       .tmp.code:2:5: info: this is where 'test1' was first declared
+       .tmp.code:9:5: error: function 'test1' redeclared
+       .tmp.code:2:5: info: this is where 'test1' was first declared
+
+Test for errors with references
+
+###### test list
+       oceani_failing_tests += ref_err1 ref_err2
+
+###### test: ref_err1
+       func main()
+               ref:@number
+               @foo = ref
+               ref = @old()
+               if ref == @null:
+                       print "null"
+
+###### output: ref_err1
+       .tmp.code:4:9: error: only "@free" makes sense here: foo
+       .tmp.code:5:15: error: Only reference function is "@new()": old
+       .tmp.code:6:19: error: Only reference value is "@nil": null
+
+###### test: ref_err2
+       func main()
+               ref:@number
+               ref2:@string
+               num:number = @new()
+               print num@
+               if num == @nil or ref == ref2 or ref == 2 or ref.foo:
+                       @free = num
+
+###### output: ref_err2
+       .tmp.code:5:22: error: @new() can only be used with references, not number
+       .tmp.code:5:8: info: variable 'num' was set as number here.
+       .tmp.code:6:14: error: Cannot dereference number
+       .tmp.code:7:19: error: @nil can only be used with reference, not number
+       .tmp.code:7:33: error: expected @number but variable 'ref2' is @string
+       .tmp.code:4:8: info: this is where 'ref2' was set to @string
+       .tmp.code:7:48: error: expected @number found number
+       .tmp.code:7:53: error: field reference on number is not supported
+       .tmp.code:7:56: error: have none but need Boolean
+       .tmp.code:8:17: error: @free can only be assigned a reference, not number
+       .tmp.code:8:17: error: @free can only be assigned a reference, not number
+       oceani: type error in program - not running.
+
 ## Test erroneous command line args
 
 To improve coverage, we want to test correct handling of strange command
 ## Test erroneous command line args
 
 To improve coverage, we want to test correct handling of strange command
@@ -871,6 +1238,19 @@ command list possible.
            echo  "passed"; \
            ./coverage_oceani $${1+"$$@"} > /dev/null 2>&1 ;\
        done || true
            echo  "passed"; \
            ./coverage_oceani $${1+"$$@"} > /dev/null 2>&1 ;\
        done || true
+###### valgrind test code
+       @[ -n "$$SKIP_VALGRIND" ] || for t in $(oceani_special_tests); do\
+           echo -n "Valgrind $$t.. "; \
+           i="$$IFS"; IFS=,; set $$t; IFS="$$i"; shift ;\
+           if valgrind --error-exitcode=42 --log-file=.tmp.valg ./oceani $${1+"$$@"} > .tmp.have 2>&1 ;\
+              [ $$? -eq 42 ]; then \
+                      echo "FAILED"; cat .tmp.valg; exit 1; fi ; \
+           if grep 'LEAK SUMMARY' .tmp.valg > /dev/null; then \
+              echo "valgrind found LEAKS"; cat .tmp.valg ; exit 1 ; fi; \
+           if grep 'in use at exit [1-9]' .tmp.valg > /dev/null; then \
+              echo "valgrind found memory in use at exit"; cat .tmp.valg ; exit 1 ; fi; \
+           echo " passed"; \
+       done
 
 ###### test list
        oceani_special_tests += "cmd"
 
 ###### test list
        oceani_special_tests += "cmd"