Commits

Anonymous committed be78940

Test for order not mattering in union types and struct creation.

Comments (0)

Files changed (5)

     | struct person { name: string; age: integer }
     | main = fun() {
     |   var j = make person(name:"Jake", age:"Old enough to know better");
-    |   j
+    |   j.age
     | }
     ? type mismatch
 
     | struct person { name: string; age: integer }
     | main = fun() {
     |   var j = make person(name:"Jake");
-    |   j
+    |   j.age
     | }
     ? argument mismatch
 
     | struct person { name: string }
     | main = fun() {
-    |   make person(name:"Jake", age:23);
+    |   var j = make person(name:"Jake", age:23);
+    |   j.age
     | }
     ? argument mismatch
 
+Order of field initialization when making a struct doesn't matter.
+
+    | struct person { name: string; age: integer }
+    | main = fun() {
+    |   var j = make person(age: 23, name:"Jake");
+    |   j.age
+    | }
+    = 23
+
+Structs can be tested for equality.  (Since structs are immutable, it
+doesn't matter if this is structural equality or identity.)
+
+    | struct person { age: integer; name: string }
+    | main = fun() {
+    |   var j = make person(age: 23, name:"Jake");
+    |   var k = make person(age: 23, name:"Jake");
+    |   j == k
+    | }
+    = True
+
+    | struct person { name: string; age: integer }
+    | main = fun() {
+    |   var j = make person(age: 23, name:"Jake");
+    |   var k = make person(name:"Jake", age: 23);
+    |   j == k
+    | }
+    = True
+
+    | struct person { age: integer; name: string }
+    | main = fun() {
+    |   var j = make person(age: 23, name:"Jake");
+    |   var k = make person(age: 23, name:"John");
+    |   j == k
+    | }
+    = False
+
 Structs can be passed to functions.
 
     | struct person { name: string; age: integer }
     | }
     = 2
 
+Order of types in a union doesn't matter.
+
+    | fun foo(a, b: integer|string) {
+    |   a + 1
+    | }
+    | main = fun() {
+    |   var a = 0;
+    |   a = foo(a, 333 as integer|string);
+    |   a = foo(a, "hiya" as string|integer);
+    |   a
+    | }
+    = 2
+
 The `typecase` construct can operate on the "right" type of a union.
 
     | fun foo(a, b: integer|string) {
 
 Name mangling for compilers (prepend with `_` most likely.)
 
-Tests for struct equality, union value equality, unions of unions.
-
-Test that order doesn't matter in unions, or in field assignments during a make.
+Tests for unions of unions.
 
 ### Implementation ###
 
-Handle empty structs correctly on stackmac.
+Struct equality in Javascript, stackmac backends.
+
+"struct size" function in stackmac backend, for structs with no fields or
+void fields.
 
 Figure out a way to do `input`, `read`, and `write` with node.js backend.
 
 
 "assignable" in typechecker -- can be done more cleanly with ScopedDict?
 
+Get rid of redundant struct_fields attr in checker.
+
 ### Design ###
 
 Convenience:
 *   Should we have automatic promotion (value tagging?)
     Since it causes an operation, I think it should be explicit, but the
     explicit syntax could be more lightweight.
+*   Lua-esque `:` operator: `a:b(c)` -> `a.b(a, c)`
 
 Type promotion with higher precedence?  So that it can be used at toplevel.
 

src/castile/backends/stackmac.py

             assert ast.children[0].type == 'VarRef'
             self.out.write('set_local %s_local_%s\n' % (self.fun_lit, ast.children[0].value))
         elif ast.type == 'Make':
+            # TODO store in the order defined in the struct?
+            fields = {}
             for child in ast.children[1:]:
-                self.compile(child)
+                fields[child.aux] = child   # FieldInit.aux = position in struct
+            for position in sorted(fields):
+                self.compile(fields[position])
             self.out.write('push %d\n' % (len(ast.children) - 1))
             self.out.write('make_struct\n')  # sigh
         elif ast.type == 'FieldInit':

src/castile/checker.py

     pass
 
 
+class StructDefinition(object):
+    def __init__(self, name, field_names, content_types):
+        self.name = name
+        self.field_names = field_names  # dict of name -> position
+        self.content_types = content_types  # list of types in order
+
+
 class TypeChecker(object):
     def __init__(self):
         global_context = {}
             struct_fields[field_name] = i
             i += 1
             te.append(self.type_of(child.children[0]))
-        self.structs[name] = StructDefinition(ast.value, te)
+        self.structs[name] = StructDefinition(ast.value, struct_fields, te)
 
     # context is modified as side-effect of traversal
     def type_of(self, ast):
                 raise CastileTypeError("argument mismatch")
             i = 0
             for defn in ast.children[1:]:
+                name = defn.value
                 t1 = self.type_of(defn)
-                self.assert_eq(t1, struct_defn.content_types[i])
+                pos = struct_defn.field_names[name]
+                defn.aux = pos
+                self.assert_eq(t1, struct_defn.content_types[pos])
                 i += 1
             return t
         elif ast.type == 'FieldInit':

src/castile/types.py

         return "struct %s" % self.name
 
 
-# NOTE: NOT A TYPE
-class StructDefinition(object):
-    def __init__(self, name, content_types):
-        self.name = name
-        self.content_types = content_types
-
-
 class Union(Type):
     def __init__(self, content_types):
         self.content_types = content_types
 
     def __str__(self):
         h = "union("
-        h += ', '.join([str(t) for t in self.content_types])
+        h += ', '.join(sorted([str(t) for t in self.content_types]))
         h += ')'
         return h