From: Michael D. Lowis Date: Sat, 11 Aug 2018 17:54:40 +0000 (-0400) Subject: added recognition of method call syntax for functions X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=1e16cc7c7f6275965a61176e94125e48ccf0c2d0;p=proto%2Fsclpl.git added recognition of method call syntax for functions --- diff --git a/example.src b/example.src index 02b3cf1..2b1dcd7 100644 --- a/example.src +++ b/example.src @@ -44,5 +44,5 @@ fun main(args string[]) int { fun main(args string[]) int { 123 } + foo.bar() } - diff --git a/source/lexer.l b/source/lexer.l index ce19730..e5a4587 100644 --- a/source/lexer.l +++ b/source/lexer.l @@ -53,6 +53,7 @@ NOSPACE [^ \t\r\n] "]" { return ']'; } "{" { return '{'; } "}" { return '}'; } +"." { return '.'; } "," { return ','; } "'" { return '\''; } ":" { return ':'; } diff --git a/source/parser.c b/source/parser.c index 98ef30f..99ce7fe 100644 --- a/source/parser.c +++ b/source/parser.c @@ -161,13 +161,24 @@ static AST* expression(Parser* p) { expression_block(p); } else if (matches(p, T_IF)) { if_expression(p); +// } else if (matches(p, T_ID)) { +// identifier(p); +// if (matches(p, '(')) +// func_expr_list(p); } else if (matches(p, T_ID)) { identifier(p); - if (matches(p, '(')) - func_expr_list(p); } else { constant(p); } + + /* determine if this is a function call */ + if (matches(p, '(')) { + func_expr_list(p); + } else if (accept(p, '.')) { + identifier(p); + func_expr_list(p); + } + return NULL; } diff --git a/source/rt/gc.c b/source/rt/gc.c index c4f0b9a..3dec0ed 100644 --- a/source/rt/gc.c +++ b/source/rt/gc.c @@ -58,3 +58,121 @@ void gc_setref(void** ref, void* val) { void* gc_getref(void** ref) { return (void*)((uintptr_t)*ref & ~DIRTY_BIT); } + +/*****************************************************************************/ + +typedef struct hash_entry_t { + struct hash_entry_t* next; + uintptr_t hash; +} hash_entry_t; + +typedef struct { + size_t size; + size_t bktid; + hash_entry_t** buckets; +} hash_t; + +static void hash_set(hash_t* hash, hash_entry_t* entry); + +#define NUM_PRIMES (sizeof(Primes)/sizeof(unsigned int)) + +static unsigned int Primes[] = { + 5, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, + 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, + 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, + 805306457, 1610612741 +}; + +static void hash_init(hash_t* hash) { + hash->size = 0; + hash->bktid = 0; + hash->buckets = (hash_entry_t**)calloc(sizeof(hash_entry_t*), Primes[hash->bktid]); +} + +static void find_entry(hash_entry_t** parent, hash_entry_t** current, hash_entry_t* entry) { + while(*current != NULL) { + if (((*current)->hash == entry->hash) && + ((*current)->object == entry->object)) + break; + *parent = *current; + *current = (*current)->next; + } +} + +static void rehash(hash_t* hash) { + unsigned int oldcount, i; + hash_entry_t** oldbuckets; + hash_entry_t *node, *entry; + if ((hash->bktid + 1) < NUM_PRIMES) { + oldcount = hash->bktid++; + oldbuckets = hash->buckets; + hash->buckets = (hash_entry_t**)calloc(sizeof(hash_entry_t*), Primes[hash->bktid]); + hash->size = 0; + /* Iterate over all of the old buckets */ + for (i = 0; i < Primes[oldcount]; i++) { + node = oldbuckets[i]; + /* re-insert all entries in the bucket into the new bucket table */ + while (node != NULL) { + entry = node; + node = entry->next; + hash_set(hash, entry); + } + } + /* Free the old bucket table */ + free(oldbuckets); + } +} + +static uint64_t hash64(uint64_t key) { + key = (~key) + (key << 21); + key = key ^ (key >> 24); + key = (key + (key << 3)) + (key << 8); + key = key ^ (key >> 14); + key = (key + (key << 2)) + (key << 4); + key = key ^ (key >> 28); + key = key + (key << 31); + return key; +} + +static void hash_set(hash_t* hash, hash_entry_t* entry) { + unsigned int index; + hash_entry_t *parent, *node, *deadite; + if (hash->size >= Primes[hash->bktid]) + rehash(hash); + entry->hash = hash64((uint64_t)(entry->object)); + index = (entry->hash % Primes[hash->bktid]); + parent = NULL; + node = hash->buckets[index]; + deadite = NULL; + find_entry(&parent, &node, entry); + if ((parent == NULL) && (node == NULL)) { + hash->buckets[index] = entry; + entry->next = NULL; + hash->size++; + } else if (node == NULL) { + parent->next = entry; + entry->next = NULL; + hash->size++; + } +} + +static hash_entry_t* hash_del(hash_t* hash, hash_entry_t* entry) { + unsigned int index; + hash_entry_t *parent, *node, *ret = NULL; + entry->hash = hash64((uint64_t)(entry->object)); + index = (entry->hash % Primes[hash->bktid]); + parent = NULL; + node = hash->buckets[index]; + find_entry(&parent, &node, entry); + if (node != NULL) { + ret = node; + node = node->next; + if (parent != NULL) + parent->next = node; + else + hash->buckets[index] = node; + hash->size--; + } + return ret; +} + diff --git a/spec/parser_spec.rb b/spec/parser_spec.rb index 0452253..ec3807e 100644 --- a/spec/parser_spec.rb +++ b/spec/parser_spec.rb @@ -1,9 +1,9 @@ require 'open3' describe "sclpl grammar" do -# context "definitions" do + context "definitions" do # it "should parse a value definition with type annotation" do -# expect(ast('def foo int 123;')).to eq([ ['def', 'foo', 'T_INT:123'] ]) +# expect(ast('123')).to eq([ ['def', 'foo', 'T_INT:123'] ]) # end # # it "should parse a function definition with return type annotation" do @@ -48,7 +48,7 @@ describe "sclpl grammar" do # ['def', 'foo', ['fn', ['T_ID:a', 'T_ID:b', 'T_ID:c'], # ["let", ["$:0", "T_INT:123"], "$:0"]]]]) # end -# end + end # # context "literals" do # it "should parse a string" do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 142c88f..37828ae 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -30,7 +30,7 @@ def re_structure( token_array, offset = 0 ) end def ast(input, pass="ast") - out = cli(["-A#{pass}"], input) + out = cli(["-A#{pass}"], "fun test() int { #{input} }") # Prep the parens for reading out.gsub!(/([()])|tree/,' \1 ') # Replace string literals so we can tokenize on spaces