Skip to content

Commit

Permalink
Change some custom nodes to be regular AstNodes
Browse files Browse the repository at this point in the history
In particular, the entire jeff65.gold.storage module is gone, along with
jeff65.gold.passes.asm.AsmRun. As an additional advantage, some compiler
passes which were previously imperative are now pattern-based.

(This was rescued from PR #37 asm-blocks, where it was mixed in with a
bunch of other changes.)
  • Loading branch information
jdpage committed Aug 9, 2018
1 parent 26950d5 commit 1434ce5
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 139 deletions.
81 changes: 44 additions & 37 deletions jeff65/gold/passes/asm.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.

import struct
from .. import storage
from ... import ast, pattern
from ...pattern import Predicate as P

Expand All @@ -25,77 +24,85 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)


class AsmRun:
def __init__(self, data):
self.data = data

def __repr__(self):
return "<asm {}>".format(self.data)
def asmrun(fmt, *args):
return ast.AstNode('asmrun', attrs={
'bin': struct.pack(fmt, *args)
})


@pattern.transform(pattern.Order.Any)
class AssembleWithRelocations:
transform_attrs = False

@pattern.match(
ast.AstNode('lda', attrs={
'storage': storage.ImmediateStorage(
P('value'), P.require(1, AssemblyError)),
}))
ast.AstNode('lda', children=[
ast.AstNode('immediate_storage', attrs={
'value': P('value'),
'width': P.require(1, AssemblyError),
})
]))
def lda_imm(self, value):
return AsmRun(struct.pack('<BB', 0xa9, value))
return asmrun('<BB', 0xa9, value)

@pattern.match(
ast.AstNode('sta', attrs={
'storage': storage.AbsoluteStorage(
P('address'), P.require(1, AssemblyError)),
}))
ast.AstNode('sta', children=[
ast.AstNode('absolute_storage', attrs={
'address': P('address'),
'width': P.require(1, AssemblyError),
})
]))
def sta_abs(self, address):
return AsmRun(struct.pack('<BH', 0x8d, address))
return asmrun('<BH', 0x8d, address)

@pattern.match(
ast.AstNode('jmp', attrs={
'storage': storage.AbsoluteStorage(P('address'), P.any()),
}))
ast.AstNode('jmp', children=[
ast.AstNode('absolute_storage', attrs={
'address': P('address'),
})
]))
def jmp(self, address):
return AsmRun(struct.pack('<BH', 0x4c, address))
return asmrun('<BH', 0x4c, address)

@pattern.match(ast.AstNode('rts'))
def rts(self):
return AsmRun(b'\x60')
return asmrun('<B', 0x60)


@pattern.transform(pattern.Order.Any)
class FlattenSymbol:
transform_attrs = False

class FlattenSymbol(ast.TranslationPass):
def exit_fun(self, node):
return ast.AstNode('fun_symbol', span=node.span, attrs={
'name': node.attrs['name'],
'type': node.attrs['type'],
'text': b"".join(c.data for c in node.children)
@pattern.match(
ast.AstNode('fun', attrs={
'name': P('name'),
'type': P('ty'),
}, children=[
P.zero_or_more_nodes('asmruns', allow='asmrun')
]))
def fun(self, name, ty, asmruns):
return ast.AstNode('fun_symbol', attrs={
'name': name,
'type': ty,
'text': b"".join(r.attrs['bin'] for r in asmruns)
})


def lda(arg, span):
assert type(arg) is storage.ImmediateStorage
return ast.AstNode('lda', span=span, attrs={
'storage': arg,
'size': 2,
})
}, children=[arg])


def sta(arg, span):
assert type(arg) is storage.AbsoluteStorage
return ast.AstNode('sta', span=span, attrs={
'storage': arg,
'size': 3,
})
}, children=[arg])


def jmp(arg, span):
assert type(arg) is storage.AbsoluteStorage
return ast.AstNode('jmp', span=span, attrs={
'storage': arg,
'size': 3,
})
}, children=[arg])


def rts(span):
Expand Down
4 changes: 2 additions & 2 deletions jeff65/gold/passes/lower.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ class LowerAssignment(ast.TranslationPass):
def exit_set(self, node):
lhs = node.children[0]
rhs = node.children[1]
assert node.attrs['type'].width == lhs.width
assert node.attrs['type'].width == rhs.width
assert node.attrs['type'].width == lhs.attrs['width']
assert node.attrs['type'].width == rhs.attrs['width']

return [
asm.lda(rhs, node.span),
Expand Down
11 changes: 8 additions & 3 deletions jeff65/gold/passes/resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

from . import binding
from .. import mem
from ..storage import AbsoluteStorage, ImmediateStorage
from ... import ast, pattern
from ...pattern import Predicate as P

Expand All @@ -34,14 +33,20 @@ class ResolveStorage:
})
]))
def deref_to_absolute(self, ty, address):
return AbsoluteStorage(address, ty.width)
return ast.AstNode('absolute_storage', attrs={
'address': address,
'width': ty.width
})

