Skip to content

Instantly share code, notes, and snippets.

@croepha
Created June 15, 2017 19:05
Show Gist options
  • Save croepha/a14bbacd9a2f28dfb73de1ef3f1df582 to your computer and use it in GitHub Desktop.
Save croepha/a14bbacd9a2f28dfb73de1ef3f1df582 to your computer and use it in GitHub Desktop.
super crappy meta compiler
#if 0
set -x
#remote ubuntu-vmw
#release_mode=1
skip_meta
skip_test=1
#// test_source=/mnt/hgfs/cro/Documents/Shared/cro_meta_build/test_source.cpp
#// test_args $test_source $test_source.meta_out.cpp
#// EXTRA_COMMANDS="time clang++-3.8 -g --std=c++11 -I /mnt/hgfs/cro/Documents/Shared/ -Wno-writable-strings $test_source.meta_out.cpp -o $test_source.bin; time $test_source.bin"
run_next="test_source.cpp"
#PP_DUMP=1
return
# /* (sh-mode)
set -e
set -o pipefail
SSH="ssh -t -q cro@ubuntu-vmw"
RPATH=/mnt/hgfs/cro/Documents/Shared/cro_meta_build/
LPATH=/Users/cro/Documents/Shared/cro_meta_build/
2
[ "x1" = "x$IS_REMOTE" ] || {
time $SSH IS_REMOTE=1 bash $RPATH/test10.cpp 2>&1 | sed 's/\/mnt\/hgfs\/cro\//\/Users\/cro\//'
exit
}
# -Ofast
# -fsanitize=address -fsanitize=undefined \
[ ! ]&& time clang++-3.8 -g3 --std=c++11 -fPIC -Wall \
-I /mnt/hgfs/cro/Documents/Shared/ \
-fsanitize=address -fsanitize=undefined \
$RPATH/test10.cpp \
-Wno-writable-strings \
-o $RPATH/test10 &&
echo "Metaprogram compilation finished" || exit
[ ! ]&&{
cd $RPATH
time $RPATH/test10
}
true; exit # (c++-mode)
*/
#endif
/*
(load-library "realgud")
(call-interactively `realgud:gdb )
/ssh:ubuntu-vmw:/mnt/hgfs/cro/Documents/Shared/cro_meta_build/
2
realgud:gdb
*/
#include <basic_language_helpers.h>
inline bool aisw(char** s, char* prefix) {
auto l = strlen(prefix);
if ( strncmp(*s, prefix, l) == 0) {
*s += l;
return true;
}
return false;
}
inline void adv_ws(char** p, char* pe) { while (**p == ' ' && *p<pe) (*p)++; }
inline void adv_name(char** p, char* pe) {
while (((**p >= 'a' && **p <= 'z') ||
(**p >= 'A' && **p <= 'Z') ||
(**p >= '0' && **p <= '9') ||
(**p == '_')) && *p < pe) (*p)++;
}
#define LinkListTypeName_AttrType string
#define LinkListMemberName_AttrType string
#define LinkListInList_AttrType boolean
#define LinkListDebugCheckMutex_AttrType string
struct TransformAttribute {
enum Keys {
LinkListTypeName,
LinkListMemberName,
LinkListInList,
LinkListDebugCheckMutex,
} key;
union {
bool boolean;
char* string;
u64 unsigned_number;
s64 signed_number;
void* pointer;
};
TransformAttribute* next;
};
struct StringListItem {
char* value;
StringListItem* next;
};
struct Transform {
enum Types {SinglyLinkedList } type;
TransformAttribute* attributes;
Transform* next;
StringListItem* list_names;
};
#define cg_push(list, item) __cg_push(&list, item)
#define cg_alloc_to_list(list) ({ auto _m_ = cg_alloc(__typeof__(*list)); assert(_m_); cg_push(list, _m_); _m_; });
inline void __cg_init_free (StringListItem** list, StringListItem* all_array, int all_array_count) {
StringListItem **next = list;
for (int i=0; i<all_array_count; i++) {
*next = &all_array[i];
next = &all_array[i].next;
}
}
inline StringListItem* __cg_pop (StringListItem** l) {
auto c = *l; if(!c) return NULL;
*l = c-> next;
c-> next = NULL;
return c;
}
inline void __cg_push(StringListItem** l, StringListItem* c) {
ASSERT(!c-> next);
c-> next = *l;
*l = c;
}
inline void __cg_init_free (Transform** list, Transform* all_array, int all_array_count) {
Transform **next = list;
for (int i=0; i<all_array_count; i++) {
*next = &all_array[i];
next = &all_array[i].next;
}
}
inline Transform* __cg_pop (Transform** l) {
auto c = *l; if(!c) return NULL;
*l = c-> next;
c-> next = NULL;
return c;
}
inline void __cg_push(Transform** l, Transform* c) {
ASSERT(!c-> next);
c-> next = *l;
*l = c;
}
inline void __cg_init_free (TransformAttribute** list, TransformAttribute* all_array, int all_array_count) {
TransformAttribute **next = list;
for (int i=0; i<all_array_count; i++) {
*next = &all_array[i];
next = &all_array[i].next;
}
}
inline TransformAttribute* __cg_pop (TransformAttribute** l) {
auto c = *l; if(!c) return NULL;
*l = c-> next;
c-> next = NULL;
return c;
}
inline void __cg_push(TransformAttribute** l, TransformAttribute* c) {
ASSERT(!c-> next);
c-> next = *l;
*l = c;
}
#define attr_get(_m_transform, key_name) \
({ auto a = __attr_get(_m_transform, TransformAttribute::Keys::key_name); a->key_name ## _AttrType; })
inline TransformAttribute* __attr_get(Transform* t, TransformAttribute::Keys key_name) {
for (auto i = t->attributes; i; i=i->next) {
if (i->key == key_name) return i;
}
assert(!"Key not found");
}
#define attr_set(_m_transform, key_name, value) \
{ auto a = __attr_set(_m_transform, TransformAttribute::Keys::key_name, memory); a->key_name ## _AttrType = value; }
inline TransformAttribute* __attr_set(Transform* t, TransformAttribute::Keys key_name, MemoryStack* memory) {
// for (auto i = t->attributes; i; i=i->next) {
// if (i->key == key_name) {
// i->
// return;
// }
// }
// assert(!"Key not found");
auto __a = cg_alloc_to_list(t->attributes);
auto& a = *__a;
assert(&a);
a.key = key_name;
return &a;
}
Transform* find_transform_from_list_name(int* list_id_, char* list_name_s, char* list_name_e, Transform* transforms) {
Transform* transform = NULL;
u8 list_id = 0;
for (auto t = transforms; t; t=t->next) {
list_id = 1;
for (auto ln = t->list_names; ln; ln=ln->next) {
if (strncmp(ln->value, list_name_s, list_name_e-list_name_s) == 0) {
transform = t;
break;
}
assert(list_id < 250);
list_id++;
}
if (transform) break;
}
*list_id_ = list_id;
return transform;
}
int main(int argc, char* argv[]) {
auto memory_ = MemoryStack_init(1<<20); // 1GB
auto memory = &memory_;
assert(argc == 3);
//char* file_path = "/mnt/hgfs/cro/Documents/Shared/cro_meta_build/test_source.cpp";
char* file_path = argv[1];
char* pp_file_path = argv[2];
auto file = fopen(file_path, "r");
assert(file);
Transform* transforms = NULL;
char line_buffer[4096];
line_buffer[0] = 0;
auto pe = &line_buffer[COUNT_OF(line_buffer)];
while( fgets(line_buffer, sizeof(line_buffer)-20, file) ) {
auto p = &line_buffer[0];
adv_ws(&p, pe);
if (aisw(&p, "cg_list(")) {
auto type_s = p;
adv_name(&p, pe);
auto type_e = p;
adv_ws(&p, pe);
assert(*p++ == ',')
adv_ws(&p, pe);
auto list_name_s = p;
adv_name(&p, pe);
auto list_name_e = p;
adv_ws(&p, pe);
char *member_name_s = "next";
char *member_name_e = member_name_s + strlen(member_name_s);
bool in_list = false;
char *mutex_name_s = "";
char *mutex_name_e = mutex_name_s;
while (*p == ',') {
p++;
adv_ws(&p, pe);
char* param_s = p;
adv_name(&p, pe);
char* param_e = p;
adv_ws(&p, pe);
assert(*p=='=');
p++;
adv_ws(&p, pe);
if(strncmp("member_name", param_s, param_e-param_s) == 0) {
member_name_s = p;
adv_name(&p, pe);
member_name_e = p;
} else if(strncmp("in_list", param_s, param_e-param_s) == 0) {
char* s=p;
adv_name(&p, pe);
char* e=p;
if(strncmp("true", s, e-s) == 0) {
in_list = true;
}
} else if(strncmp("mutex", param_s, param_e-param_s) == 0) {
mutex_name_s=p;
adv_name(&p, pe);
mutex_name_e=p;
} else {
assert(!"Invalid default case");
}
adv_ws(&p, pe);
}
assert(*p == ')')
Transform* transform = NULL;
for (auto t = transforms; t; t=t->next) {
if (t->type == Transform::Types::SinglyLinkedList &&
strncmp(attr_get(t, LinkListTypeName ), type_s, type_e-type_s) == 0 &&
strncmp(attr_get(t, LinkListMemberName), member_name_s, member_name_e-member_name_s) == 0
) { transform = t; }
}
if (!transform) {
transform = cg_alloc_to_list(transforms);
assert(transform);
transform->type = Transform::Types::SinglyLinkedList;
attr_set(transform, LinkListTypeName, alloc_string(type_s, type_e));
attr_set(transform, LinkListMemberName, alloc_string(member_name_s, member_name_e));
attr_set(transform, LinkListInList, in_list);
if (mutex_name_e > mutex_name_s) {
attr_set(transform, LinkListDebugCheckMutex, alloc_string(mutex_name_s, mutex_name_e));
} else {
attr_set(transform, LinkListDebugCheckMutex, NULL);
}
printf("Registered linked list: type:%.*s in_list:%d debug_mutex:%.*s \n", type_e-type_s, type_s, in_list, mutex_name_e-mutex_name_s, mutex_name_s );
};
for (auto s= transform->list_names; ; s=s->next) {
if (!s) {
s = cg_alloc_to_list(transform->list_names);
s->value = alloc_string(list_name_s, list_name_e);
break;
} else if (strncmp(list_name_s, s->value, list_name_e - list_name_s) == 0) {
break;
}
}
}
}
auto pp_file = fopen(pp_file_path, "w");
assert(pp_file_path);
int pp_line = 1;
fprintf(pp_file, "#define cg_list(type, name, ...) type* name\n"); pp_line++;
fprintf(pp_file, "#define cg_list_memberName(type, name, m_name) type* name\n"); pp_line++;
fprintf(pp_file,
"#define cg_alloc_to_list(list) { auto _ = alloc(*list); assert(_); cg_push(list, _); _ } \n"
); pp_line++;
fprintf(pp_file, "#line 1 \"%s\"\n", file_path); pp_line++;
char type_name_that_we_are_in[1024];
type_name_that_we_are_in[0] = 0;
int ws_count_for_ending = 0;
int line = 0;
rewind(file);
line_buffer[0] = 0;
while( fgets(line_buffer, sizeof(line_buffer)-20, file) ) {
line++;
// printf("line\n");
char to_append[8192];
char* to_append_buffer_end = &to_append[sizeof(to_append)-1];
char* to_append_end = to_append;
char to_prepend[4096];
char* to_prepend_buffer_end = &to_prepend[sizeof(to_prepend)-1];
char* to_prepend_end = to_prepend;
auto p = &line_buffer[0];
while (*p == ' ' && p<pe) p++;
if(type_name_that_we_are_in[0]) {
if (p[0] == '}') {
for(auto t=transforms; t; t=t->next) {
auto struct_name = attr_get(t, LinkListTypeName);
if(strcmp(struct_name, type_name_that_we_are_in)!=0) continue;
auto member_name = attr_get(t, LinkListMemberName);
auto in_list_test = attr_get(t, LinkListInList);
auto debug_check_mutex = attr_get(t, LinkListDebugCheckMutex);
#define _string_add(_string_name, ...) _string_name ## _end += snprintf(_string_name ## _end, _string_name ## _buffer_end - _string_name ## _end, __VA_ARGS__); assert( _string_name ## _buffer_end > _string_name ## _end)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-extra-args"
#define _s(...) _string_add(to_prepend, __VA_ARGS__, struct_name, member_name)
_s("%1$s* _cg_ll_%2$s;\n");
if (in_list_test) {
_s("u8 _cg_ll_in_%2$s;\n");
}
#undef _s
#define _s(...) _string_add(to_append, __VA_ARGS__, struct_name, member_name, debug_check_mutex)
_s(" // Generated code for linked list with member name: %2$s type: %1$s \n");
_s(" // Lists: \n");
int list_id = 1;
for (auto ln = t->list_names; ln; ln=ln->next) {
_string_add(to_append,
" // #%d - %s\n", list_id, ln->value);
_string_add(to_append,
"#define _cg_ll_%s_%s_%s %d \n", struct_name, member_name, ln->value, list_id);
list_id++;
}
_s(" inline void __cg_init_free_mn_%2$s (%1$s** list, %1$s* all_array, int all_array_count, int list_id) { \n");
if (debug_check_mutex) {
_s(" ASSERT(pthread_mutex_lock(&%3$s) == EDEADLK); \n");
}
_s(" %1$s **next = list; \n");
_s(" for (int i=0; i<all_array_count; i++) { \n");
_s(" *next = &all_array[i]; \n");
if (in_list_test) {
_s(" (*next)->_cg_ll_in_%2$s = list_id ; \n");
}
_s(" next = &all_array[i]._cg_ll_%2$s; \n");
_s(" } \n");
_s(" } \n");
_s(" inline %1$s* __cg_pop_mn_%2$s (%1$s** l, int list_id) { \n");
if (debug_check_mutex) {
_s(" ASSERT(pthread_mutex_lock(&%3$s) == EDEADLK); \n");
}
_s(" auto c = *l; if(!c) return NULL; \n");
if (in_list_test) {
_s(" ASSERT(c->_cg_ll_in_%2$s == list_id); \n");
_s(" c->_cg_ll_in_%2$s = 0; \n");
}
_s(" *l = c-> _cg_ll_%2$s; \n");
_s(" c-> _cg_ll_%2$s = NULL; \n");
_s(" return c; \n");
_s(" } \n");
_s(" inline void __cg_push_mn_%2$s(%1$s** l, %1$s* c, int list_id) { \n");
if (debug_check_mutex) {
_s(" ASSERT(pthread_mutex_lock(&%3$s) == EDEADLK); \n");
}
if (in_list_test) {
_s(" ASSERT(c->_cg_ll_in_%2$s == 0); \n");
_s(" c->_cg_ll_in_%2$s = list_id; \n");
}
_s(" ASSERT(!c-> _cg_ll_%2$s); \n");
_s(" c-> _cg_ll_%2$s = *l; \n");
_s(" *l = c; \n");
_s(" } \n");
_s(" inline void __cg_remove_mn_%2$s(%1$s** l, %1$s* c, int list_id) { \n");
if (debug_check_mutex) {
_s(" ASSERT(pthread_mutex_lock(&%3$s) == EDEADLK); \n");
}
if (in_list_test) {
_s(" ASSERT(c->_cg_ll_in_%2$s == list_id); \n");
_s(" c->_cg_ll_in_%2$s = 0; \n");
}
_s(" for (;*l != c; l = &(*l)->_cg_ll_%2$s); //segfault here means tryng to remove when not in list \n");
_s(" *l = c->_cg_ll_%2$s; c->_cg_ll_%2$s = NULL; \n");
_s(" } \n");
if(in_list_test) {
_s(" inline bool __cg_in_mn_%2$s(%1$s* c, int list_id) { \n");
if (debug_check_mutex) {
_s(" ASSERT(pthread_mutex_lock(&%3$s) == EDEADLK); \n");
}
_s(" return c->_cg_ll_in_%2$s == list_id; \n");
_s(" } \n");
}
#undef _s
#pragma clang diagnostic pop
}
type_name_that_we_are_in[0] = 0;
}
} else {
ws_count_for_ending = p - &line_buffer[0];
if (strncmp(p, "struct", strlen("struct")) == 0) {
// printf("found struct\n");
p = p + strlen("struct");
adv_ws(&p, pe);
auto type_name_s = p;
adv_name(&p, pe);
auto type_name_e = p;
assert(type_name_e-type_name_s<sizeof(type_name_that_we_are_in) - 1);
strncpy(type_name_that_we_are_in, type_name_s, type_name_e-type_name_s);
type_name_that_we_are_in[type_name_e-type_name_s] = 0;
}
if (auto sp = strstr(line_buffer, "cg_init_free")) {
adv_name(&sp, pe);
adv_ws(&sp, pe);
assert(*sp++ == '(');
adv_ws(&sp, pe);
auto list_name_s = sp;
adv_name(&sp, pe);
auto list_name_e = sp;
int list_id = 0;
auto transform = find_transform_from_list_name(&list_id, list_name_s, list_name_e, transforms);
to_prepend_end += snprintf(
to_prepend_end, to_prepend_buffer_end - to_prepend_end,
"#undef cg_init_free \n"
"#define cg_init_free(list, all_array) __cg_init_free_mn_%s(&list, all_array, COUNT_OF(all_array), %d)\n"
, attr_get(transform, LinkListMemberName),
list_id
);
}
if (auto sp = strstr(line_buffer, "cg_pop")) {
adv_name(&sp, pe);
adv_ws(&sp, pe);
assert(*sp++ == '(');
adv_ws(&sp, pe);
auto list_name_s = sp;
adv_name(&sp, pe);
auto list_name_e = sp;
int list_id = 0;
auto transform = find_transform_from_list_name(&list_id, list_name_s, list_name_e, transforms);
to_prepend_end += snprintf(
to_prepend_end, to_prepend_buffer_end - to_prepend_end,
"#undef cg_pop \n"
"#define cg_pop(list) __cg_pop_mn_%s(&list, %d) \n"
, attr_get(transform, LinkListMemberName), list_id
);
}
if (auto sp = strstr(line_buffer, "cg_push")) {
adv_name(&sp, pe);
adv_ws(&sp, pe);
assert(*sp++ == '(');
adv_ws(&sp, pe);
auto list_name_s = sp;
adv_name(&sp, pe);
auto list_name_e = sp;
int list_id = 0;
auto transform = find_transform_from_list_name(&list_id, list_name_s, list_name_e, transforms);
to_prepend_end += snprintf(
to_prepend_end, to_prepend_buffer_end - to_prepend_end,
"#undef cg_push \n"
"#define cg_push(list, item) __cg_push_mn_%s(&list, item, %d)\n"
, attr_get(transform, LinkListMemberName), list_id
);
}
if (auto sp = strstr(line_buffer, "cg_in")) {
adv_name(&sp, pe);
adv_ws(&sp, pe);
assert(*sp++ == '(');
adv_ws(&sp, pe);
auto list_name_s = sp;
adv_name(&sp, pe);
auto list_name_e = sp;
int list_id = 0;
auto transform = find_transform_from_list_name(&list_id, list_name_s, list_name_e, transforms);
if (!transform) printf("%s:%d: error: List name not found: %.*s\n", file_path, line, list_name_e-list_name_s, list_name_s);
to_prepend_end += snprintf(
to_prepend_end, to_prepend_buffer_end - to_prepend_end,
"#undef cg_in \n"
"#define cg_in(list, item) __cg_in_mn_%s(item, %d)\n"
, attr_get(transform, LinkListMemberName), list_id
);
}
if (auto sp = strstr(line_buffer, "cg_remove")) {
adv_name(&sp, pe);
adv_ws(&sp, pe);
assert(*sp++ == '(');
adv_ws(&sp, pe);
auto list_name_s = sp;
adv_name(&sp, pe);
auto list_name_e = sp;
int list_id = 0;
auto transform = find_transform_from_list_name(&list_id, list_name_s, list_name_e, transforms);
to_prepend_end += snprintf(
to_prepend_end, to_prepend_buffer_end - to_prepend_end,
"#undef cg_remove \n"
"#define cg_remove(list, item) __cg_remove_mn_%s(&list, item, %d)\n"
, attr_get(transform, LinkListMemberName), list_id
);
}
if (auto sp = strstr(line_buffer, "cg_for")) {
adv_name(&sp, pe);
adv_ws(&sp, pe);
assert(*sp++ == '(');
adv_ws(&sp, pe);
auto list_name_s = sp;
adv_name(&sp, pe);
auto list_name_e = sp;
int list_id = 0;
auto transform = find_transform_from_list_name(&list_id, list_name_s, list_name_e, transforms);
to_prepend_end += snprintf(
to_prepend_end, to_prepend_buffer_end - to_prepend_end,
"#undef cg_for \n"
"#define cg_for(list, _m_i) for (auto _m_i = list; _m_i; _m_i=_m_i->_cg_ll_%s) \n"
, attr_get(transform, LinkListMemberName)
);
}
}
int new_preprened_lines = 0;
*to_prepend_end = 0;
for (char* p = to_prepend; *p; p++) if (*p == '\n') new_preprened_lines++;
if(new_preprened_lines) {
fprintf(pp_file, "#line %d \"%s\" \n", pp_line+1, pp_file_path); pp_line++;
pp_line+= new_preprened_lines;
}
fputs(to_prepend, pp_file);
if(new_preprened_lines) {
fprintf(pp_file, "#line %d \"%s\" \n", line, file_path); pp_line++;
}
fputs(line_buffer, pp_file); pp_line++;
int new_appended_lines = 0;
*to_append_end = 0;
for (char* p = to_append; *p; p++) if (*p == '\n') new_appended_lines++;
if(new_appended_lines) {
fprintf(pp_file, "#line %d \"%s\" \n", pp_line + 1, pp_file_path); pp_line++;
pp_line+= new_appended_lines;
}
fputs(to_append, pp_file);
if(new_appended_lines) {
fprintf(pp_file, "#line %d \"%s\" \n", line+1, file_path); pp_line++;
}
}
fclose(pp_file);
// printf("Metaprogram finished\n");
// char system_command_buff[4096];
// STRING_FMT(system_command_buff, "clang++-3.8 -g --std=c++11 -I /mnt/hgfs/cro/Documents/Shared/ -Wno-writable-strings %s -o %s", pp_file_path, bin_file_path);
// STRING_FMT(system_command_buff, "gcc -g3 --std=c++11 -I /mnt/hgfs/cro/Documents/Shared/ -Wno-write-strings %s -o %s", pp_file_path, bin_file_path);
// auto ret2 = system(system_command_buff);
// assert(WEXITSTATUS(ret2) == 0);
// auto ret3 = system(bin_file_path);
// assert(WEXITSTATUS(ret3) == 0);
free(memory->base);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment