|
|
@ -0,0 +1,233 @@ |
|
|
|
// This example serves to illustrate the possibility |
|
|
|
// of adding the object aspect to C |
|
|
|
// using the everyExternalDeclaration function. |
|
|
|
|
|
|
|
#include <stdio.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <string.h> |
|
|
|
|
|
|
|
struct Symbol { |
|
|
|
char *name; |
|
|
|
int class, selector; |
|
|
|
}; |
|
|
|
|
|
|
|
struct Symbol *newSymbol(char *name) |
|
|
|
{ |
|
|
|
struct Symbol *symbol = malloc(sizeof(*symbol)); |
|
|
|
symbol->name = strdup(name); |
|
|
|
symbol->class = 0; |
|
|
|
symbol->selector = 0; |
|
|
|
return symbol; |
|
|
|
} |
|
|
|
|
|
|
|
struct Symbol **symbols = 0; |
|
|
|
int nSymbols = 0; |
|
|
|
|
|
|
|
struct Symbol *intern(char *name) |
|
|
|
{ |
|
|
|
int lo = 0; |
|
|
|
int hi = nSymbols - 1; |
|
|
|
while (lo <= hi ) { |
|
|
|
int mid = (lo+hi)/2; |
|
|
|
int cmp = strcmp(name, symbols[mid]->name); |
|
|
|
if (cmp > 0) lo = mid + 1; |
|
|
|
else if (cmp < 0) hi = mid - 1; |
|
|
|
else return symbols[mid]; |
|
|
|
} |
|
|
|
symbols = realloc(symbols, sizeof(*symbols) * ++nSymbols); |
|
|
|
memmove(symbols + lo + 1, symbols + lo, sizeof(*symbols)*(nSymbols - lo - 1)); |
|
|
|
return symbols[lo] = newSymbol(name); |
|
|
|
} |
|
|
|
|
|
|
|
typedef void *(*method_t)(); |
|
|
|
|
|
|
|
void *method_dnu() |
|
|
|
{ |
|
|
|
printf("method not found\n"); |
|
|
|
exit(1); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
method_t **methods = 0; |
|
|
|
int nClasses = 0; |
|
|
|
int nSelectors = 0; |
|
|
|
|
|
|
|
int ensureClass(struct Symbol *symbol) |
|
|
|
{ |
|
|
|
if (symbol->class == 0) { |
|
|
|
if (nClasses == 0) nClasses++; |
|
|
|
symbol->class = nClasses++; |
|
|
|
methods = realloc(methods, sizeof(*methods)*nClasses); |
|
|
|
methods[symbol->class] = malloc(sizeof(*methods)*nSelectors); |
|
|
|
for (int i = 0; i<nSelectors; ++i) |
|
|
|
methods[symbol->class][i] = method_dnu; |
|
|
|
} |
|
|
|
return symbol->class; |
|
|
|
} |
|
|
|
|
|
|
|
int ensureSelector(struct Symbol *symbol) |
|
|
|
{ |
|
|
|
if (symbol->selector == 0) { |
|
|
|
if (nSelectors == 0) nSelectors++; |
|
|
|
symbol->selector = nSelectors++; |
|
|
|
for (int i = 0; i<nClasses; ++i) { |
|
|
|
methods[i] = realloc(methods[i], sizeof(**methods)*nSelectors); |
|
|
|
methods[i][nSelectors-1] = method_dnu; |
|
|
|
} |
|
|
|
} |
|
|
|
return symbol->selector; |
|
|
|
} |
|
|
|
|
|
|
|
int findClass(char *class) |
|
|
|
{ |
|
|
|
return ensureClass(intern(class)); |
|
|
|
} |
|
|
|
|
|
|
|
int findSelector(char *selector) |
|
|
|
{ |
|
|
|
return ensureSelector(intern(selector)); |
|
|
|
} |
|
|
|
|
|
|
|
void addMethod(int class, int selector, method_t method) |
|
|
|
{ |
|
|
|
methods[class][selector] = method; |
|
|
|
} |
|
|
|
|
|
|
|
#define lookup(C, S) (methods[C][S]) |
|
|
|
|
|
|
|
struct Object { |
|
|
|
int class; |
|
|
|
}; |
|
|
|
|
|
|
|
#define send(R, M, ...) ({ struct Object *__ = (struct Object *)(R); lookup(__->class, _selector_##M)(__, ##__VA_ARGS__); }) |
|
|
|
|
|
|
|
struct __oop { int class; }; |
|
|
|
|
|
|
|
typedef struct __oop *oop; |
|
|
|
|
|
|
|
@import("../src/parsimonyLibrary/boot.mc") |
|
|
|
|
|
|
|
@{ |
|
|
|
|
|
|
|
rmSemi(x) { |
|
|
|
x.semicolon = null; |
|
|
|
x; |
|
|
|
} |
|
|
|
|
|
|
|
makeln(x, tabs, newLine) { |
|
|
|
x.semicolon.comment = newComment("\n"); |
|
|
|
nbTabs = 0; |
|
|
|
nbLn = 1; |
|
|
|
if (tabs != null) { nbTabs = tabs; } |
|
|
|
if (newLine != null) { nbLn = newLine; } |
|
|
|
for (i = 1; i<nbLn; i++) { |
|
|
|
x.semicolon.comment.text = x.semicolon.comment.text + "\n"; |
|
|
|
} |
|
|
|
for (i = 0; i<tabs; i++) { |
|
|
|
x.semicolon.comment.text = x.semicolon.comment.text + " "; |
|
|
|
} |
|
|
|
x; |
|
|
|
} |
|
|
|
|
|
|
|
program.objects = {}; |
|
|
|
program.objects.class = {}; |
|
|
|
program.objects.methods = {}; |
|
|
|
|
|
|
|
class() |
|
|
|
{ |
|
|
|
program.objects.function = "class"; |
|
|
|
nil; |
|
|
|
} |
|
|
|
|
|
|
|
method(object_name) |
|
|
|
{ |
|
|
|
program.objects.currentClassName = object_name; |
|
|
|
program.objects.function = "method"; |
|
|
|
nil; |
|
|
|
} |
|
|
|
|
|
|
|
constructor(object_name) { |
|
|
|
program.objects.currentClassName = object_name; |
|
|
|
program.objects.function = "constructor"; |
|
|
|
nil; |
|
|
|
} |
|
|
|
|
|
|
|
send(object, method) |
|
|
|
{ |
|
|
|
rmSemi(`declaration send(@@(newText(object)), @@(newText(method)));); |
|
|
|
} |
|
|
|
|
|
|
|
everyExternalDeclaration(s) |
|
|
|
{ |
|
|
|
/*********** Class function ************/ |
|
|
|
if (program.objects.function == "class") { |
|
|
|
program.objects.class[program.last.name.identifier] = {}; |
|
|
|
for (i=length(program.last.declarationL); i>0; i--) { |
|
|
|
program.last.declarationL[i] = program.last.declarationL[i-1]; |
|
|
|
}; |
|
|
|
program.last.declarationL[0] = `declaration int class; ; |
|
|
|
program.objects.function = "none"; |
|
|
|
return s; |
|
|
|
} |
|
|
|
/*********** Method function ************/ |
|
|
|
if (program.objects.function == "method") { |
|
|
|
intern(program.objects.methods, program.last.declarators.declarators.identifier); |
|
|
|
for (i in program.objects.class) { |
|
|
|
if (string(i) == program.objects.currentClassName) intern(program.objects.class[i], program.last.declarators.declarators.identifier); |
|
|
|
} |
|
|
|
program.last.declarators.declarators.identifier = program.objects.currentClassName + "_" + string(program.last.declarators.declarators.identifier); |
|
|
|
param = rmSemi(`declaration struct __oop *__self;); |
|
|
|
if (length(s.declarators.paramTypeL) > 0) { |
|
|
|
append(s.declarators.paramTypeL, newComma()); |
|
|
|
append(s.declarators.paramTypeL, param); |
|
|
|
} else { |
|
|
|
s.declarators.paramTypeL = {}; |
|
|
|
s.declarators.paramTypeL[0] = param; |
|
|
|
} |
|
|
|
tmp = {}; |
|
|
|
tmp[0] = makeln(`declaration struct @@(newId(program.objects.currentClassName, " ")) *self = (struct @@(newId(program.objects.currentClassName, " ")) *) __self;, 1); |
|
|
|
s.compoundS.expression = fusion(tmp, s.compoundS.expression); |
|
|
|
program.objects.function = "none"; |
|
|
|
return s; |
|
|
|
} |
|
|
|
/*********** Constructor function ************/ |
|
|
|
if (program.objects.function == "constructor") { |
|
|
|
rawDeclaration = makeln(`declaration class = findClass(@@(newText("\"" + program.objects.currentClassName + "\"")));, 1); |
|
|
|
t = {}; |
|
|
|
append(t, makeln(`declaration struct @@(newId(program.objects.currentClassName, " ")) *self = calloc(1, sizeof *self);, 1)); |
|
|
|
// take the structure of self->foo |
|
|
|
lhs = treeCopy(s.compoundS.expression[0].expression.lhs); |
|
|
|
lhs.rhs = newId("class", " "); |
|
|
|
// Change foo to Class |
|
|
|
rawDeclaration.declarators[0].lhs = lhs; |
|
|
|
// prepare the right object to return |
|
|
|
append(s.compoundS.expression, rawDeclaration); |
|
|
|
append(s.compoundS.expression, makeln(`statement return (struct __oop *) self;)); |
|
|
|
s.compoundS.expression = fusion(t, s.compoundS.expression); |
|
|
|
program.objects.function = "none"; |
|
|
|
return s; |
|
|
|
} |
|
|
|
/*********** Main function ************/ |
|
|
|
if (s.declarators != null && s.declarators.declarators != null && string(s.declarators.declarators.identifier) == "main") { |
|
|
|
t = {}; |
|
|
|
for(i in program.objects.methods) { |
|
|
|
methodName = string(program.objects.methods[i]); |
|
|
|
append(t, makeln(`declaration int @@(newId("_selector_" + methodName)) = findSelector(@@(newId("\"" + methodName + "\"")));, 1)); |
|
|
|
} |
|
|
|
for (i in program.objects.class) { |
|
|
|
className = string(i); |
|
|
|
append(t, makeln(`declaration int @@(newId("_class_" + className)) = findClass(@@(newId("\"" + className + "\"")));, 1)); |
|
|
|
for (k in program.objects.class[i]) { |
|
|
|
linkedMethod = string(program.objects.class[i][k]); |
|
|
|
castMethod = "(method_t) " + className + "_" + linkedMethod; |
|
|
|
append(t, makeln(`declaration addMethod(@@(newId("_class_" + className)), @@(newId("_selector_" + linkedMethod)), @@(newId(castMethod)));, 1)); |
|
|
|
} |
|
|
|
} |
|
|
|
s.compoundS.expression = fusion(t, s.compoundS.expression); |
|
|
|
return s; |
|
|
|
} |
|
|
|
s; |
|
|
|
} |
|
|
|
|
|
|
|
nil; |
|
|
|
} |