From b4dbb6575c5dfebc73ad80b5ea40f3fd2816fd9e Mon Sep 17 00:00:00 2001 From: Theo Souchon Date: Fri, 23 Dec 2022 16:36:42 +0900 Subject: [PATCH] update on the automatic creation of an object --- ccmeta.leg | 34 ++- parsimonyLibrary/boot.mc | 26 +- parsimonyLibrary/dynamicObject.c | 134 +++++++++++ parsimonyLibrary/dynamicObject.mc | 223 ++++++++++++++++++ tests-parsimony/objectExample.c | 7 +- .../{projExample.c => projectExample.c} | 0 tests-parsimony/realObject.c | 40 ++++ 7 files changed, 448 insertions(+), 16 deletions(-) create mode 100644 parsimonyLibrary/dynamicObject.c create mode 100644 parsimonyLibrary/dynamicObject.mc rename tests-parsimony/{projExample.c => projectExample.c} (100%) create mode 100644 tests-parsimony/realObject.c diff --git a/ccmeta.leg b/ccmeta.leg index 6c8de2a..8cc95ba 100644 --- a/ccmeta.leg +++ b/ccmeta.leg @@ -396,6 +396,7 @@ oop new_C_functionDef(oop specifiers, oop declarator, oop declarationList, oop c map_set(object, declarators_symbol, declarator); map_set(object, declarationL_symbol,declarationList); map_set(object, compoundS_symbol, compoundStatement); + map_set(program, intern("last"), object); return object; } @@ -1342,6 +1343,15 @@ oop everyExternalDeclaration(oop s) return s; } +oop ensureId(oop s) +{ + if (!is(Map, s) || map_get(s, __proto___symbol) != C_id_proto) { + fprintf(stderr, "Meta expression did not return required Id\n"); + exit(1); + } + return s; +} + %} @@ -1362,6 +1372,8 @@ error = EOL* < (!EOL .)* EOL* (!EOL .)* > &{ error(yytext), 1 } idOpt = id | {$$=newNullObject()} id = { $$= new_C_id(yytext) } - + | META_AT META_LPAREN m:meta_exp META_RPAREN { $$= ensureId(eval(globals,m)) } - + ID = &{ !is_C_keyword(yytext) } name = { $$= new_C_id(yytext) } - @@ -1699,8 +1711,8 @@ structOrUnionSpecifier = s:structOrUnion @{ C_scopeEnd() } | &{ C_scopeAbort() } ) - # ..., or after the closing brace. - ( b:attributeSpecifiers &{gnu} | {b=newNullObject()} ) + # ..., or after the closing brace. + ( b:attributeSpecifiers &{gnu} | {b=newNullObject()} ) | i:id {l=d=r=b=newNullObject()} ) { $$= new_C_structSpec(s, a, i, l, d, r, b) } @@ -2427,14 +2439,15 @@ META_FLOAT = < [-+]* [0-9]+ '.' [0-9]* ('e'[-+]*[0-9]+)? > { $$= make #--------------------------------------------- Meta operator ----------------------------------------------# -MO_OPERATION = META_BACKTICK ( MO_INITIALIZER i:initializer { $$= newUnary(Quote_proto ,i) } - | MO_CONSTANT c:constant { $$= newUnary(Quote_proto ,c) } - | MO_STATEMENT c:statement { $$= newUnary(Quote_proto ,c) } - | MO_INTEGER i:integerConstant { $$= newUnary(Quote_proto ,i) } - | MO_DECLARATION i:declaration { $$= newUnary(Quote_proto ,i) } - | MO_STRING i:stringLiteral { $$= newUnary(Quote_proto ,i) } - | MO_FUN i:functionDefinition { $$= newUnary(Quote_proto ,i) } - | MO_ED i:externalDeclaration{ $$= newUnary(Quote_proto ,i) } +MO_OPERATION = META_BACKTICK ( MO_INITIALIZER i:initializer { $$= newUnary(Quote_proto ,i) } + | MO_CONSTANT c:constant { $$= newUnary(Quote_proto ,c) } + | MO_STATEMENT c:statement { $$= newUnary(Quote_proto ,c) } + | MO_INTEGER i:integerConstant { $$= newUnary(Quote_proto ,i) } + | MO_DECLARATION i:declaration { $$= newUnary(Quote_proto ,i) } + | MO_STRING i:stringLiteral { $$= newUnary(Quote_proto ,i) } + | MO_FUN i:functionDefinition { $$= newUnary(Quote_proto ,i) } + | MO_ED i:externalDeclaration { $$= newUnary(Quote_proto ,i) } + | MO_EXPRESSION i:expression { $$= newUnary(Quote_proto ,i) } ) MO_INITIALIZER = 'initializer' ![(a-zA-Z0-9_] -- @@ -2445,6 +2458,7 @@ MO_DECLARATION = 'declaration' ![(a-zA-Z0-9_] -- MO_STRING = 'string' ![(a-zA-Z0-9_] -- MO_FUN = 'fun' ![(a-zA-Z0-9_] -- MO_ED = 'ed' ![(a-zA-Z0-9_] -- +MO_EXPRESSION = 'expression' ![(a-zA-Z0-9_] -- #--------------------------------------------- Meta rules ----------------------------------------------# diff --git a/parsimonyLibrary/boot.mc b/parsimonyLibrary/boot.mc index 64b3d63..ac70d5d 100644 --- a/parsimonyLibrary/boot.mc +++ b/parsimonyLibrary/boot.mc @@ -15,7 +15,7 @@ } getId(x) { { identifier: x, __proto__: C_id }; } - + getEnum(x) { { attributeL: null, expression: null, name: getId(x), __proto__: C_enum }; } getComma() { { text: ",", comment: { text : " ", __proto__: Comment }, __proto__: Token }; } @@ -27,6 +27,30 @@ s[length(s)] = e; } + // add or don't change an element in a dictionnary + intern(s, e) { + lo = 0; + hi = length(s) - 1; + while (lo <= hi) { + mid = (lo+hi)/2; + if (e > s[mid]) lo = mid + 1; + else if (e < s[mid]) hi = mid - 1; + else return e; + } + for (i = length(s); i > lo; i = i - 1) { + s[i] = s[i-1]; + } + return s[lo] = e; + } + + fusion(s1, s2) { + for (i in s2) { + append(s1, s2[i]); + } + return s1; + // return treeCopy(s1); + } + // If g then we add a filter on the application of the function f to each element of seq map(f, seq, g) { out = {}; diff --git a/parsimonyLibrary/dynamicObject.c b/parsimonyLibrary/dynamicObject.c new file mode 100644 index 0000000..db7d5d1 --- /dev/null +++ b/parsimonyLibrary/dynamicObject.c @@ -0,0 +1,134 @@ +#include +#include +#include + +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; iclass][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; iselector; +} + +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; +}; + +void *Object_print() +{ + printf("Object\n"); + return 0; +} + +struct Point { + int class; + double x, y; +}; + +void *Point_print(struct Point *self) +{ + printf("Point(%f, %f)\n", self->x, self->y); + return 0; +} + +#define send(R, M, ...) ({ struct Object *__ = (struct Object *)(R); lookup(__->class, _selector_##M)(__, ##__VA_ARGS__); }) + +int main() +{ + int _selector_print = findSelector("print" ); + int _class_object = findClass ("Object" ); + int _class_point = findClass ("Point" ); + + addMethod(_class_object, _selector_print, Object_print); + struct Object *o = calloc(1, sizeof(*o)); + o->class = _class_object; + send(o, print); + + addMethod(_class_point, _selector_print, Point_print); + struct Point *p = calloc(1, sizeof(*p)); + p->class = _class_point; + send(p, print); + + return 0; +} \ No newline at end of file diff --git a/parsimonyLibrary/dynamicObject.mc b/parsimonyLibrary/dynamicObject.mc new file mode 100644 index 0000000..3b9a845 --- /dev/null +++ b/parsimonyLibrary/dynamicObject.mc @@ -0,0 +1,223 @@ +#include +#include +#include + +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; iclass][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; iselector; +} + +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__); }) + +@import("parsimonyLibrary/boot.mc") + +@{ + 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) + { + rawSend = (`declaration send(obj, met);); + rawSend.semicolon = null; + rawSend.declarators[0].paramTypeL[0].identifier = object; + rawSend.declarators[0].paramTypeL[2].identifier = method; + treeCopy(rawSend); + } + + everyExternalDeclaration(s) + { + 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] = treeCopy(`declaration int class; ); + program.objects.function = "none"; + return s; + } + if (program.objects.function == "method") { + intern(program.objects.methods, string(program.last.declarators.declarators.identifier)); + for (i in program.objects.class) { + if (string(i) == string(program.objects.currentClassName)) intern(program.objects.class[i], string(program.last.declarators.declarators.identifier)); + } + program.last.declarators.declarators.identifier = string(program.objects.currentClassName) + "_" + string(program.last.declarators.declarators.identifier); + param = (`declaration struct __oop *__self; + ); + param.semicolon = null; + if (length(s.declarators.paramTypeL) > 0) { + append(s.declarators.paramTypeL, getComma()); + append(s.declarators.paramTypeL, treeCopy(param)); + } else { + s.declarators.paramTypeL = {}; + s.declarators.paramTypeL[0] = treeCopy(param); + } + tmp = {}; + tmp[0] = (`declaration struct @(getId(string(program.objects.currentClassName))) *self = (struct @(getId(string(program.objects.currentClassName))) *) __self; + ); + tmp[0].specifiers[0].name.identifier = string(program.objects.currentClassName); + tmp[0].declarators[0].rhs.typeName.specifiers[0].name.identifier = string(program.objects.currentClassName); + s.compoundS.expression = treeCopy(fusion(tmp, s.compoundS.expression)); + // string(program.objects.currentClassName); + // s.declarators.paramTypeL + program.objects.function = "none"; + return s; + } + if (program.objects.function == "constructor") { + rawDeclaration = (`declaration class = findClass("foo"); + ); + rawDeclaration.declarators[0].rhs.paramTypeL[0].text[0].value = "\"" + string(program.objects.currentClassName) + "\""; + size = length(s.compoundS.expression); + lhs = treeCopy(s.compoundS.expression[size-2].expression.lhs); + lhs.rhs = rawDeclaration.declarators[0].lhs; + rawDeclaration.declarators[0].lhs = lhs; + s.compoundS.expression[size] = s.compoundS.expression[size-1]; + s.compoundS.expression[size-1] = rawDeclaration; + program.objects.function = "none"; + return s; + } + if (s.declarators != null && s.declarators.declarators != null && string(s.declarators.declarators.identifier) == "main") { + rawSelector = (`declaration int _selector_ = findSelector("foo"); + ); + rawClass = (`declaration int _class_ = findClass("foo"); + ); + t = {}; + for (i in program.objects.methods) { + rawSelector.declarators[0].lhs.identifier = "_selector_" + string(program.objects.methods[i]); + rawSelector.declarators[0].rhs.paramTypeL[0].text[0].value = "\"" + string(program.objects.methods[i]) + "\""; + append(t, treeCopy(rawSelector)); + } + classKeys = keys(program.objects.class); + for (i in classKeys) { + rawClass.declarators[0].lhs.identifier = "_class_" + string(classKeys[i]); + rawClass.declarators[0].rhs.paramTypeL[0].text[0].value = "\"" + string(classKeys[i]) + "\""; + append(t, treeCopy(rawClass)); + } + rawAddMethod = (`declaration addMethod(_class_, _selector_, foo); + ); + for (i in program.objects.class) { + for (k in program.objects.class[i]) { + newObject = treeCopy(rawAddMethod); + newObject.declarators[0].paramTypeL[0].identifier = string(rawAddMethod.declarators[0].paramTypeL[0].identifier) + string(i); + newObject.declarators[0].paramTypeL[2].identifier = string(rawAddMethod.declarators[0].paramTypeL[2].identifier) + string(program.objects.class[i][k]); + newObject.declarators[0].paramTypeL[4].identifier = string(i) + "_" + string(program.objects.class[i][k]); + append(t, treeCopy(newObject)); + } + } + s.compoundS.expression = fusion(t, s.compoundS.expression); + return s; + } + s; + } + + nil; +} \ No newline at end of file diff --git a/tests-parsimony/objectExample.c b/tests-parsimony/objectExample.c index afcb004..9ea252b 100644 --- a/tests-parsimony/objectExample.c +++ b/tests-parsimony/objectExample.c @@ -3,7 +3,7 @@ typedef long long int_t; typedef long double flt_t; -@beginObject(typeName:"typeName", objectName:"objectName") +@beginObject() struct Integer { int_t i; @@ -21,8 +21,5 @@ struct Symbol { char *name; }; -struct foo { - char *name; -}; - @endObject + diff --git a/tests-parsimony/projExample.c b/tests-parsimony/projectExample.c similarity index 100% rename from tests-parsimony/projExample.c rename to tests-parsimony/projectExample.c diff --git a/tests-parsimony/realObject.c b/tests-parsimony/realObject.c new file mode 100644 index 0000000..5adb552 --- /dev/null +++ b/tests-parsimony/realObject.c @@ -0,0 +1,40 @@ +@import("parsimonyLibrary/dynamicObject.mc") + +#include + +struct __oop { int class; }; + +typedef struct __oop *oop; + +@class struct Point { double x, y; }; + + +@constructor("Point") oop newPoint(double x, double y) +{ + struct Point *p = calloc(1, sizeof *p); // auto + self->x = x; + self->y = y; + return self; // need to cast (struct __oop *) self +} + +@method("Point") double magnitude() +{ + printf("point method : %f\n", sqrt(self->x * self->x * self->y * self->y)); + return sqrt(self->x * self->x * self->y * self->y); +} + +@method("Point") double getX() +{ + printf("point method : %f\n", self->x); + return self->x; +} + +int main() +{ + oop p = newPoint(3, 4); + + @send("p", "magnitude"); + + return 0; +} +