OPTLEVEL=1
# cleanup old files
-rm -f cerise-c libruntime.a runtime/*.o
-
-# compile all runtime sources
-for f in runtime/*.c; do
- printf "CC %s\n" "$f"
- gcc -c -I. -O$OPTLEVEL -o "${f%.c}.o" "$f" &
-done
-wait
-
-# compile the static lib
-printf "LIB %s\n" libruntime.a
-ar rcs libruntime.a runtime/*.o
-
-# generate and compile the main function
-printf "#include \"runtime.h\"\nENTRYPOINT(%s)\n" TestSuite_Main > main.c
-gcc -c -I. -O$OPTLEVEL -o main.o main.c
-
-# now compile the cerise file and link
-printf "\n"
-./cerise-c.rb > cerise-c.c \
- && gcc -I. -O$optlevel -o cerise-c main.o cerise-c.o libruntime.a \
- && size cerise-c \
- && printf "\n" \
- && ./cerise-c
+rm -f cerise-c
+# run the compiler and resulting binary
+./cerise-c.rb cerise-c.m && ./cerise-c
exports (Main)
-TestLiterals()
-{
-# assert 42
-# assert 42.0
- assert true
- #assert false
- #assert nil
-# assert "123"
-}
-
TestBoolOps()
{
assert true == true
{
assert "foo" == "foo"
assert "foo" != "bar"
-# assert ("foo" + "bar") == "foobar"
+ assert ("foo" + "bar") == "foobar"
+ assert("foo"[0] == 'f')
+
+
+
# assert ("foo" + 123) == "foo123"
# assert ("foo" + 123.0) == "foo123.000000"
# assert ("foo" + true) == "footrue"
TestEqOps() {
assert ("" == "") == true
- assert ("" == "a") == true
+ assert ("" != "a") == true
assert (1 == 1) == true
assert (1 == 2) == false
assert (1.0 == 1.0) == true
}
TestNeqOps() {
-# assert ("" != "") == false
-# assert ("" != 1) == true
-# assert ("" != 1.0) == true
-# assert ("" != true) == true
-# assert ("" != false) == true
+ assert ("" != "") == false
+ assert ("" != "a") == true
+ assert (1 != 1) == false
+ assert (2 != 1) == true
+ assert (1.0 != 1.0) == false
+ assert (2.0 != 1.0) == true
+ assert (true != true) == false
+ assert (false != false) == false
+ assert (true != false) == true
+ assert (false != true) == true
# assert ("" != []) == true
# assert ("" != {}) == true
}
Main()
{
AddTwoNums(1,2) + 5
- TestLiterals()
TestBoolOps()
TestIntOps()
TestRealOps()
end
def type_to_s(type)
- if type.is_a? Symbol
+ if type == :string
+ "_string"
+ elsif type.is_a? Symbol
type
elsif type.form == :array
"_array"
elsif v.value == true || v.value == false
putln "#{type} #{var} = (#{v.value});"
elsif v.value.is_a? String
- putln "#{type} #{var} = MakeString(#{v.value});"
+ putln "#{type} #{var} = String_Create(#{v.value}, #{v.value.length-2});"
elsif v.value.is_a? Array
- putln "#{type} #{var} = MakeArray(#{v.value.length});"
+ putln "#{type} #{var} = Array_Create(#{v.value.length});"
v.value.each_with_index do |e, i|
val = emit(e)
putln "Array_Set(#{var}, #{i}, #{val});"
end
elsif v.value.is_a? Hash
- putln "Value #{var} = MakeDict(#{v.value.length});"
+ putln "Value #{var} = Dictionary_Create(#{v.value.length});"
v.value.each do |k, v|
val = emit(v)
- putln "Dict_Set(#{var}, MakeString(#{k.value}), #{val});"
+ putln "Dict_Set(#{var}, String_Create(#{k.value}), #{val});"
end
else
raise "code emitting constants of this type not implemented"
lvar = emit(v.left)
rvar = emit(v.right)
result = mktemp();
- putln "#{type} #{result} = Object_Get(#{lvar}, #{rvar});"
+ if v.left.type == :string
+ putln "#{type} #{result} = String_Get(#{lvar}, #{rvar});"
+ else
+ putln "#{type} #{result} = Array_Get(#{lvar}, #{rvar});"
+ end
else
lvar = emit(v.left)
rvar = emit(v.right)
result = mktemp();
case v.op
when "+"
- putln "#{type} #{result} = (#{lvar} + #{rvar});"
+ if v.type == :string
+ putln "#{type} #{result} = String_Concat(#{lvar}, #{rvar});"
+ else
+ putln "#{type} #{result} = (#{lvar} + #{rvar});"
+ end
when "-"
putln "#{type} #{result} = (#{lvar} - #{rvar});"
when "*"
when ">="
putln "#{type} #{result} = (#{lvar} >= #{rvar});"
when "=="
- putln "#{type} #{result} = (#{lvar} == #{rvar});"
+ if v.left.type == :string
+ putln "#{type} #{result} = (0 == String_Compare(#{lvar}, #{rvar}));"
+ else
+ putln "#{type} #{result} = (#{lvar} == #{rvar});"
+ end
when "!="
- putln "#{type} #{result} = (#{lvar} != #{rvar});"
+ if v.left.type == :string
+ putln "#{type} #{result} = (0 != String_Compare(#{lvar}, #{rvar}));"
+ else
+ putln "#{type} #{result} = (#{lvar} != #{rvar});"
+ end
else
raise "not implemented"
end
f.puts "ENTRYPOINT(#{mod.name}_Main)"
end
`gcc -c -I. -O1 -o main.o main.c`
- `gcc -I. -O1 -o #{binname} #{deps.join(" ")} main.o libruntime.a`
+ `gcc -I. -O1 -o #{binname} #{deps.join(" ")} main.o`
end
end
end
\ No newline at end of file
INTEGER = /[0-9]+/
FLOATING = /[0-9]+\.[0-9]+/
STRING = /"(\\"|[^"])*"/
+ CHAR = /'(\\'|[^'])'/
ID_TYPES = {
"true" => :bool,
"false" => :bool,
type = :int
elsif @data.scan(STRING)
type = :string
+ elsif @data.scan(CHAR)
+ type = :char
elsif @data.scan(BRACES)
type = @data.matched
elsif @data.scan(OPERATORS)
IR::Const.new(tok.pos, :string, tok.text)
elsif tok.type == :int
IR::Const.new(tok.pos, :int, tok.text.to_i)
+ elsif tok.type == :char
+ IR::Const.new(tok.pos, :int, tok.text[1].ord)
elsif tok.type == :float
IR::Const.new(tok.pos, :float, tok.text.to_f)
elsif tok.type == :void
def check_binary(env, expr, vtype)
if expr.op == "["
left_type = infer(env, expr.left)
- if (left_type.is_a? Value::Type) and left_type.form == :array
+ if left_type == :string
+ check(env, expr.right, :int)
+ expr.type = :int
+ elsif not (left_type.is_a? Value::Type)
+ error(expr.loc, "type '#{left_type}' is not indexable")
+ elsif left_type.form == :array
check(env, expr.right, :int)
expr.type = left_type.base
- elsif (left_type.is_a? Value::Type) and left_type.form == :hash
+ elsif left_type.form == :hash
check(env, expr.right, left_type.base[0])
expr.type = left_type.base[1]
else
typedef intptr_t _value;
-typedef struct string {
+typedef struct _string {
uint64_t length;
uint8_t bytes[];
-}* string;
+}* _string;
typedef struct array {
uint64_t length;
_value* values;
}* _array;
-typedef struct dict_node {
- struct dict_node* left;
- struct dict_node* right;
+typedef struct _dict_node {
+ struct _dict_node* left;
+ struct _dict_node* right;
_value key;
_value value;
uint32_t hash;
-}* dict_node;
+}* _dict_node;
typedef struct dict {
uint64_t length;
- dict_node root;
+ _dict_node root;
}* _dict;
-string MakeString(char* s);
-_array MakeArray(int32_t nslots);
-_dict MakeDict(int32_t nslots);
-void Assert(char* file, int lineno, bool val);
+/* Runtime Errors
+ *************************************************/
+
+static inline void RuntimeError(char* s)
+{
+ fprintf(stderr, "fatal error: %s\n", s);
+ exit(1);
+}
+
+static inline void Assert(char* file, int lineno, bool val)
+{
+ if (!val) {
+ fprintf(stderr, "%s:%d:error: Assertion failed\n", file, lineno);
+ exit(1);
+ }
+}
+
+/* Strings
+ *************************************************/
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshift-count-overflow"
+
+static inline _array Array_Create(int32_t nslots)
+{
+ _array array = calloc(1, sizeof(struct array));
+ array->length = nslots;
+ nslots--;
+ nslots |= nslots >> 1;
+ nslots |= nslots >> 2;
+ nslots |= nslots >> 4;
+ nslots |= nslots >> 8;
+ nslots |= nslots >> 16;
+ nslots |= nslots >> 32;
+ nslots++;
+ array->capacity = nslots;
+ array->values = calloc(array->capacity, sizeof(_value));
+ return array;
+}
+
+#pragma GCC diagnostic pop
static inline void Array_Set(_array ary, int index, _value val)
{
+ if (index >= ary->length) {
+ RuntimeError("array index out of bounds");
+ }
+ ary->values[index] = val;
}
-/* Garbage Collection
+static inline _value Array_Get(_array ary, int index)
+{
+ if (index >= ary->length) {
+ RuntimeError("array index out of bounds");
+ }
+ return ary->values[index];
+}
+
+/* Strings
*************************************************/
-void* GC_Allocate(size_t nbytes);
+static inline _string String_Create(char* s, size_t len)
+{
+ _string str = malloc(sizeof(_string) + len + 1);
+ memcpy(str->bytes, s, len+1);
+ str->length = len;
+ return str;
+}
+
+static inline _value String_Get(_string str, int index)
+{
+ if (index >= str->length)
+ {
+ RuntimeError("string index out of bounds");
+ }
+ return str->bytes[index];
+}
+
+static inline _string String_Concat(_string a, _string b)
+{
+ _string str = malloc(sizeof(_string) + a->length + b->length + 1);
+ memcpy(str->bytes, a->bytes, a->length);
+ memcpy(&(str->bytes[a->length]), b->bytes, b->length + 1);
+ str->length = a->length + b->length;
+ return str;
+}
+
+static inline _value String_Compare(_string a, _string b)
+{
+ return strcmp(a->bytes, b->bytes);
+}
+/* Program Entry Point Definition
+ *************************************************/
#define ENTRYPOINT(func) \
int main(int argc, char** argv) { \
+++ /dev/null
-#include "runtime.h"
-
-static uint64_t NextPow2(uint64_t val) {
- val--;
- val |= val >> 1;
- val |= val >> 2;
- val |= val >> 4;
- val |= val >> 8;
- val |= val >> 16;
- val |= val >> 32;
- val++;
- return val;
-}
-
-Value MakeArray(int32_t nslots) {
- Array* array = GC_Allocate(sizeof(Array));
- array->length = nslots;
- array->capacity = NextPow2(nslots);
- array->values = GC_Allocate(nslots * sizeof(Value));
- return (Value){ .as_uint64 = (NAN_TAG_ARRAY | (uintptr_t)array) };
-}
-
-void Array_Set(Value array, int index, Value value)
-{
- Array* ary = ValueAsArray(array);
- if (index >= ary->length) {
- RuntimeError("array index out of bounds");
- }
- ary->values[index] = value;
-}
-
-Value Array_Get(Value array, int index)
-{
- Array* ary = ValueAsArray(array);
- if (index >= ary->length) {
- RuntimeError("array index out of bounds");
- }
- return ary->values[index];
-}
+++ /dev/null
-#include "runtime.h"
-
-void Assert(char* file, int lineno, Value val) {
- if (IsFalse(val) || IsNil(val)) {
- fprintf(stderr, "%s:%d:error: Assertion failed\n", file, lineno);
- exit(1);
- }
-}
+++ /dev/null
-#include "runtime.h"
-
-static uint32_t Hash(Value val) {
- String* string = ValueAsString(val);
- char* key = string->bytes;
- uint32_t a=31415u, b=27183u, hash;
- for (hash=0; *key; key++, a *= b) {
- hash = (a * hash) + *key;
- }
- hash = (hash + 0x7ed55d16) + (hash << 12);
- hash = (hash ^ 0xc761c23c) ^ (hash >> 19);
- hash = (hash + 0x165667b1) + (hash << 5);
- hash = (hash + 0xd3a2646c) ^ (hash << 9);
- hash = (hash + 0xfd7046c5) + (hash << 3);
- hash = (hash ^ 0xb55a4f09) ^ (hash >> 16);
- return hash;
-}
-
-static int CompareNode(DictNode* left, DictNode* right) {
- int cmp = left->hash - right->hash;
- if (cmp == 0) {
- cmp = ValueAsBool(OpEq(left->key, right->key)) ? 0 : 1;
- }
- return cmp;
-}
-
-static DictNode** FindNode(DictNode** root, DictNode* node) {
- DictNode** curr = root;
- while(*curr != NULL) {
- int cmp = CompareNode(node, *curr);
- if (cmp < 0)
- curr = &((*curr)->left);
- else if (cmp > 0)
- curr = &((*curr)->right);
- else
- break;
- }
- return curr;
-}
-
-Value MakeDict(int32_t nslots) {
- Dict* dict = GC_Allocate(sizeof(Dict));
- return (Value){ .as_uint64 = (NAN_TAG_DICT | (uintptr_t)dict) };
-}
-
-void Dict_Set(Value dictionary, Value key, Value value)
-{
- DictNode node = {
- .hash = Hash(key),
- .key = key,
- .value = value
- };
- Dict* dict = ValueAsDict(dictionary);
- DictNode** curr = FindNode(&(dict->root), &node);
- if (!*curr) {
- DictNode* new_node = GC_Allocate(sizeof(DictNode));
- *new_node = node;
- *curr = new_node;
- dict->length++;
- } else {
- (*curr)->value = value;
- }
-}
-
-Value Dict_Get(Value dictionary, Value key)
-{
- DictNode node = {
- .hash = Hash(key),
- .key = key,
- };
- Dict* dict = ValueAsDict(dictionary);
- DictNode** curr = FindNode(&(dict->root), &node);
- Value result = MakeNil();
- if (*curr) {
- result = (*curr)->value;
- }
- return result;
-}
+++ /dev/null
-#include "runtime.h"
-
-Value Error(Value val) {
- RuntimeError(ValueAsString(val)->bytes);
- return MakeNil();
-}
-
-void RuntimeError(char* s) {
- fprintf(stderr, "fatal error: %s\n", s);
- exit(1);
-}
+++ /dev/null
-#include "runtime.h"
-
-#define FIRST_GEN_SIZE ((1024*1024) / sizeof(Value))
-
-Value First_Gen_Heap[FIRST_GEN_SIZE];
-Value* Heap_Next = First_Gen_Heap;
-Value* Heap_End = First_Gen_Heap + FIRST_GEN_SIZE;
-
-void* GC_Allocate(size_t nbytes) {
- size_t ncells = nbytes / sizeof(Value);
- if ((nbytes - (ncells * sizeof(Value))) > 0) {
- ncells++;
- }
- Value* obj = Heap_Next;
- Heap_Next += ncells;
- if (Heap_Next > Heap_End) {
- fprintf(stderr, "out of memory");
- exit(1);
- }
- return obj;
-}
+++ /dev/null
-#include "runtime.h"
-
-Value Length(Value val) {
- Value result = MakeInt(0);
- if (IsDict(val)) {
- result = MakeInt( ValueAsDict(val)->length );
- } else if (IsArray(val)) {
- result = MakeInt( ValueAsArray(val)->length );
- } else if (IsString(val)) {
- result = MakeInt( ValueAsString(val)->length );
- } else {
- RuntimeError("value is not an aggregate type");
- }
- return result;
-}
+++ /dev/null
-#include "runtime.h"
-
-Value Object_Get(Value object, Value key)
-{
- Value result = MakeNil();
- if (IsDict(object)) {
- result = Dict_Get(object, key);
- } else if (IsArray(object)) {
- result = Array_Get(object, ValueAsInt(key));
- } else if (IsString(object)) {
- result = String_Get(object, ValueAsInt(key));
- } else {
- RuntimeError("object is not indexable");
- }
- return result;
-}
-
-void Object_Set(Value object, Value key, Value value)
-{
- if (IsDict(object)) {
- Dict_Set(object, key, value);
- } else if (IsArray(object)) {
- Array_Set(object, ValueAsInt(key), value);
- } else {
- RuntimeError("object is not assignable");
- }
-}
+++ /dev/null
-#include "runtime.h"
-
-Value OpAdd(Value left, Value right) {
- Value result;
- if (IsInt(left)) {
- result = MakeInt(ValueAsInt(left) + ValueAsInt(right));
- } else if (IsReal(left)) {
- result = MakeReal(ValueAsReal(left) + ValueAsReal(right));
- } else if (IsString(left)) {
- right = ToString(right);
- String* left_str = ValueAsString(left);
- String* right_str = ValueAsString(right);
- size_t sz = left_str->length + right_str->length;
- String* str = GC_Allocate(sizeof(String) + sz + 1);
- str->length = sz;
- memcpy(
- str->bytes,
- left_str->bytes,
- left_str->length);
- memcpy(
- &str->bytes[left_str->length],
- right_str->bytes,
- right_str->length + 1);
- result = (Value){ .as_uint64 = (NAN_TAG_STRING | (uint64_t)str) };
- } else {
- RuntimeError("addition operator used on invalid type");
- }
- return result;
-}
+++ /dev/null
-#include "runtime.h"
-
-Value OpDiv(Value left, Value right) {
- Value result;
- if (IsInt(left)) {
- result = MakeInt(ValueAsInt(left) / ValueAsInt(right));
- } else if (IsReal(left)) {
- result = MakeReal(ValueAsReal(left) / ValueAsReal(right));
- } else {
- fprintf(stderr, "fatal error: addition operator used on invalid type\n");
- exit(1);
- }
- return result;
-}
+++ /dev/null
-#include "runtime.h"
-
-Value OpEq(Value left, Value right) {
- Value result;
- if (IsBool(left) && IsBool(right)) {
- result = MakeBool(ValueAsBool(left) == ValueAsBool(right));
- } else if (IsInt(left) && IsInt(right)) {
- result = MakeBool(ValueAsInt(left) == ValueAsInt(right));
- } else if (IsReal(left) && IsReal(right)) {
- result = MakeBool(ValueAsReal(left) == ValueAsReal(right));
- } else if (IsString(left) && IsString(right)) {
- result = MakeBool(!strcmp(ValueAsString(left)->bytes, ValueAsString(right)->bytes));
- } else {
- result = MakeBool(false);
- }
- return result;
-}
+++ /dev/null
-#include "runtime.h"
-
-Value OpGt(Value left, Value right) {
- Value result;
- if (IsInt(left) && IsInt(right)) {
- result = MakeBool(ValueAsInt(left) > ValueAsInt(right));
- } else if (IsReal(left) && IsReal(right)) {
- result = MakeBool(ValueAsReal(left) > ValueAsReal(right));
- } else {
- result = MakeBool(false);
- }
- return result;
-}
+++ /dev/null
-#include "runtime.h"
-
-Value OpGtEq(Value left, Value right) {
- Value result;
- if (IsInt(left)) {
- result = MakeBool(ValueAsInt(left) >= ValueAsInt(right));
- } else if (IsReal(left)) {
- result = MakeBool(ValueAsReal(left) >= ValueAsReal(right));
- } else {
- result = MakeBool(false);
- }
- return result;
-}
+++ /dev/null
-#include "runtime.h"
-
-Value OpLt(Value left, Value right) {
- Value result;
- if (IsInt(left) && IsInt(right)) {
- result = MakeBool(ValueAsInt(left) < ValueAsInt(right));
- } else if (IsReal(left) && IsReal(right)) {
- result = MakeBool(ValueAsReal(left) < ValueAsReal(right));
- } else {
- result = MakeBool(false);
- }
- return result;
-}
+++ /dev/null
-#include "runtime.h"
-
-Value OpLtEq(Value left, Value right) {
- Value result;
- if (IsInt(left) && IsInt(right)) {
- result = MakeBool(ValueAsInt(left) <= ValueAsInt(right));
- } else if (IsReal(left) && IsReal(right)) {
- result = MakeBool(ValueAsReal(left) <= ValueAsReal(right));
- } else {
- result = MakeBool(false);
- }
- return result;
-}
+++ /dev/null
-#include "runtime.h"
-
-Value OpMod(Value left, Value right) {
- Value result;
- if (IsInt(left)) {
- result = MakeInt(ValueAsInt(left) % ValueAsInt(right));
- } else {
- fprintf(stderr, "fatal error: addition operator used on invalid type\n");
- exit(1);
- }
- return result;
-}
+++ /dev/null
-#include "runtime.h"
-
-Value OpMul(Value left, Value right) {
- Value result;
- if (IsInt(left)) {
- result = MakeInt(ValueAsInt(left) * ValueAsInt(right));
- } else if (IsReal(left)) {
- result = MakeReal(ValueAsReal(left) * ValueAsReal(right));
- } else {
- fprintf(stderr, "fatal error: addition operator used on invalid type\n");
- exit(1);
- }
- return result;
-}
+++ /dev/null
-#include "runtime.h"
-
-Value OpNeq(Value left, Value right) {
- Value result;
- if (IsBool(left) && IsBool(right)) {
- result = MakeBool(ValueAsBool(left) != ValueAsBool(right));
- } else if (IsInt(left) && IsInt(right)) {
- result = MakeBool(ValueAsInt(left) != ValueAsInt(right));
- } else if (IsReal(left) && IsReal(right)) {
- result = MakeBool(ValueAsReal(left) != ValueAsReal(right));
- } else if (IsString(left) && IsString(right)) {
- result = MakeBool(0 != strcmp(ValueAsString(left)->bytes, ValueAsString(right)->bytes));
- } else {
- result = MakeBool(true);
- }
- return result;
-}
+++ /dev/null
-#include "runtime.h"
-
-Value OpSub(Value left, Value right) {
- Value result;
- if (IsInt(left)) {
- result = MakeInt(ValueAsInt(left) - ValueAsInt(right));
- } else if (IsReal(left)) {
- result = MakeReal(ValueAsReal(left) - ValueAsReal(right));
- } else {
- fprintf(stderr, "fatal error: addition operator used on invalid type\n");
- exit(1);
- }
- return result;
-}
+++ /dev/null
-#include "runtime.h"
-
-Value MakeString(char* s) {
- size_t sz = strlen(s);
- String* str = GC_Allocate(sizeof(String) + sz + 1);
- str->length = sz;
- strncpy(str->bytes, s, sz+1);
- Value ret = (Value){ .as_uint64 = (NAN_TAG_STRING | (uint64_t)str) };
- assert(IsString(ret));
- return ret;
-}
-
-Value String_Get(Value hash, int index)
-{
- String* str = ValueAsString(hash);
- if (index >= str->length) {
- RuntimeError("string index out of bounds");
- }
- return MakeInt( str->bytes[index] );
-}
+++ /dev/null
-#include "runtime.h"
-
-Value ToString(Value val) {
- Value retval;
- if (IsString(val)) {
- retval = val;
- } else if (IsNil(val)) {
- retval = MakeString("nil");
- } else if (IsBool(val)) {
- retval = MakeString(IsTrue(val) ? "true" : "false");
- } else if (IsInt(val)) {
- char str[64];
- snprintf(str, sizeof(str), "%d", ValueAsInt(val));
- retval = MakeString(str);
- } else if (IsReal(val)) {
- char str[64];
- snprintf(str, sizeof(str), "%f", ValueAsReal(val));
- retval = MakeString(str);
- } else {
- assert(!"could not convert string");
- }
- return retval;
-}