@pattern.match(
ast.AstNode('numeric', attrs={
'value': P.lt(256, 'value', require=True),
}))
def numeric_to_immediate(self, value):
return ImmediateStorage(value, 1)
return ast.AstNode('immediate_storage', attrs={
'value': value,
'width': 1,
})


class ResolveUnits(binding.ScopedPass):
Expand Down
53 changes: 0 additions & 53 deletions jeff65/gold/storage.py

This file was deleted.

95 changes: 51 additions & 44 deletions tests/test_pass_assemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
assert_raises)
from jeff65 import ast
from jeff65.blum import types
from jeff65.gold import storage
from jeff65.gold.passes import asm

sys.stderr = sys.stdout
Expand All @@ -16,7 +15,7 @@ def assemble(node):
assert_equal(1, len(result))
# check that the previous AST wasn't mutated
assert_equal(backup, node.pretty())
return result[0]
return result[0].attrs['bin']


def flatten(unit):
Expand All @@ -28,63 +27,71 @@ def flatten(unit):


def test_assemble_rts():
a = asm.rts(None)
assert_equal('rts', a.t)
assert_equal(1, a.attrs['size'])
b = assemble(a)
assert_equal(bytes([0x60]), b.data)
assert_equal(b'\x60', assemble(asm.rts(None)))


def test_assemble_jmp_abs():
a = asm.jmp(storage.AbsoluteStorage(0xbeef, 0), None)
assert_equal('jmp', a.t)
assert_equal(3, a.attrs['size'])
b = assemble(a)
assert_equal(bytes([0x4c, 0xef, 0xbe]), b.data)
assert_equal(b'\x4c\xef\xbe', assemble(
asm.jmp(ast.AstNode('absolute_storage', attrs={
'address': 0xbeef,
'width': 0,
}), None)
))


def test_assemble_lda_imm():
a = asm.lda(storage.ImmediateStorage(0x42, 1), None)
assert_equal('lda', a.t)
assert_equal(2, a.attrs['size'])
b = assemble(a)
assert_equal(bytes([0xa9, 0x42]), b.data)
assert_equal(b'\xa9\x42', assemble(
asm.lda(ast.AstNode('immediate_storage', attrs={
'value': 0x42,
'width': 1,
}), None)
))


def test_assemble_lda_imm_too_wide():
a = asm.lda(storage.ImmediateStorage(0xcafe, 2), None)
assert_raises(asm.AssemblyError, assemble, a)
assert_raises(
asm.AssemblyError, assemble,
asm.lda(ast.AstNode('immediate_storage', attrs={
'value': 0xcafe,
'width': 2,
}), None)
)


def test_assemble_sta_abs():
a = asm.sta(storage.AbsoluteStorage(0xbeef, 1), None)
assert_equal('sta', a.t)
assert_equal(3, a.attrs['size'])
b = assemble(a)
assert_equal(bytes([0x8d, 0xef, 0xbe]), b.data)
assert_equal(b'\x8d\xef\xbe', assemble(
asm.sta(ast.AstNode('absolute_storage', attrs={
'address': 0xbeef,
'width': 1,
}), None)
))


def test_assemble_sta_abs_too_wide():
a = asm.sta(storage.AbsoluteStorage(0xbeef, 2), None)
assert_raises(asm.AssemblyError, assemble, a)
assert_raises(
asm.AssemblyError, assemble,
asm.sta(ast.AstNode('absolute_storage', attrs={
'address': 0xbeef,
'width': 2,
}), None)
)


def test_flatten_symbol():
a = ast.AstNode('unit', attrs={
'known_names': {},
}, children=[
ast.AstNode('fun', attrs={
'name': 'meaning-of-life',
'type': types.FunctionType(types.u8),
}, children=[
asm.AsmRun(bytes([0xa9, 0x42])),
asm.AsmRun(bytes([0x60])),
])
])
b = flatten(a)
assert_equal(1, len(b.children))
sym = b.children[0]
assert_equal(0, len(sym.children))
assert_equal('meaning-of-life', sym.attrs['name'])
assert_equal(types.FunctionType(types.u8), sym.attrs['type'])
assert_equal(bytes([0xa9, 0x42, 0x60]), sym.attrs['text'])
assert_equal(
ast.AstNode('unit', children=[
ast.AstNode('fun_symbol', attrs={
'name': 'meaning-of-life',
'type': types.FunctionType(types.u8),
'text': b'\xa9\x42\x60',
})
]), flatten(ast.AstNode('unit', children=[
ast.AstNode('fun', attrs={
'name': 'meaning-of-life',
'type': types.FunctionType(types.u8),
}, children=[
ast.AstNode('asmrun', attrs={'bin': b'\xa9\x42'}),
ast.AstNode('asmrun', attrs={'bin': b'\x60'}),
])
]))
)

0 comments on commit 1434ce5

Please sign in to comment.