Skip to content

Commit

Permalink
Finally dump use of a names dictionary in compiled programs
Browse files Browse the repository at this point in the history
Everything is now an lname.
  • Loading branch information
jonathanhogg committed Feb 8, 2024
1 parent 3133580 commit 2ccca1e
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 54 deletions.
7 changes: 4 additions & 3 deletions src/flitter/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ def read_bytes(self):
return data

def read_flitter_program(self, static=None, dynamic=None):
current_program = self._cache.get('flitter', False)
key = 'flitter', tuple(sorted(static.items())) if static else None, tuple(dynamic) if dynamic else ()
current_program = self._cache.get(key, False)
if current_program is not False and self.check_unmodified():
return current_program
if self._mtime is None:
Expand All @@ -123,7 +124,7 @@ def read_flitter_program(self, static=None, dynamic=None):
now = system_clock()
simplify_time += now
compile_time = -now
program = top.compile()
program = top.compile(initial_lnames=tuple(dynamic) if dynamic else ())
program.set_top(top)
program.set_path(self)
compile_time += system_clock()
Expand All @@ -141,7 +142,7 @@ def read_flitter_program(self, static=None, dynamic=None):
except Exception as exc:
logger.opt(exception=exc).error("Error reading program: {}", self._path)
program = current_program
self._cache['flitter'] = program
self._cache[key] = program
return program

def read_csv_vector(self, row_number):
Expand Down
2 changes: 1 addition & 1 deletion src/flitter/engine/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ async def run(self):
now = system_clock()
simplify_time += now
compile_time = -now
run_program = top.compile()
run_program = top.compile(initial_lnames=tuple(names))
run_program.set_path(current_program.path)
run_program.set_top(top)
compile_time += system_clock()
Expand Down
28 changes: 18 additions & 10 deletions src/flitter/language/tree.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ cdef Expression sequence_pack(list expressions):


cdef class Expression:
def compile(self):
def compile(self, tuple initial_lnames=()):
cdef Program program = Program.__new__(Program)
self._compile(program, [])
program.initial_lnames = initial_lnames
self._compile(program, list(initial_lnames))
program.optimize()
program.link()
return program
Expand Down Expand Up @@ -110,12 +111,14 @@ cdef class Top(Expression):
if m:
program.append(m)
cdef str name
cdef int i
for i, name in enumerate(reversed(lnames)):
program.local_load(i)
program.store_global(name)
if lnames:
program.local_drop(len(lnames))
m = len(program.initial_lnames)
cdef int i, n=len(lnames)
if n > m:
for i in range(n-m):
name = lnames[n-1-i]
program.local_load(i)
program.store_global(name)
program.local_drop(n-m)

cdef Expression _simplify(self, Context context):
cdef list expressions = []
Expand Down Expand Up @@ -260,7 +263,11 @@ cdef class Name(Expression):
program.local_load(i)
break
else:
program.name(self.name)
if self.name in dynamic_builtins:
program.literal(dynamic_builtins[self.name])
else:
logger.warning("Name should have been removed by simplifier: {}", self.name)
program.literal(null_)

