Commits

catseye  committed 5f1e126

Use void * for functions in C backend. Add some OO/MM/GC notes.

  • Participants
  • Parent commits 5dace69

Comments (0)

Files changed (3)

File README.markdown

 
 Functions can be passed to functions and returned from functions.
 
-    | fun double(x) { x * 2 }
+    | fun doubble(x) { x * 2 }
     | fun triple(x) { x * 3 }
     | fun apply_and_add_one(f: (integer -> integer), x) { f(x) + 1 }
-    | fun select(a) { if a > 10 { return double } else { return triple } }
+    | fun sellect(a) { if a > 10 { return doubble } else { return triple } }
     | fun main() {
-    |   t = select(5);
-    |   d = select(15);
+    |   t = sellect(5);
+    |   d = sellect(15);
     |   p = t(10);
     |   apply_and_add_one(d, p)
     | }

File TODO.markdown

 a block, its scope is that block.  It cannot be seen after that block closes.
 (Shadowing is not possible; if the first assignment was before, that outer
 variable is what gets updated.)
+
+### Object Orientation ###
+
+Castile will likely not have any "real" object-oriented features.  Probably,
+only nominal subtyping, with a Lua-like method call operator.  Meaning
+something like this:
+
+    struct counter {
+      value: integer;
+      bump: counter, integer -> counter
+    }
+    
+    struct named_counter < counter {
+      name: string;
+    }
+
+    forward bump: counter, integer -> counter
+
+    bump = fun(c: counter, v: integer) {
+      return make counter(value=c.value + v, bump=bump;
+    }
+
+    new_counter = fun(init) {
+      return make counter(value=init, bump=bump);
+    }
+
+    new_named_counter = fun(init) {
+      g = make named_counter(value=init, bump=bump, name="Jeremy");
+      return g:bump(5);
+    }
+
+`bump` can operate on a `named_counter` type, but only because it
+is declared to be a subtype of `counter`, so its fields are known to be
+a superset of `counter`'s fields.  The `bump` method itself is not defined
+within either structure, and the `:` syntax is used to pass the object as
+the first argument.
+
+### Memory Management ###
+
+Some notes on memory management.
+
+Some properties of Castile have some potential for simplifying memory
+management.  For example, structures are immutable.  I do not expect to
+be able to get away with avoiding garbage collection completely, but I
+suspect there to be ways to tie reference counting to execution in a
+"nice" fashion.  Although this will likely still be difficult.
+
+I'd like Castile's memory allocation system to be based on the following
+idea:
+
+Every time you call a function of type `A -> B`, you have created an
+object of type `B`.
+
+If, in some function, your argument `a` to the call of the function of type
+`A -> B` was your last use of `a`, you have destroyed an object of type `a`.
+(Unless objects of type `B` contain objects of type `A`.)
+
+If you call a function of type `A -> A`, you haven't created or destroyed
+any objects.  (Even if you discard the argument and allocate a new `A` to
+be returned, you can just "allocate" the new `A` over the old one.)
+
+I don't know enough about linear types to know how well that can be
+expressed with them.
+
+Suppose you are `f`, a function `A -> B`, and `B` contains `A`.  You
+actually ignore the `A` given to you, and call another function `g` to
+allocate a new `B` containing the new `A`.
+
+It would seem that the caller of `f` must pass "this is the last use of
+the argument" to you, and that you must pass "it's ok to overwrite
+my `A` with your new `A`" to `g`.  This is complicated enough communication
+that it would probably be best modelled as a global dictionary of some sort,
+rather than each function telling each other function what's up.  For
+example, at the point of the last use of the `A` just before calling `f`, the
+address of that `A` could be placed on a list of "newly available `A`s."

File src/castile/backends/c.py

                 self.out.write(sep)
             self.compile(asts[-1])
 
+    # as used in local variable declarations
     def c_type(self, type):
         if type == Integer():
             return 'int'
         elif isinstance(type, Struct):
             return 'struct %s *' % type.name
         elif isinstance(type, Function):
-            #s = '/* {CTYPE %s */' % type
-            s = '('
-            s += self.c_type(type.return_type) + ' (*)('
-            s += ', '.join([self.c_type(a) for a in type.arg_types])
-            s += '))'
-            #s += '/* }CTYPE */'
-            return s
+            return 'void *'
         elif isinstance(type, Union):
             # oh dear
             return 'void *'
         else:
             raise NotImplementedError(type)
 
-    def c_decl(self, type, name, ptr=False, args=False):
-        if type == Integer():
-            return 'int %s' % name
-        elif type == String():
-            return 'char * %s' % name
-        elif type == Void():
-            return 'void %s' % name
-        elif type == Boolean():
-            return 'int %s' % name
-        elif isinstance(type, Struct):
-            return 'struct %s * %s' % (type.name, name)
-        elif isinstance(type, Function):
-            #s = '/* {CDECL %s */' % type
+    def c_decl(self, type, name, args=True):
+        if isinstance(type, Function):
             s = ''
             s += self.c_type(type.return_type) 
-            if ptr:
-                s += ' (*%s)' % name
-            else:
-                s += ' %s' % name
+            s += ' %s' % name
             if args:
                 s += '('
                 s += ', '.join([self.c_type(a) for a in type.arg_types])
                 s += ')'
-            #s += '/* }CDECL */'
             return s
-        elif isinstance(type, Union):
-            # oh dear
-            return 'void * %s' % name
         else:
-            raise NotImplementedError(type)
+            return '%s %s' % (self.c_type(type), name)
 
     def compile(self, ast):
         if ast.tag == 'Program':
                 self.compile(ast.children[0])
                 self.out.write(';\n')
         elif ast.tag == 'Forward':
-            self.out.write('extern %s;\n' % self.c_decl(ast.children[0].type, ast.value, args=True))
+            self.out.write('extern %s;\n' % self.c_decl(ast.children[0].type, ast.value))
         elif ast.tag == 'StructDefn':
             self.out.write('struct %s {' % ast.value)
             for child in ast.children:
             for child in ast.children:
                 self.compile(child)
         elif ast.tag == 'VarDecl':
-            self.out.write('%s;\n' % self.c_decl(ast.type, ast.value, ptr=True, args=True))
+            self.out.write('%s %s;\n' % (self.c_type(ast.type), ast.value))
         elif ast.tag == 'Block':
             self.out.write('{\n')
             for child in ast.children:
         elif ast.tag == 'VarRef':
             self.out.write(ast.value)
         elif ast.tag == 'FunCall':
+            self.out.write("((")
+            self.out.write(self.c_decl(ast.children[0].type, '(*)'))
+            self.out.write(")")
             self.compile(ast.children[0])
+            self.out.write(")")
             self.out.write('(')
             self.commas(ast.children[1:])
             self.out.write(')')