From 638db058287472892fbbb450b3dfc3ae6f458e01 Mon Sep 17 00:00:00 2001 From: mtardy Date: Thu, 16 Jul 2020 22:13:39 +0200 Subject: [PATCH] Add Pr.Piumarta's code and reindent using spaces with width 4 --- calc.leg | 163 ++++++++++++-------- object.c | 444 +++++++++++++++++++++++++++++++----------------------- test2.txt | 65 ++++++++ 3 files changed, 416 insertions(+), 256 deletions(-) create mode 100644 test2.txt diff --git a/calc.leg b/calc.leg index 79f5824..31ff6d0 100644 --- a/calc.leg +++ b/calc.leg @@ -7,21 +7,28 @@ */ #define SYMBOL_PAYLOAD \ - oop value; \ - int defined + oop value; \ + int defined #define SYMBOL_INITIALISE(S) \ - S.value = null; \ - S.defined = false + S.value = null; \ + S.defined = false #include "object.c" +oop globals; + // this should stay out of object.c because it manipulates Symbol members defined in this file oop update_symbol_value(oop symbol, oop integer) { - set(symbol, Symbol, value, integer); - return symbol; + set(symbol, Symbol, value, integer); + return symbol; +} + +oop apply(oop function, oop parameters) +{ + return get(function, Function, primitive)(parameters); } #define YYSTYPE oop @@ -30,65 +37,72 @@ YYSTYPE yylval; %} -start = e:exp { yylval = e } - -exp = - (a:assign { $$ = a } - | d:delete { $$ = d } - | p:prim { $$ = p } - ) - -assign = l:IDENT EQUAL p:prim { $$ = update_symbol_value(l, p) } - -# it is really unhappy that I have to repeate the code in value because -# I need both information: map identifier and the key -delete = DEL - ( i:IDENT DOT p:STRING - | i:IDENT LBRAC p:prim RBRAC - ) { $$ = map_del(get(i, Symbol, value), p) } - -prim = ( s:sum { $$ = s } - | s:string { $$ = s } - | m:map { $$ = m } - ) +start = - e:exp { yylval = e } -# Map -map = LCB RCB { $$ = makeMap() } - | LCB p:prop RCB { $$ = p; } - -prop = k:STRING COLON v:prim COMMA p:prop { $$ = map_set(p, k, v) } - | k:STRING COLON v:prim { $$ = map_set(makeMap(), k, v) } - -# String -string = (SQUOTE | DQUOTE) s:STRING (SQUOTE | DQUOTE) { $$ = s } +exp = l:IDENT EQUAL p:exp { $$ = update_symbol_value(l, p) } + | l:postfix DOT i:IDENT EQUAL p:exp { $$ = map_set(l, i, p) } + | l:postfix LBRAC i:exp RBRAC EQUAL p:exp { $$ = map_set(l, i, p) } + | s:sum { $$ = s } # Number -sum = l:prod - ( PLUS+ r:prod { get(l, Integer, value) += get(r, Integer, value) } - | MINUS r:prod { get(l, Integer, value) -= get(r, Integer, value) } - )* { $$ = l } - -prod = l:sign - ( MULTI r:sign { get(l, Integer, value) *= get(r, Integer, value) } - | DIVIDE r:sign { get(l, Integer, value) /= get(r, Integer, value) } - | MODULO r:sign { get(l, Integer, value) %= get(r, Integer, value) } - )* { $$ = l } - -sign = MINUS n:sign { set(n, Integer, value, -get(n, Integer, value)); $$ = n } - | PLUS n:sign { $$ = n } - | n:value { $$ = n } - -value = n:NUMBER { $$ = n } - | NULL { $$ = null } - | i:IDENT DOT s:STRING { $$ = map_get(get(i, Symbol, value), s) } -# Here between the [ ] I put an exp but the only possible type is String so it is pretty limited -# And I might directly write "prim"? - | i:IDENT LBRAC p:exp RBRAC { $$ = map_get(get(i, Symbol, value), p) } - | i:IDENT { $$ = get(i, Symbol, value) } - -- = [ \t\n\r]* -IDENT = < [a-zA-Z][a-zA-Z0-9_]* > - { $$ = intern(yytext) } -STRING = < [a-zA-Z][a-zA-Z0-9_]* > - { $$ = makeString(yytext) } -NUMBER = < [0-9]+ > - { $$ = makeInteger(atoi(yytext)) } +sum = l:prod + ( PLUS+ r:prod { get(l, Integer, value) += get(r, Integer, value) } + | MINUS r:prod { get(l, Integer, value) -= get(r, Integer, value) } + )* { $$ = l } + +prod = l:prefix + ( MULTI r:prefix { get(l, Integer, value) *= get(r, Integer, value) } + | DIVIDE r:prefix { get(l, Integer, value) /= get(r, Integer, value) } + | MODULO r:prefix { get(l, Integer, value) %= get(r, Integer, value) } + )* { $$ = l } + +prefix = MINUS n:prefix { set(n, Integer, value, -get(n, Integer, value)); $$ = n } + | PLUS n:prefix { $$ = n } + | n:postfix { $$ = n } + +postfix = i:value ( DOT s:IDENT p:parameterList { map_set(p, intern("this"), i); i = apply(map_get(i, s), p) } + | DOT s:IDENT !EQUAL { i = map_get(i, s) } + | LBRAC p:exp RBRAC !EQUAL { i = map_get(i, p) } + | p:parameterList { i = apply(i, p) } + ) * { $$ = i } + +parameterList = LPAREN m:makeMap + ( e:exp { map_append(m, e) } + ( COMMA e:exp { map_append(m, e) } + ) * + ) ? + RPAREN { $$ = m } + +value = n:NUMBER { $$ = n } + | s:string { $$ = s } + | s:symbol { $$ = s } + | m:map { $$ = m } + | NULL { $$ = null } + | i:IDENT { $$ = get(i, Symbol, value) } + | LPAREN i:exp RPAREN { $$ = i } + +string = SQUOTE < (!SQUOTE .)* > SQUOTE { $$ = makeString(yytext) } + | DQUOTE < (!DQUOTE .)* > DQUOTE { $$ = makeString(yytext) } + +symbol = HASH ( i:IDENT { $$ = i } + | i:string { $$ = intern(get(i, String, value)) } + ) + +map = LCB m:makeMap + ( k:IDENT COLON v:exp { map_set(m, k, v) } + ( COMMA k:IDENT COLON v:exp { map_set(m, k, v) } + ) * + ) ? + RCB { $$ = m } + +makeMap = { $$ = makeMap() } + +- = [ \t\n\r]* + | "//" ( ![\n\r] . )* + +IDENT = < [a-zA-Z][a-zA-Z0-9_]* > - { $$ = intern(yytext) } +NUMBER = < [0-9]+ > - { $$ = makeInteger(atoi(yytext)) } +HASH = '#' - PLUS = '+' - MINUS = '-' - MULTI = '*' - @@ -96,7 +110,6 @@ DIVIDE = '/' - MODULO = '%' - EQUAL = '=' - NULL = 'null' - -DEL = 'del' - COLON = ':' - COMMA = ',' - DOT = '.' - @@ -104,16 +117,32 @@ LCB = '{' - RCB = '}' - LBRAC = '[' - RBRAC = ']' - +LPAREN = '(' - +RPAREN = ')' - DQUOTE = '"' - SQUOTE = "'" - %% +; + +oop prim_exit(oop params) +{ + printf("bye bye with params "); + println(params); + exit(0); +} int main(int argc, char **argv) { - while (yyparse()) { - println(yylval); - } + // globals = makeMap(); + + set(intern("exit"), Symbol, value, makeFunction(prim_exit)); // map_set(globals, intern("exit"), makeFunction(prim_exit)); + + while (yyparse()) { + println(yylval); + } + + return 0; - return 0; + (void)yyAccept; } diff --git a/object.c b/object.c index efe1918..d21b2a1 100644 --- a/object.c +++ b/object.c @@ -1,282 +1,348 @@ #include +#include #include #include -#include // NEVER, EVER HAVE TO CALL FREE (EVER) AGAIN (YES, REALLY) +#include // NEVER, EVER HAVE TO CALL FREE (EVER) AGAIN (YES, REALLY) -#define malloc(n) GC_MALLOC(n) -#define realloc(o, n) GC_REALLOC(o, n) +#define malloc(n) GC_MALLOC(n) +#define realloc(o, n) GC_REALLOC(o, n) -typedef enum { Undefined, Integer, String, Symbol, Map } type_t; +typedef enum { + Undefined, + Integer, + String, + Symbol, + Function, + Map +} type_t; union object; typedef union object *oop; struct Undefined { - type_t type; + type_t type; }; struct Integer { - type_t type; - int value; + type_t type; + int value; }; struct String { - type_t type; - char *value; - size_t size; + type_t type; + char *value; + size_t size; }; struct Symbol { - type_t type; - char *name; -# if defined(SYMBOL_PAYLOAD) - SYMBOL_PAYLOAD; -# endif // defined(SYMBOL_PAYLOAD) + type_t type; + char *name; +#if defined(SYMBOL_PAYLOAD) + SYMBOL_PAYLOAD; +#endif // defined(SYMBOL_PAYLOAD) +}; + +typedef oop (*primitive_t)(oop params); + +struct Function { + type_t type; + primitive_t primitive; }; struct Pair { - oop key; - oop value; + oop key; + oop value; }; struct Map { - type_t type; - struct Pair *elements; // even are keys, odd are values [ key val key val key val ] - size_t size; - size_t capacity; + type_t type; + struct Pair *elements; // even are keys, odd are values [ key val key val key val ] + size_t size; + size_t capacity; }; union object { - type_t type; - struct Undefined Undefined; - struct Integer Integer; - struct String String; - struct Symbol Symbol; - struct Map Map; + type_t type; + struct Undefined Undefined; + struct Integer Integer; + struct String String; + struct Symbol Symbol; + struct Function Function; + struct Map Map; }; -union object _null = { .Undefined = { Undefined } }; +union object _null = {.Undefined = {Undefined}}; oop null = &_null; -type_t getType(oop ptr) { - assert(ptr); - return ptr->type; +type_t getType(oop ptr) +{ + assert(ptr); + return ptr->type; } -int is(type_t type, oop obj) { - return type == getType(obj); +int is(type_t type, oop obj) +{ + return type == getType(obj); } -oop _checkType(oop ptr, type_t type) { - assert(ptr); - assert(ptr->type == type); - return ptr; +oop _checkType(oop ptr, type_t type, char *file, int line) +{ + assert(ptr); + if (ptr->type != type) { + fprintf(stderr, "\n%s:%i: expected %i got %i\n", file, line, type, ptr->type); + } + assert(ptr->type == type); + return ptr; } // added parens around expansion to protect assignment -#define get(PTR, TYPE, FIELD) (_checkType(PTR, TYPE)->TYPE.FIELD) -#define set(PTR, TYPE, FIELD, VALUE) (_checkType(PTR, TYPE)->TYPE.FIELD = VALUE) +#define get(PTR, TYPE, FIELD) (_checkType(PTR, TYPE, __FILE__, __LINE__)->TYPE.FIELD) +#define set(PTR, TYPE, FIELD, VALUE) (_checkType(PTR, TYPE, __FILE__, __LINE__)->TYPE.FIELD = VALUE) void *memcheck(void *ptr) { - if (NULL == ptr) { - fprintf(stderr, "Error: out of memory\n"); - exit(EX_OSERR); // this is as close as we have for 'resource unavailable' - } - return ptr; + if (NULL == ptr) { + fprintf(stderr, "Error: out of memory\n"); + exit(EX_OSERR); // this is as close as we have for 'resource unavailable' + } + return ptr; } -oop makeInteger(int value) { - oop newInt = memcheck(malloc(sizeof(union object))); - newInt->type = Integer; - newInt->Integer.value = value; - return newInt; +oop makeInteger(int value) +{ + oop newInt = memcheck(malloc(sizeof(union object))); + newInt->type = Integer; + newInt->Integer.value = value; + return newInt; } -oop makeString(char *value) { - oop newString = memcheck(malloc(sizeof(union object))); - newString->type = String; - newString->String.value = memcheck(strdup(value)); - newString->String.size = strlen(value); - return newString; +oop makeString(char *value) +{ + oop newString = memcheck(malloc(sizeof(union object))); + newString->type = String; + newString->String.value = memcheck(strdup(value)); + newString->String.size = strlen(value); + return newString; } -oop makeSymbol(char *name) { - oop newSymb = memcheck(malloc(sizeof(union object))); - newSymb->type = Symbol; - newSymb->Symbol.name = name; -# if defined(SYMBOL_INITIALISE) - SYMBOL_INITIALISE(newSymb->Symbol); -# endif // defined(SYMBOL_INITIALISE) - return newSymb; +oop makeSymbol(char *name) +{ + oop newSymb = memcheck(malloc(sizeof(union object))); + newSymb->type = Symbol; + newSymb->Symbol.name = name; +#if defined(SYMBOL_INITIALISE) + SYMBOL_INITIALISE(newSymb->Symbol); +#endif // defined(SYMBOL_INITIALISE) + return newSymb; } -oop makeMap() { - oop newMap = memcheck(malloc(sizeof(union object))); - newMap->type = Map; - return newMap; +oop makeFunction(primitive_t primitive) +{ + oop newFunc = memcheck(malloc(sizeof(union object))); + newFunc->type = Function; + newFunc->Function.primitive = primitive; + return newFunc; +} + +oop makeMap() +{ + oop newMap = memcheck(malloc(sizeof(union object))); + newMap->type = Map; + return newMap; +} + +int oopcmp(oop a, oop b) +{ + type_t ta = getType(a), tb = getType(b); + if (ta == tb) { + switch (getType(a)) { + case Integer: + return get(a, Integer, value) - get(b, Integer, value); + case String: + return strcmp(get(a, String, value), get(b, String, value)); + case Symbol: + return strcmp(get(a, Symbol, name), get(b, Symbol, name)); + default: + return (intptr_t)a - (intptr_t)b; + } + } + return ta - tb; } ssize_t map_search(oop map, oop key) { - assert(map); assert(key); - ssize_t l = 0, r = get(map, Map, size) - 1; - while (l <= r) { - ssize_t mid = (l + r) / 2; - int cmpres = strcmp(get(get(map, Map, elements)[mid].key, String, value), get(key, String, value)); - if (cmpres > 0) r = mid - 1; - else if (cmpres < 0) l = mid + 1; - else return mid; // non-negative result => element found at this index - } - return -1 - l; // negative result => 'not found', reflected around -1 instead of 0 to allow 'not found' at index 0 + assert(map); + assert(key); + ssize_t l = 0, r = get(map, Map, size) - 1; + while (l <= r) { + ssize_t mid = (l + r) / 2; + int cmpres = oopcmp(get(map, Map, elements)[mid].key, key); + if (cmpres > 0) r = mid - 1; + else if (cmpres < 0) l = mid + 1; + else return mid; // non-negative result => element found at this index + } + return -1 - l; // negative result => 'not found', reflected around -1 instead of 0 to allow 'not found' at index 0 } -oop map_get(oop map, oop key) { - assert(is(Map, map)); - assert(is(String, key)); - ssize_t pos = map_search(map, key); - if (pos < 0) return null; +oop map_get(oop map, oop key) +{ + assert(is(Map, map)); + //assert(is(String, key)); + ssize_t pos = map_search(map, key); + if (pos < 0) return null; return get(map, Map, elements)[pos].value; } #define MAP_CHUNK_SIZE 8 -oop map_set(oop map, oop key, oop value) { - assert(is(Map, map)); - assert(is(String, key)); - assert(value); - ssize_t pos = map_search(map, key); - if (pos >= 0) { - get(map, Map, elements)[pos].value = value; - // In your opinion, which is better in C - // - Writing "return map" here and then write the rest of the function's code flat - // - Or use this if / else statement (like here) because of the symmetry of the pb - // and the fact that we return the same stuff anyway - } else { - pos = -1 - pos; - // check capacity and expand if needed - if (get(map, Map, size) >= get(map, Map, capacity)) { - size_t newCapacity = get(map, Map, capacity) + MAP_CHUNK_SIZE; - set(map, Map, elements, memcheck(realloc( - get(map, Map, elements), - sizeof(struct Pair) * newCapacity)) - ); - set(map, Map, capacity, newCapacity); - } - // insert - memmove(get(map, Map, elements) + pos + 1, get(map, Map, elements) + pos, sizeof(struct Pair) * get(map, Map, size) - pos); - // Maybe this syntax is not very nice and I should access the Pair stuff differently? - // I mean modifying something on a line that begin with "get"... :/ - get(map, Map, elements)[pos].value = value; - get(map, Map, elements)[pos].key = key; - set(map, Map, size, ++get(map, Map, size)); - } +oop map_set(oop map, oop key, oop value) +{ + assert(is(Map, map)); + //assert(is(String, key)); + assert(value); + ssize_t pos = map_search(map, key); + if (pos >= 0) { + get(map, Map, elements)[pos].value = value; + // In your opinion, which is better in C + // - Writing "return map" here and then write the rest of the function's code flat + // - Or use this if / else statement (like here) because of the symmetry of the pb + // and the fact that we return the same stuff anyway + } else { + pos = -1 - pos; + // check capacity and expand if needed + if (get(map, Map, size) >= get(map, Map, capacity)) { + size_t newCapacity = get(map, Map, capacity) + MAP_CHUNK_SIZE; + set(map, Map, elements, memcheck(realloc(get(map, Map, elements), sizeof(struct Pair) * newCapacity))); + set(map, Map, capacity, newCapacity); + } + // insert + memmove(get(map, Map, elements) + pos + 1, get(map, Map, elements) + pos, sizeof(struct Pair) * get(map, Map, size) - pos); + // Maybe this syntax is not very nice and I should access the Pair stuff differently? + // I mean modifying something on a line that begin with "get"... :/ + get(map, Map, elements)[pos].value = value; + get(map, Map, elements)[pos].key = key; + set(map, Map, size, ++get(map, Map, size)); + } return map; } -oop map_del(oop map, oop key) { - assert(is(Map, map)); - assert(is(String, key)); - ssize_t pos = map_search(map, key); - if (pos < 0) return map; - if (pos < get(map, Map, size) - 1) { - memmove(get(map, Map, elements) + pos, get(map, Map, elements) + pos + 1, sizeof(struct Pair) * get(map, Map, size) - pos); - } - set(map, Map, size, --get(map, Map, size)); +oop map_del(oop map, oop key) +{ + assert(is(Map, map)); + assert(is(String, key)); + ssize_t pos = map_search(map, key); + if (pos < 0) return map; + if (pos < get(map, Map, size) - 1) { + memmove(get(map, Map, elements) + pos, get(map, Map, elements) + pos + 1, sizeof(struct Pair) * get(map, Map, size) - pos); + } + set(map, Map, size, --get(map, Map, size)); return map; } +oop map_append(oop map, oop value) +{ + return map_set(map, makeInteger(get(map, Map, size)), value); +} -void print(oop ast) { - assert(ast); - switch (ast->type) { - case Undefined: - printf("null"); - return; - case Integer: - printf("%i", get(ast, Integer, value)); - return; - case String: - printf("'%s'", get(ast, String, value)); - return; - case Symbol: - printf("%s=", get(ast, Symbol, name)); - print(get(ast, Symbol, value)); - return; - case Map: - printf("{"); - for (size_t i = 0; i < get(ast, Map, size); i++) { - printf(" "); - // I could write this instead but I want a special print for my string key name - // print(get(ast, map, elements)[i].key); - printf("%s", get(get(ast, Map, elements)[i].key, String, value)); - printf(": "); - print(get(ast, Map, elements)[i].value); - if (i < get(ast, Map, size) - 1) printf(","); - else printf(" "); - } - printf("}"); - return; - } - assert(0); +void print(oop ast) +{ + assert(ast); + switch (ast->type) { + case Undefined: + printf("null"); + return; + case Integer: + printf("%i", get(ast, Integer, value)); + return; + case String: + printf("'%s'", get(ast, String, value)); + return; + case Symbol: + printf("%s=", get(ast, Symbol, name)); + print(get(ast, Symbol, value)); + return; + case Function: + printf("Function@%p", get(ast, Function, primitive)); + return; + case Map: + printf("{"); + for (size_t i = 0; i < get(ast, Map, size); i++) { + printf(" "); + // I could write this instead but I want a special print for my string key name + print(get(ast, Map, elements)[i].key); + //printf("%s", get(get(ast, Map, elements)[i].key, String, value)); + printf(": "); + print(get(ast, Map, elements)[i].value); + if (i < get(ast, Map, size) - 1) printf(","); + else printf(" "); + } + printf("}"); + return; + } + assert(0); } void println(oop ast) { - print(ast); - printf("\n"); + print(ast); + printf("\n"); } #define SYMBOL_TABLE_CHUNK 1024 -typedef struct table_t { - oop *array; - size_t size; - size_t capacity; +typedef struct table_t +{ + oop *array; + size_t size; + size_t capacity; } table_t; -#define TABLE_INITIALISER { NULL, 0, 0 } // first call to table_insert() will initialise storage +#define TABLE_INITIALISER \ + { \ + NULL, 0, 0 \ + } // first call to table_insert() will initialise storage -table_t table = TABLE_INITIALISER; // safe but not strictly needed on Unix because BSS segment is initialised to all zeroes +table_t table = TABLE_INITIALISER; // safe but not strictly needed on Unix because BSS segment is initialised to all zeroes ssize_t table_search(table_t *table, char *ident) { - assert(table); assert(ident); - ssize_t l = 0, r = table->size - 1; - while (l <= r) { - ssize_t mid = (l + r) / 2; - int cmpres = strcmp(get(table->array[mid], Symbol, name), ident); - if (cmpres > 0) r = mid - 1; - else if (cmpres < 0) l = mid + 1; - else return mid; // non-negative result => element found at this index - } - return -1 - l; // negative result => 'not found', reflected around -1 instead of 0 to allow 'not found' at index 0 + assert(table); + assert(ident); + ssize_t l = 0, r = table->size - 1; + while (l <= r) { + ssize_t mid = (l + r) / 2; + int cmpres = strcmp(get(table->array[mid], Symbol, name), ident); + if (cmpres > 0) r = mid - 1; + else if (cmpres < 0) l = mid + 1; + else return mid; // non-negative result => element found at this index + } + return -1 - l; // negative result => 'not found', reflected around -1 instead of 0 to allow 'not found' at index 0 } // ssize_t result because -1 means 'error' ssize_t table_insert(table_t *table, oop object, size_t pos) { - assert(is(Symbol, object)); - if (pos > table->size) { // don't need to check for pos < 0 because size_t is unsigned - return -1; - } - - if (table->size >= table->capacity) { - table->array = memcheck(realloc(table->array, sizeof(oop) * (table->capacity + SYMBOL_TABLE_CHUNK))); - table->capacity += SYMBOL_TABLE_CHUNK; - } - - memmove(table->array + pos + 1, table->array + pos, sizeof(*table->array) * (table->size - pos)); - table->array[pos] = object; - return ++(table->size); + assert(is(Symbol, object)); + if (pos > table->size) { // don't need to check for pos < 0 because size_t is unsigned + return -1; + } + + if (table->size >= table->capacity) { + table->array = memcheck(realloc(table->array, sizeof(oop) * (table->capacity + SYMBOL_TABLE_CHUNK))); + table->capacity += SYMBOL_TABLE_CHUNK; + } + + memmove(table->array + pos + 1, table->array + pos, sizeof(*table->array) * (table->size - pos)); + table->array[pos] = object; + return ++(table->size); } oop intern(char *ident) { - ssize_t res= table_search(&table, ident); // < 0 => not found - if (res >= 0) return table.array[res]; - res= -1 - res; // 'un-negate' the result by reflecting it around X=-1 + ssize_t res = table_search(&table, ident); // < 0 => not found + if (res >= 0) return table.array[res]; + res = -1 - res; // 'un-negate' the result by reflecting it around X=-1 oop new_symbol = makeSymbol(memcheck(strdup(ident))); - table_insert(&table, new_symbol, res); - return new_symbol; + table_insert(&table, new_symbol, res); + return new_symbol; } diff --git a/test2.txt b/test2.txt new file mode 100644 index 0000000..c1276ac --- /dev/null +++ b/test2.txt @@ -0,0 +1,65 @@ +"hello" +#"foo" +#"***" +42 +3+4 +s = "abc" +s +o = {} +o +o +o.x = 42 +o.x + +"checkpoint 1" + +{ prop1 : 12+2 } + +"checkpoint 2" + +{ prop1 : 12+2 }.prop1 + +"checkpoint 3" + +myObj = { prop1: 12+2, prop2: { subProp1: "hey", subProp2: --12 } } +myStr = "prop1" +myObj[myStr] +mySym = #prop1 +myObj[mySym] + +"checkpoint 4" + +myObj.prop2.subProp1 + +myObj.undefinedProp +myObj[#undeinedProp] + +myObj.foo = 123 +myObj.prop2.subProp2 + +myObj.prop2.subProp2 = 42 +myObj.prop2.subProp2 + +"checkpoint 5" + +myObj[42] +myObj[42]=666 + +"checkpoint 6" + +myObj[42] = 666 + +"checkpoint 7" + +myObj[42] + +exit + + + +sys = {} +sys.id = "i am sys obj" + +sys.bye = exit + +sys.bye(1,2,3)