language

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit fd937c7f328509c1b4b8329a6460c99e079cb2b8
parent 9714eedc94447ca125c5986d5a96219cdbd6d75f
Author: Paul Longtine <paullongtine@gmail.com>
Date:   Tue, 24 May 2016 13:26:45 -0400

Properly namespacing with the compiler

Diffstat:
Mdoc/SPECIFICATION | 30+++++++++++++++++++++---------
Msrc/lc/interpreter.py | 72++++++++++++++++++++++++++----------------------------------------------
Asrc/lc/namespace.py | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/lc/parser.py | 12++++--------
Msrc/lc/test_files/class.ti | 28+++++++++++++++++++++++++---
Msrc/vm/src/ins_def.c | 2+-
Msrc/vm/src/proc.c | 2+-
7 files changed, 163 insertions(+), 68 deletions(-)

diff --git a/doc/SPECIFICATION b/doc/SPECIFICATION @@ -87,6 +87,11 @@ In this definition, the namespace will provide the following key mechanisms: * Implicitly move in/out of scopes +The scope arguement is a single byte, where the format is as follows: + + Namespace|Scope + 0000000 |0 + Scopes are handled by referencing to either the Global Scope or the Local Scope. The Local Scope is denoted by '0' in the scope arguement when refering to names, and this scope is initialized when evaluating any new block of code. When a diff @@ -98,21 +103,27 @@ function calls, you can traverse n instances of previous namespaces. For example, take this namespace level graphic, where each Level is a namespace instance: - Level 0: Global namespace, denoted by '1'. - Level 1: Namespace level, where Local Level is at 1, denoted by '0'. + Level 0: Global namespace, LSB == '1'. + Level 1: Namespace level, where Local Level is at 1, LSB == '0'. When a function is called, another namespace level is created and the local level increases, like so: - Level 0: Global namespace, denoted by '1'. + Level 0: Global namespace, LSB == '1'. Level 1: Namespace level. - Level 2: Namespace level, where Local Level is at 2, denoted by '0'. + Level 2: Namespace level, where Local Level is at 2, LSB == '0'. -Global scope names (denoted by a '1' in the scope arguement) are persistient + +Global scope names (LSB == 1 in the scope arguement) are persistient through the runtime as they handle all function definitions, objects, and names declared in the global scope. The "Local Level" is at where references that have a scope arguement of '0' refer to when accessing names. +The Namespace arguement refers to which Namespace the variable exists in. +When the namespace arguement equals 0, the current namespace is referenced. +The global namespace is 1 by default, and any other namespaces must be declared +by using the + VARIABLE DEFINITION Variables in this definiton provide the following mechanims: @@ -160,12 +171,13 @@ collection of methods. BYTECODE SPEC -Bytecode is organised in the following manner: +Bytecode is arranged in the following order: - <opcode> (arg 0... (arg n < 3 ) ) + <opcode>, <arg 0>, <arg 1>, <arg 2> Where the <opcode> is a single byte denoting which subroutine to call with the -following arguements when executed. +following arguements when executed. Different opcodes have different arguement +lengths, some having 0 arguements, and others having 3 arguements. Interpreting Bytecode Instructions @@ -300,7 +312,7 @@ FF DEFUN N<ref> S<type> D<args> - Un-funs everything. no, no- it defines a FE DECLASS N<ref> D<args> - Defines a class. -FD DENS S<ref> - Specifies a namespace scope +FD DENS S<ref> - Declares namespace F2 ENDCLASS - End of class block diff --git a/src/lc/interpreter.py b/src/lc/interpreter.py @@ -3,6 +3,7 @@ from lexer import * from bytecode import * from memonic import * from helper import * +from namespace import * class AbstractToken(): def __init__(self, interpreter_instance, raw_data): @@ -22,29 +23,25 @@ class Label(AbstractToken): def update(self): f = lambda y, x: y(y, x[0]) if type(x) is list else x self.data = f(f, self.data) + self.is_property = False - self.obj = None + self.parent = None + self.name = None names = self.data.rsplit(".", 1) if len(names) > 1: self.is_property = True - self.obj = Label(self.i, names[0]) - self.data = names[1] - namespace = [self.i.objects[self.obj.data]] - else: - namespace = self.i.names - - self.scope = 0 - self.expr = 0 - for n, i in enumerate(namespace): - if self.data in i: - self.expr = i.index(self.data) + 1 - self.scope = 0 if n > 0 else 1 - break + self.parent = Label(self.i, names[0]) - if self.expr == 0: - print("Undefined variable '{}'".format(self.data)) + self.name = names[1] + + t = self.i.ns.resolve_with_obj(self.parent, self.name) + else: + self.name = names[0] + t = self.i.ns.resolve(self.name) + self.scope = t[0] + self.expr = t[1] def action(self, s=False): if s: @@ -89,14 +86,14 @@ class Parameters(AbstractToken): if x != ",": tmp.append(x) elif x == ",": - self.i.name_dec(tmp[1:]) + self.i.new_name_token(tmp[1:]) t = Type(self.i, tmp[:-1]) l = Label(self.i, tmp[1:]) self.expr.append([t, l]) tmp = [] if len(tmp) > 0: - self.i.name_dec(tmp[1:]) + self.i.new_name_token(tmp[1:]) t = Type(self.i, tmp[:-1]) l = Label(self.i, tmp[1:]) self.expr.append([t, l]) @@ -219,6 +216,7 @@ class Directive(): class Interpreter(): def __init__(self, filename): self.p = Parser(filename) + self.ns = Namespace() self.program = self.p.get_statements() @@ -226,12 +224,6 @@ class Interpreter(): self.ln = 0 - self.scopestack = [] - self.names = [[]] - self.objects = {} - self.cur_obj_scope = "" - self.scope = 0 - self.cur_directives = [] self.directives = [self.cur_directives] @@ -249,52 +241,40 @@ class Interpreter(): return self.program[self.ln + n] def ns_persist(self, index): - self.objects[self.line[1][index][0]] = [] - self.cur_obj_scope = self.line[1][index][0] + self.ns.target(self.line[1][index][0]) return False def ns_save(self): - self.objects[self.cur_obj_scope] = self.names[self.scope] + self.ns.release() return False def ns_copy(self, key, index): - self.objects[self.line[1][key][0]] = self.objects[self.line[1][index][0]] + self.ns.copy(self.line[1][key][0], self.line[1][index][0]) return False def new_name(self, index): - self.name_dec(self.line[1][index]) + self.new_name_token(self.line[1][index]) return False - def name_dec(self, token): + def new_name_token(self, token): f = lambda y, x: y(y, x[0]) if type(x) is list else x - t = f(f, token) - - for scope in range(0, self.scope): - if t in self.names[scope]: - print("Can't instantiate name that's already in use!") - self.names[self.scope].append(t) + self.ns.name_dec(f(f, token)) def push_scope(self): - self.scopestack.append([self.names, self.scope]) - self.names = [[]] - self.scope = 0 + self.ns.push() return False def pop_scope(self): - t = self.scopestack.pop() - self.names = t[0] - self.scope = t[1] + self.ns.pop() return False def inc_scope(self): - self.names.append([]) - self.scope += 1 + self.ns.inc_scope() return False def dec_scope(self): - self.names.pop() - self.scope -= 1 + self.ns.dec_scope() return False def push_directives(self): diff --git a/src/lc/namespace.py b/src/lc/namespace.py @@ -0,0 +1,85 @@ + +class Namespace(): + # Namespace data structure: + # { + # "<name>" : [ <index, int>, None ], + # "<object>" : [ <index, int>, {"property" : [ <index, int>, None ]} + # } + def __init__(self): + self.sc = 0 + self.ns = [{}] + self.scopes = [self.ns] + self.stack = [] + + self.t = None + + def name_dec(self, name): + if name in self.ns[self.sc].keys(): + print("Declaring name that already exists!") + else: + self.ns[self.sc][name] = [len(self.ns[self.sc].keys()) + 1, None] + + def inc_scope(self): + self.ns.append({}) + self.sc += 1 + + def dec_scope(self): + self.ns.pop() + self.sc -= 1 + + def push(self): + self.stack.append([self.sc, self.ns]) + self.sc = 0 + self.ns = [{}] + + def pop(self): + tmp = self.stack.pop() + self.sc = tmp[0] + self.ns = tmp[1] + + # New namespace + def target(self, name): + self.t = name + self.push() + + self.sc = 0 + self.ns = [{}] + + # Releases target + def release(self): + tmp = self.ns[0] + self.pop() + self.ns[0][self.t][1] = tmp + self.t = None + + def copy(self, new_name, name): + self.ns[self.sc][new_name][1] = self.obj_resolve(name)[1] + + # Resolves name into object + def obj_resolve(self, name): + rv = None + for namespace in self.scopes: + for names in namespace: + if name in names.keys() and rv == None: + rv = names[name] + elif rv != None: + print("{} was found, but found again".format(name)) + + return rv + + def resolve_with_obj(self, obj, name): + t = self.obj_resolve(obj) + print(t) + + # Resolves name into scope and address + def resolve(self, name): + rv = None + + if name in self.ns[0].keys(): + rv = [1, self.ns[0][name][0]] + elif name in self.ns[-1].keys(): + rv = [0, self.ns[-1][name][0]] + else: + print("Out of scope tbi") + + return rv diff --git a/src/lc/parser.py b/src/lc/parser.py @@ -284,13 +284,11 @@ class Parser(): ], init=(lambda x: [ x.new_name(1), - ClassDef(x.eval_label(1), - x.eval_param(2)), x.ns_persist(1), + ClassDef(x.eval_label(1), + None), x.add_directive(lambda x: [x.ns_save(), - x.pop_scope(), - x.op(OP_ENDCLASS)]), - x.push_scope() + x.op(OP_ENDCLASS)]) ]) ) @@ -307,9 +305,7 @@ class Parser(): ClassDef(x.eval_label(1), None), x.add_directive(lambda x: [x.ns_save(), - x.pop_scope(), - x.op(OP_ENDCLASS)]), - x.push_scope() + x.op(OP_ENDCLASS)]) ]) ) diff --git a/src/lc/test_files/class.ti b/src/lc/test_files/class.ti @@ -1,9 +1,30 @@ +DEBUG; + +class Counter: +{ + int data = 0; + + func count -> int: + { + data = data + 1; + + return data; + } + + func reset -> void: + { + data = 0; + } +} + class ObjectFibb: { int a = 0; int b = 1; int c = 0; + Counter acc = new Counter(); + func next -> void: { if c == 0: @@ -26,10 +47,9 @@ class ObjectFibb: func run (int count) -> void: { - int x = 0; - while x < count: + acc.reset(); + while acc.count() < count: { - x = x + 1; next(); display(); } @@ -38,4 +58,6 @@ class ObjectFibb: ObjectFibb test = new ObjectFibb(); +print test.c.data; + test.run(15); diff --git a/src/vm/src/ins_def.c b/src/vm/src/ins_def.c @@ -662,7 +662,7 @@ void _ins_def_NEW (rt_t* ctx, bc_cont* line) var_cont* arg = stk_pop(ctx->argstk); // Is the arguement of the right type? - ASSERT(arg->type == builder->param[i], "Invalid object instantiation\n"); + ASSERT(arg->type == builder->param[i], "Invalid arguement stack\n"); // Declare the name in the new namespace and pass the arguements ns_dec(ctx->vars, arg->type, 0, i+offset); diff --git a/src/vm/src/proc.c b/src/vm/src/proc.c @@ -225,7 +225,7 @@ void proc_function_call_handle(rt_t* ctx, var_data_func* func) var_cont* arg = stk_pop(ctx->argstk); // Is the arguement of the right type? - ASSERT(arg->type == func->param[i], "Invalid function call\n"); + ASSERT(arg->type == func->param[i], "Invalid arguement stack\n"); // Declare the name in the new namespace and pass the arguements ns_dec(ctx->vars, arg->type, 0, i+offset);