Compiler projects using llvm
#include "coolrt.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* This file provides the runtime library for cool. It implements
   the functions of the cool classes in C
   */


/* Class name strings */
const char Object_string[] = "Object";
const char Int_string[] = "Int";
const char Bool_string[] = "Bool";
const char String_string[] = "String";
const char IO_string[] = "IO";

const char default_string[] = "";

/* Class vtable prototypes */
/*
const Object_vtable _Object_vtable_prototype = {
        .tag = 0,
        .size = sizeof(struct Object),
        .name = Object_string,

        .abort_object     = Object_abort,
        .type_name_object = Object_type_name,
        .copy_object      = Object_copy
};

const Int_vtable _Int_vtable_prototype = {
        .tag = 1,
        .size = sizeof(struct Int),
        .name = Int_string,

        .abort_int     = Object_abort,
        .type_name_int = Object_type_name,
        .copy_int      = Object_copy
};

const Bool_vtable _Bool_vtable_prototype = {
        .tag = 2,
        .size = sizeof(struct Bool),
        .name = Bool_string,

        .abort_bool     = Object_abort,
        .type_name_bool = Object_type_name,
        .copy_bool      = Object_copy
};

const String_vtable _String_vtable_prototype = {
        .tag = 3,
        .size = sizeof(struct String),
        .name = String_string,

        .abort_string     = Object_abort,
        .type_name_string = Object_type_name,
        .copy_string      = Object_copy,
        .length_string    = String_length,
        .concat_string    = String_concat,
        .substr_string    = String_substr
};

const IO_vtable _IO_vtable_prototype = {
        .tag = 4,
        .size = sizeof(struct IO),
        .name = IO_string,

        .abort_io      = Object_abort,
        .type_name_io  = Object_type_name,
        .copy_io       = Object_copy,
        .out_string_io = IO_out_string,
        .out_int_io    = IO_out_int,
        .in_string_io  = IO_in_string,
        .in_int_io     = IO_in_int
};

*/

/*
// Methods in class object (only some are provided to you)
*/
Object* Object_new()
{
    Object* o = (Object *) malloc(sizeof(Object));
    if (o == 0) {
        fprintf(stderr, "At %s(line %d): Out of memory\n", __FILE__, __LINE__);
        Object_abort((Object *) 0);
    }
    o->vtblptr = &_Object_vtable_prototype;
    return o;
}

Object* Object_abort(Object* self)
{
    printf("Abort called from class %s\n",
           !self ? "Unknown" : self->vtblptr->name);
    exit(1);
    return self;
}

String* Object_type_name(Object* self)
{
    if (self == 0) {
        fprintf(stderr, "At %s(line %d): self is NULL\n", __FILE__, __LINE__);
        abort();
    }
    String* s = String_new();
    s->val = self->vtblptr->name;
    return s;
}

Object* Object_copy(Object* self)
{
    if (self == 0) {
        fprintf(stderr, "At %s(line %d): self is NULL\n", __FILE__, __LINE__);
        abort();
    }

    unsigned size = self->vtblptr->size;
    assert(size > 0);
    Object* obj = (Object *) malloc(size);
    if (obj == 0) {
        fprintf(stderr, "At %s(line %d): malloc failed in Object::copy()\n",
                __FILE__, __LINE__);
        abort();
    }
    memcpy(obj, self, size);
    return obj;
}

/*
// Methods in class IO (only some are provided to you)
*/
IO* IO_new()
{
    IO* io = (IO *) malloc(sizeof(IO));
    if (io == 0) {
        fprintf(stderr, "At %s(line %d): Out of memory\n", __FILE__, __LINE__);
        Object_abort((Object *) 0);
    }
    io->vtblptr = &_IO_vtable_prototype;
    return io;
}

IO* IO_out_string(IO* self, String* s)
{
    if (self == 0 || s == 0) {
        fprintf(stderr, "At %s(line %d): NULL object\n", __FILE__, __LINE__);
        abort();
    }
    printf("%s", s->val);
    return self;
}

IO* IO_out_int(IO* self, int x)
{
    if (self == 0) {
        fprintf(stderr, "At %s(line %d): NULL object\n", __FILE__, __LINE__);
        abort();
    }
    printf("%d", x);
    return self;
}

/*
 * Get one line from stream using get_line(), then discard newline character.
 * Allocate string *in_string_p and store result there.
 * Return number of chars read.
 */
static int get_one_line(char** in_string_p, FILE* stream)
{
    /* Get one line worth of input */
    size_t len = 0;
    ssize_t num_chars_read;
    num_chars_read = getline(in_string_p, &len, stdin);
    if (*in_string_p == 0) {
        fprintf(
            stderr, "At %s(line %d): allocation failed in IO::in_string()\n",
            __FILE__, __LINE__);
        exit(1);
    }

    /* Discard the newline char, if any.  It may not exist if EOF reached. */
    if (num_chars_read > 0 && (*in_string_p)[num_chars_read - 1] == '\n') {
        (*in_string_p)[num_chars_read - 1] = '\0';
        --len;
    }

    return len;
}