cdef Expression _simplify(self, Context context):
if self.name in context.names:
Expand Down Expand Up @@ -1275,7 +1282,8 @@ cdef class Function(Expression):
program.local_load(i)
break
else:
program.name(name)
logger.warning("Name should have been removed by simplifier: {}", name)
program.literal(null_)
function_lnames.append(name)
function_lnames.append(self.name)
cdef list parameters = []
Expand Down
2 changes: 1 addition & 1 deletion src/flitter/language/vm.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ cdef class Program:
cdef bint linked
cdef readonly object path
cdef readonly object top
cdef readonly tuple initial_lnames
cdef readonly VectorStack stack
cdef readonly VectorStack lnames
cdef int next_label
Expand All @@ -53,7 +54,6 @@ cdef class Program:
cpdef void local_push(self, int count)
cpdef void local_load(self, int offset)
cpdef void local_drop(self, int count)
cpdef void name(self, str name)
cpdef void lookup(self)
cpdef void lookup_literal(self, Vector value)
cpdef void range(self)
Expand Down
32 changes: 12 additions & 20 deletions src/flitter/language/vm.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ cdef enum OpCode:
Mod
Mul
MulAdd
Name
Ne
Neg
Next
Expand Down Expand Up @@ -144,7 +143,6 @@ cdef dict OpCodeNames = {
OpCode.Mod: 'Mod',
OpCode.Mul: 'Mul',
OpCode.MulAdd: 'MulAdd',
OpCode.Name: 'Name',
OpCode.Ne: 'Ne',
OpCode.Neg: 'Neg',
OpCode.Next: 'Next',
Expand Down Expand Up @@ -808,6 +806,7 @@ cdef inline execute_tag(VectorStack stack, str name):
cdef class Program:
def __cinit__(self):
self.instructions = []
self.initial_lnames = ()
self.linked = False
self.next_label = 1

Expand All @@ -825,6 +824,7 @@ cdef class Program:

def execute(self, Context context, list initial_stack=None, list lnames=None, bint record_stats=False):
"""This is a test-harness function. Do not use."""
assert self.initial_lnames == ()
if not self.linked:
self.link()
if context.lnames is None:
Expand Down Expand Up @@ -852,9 +852,18 @@ cdef class Program:
self.lnames = VectorStack.__new__(VectorStack)
context.lnames = self.lnames
context.path = self.path
cdef int i, n=PyTuple_GET_SIZE(self.initial_lnames)
cdef PyObject* objptr
for i in range(n):
objptr = PyDict_GetItem(context.names, <object>PyTuple_GET_ITEM(self.initial_lnames, i))
if objptr != NULL:
push(self.lnames, <Vector>objptr)
else:
push(self.lnames, null_)
push(self.stack, Vector(context.root))
self._execute(context, 0, record_stats)
context.root = pop(self.stack).objects[0]
drop(self.lnames, n)
assert (<VectorStack>self.stack).top == -1, "Bad stack"
assert (<VectorStack>self.lnames).top == -1, "Bad lnames"

Expand Down Expand Up @@ -958,9 +967,6 @@ cdef class Program:
cpdef void local_drop(self, int count):
self.instructions.append(InstructionInt(OpCode.LocalDrop, count))

cpdef void name(self, str name):
self.instructions.append(InstructionStr(OpCode.Name, name))

cpdef void lookup(self):
self.instructions.append(Instruction(OpCode.Lookup))

Expand Down Expand Up @@ -1070,15 +1076,14 @@ cdef class Program:
global CallOutCount, CallOutDuration
cdef VectorStack stack=context.stack, lnames=context.lnames
cdef int i, n, program_end=len(self.instructions)
cdef dict global_names=context.names, builtins=all_builtins, state=context.state._state
cdef dict global_names=context.names, state=context.state._state
cdef list loop_sources=[]
cdef LoopSource loop_source = None
cdef double duration

cdef list instructions=self.instructions
cdef Instruction instruction=None
cdef str filename
cdef object name
cdef tuple names, args, nodes
cdef Vector r1, r2, r3
cdef dict import_names, kwargs
Expand Down Expand Up @@ -1180,19 +1185,6 @@ cdef class Program:
push(lnames, r1.item(i))
r1 = None

elif instruction.code == OpCode.Name:
name = (<InstructionStr>instruction).value
objptr = PyDict_GetItem(global_names, name)
if objptr == NULL:
objptr = PyDict_GetItem(builtins, name)
if objptr != NULL:
push(stack, <Vector>objptr)
else:
push(stack, null_)
PySet_Add(context.errors, f"Unbound name '{<str>name}'")
name = None
objptr = NULL

elif instruction.code == OpCode.Lookup:
objptr = PyDict_GetItem(state, peek(stack))
if objptr != NULL:
Expand Down
31 changes: 12 additions & 19 deletions tests/test_vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,6 @@ def test_Mul(self):
stack = self.program.execute(self.context)
self.assertEqual(stack, [12])

def test_Name(self):
self.names['y'] = 12
self.program.name('x')
self.program.name('y')
stack = self.program.execute(self.context)
self.assertEqual(stack, [null, 12])

def test_Ne(self):
self.program.literal(3)
self.program.literal(4)
Expand Down Expand Up @@ -640,38 +633,38 @@ def setUp(self):

def test_no_args(self):
self.test_function.return_value = Vector(12)
self.program.name('test')
self.program.local_load(0)
self.program.call(0)
stack = self.program.execute(self.context)
stack = self.program.execute(self.context, lnames=[self.test_function])
self.assertEqual(stack, [12])
self.test_function.assert_called_once_with()

def test_one_arg(self):
self.test_function.return_value = Vector(12)
self.program.literal(1)
self.program.name('test')
self.program.local_load(0)
self.program.call(1)
stack = self.program.execute(self.context)
stack = self.program.execute(self.context, lnames=[self.test_function])
self.assertEqual(stack, [12])
self.test_function.assert_called_once_with(Vector(1))

def test_multiple_args(self):
self.test_function.return_value = Vector(12)
self.program.literal(1)
self.program.literal(2)
self.program.name('test')
self.program.local_load(0)
self.program.call(2)
stack = self.program.execute(self.context)
stack = self.program.execute(self.context, lnames=[self.test_function])
self.assertEqual(stack, [12])
self.test_function.assert_called_once_with(Vector(1), Vector(2))

def test_kwargs(self):
self.test_function.return_value = Vector(12)
self.program.literal(1)
self.program.literal(2)
self.program.name('test')
self.program.local_load(0)
self.program.call(0, ('x', 'y'))
stack = self.program.execute(self.context)
stack = self.program.execute(self.context, lnames=[self.test_function])
self.assertEqual(stack, [12])
self.test_function.assert_called_once_with(x=Vector(1), y=Vector(2))

Expand All @@ -680,9 +673,9 @@ def test_args_kwargs(self):
self.program.literal(1)
self.program.literal(2)
self.program.literal(3)
self.program.name('test')
self.program.local_load(0)
self.program.call(1, ('x', 'y'))
stack = self.program.execute(self.context)
stack = self.program.execute(self.context, lnames=[self.test_function])
self.assertEqual(stack, [12])
self.test_function.assert_called_once_with(Vector(1), x=Vector(2), y=Vector(3))

Expand All @@ -691,9 +684,9 @@ def test_context_func(self):
self.program.literal(1)
self.program.literal(2)
self.program.literal(3)
self.program.name('context')
self.program.local_load(0)
self.program.call(1, ('x', 'y'))
stack = self.program.execute(self.context)
stack = self.program.execute(self.context, lnames=[self.context_function])
self.assertEqual(stack, [12])
self.context_function.assert_called_once_with(self.context, Vector(1), x=Vector(2), y=Vector(3))

Expand Down

0 comments on commit 2ccca1e

Please sign in to comment.