sourcemod/sourcepawn/compiler/sctracker.c
David Anderson 63ad5eff18 Introduce basic methodmaps (PR #38).
commit 1e5213d43fdd170bb0c30af914a4e40610014b2b
Author: David Anderson <dvander@alliedmods.net>
Date:   Sat Jun 21 04:09:27 2014 -0700

    Quell MSVC C99 bugs.

commit f2e166c5925fda49b5abeadc0aa0f9156b99cf11
Author: David Anderson <dvander@alliedmods.net>
Date:   Sat Jun 21 03:59:23 2014 -0700

    Fix varying levels of stupid memory errors.

commit b0773d7be45345351ab1c1738681d5215a97f3f3
Author: David Anderson <dvander@alliedmods.net>
Date:   Sat Jun 21 03:36:39 2014 -0700

    Fix memory leak in parsing some control flow structures.

commit 5aca55713cfc2dd09c5900132fc4a6be51e3e309
Author: David Anderson <dvander@alliedmods.net>
Date:   Sat Jun 21 03:35:17 2014 -0700

    Fix memory leak in struct parsing.

commit b46ec5cd281b46177e83c4f0a4acac9cc1065c53
Author: David Anderson <dvander@alliedmods.net>
Date:   Sat Jun 21 03:32:03 2014 -0700

    Fix build.

commit 17bbbb9a46bfc00862adca7d3e15369a48e9ac0f
Merge: c083409 2107599
Author: David Anderson <dvander@alliedmods.net>
Date:   Sat Jun 21 01:26:27 2014 -0700

    Merge branch 'master' into methodmaps

commit c083409b569abff13f24d3b8c47f8ff199036840
Author: David Anderson <dvander@alliedmods.net>
Date:   Fri Jun 20 23:49:36 2014 -0700

    Add VS2k13 support.

commit b7993778494d538cb1c1965116030142a7f7765b
Author: David Anderson <dvander@alliedmods.net>
Date:   Fri Jun 20 01:28:08 2014 -0700

    Implement destructors.

commit 1a340dec260d079ed1b79351ed7b50b58a997cea
Author: David Anderson <dvander@alliedmods.net>
Date:   Fri Jun 20 00:08:04 2014 -0700

    Add some tests.

commit 12db52ee64eb009ead9294495e9034c63ab75b09
Author: David Anderson <dvander@alliedmods.net>
Date:   Fri Jun 20 00:05:49 2014 -0700

    Initial implementation of constructors.

commit 074669a658caa2822aa864164b615a244c00a0bc
Author: David Anderson <dvander@alliedmods.net>
Date:   Thu Jun 19 22:42:35 2014 -0700

    Add simple test harness.

commit 27c1e3cf14e1e6c5cf35c80c792cce2744b804d7
Author: David Anderson <dvander@alliedmods.net>
Date:   Thu Jun 19 22:15:42 2014 -0700

    Big refactoring for new syntax.

commit f3c37fdc919e76ee0815e2394cbe8d221f9fc0ca
Author: David Anderson <dvander@alliedmods.net>
Date:   Thu Jun 19 22:12:54 2014 -0700

    Refactor tests for the new syntax.

commit 6211f392f8e722b907474cf380cfac4347e46b8e
Author: David Anderson <dvander@alliedmods.net>
Date:   Wed Jun 18 22:25:48 2014 -0700

    Make lexer tokens an enum.

commit 5210b013756b0b00de3a61c6490685c768ff8cbd
Author: David Anderson <dvander@alliedmods.net>
Date:   Tue Jun 17 06:48:15 2014 -0700

    Add comment.

commit 06688ff4aced14077dd21a9cc1db4c26c7420ff3
Author: David Anderson <dvander@alliedmods.net>
Date:   Tue Jun 17 06:46:10 2014 -0700

    Allow |this| to be a base type of the methodmap.

commit 05cf3682020e0e6d9f47b1a0a6727b9edbfe7622
Author: David Anderson <dvander@alliedmods.net>
Date:   Mon Jun 16 22:11:58 2014 -0700

    Unify duplicate typesymbol checking.

commit 09161bf2691c8c1ed25b9b70fda01c336f21aa0b
Author: David Anderson <dvander@alliedmods.net>
Date:   Mon Jun 16 19:53:36 2014 -0700

    Close loophole that allowed methodmaps for enums.

commit 5bb4aeba89fec47a4de7a7532d27830999d1fcb4
Author: David Anderson <dvander@alliedmods.net>
Date:   Mon Jun 16 01:50:42 2014 -0700

    Add tests and dbi/handle changes.

commit b9203e2491daec2a8073874d6375949483778d14
Author: David Anderson <dvander@alliedmods.net>
Date:   Mon Jun 16 01:38:29 2014 -0700

    Ensure methodmap tags are fixed.

commit 878b80fd87a2ea500d3a28ce2d53f616d1efe5e8
Author: David Anderson <dvander@alliedmods.net>
Date:   Mon Jun 16 01:36:04 2014 -0700

    Implement inheritance.

commit 6ba9e004fbae18ad68056368ddd0affdc78659f1
Author: David Anderson <dvander@alliedmods.net>
Date:   Mon Jun 16 01:31:00 2014 -0700

    Refactor matchtag() to not be insane.

commit 4ede6343b0682c6df98fa869153828e92f891bcc
Author: David Anderson <dvander@alliedmods.net>
Date:   Mon Jun 16 01:20:50 2014 -0700

    Fix indenting.

commit e3ddef8916e3dd5f4ff0fe571d6e1c3acd163352
Author: David Anderson <dvander@alliedmods.net>
Date:   Mon Jun 16 01:20:27 2014 -0700

    Initial prototype.
2014-06-21 04:10:15 -07:00

578 lines
10 KiB
C

/* vim: set ts=8 sts=2 sw=2 tw=99 et: */
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "sc.h"
#include "sctracker.h"
memuse_list_t *heapusage = NULL;
memuse_list_t *stackusage = NULL;
funcenum_t *firstenum = NULL;
funcenum_t *lastenum = NULL;
pstruct_t *firststruct = NULL;
pstruct_t *laststruct = NULL;
methodmap_t *methodmap_first = NULL;
methodmap_t *methodmap_last = NULL;
structarg_t *pstructs_getarg(pstruct_t *pstruct, const char *member)
{
int i;
for (i=0; i<pstruct->argcount; i++)
{
if (strcmp(pstruct->args[i]->name, member) == 0)
{
return pstruct->args[i];
}
}
return NULL;
}
pstruct_t *pstructs_add(const char *name)
{
pstruct_t *p = (pstruct_t *)malloc(sizeof(pstruct_t));
memset(p, 0, sizeof(pstruct_t));
strcpy(p->name, name);
if (!firststruct)
{
firststruct = p;
laststruct = p;
} else {
laststruct->next = p;
laststruct = p;
}
return p;
}
void pstructs_free()
{
pstruct_t *p, *next;
p = firststruct;
while (p)
{
while (p->argcount--)
{
free(p->args[p->argcount]);
}
free(p->args);
next = p->next;
free(p);
p = next;
}
firststruct = NULL;
laststruct = NULL;
}
pstruct_t *pstructs_find(const char *name)
{
pstruct_t *p = firststruct;
while (p)
{
if (strcmp(p->name, name) == 0)
{
return p;
}
p = p->next;
}
return NULL;
}
structarg_t *pstructs_addarg(pstruct_t *pstruct, const structarg_t *arg)
{
structarg_t *newarg;
int i;
for (i=0; i<pstruct->argcount; i++)
{
if (strcmp(pstruct->args[i]->name, arg->name) == 0)
{
/* Don't allow dup names */
return NULL;
}
}
newarg = (structarg_t *)malloc(sizeof(structarg_t));
memcpy(newarg, arg, sizeof(structarg_t));
if (pstruct->argcount == 0)
{
pstruct->args = (structarg_t **)malloc(sizeof(structarg_t *) * 1);
} else {
pstruct->args = (structarg_t **)realloc(
pstruct->args,
sizeof(structarg_t *) * (pstruct->argcount + 1));
}
newarg->offs = pstruct->argcount * sizeof(cell);
newarg->index = pstruct->argcount;
pstruct->args[pstruct->argcount++] = newarg;
return newarg;
}
void funcenums_free()
{
funcenum_t *e, *next;
e = firstenum;
while (e)
{
functag_t *tag, *nexttag;
tag = e->first;
while (tag)
{
nexttag = tag->next;
free(tag);
tag = nexttag;
}
next = e->next;
free(e);
e = next;
}
firstenum = NULL;
lastenum = NULL;
}
funcenum_t *funcenums_find_byval(int value)
{
funcenum_t *e = firstenum;
while (e)
{
if (e->value == value)
{
return e;
}
e = e->next;
}
return NULL;
}
funcenum_t *funcenums_add(const char *name)
{
funcenum_t *e = (funcenum_t *)malloc(sizeof(funcenum_t));
memset(e, 0, sizeof(funcenum_t));
if (firstenum == NULL)
{
firstenum = e;
lastenum = e;
} else {
lastenum->next = e;
lastenum = e;
}
strcpy(e->name, name);
e->value = pc_addfunctag((char *)name);
return e;
}
functag_t *functags_add(funcenum_t *en, functag_t *src)
{
functag_t *t = (functag_t *)malloc(sizeof(functag_t));
memcpy(t, src, sizeof(functag_t));
t->next = NULL;
if (en->first == NULL)
{
en->first = t;
en->last = t;
} else {
en->last->next = t;
en->last = t;
}
return t;
}
/**
* Creates a new mem usage tracker entry
*/
void _push_memlist(memuse_list_t **head)
{
memuse_list_t *newlist = (memuse_list_t *)malloc(sizeof(memuse_list_t));
if (*head != NULL)
{
newlist->list_id = (*head)->list_id + 1;
} else {
newlist->list_id = 0;
}
newlist->prev = *head;
newlist->head = NULL;
*head = newlist;
}
/**
* Pops a heap list but does not free it.
*/
memuse_list_t *_pop_save_memlist(memuse_list_t **head)
{
memuse_list_t *oldlist = *head;
*head = (*head)->prev;
return oldlist;
}
/**
* Marks a memory usage on a memory list
*/
int _mark_memlist(memuse_list_t *head, int type, int size)
{
memuse_t *use;
if (type==MEMUSE_STATIC && size==0)
{
return 0;
}
use=head->head;
if (use && (type==MEMUSE_STATIC)
&& (use->type == type))
{
use->size += size;
} else {
use=(memuse_t *)malloc(sizeof(memuse_t));
use->type=type;
use->size=size;
use->prev=head->head;
head->head=use;
}
return size;
}
void _reset_memlist(memuse_list_t **head)
{
memuse_list_t *curlist = *head;
memuse_list_t *tmplist;
while (curlist) {
memuse_t *curuse = curlist->head;
memuse_t *tmpuse;
while (curuse) {
tmpuse = curuse->prev;
free(curuse);
curuse = tmpuse;
}
tmplist = curlist->prev;
free(curlist);
curlist = tmplist;
}
*head = NULL;
}
/**
* Wrapper for pushing the heap list
*/
void pushheaplist()
{
_push_memlist(&heapusage);
}
/**
* Wrapper for popping and saving the heap list
*/
memuse_list_t *popsaveheaplist()
{
return _pop_save_memlist(&heapusage);
}
/**
* Wrapper for marking the heap
*/
int markheap(int type, int size)
{
return _mark_memlist(heapusage, type, size);
}
/**
* Wrapper for pushing the stack list
*/
void pushstacklist()
{
_push_memlist(&stackusage);
}
/**
* Wrapper for marking the stack
*/
int markstack(int type, int size)
{
return _mark_memlist(stackusage, type, size);
}
/**
* Generates code to free all heap allocations on a tracker
*/
void _heap_freeusage(memuse_list_t *heap, int dofree)
{
memuse_t *cur=heap->head;
memuse_t *tmp;
while (cur)
{
if (cur->type == MEMUSE_STATIC)
{
modheap((-1)*cur->size*sizeof(cell));
} else {
modheap_i();
}
if (dofree)
{
tmp=cur->prev;
free(cur);
cur=tmp;
} else {
cur=cur->prev;
}
}
if (dofree)
{
heap->head=NULL;
}
}
void _stack_genusage(memuse_list_t *stack, int dofree)
{
memuse_t *cur = stack->head;
memuse_t *tmp;
while (cur)
{
if (cur->type == MEMUSE_DYNAMIC)
{
/* no idea yet */
assert(0);
} else {
modstk(cur->size * sizeof(cell));
}
if (dofree)
{
tmp = cur->prev;
free(cur);
cur = tmp;
} else {
cur = cur->prev;
}
}
if (dofree)
{
stack->head = NULL;
}
}
/**
* Pops a heap list and frees it.
*/
void popheaplist()
{
memuse_list_t *oldlist;
assert(heapusage!=NULL);
_heap_freeusage(heapusage, 1);
assert(heapusage->head==NULL);
oldlist=heapusage->prev;
free(heapusage);
heapusage=oldlist;
}
void genstackfree(int stop_id)
{
memuse_list_t *curlist = stackusage;
while (curlist && curlist->list_id > stop_id)
{
_stack_genusage(curlist, 0);
curlist = curlist->prev;
}
}
void genheapfree(int stop_id)
{
memuse_list_t *curlist = heapusage;
while (curlist && curlist->list_id > stop_id)
{
_heap_freeusage(curlist, 0);
curlist = curlist->prev;
}
}
void popstacklist(int codegen)
{
memuse_list_t *oldlist;
assert(stackusage != NULL);
if (codegen)
{
_stack_genusage(stackusage, 1);
assert(stackusage->head==NULL);
} else {
memuse_t *use = stackusage->head;
while (use) {
memuse_t *temp = use->prev;
free(use);
use = temp;
}
}
oldlist = stackusage->prev;
free(stackusage);
stackusage = oldlist;
}
void resetstacklist()
{
_reset_memlist(&stackusage);
}
void resetheaplist()
{
_reset_memlist(&heapusage);
}
void methodmap_add(methodmap_t *map)
{
if (!methodmap_first) {
methodmap_first = map;
methodmap_last = map;
} else {
methodmap_last->next = map;
methodmap_last = map;
}
}
methodmap_t *methodmap_find_by_tag(int tag)
{
methodmap_t *ptr = methodmap_first;
for (; ptr; ptr = ptr->next) {
if (ptr->tag == tag)
return ptr;
}
return NULL;
}
methodmap_t *methodmap_find_by_name(const char *name)
{
int tag = pc_findtag(name);
if (tag == -1)
return NULL;
return methodmap_find_by_tag(tag);
}
methodmap_method_t *methodmap_find_method(methodmap_t *map, const char *name)
{
size_t i;
for (i = 0; i < map->nummethods; i++) {
if (strcmp(map->methods[i]->name, name) == 0)
return map->methods[i];
}
if (map->parent)
return methodmap_find_method(map->parent, name);
return NULL;
}
void methodmaps_free()
{
methodmap_t *ptr = methodmap_first;
while (ptr) {
methodmap_t *next = ptr->next;
for (size_t i = 0; i < ptr->nummethods; i++)
free(ptr->methods[i]);
free(ptr->methods);
free(ptr);
ptr = next;
}
methodmap_first = NULL;
methodmap_last = NULL;
}
LayoutSpec deduce_layout_spec_by_tag(int tag)
{
symbol *sym;
const char *name;
methodmap_t *map;
if ((map = methodmap_find_by_tag(tag)) != NULL)
return map->spec;
if (tag & FUNCTAG)
return Layout_FuncTag;
name = pc_tagname(tag);
if (pstructs_find(name))
return Layout_PawnStruct;
if ((sym = findglb(name, sGLOBAL)) != NULL)
return Layout_Enum;
return Layout_None;
}
LayoutSpec deduce_layout_spec_by_name(const char *name)
{
symbol *sym;
methodmap_t *map;
int tag = pc_findtag(name);
if (tag != -1 && (tag & FUNCTAG))
return Layout_FuncTag;
if (pstructs_find(name))
return Layout_PawnStruct;
if ((map = methodmap_find_by_name(name)) != NULL)
return map->spec;
if ((sym = findglb(name, sGLOBAL)) != NULL)
return Layout_Enum;
return Layout_None;
}
const char *layout_spec_name(LayoutSpec spec)
{
switch (spec) {
case Layout_None:
return "<none>";
case Layout_Enum:
return "enum";
case Layout_FuncTag:
return "functag";
case Layout_PawnStruct:
return "deprecated-struct";
case Layout_MethodMap:
return "methodmap";
case Layout_Class:
return "class";
}
return "<unknown>";
}
int can_redef_layout_spec(LayoutSpec def1, LayoutSpec def2)
{
// Normalize the ordering, since these checks are symmetrical.
if (def1 > def2) {
LayoutSpec temp = def2;
def2 = def1;
def1 = temp;
}
switch (def1) {
case Layout_None:
return TRUE;
case Layout_Enum:
if (def2 == Layout_Enum || def2 == Layout_FuncTag)
return TRUE;
return def2 == Layout_MethodMap;
case Layout_FuncTag:
return def2 == Layout_Enum || def2 == Layout_FuncTag;
case Layout_PawnStruct:
case Layout_MethodMap:
return FALSE;
case Layout_Class:
return FALSE;
}
return FALSE;
}