/*
 * The method IO::in_string(): String reads a string from
 * the standard input, up to but not including a newline character.
 */
String* IO_in_string(IO* self)
{
    if (self == 0) {
        fprintf(stderr, "At %s(line %d): self is NULL\n", __FILE__, __LINE__);
        abort();
    }

    /* Get one line worth of input with the newline, if any, discarded */
    char* in_string = 0;
    ssize_t len = get_one_line(&in_string, stdin);
    assert(in_string);

    /* We can take advantage of knowing the internal layout of String objects */
    String* str = String_new();
    str->val = in_string;
    return str;
}

/*
 * The method IO::in_int(): Int reads a single integer, which may be preceded
 * by whitespace.
 * Any characters following the integer, up to and including the next newline,
 * are discarded by in_int.
 */
int IO_in_int(IO* self)
{
    if (self == 0) {
        fprintf(stderr, "At %s(line %d): self is NULL\n", __FILE__, __LINE__);
        abort();
    }

    /* Get one line worth of input with the newline, if any, discarded */
    char* in_string = 0;
    ssize_t len = get_one_line(&in_string, stdin);
    assert(in_string);

    /* Now extract initial int and ignore the rest of the line */
    int x;
    int num_ints = 0;
    if (len)
        /* Discards initial spaces*/
        num_ints = sscanf(in_string, " %d", &x);

    /* If no text found, abort. */
    if (num_ints == 0) {
        fprintf(stderr,
                "At %s(line %d): Invalid integer on input in IO::in_int()\n",
                __FILE__, __LINE__);
        Object_abort((Object *) self);
    }
    return x;
}

/*
// Methods in class Int
*/
Int* Int_new()
{
    Int* x = (Int *) malloc(sizeof(Int));
    if (x == 0) {
        fprintf(stderr, "At %s(line %d): Out of memory\n", __FILE__, __LINE__);
        Object_abort((Object *) 0);
    }
    x->vtblptr = &_Int_vtable_prototype;
    x->val = 0;
    return x;
}

void Int_init(Int* self, int i) { self->val = i; }

/*
// Methods in class Bool
*/
Bool* Bool_new()
{
    Bool* b = (Bool *) malloc(sizeof(Bool));
    if (b == 0) {
        fprintf(stderr, "At %s(line %d): Out of memory\n", __FILE__, __LINE__);
        Object_abort((Object *) 0);
    }
    b->vtblptr = &_Bool_vtable_prototype;
    b->val = false;
    return b;
}

void Bool_init(Bool* self, bool b) { self->val = b; }

/*
// Methods in class String
*/
String* String_new()
{
    String* s = (String *) malloc(sizeof(String));
    if (s == 0) {
        fprintf(stderr, "At %s(line %d): Out of memory\n", __FILE__, __LINE__);
        Object_abort((Object *) 0);
    }
    s->vtblptr = &_String_vtable_prototype;
    s->val = "";
    return s;
}

int String_length(String* self)
{
    if (self == 0) {
        fprintf(stderr, "At %s(line %d): self is NULL\n", __FILE__, __LINE__);
        abort();
    }

    return strlen(self->val);
}

String* String_concat(String* self, String* s)
{
    if (self == 0 || s == 0) {
        fprintf(stderr, "At %s(line %d): NULL object\n", __FILE__, __LINE__);
        abort();
    }

    String* s1 = (String *) malloc(sizeof(String));
    if (s1 == 0) {
        fprintf(stderr, "At %s(line %d): Out of memory\n", __FILE__, __LINE__);
        Object_abort((Object *) 0);
    }
    s1->vtblptr = &_String_vtable_prototype;

    char* cats = (char *) malloc(strlen(self->val) + strlen(s->val) + 1);
    if (cats == 0) {
        fprintf(stderr, "At %s(line %d): Out of memory\n", __FILE__, __LINE__);
        Object_abort((Object *) 0);
    }
    strcpy(cats, self->val);
    strcat(cats, s->val);
    s1->val = cats;

    return s1;
}

String* String_substr(String* self, int i, int l)
{
    if (self == 0) {
        fprintf(stderr, "At %s(line %d): self is NULL\n", __FILE__, __LINE__);
        abort();
    }

    int len = strlen(self->val);
    if (i >= len || i + l - 1 >= len) {
        fprintf(stderr, "At %s(line %d): Substring out of range\n", __FILE__,
                __LINE__);
        Object_abort((Object *) 0);
    }

    String* s1 = (String *) malloc(sizeof(String));
    if (s1 == 0) {
        fprintf(stderr, "At %s(line %d): Out of memory\n", __FILE__, __LINE__);
        Object_abort((Object *) 0);
    }
    s1->vtblptr = &_String_vtable_prototype;

    char* subs = (char *) malloc(l + 1);
    if (subs == 0) {
        fprintf(stderr, "At %s(line %d): Out of memory\n", __FILE__, __LINE__);
        Object_abort((Object *) 0);
    }
    strncpy(subs, &(self->val[i]), l);
    subs[l] = '\0';
    s1->val = subs;

    return s1;
}