A pretty featureful commit:
[fur] / templates / program.c
index d027c52..063587d 100644 (file)
@@ -1,3 +1,6 @@
+#include <assert.h>
+#include <inttypes.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -7,6 +10,12 @@
 
 struct String;
 typedef struct String String;
+enum Type;
+typedef enum Type Type;
+union Instance;
+typedef union Instance Instance;
+struct Object;
+typedef struct Object Object;
 struct Runtime;
 typedef struct Runtime Runtime;
 
@@ -16,6 +25,24 @@ struct String
   char* characters;
 };
 
+enum Type
+{
+  INTEGER,
+  STRING
+};
+
+union Instance
+{
+  int32_t integer;
+  String* string;
+};
+
+struct Object
+{
+  Type type;
+  Instance instance;
+};
+
 struct Runtime
 {
   size_t permanentStringsLength;
@@ -64,21 +91,114 @@ void Runtime_addPermanentString(Runtime* self, String* string)
   self->permanentStringsLength++;
 }
 
-String* stringLiteral(Runtime* runtime, const char* literal)
+Object integerLiteral(int32_t literal)
+{
+  Object result;
+  result.type = INTEGER;
+  result.instance.integer = literal;
+  return result;
+}
+
+Object stringLiteral(Runtime* runtime, const char* literal)
+{
+  String* resultString = malloc(sizeof(String));
+  resultString->length = strlen(literal);
+  resultString->characters = malloc(resultString->length);
+  memcpy(resultString->characters, literal, resultString->length);
+  Runtime_addPermanentString(runtime, resultString);
+
+  Object result;
+  result.type = STRING;
+  result.instance.string = resultString;
+  return result;
+}
+
+// TODO Make this conditionally added
+Object builtin$add(Object left, Object right)
+{
+  assert(left.type == INTEGER);
+  assert(right.type == INTEGER);
+
+  Object result;
+  result.type = INTEGER;
+  result.instance.integer = left.instance.integer + right.instance.integer;
+  return result;
+}
+
+Object builtin$subtract(Object left, Object right)
+{
+  assert(left.type == INTEGER);
+  assert(right.type == INTEGER);
+
+  Object result;
+  result.type = INTEGER;
+  result.instance.integer = left.instance.integer - right.instance.integer;
+  return result;
+}
+
+Object builtin$multiply(Object left, Object right)
+{
+  assert(left.type == INTEGER);
+  assert(right.type == INTEGER);
+
+  Object result;
+  result.type = INTEGER;
+  result.instance.integer = left.instance.integer * right.instance.integer;
+  return result;
+}
+
+Object builtin$integerDivide(Object left, Object right)
+{
+  assert(left.type == INTEGER);
+  assert(right.type == INTEGER);
+
+  Object result;
+  result.type = INTEGER;
+  result.instance.integer = left.instance.integer / right.instance.integer;
+  return result;
+}
+
+Object builtin$modularDivide(Object left, Object right)
+{
+  assert(left.type == INTEGER);
+  assert(right.type == INTEGER);
+
+  Object result;
+  result.type = INTEGER;
+  result.instance.integer = left.instance.integer % right.instance.integer;
+  return result;
+}
+
+{% if 'pow' in builtins %}
+Object builtin$pow(Object base, Object exponent)
 {
-  String* result = malloc(sizeof(String));
-  result->length = strlen(literal);
-  result->characters = malloc(result->length);
-  memcpy(result->characters, literal, result->length);
-  Runtime_addPermanentString(runtime, result);
+  assert(base.type == INTEGER);
+  assert(exponent.type == INTEGER);
+
+  Object result;
+  result.type = INTEGER;
+  result.instance.integer = pow(base.instance.integer, exponent.instance.integer);
   return result;
 }
+{% endif %}
 
 {% if 'print' in builtins %}
-void builtin$print(String* output)
+void builtin$print(Object output)
 {
-  // Using fwrite instead of printf to handle size_t length
-  fwrite(output->characters, 1, output->length, stdout);
+  switch(output.type)
+  {
+    case INTEGER:
+      printf("%" PRId32, output.instance.integer);
+      break;
+
+    case STRING:
+      // Using fwrite instead of printf to handle size_t length
+      fwrite(output.instance.string->characters, 1, output.instance.string->length, stdout);
+      break;
+
+    default:
+      assert(false);
+  }
 }
 {% endif %}