Skip to content

Commit

Permalink
[cocas] Make using str and Path consistent
Browse files Browse the repository at this point in the history
Also use use absolute paths and as_posix() in most places
  • Loading branch information
cjvth committed Feb 2, 2024
1 parent b7234a7 commit 6f3815c
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 66 deletions.
24 changes: 10 additions & 14 deletions cocas/assembler/assembler.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,18 @@
def assemble_module(input_stream: antlr4.InputStream,
target_instructions: TargetInstructionsInterface,
macros_library: ExpandMacrosVisitor,
filepath: Path,
debug_info_path: Optional[Path] = None) -> ObjectModule:
filepath: Path) -> ObjectModule:
"""
Convert lines of an assembler file to object code
:param input_stream: contents of file
:param target_instructions: information how to convert mnemonics to code segments
:param macros_library: standard macros of assembler
:param filepath: path of the file to use in error handling
:param debug_info_path: transformed path of the file to use in debug information
"""
macro_expanded_input_stream = process_macros(input_stream, macros_library, str(filepath))
r = build_ast(macro_expanded_input_stream, str(filepath))
return generate_object_module(r, target_instructions, debug_info_path)
macro_expanded_input_stream = process_macros(input_stream, macros_library, filepath)
r = build_ast(macro_expanded_input_stream, filepath)
return generate_object_module(r, target_instructions)


def get_debug_info_path(filepath: Path,
Expand Down Expand Up @@ -65,7 +63,7 @@ def assemble_files(target: str,
"""
_ = absolute_path
target_instructions = import_target(target)
macros_library = read_mlb(str(mlb_path(target)))
macros_library = read_mlb(mlb_path(target))
objects = []

for filepath in files:
Expand All @@ -74,21 +72,19 @@ def assemble_files(target: str,
data = codecs.decode(data, 'utf8', 'strict')
if not data.endswith('\n'):
data += '\n'
input_stream = antlr4.InputStream(data)
obj = assemble_module(input_stream, target_instructions, macros_library, filepath)

debug_info_path = get_debug_info_path(filepath, debug, relative_path, realpath)
input_stream = antlr4.InputStream(data)
obj = assemble_module(input_stream, target_instructions, macros_library, filepath, debug_info_path)
if debug_info_path:
fp = filepath.as_posix()
obj.source_file_path = filepath
fp = filepath.absolute().as_posix()
dip = debug_info_path.as_posix()
for i in chain(obj.asects, obj.rsects):
for j in i.code_locations.values():
if j.file == fp:
j.file = dip
else:
f = Path(j.file).absolute()
if realpath:
f = f.resolve()
j.file = f.relative_to(relative_path).as_posix()
j.file = get_debug_info_path(Path(j.file), debug, relative_path, realpath)
objects.append((filepath, obj))
return objects
10 changes: 6 additions & 4 deletions cocas/assembler/ast_builder.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from base64 import b64decode
from pathlib import Path

from antlr4 import CommonTokenStream, InputStream

Expand Down Expand Up @@ -252,16 +253,17 @@ def visitArguments(self, ctx: AsmParser.ArgumentsContext):
return [self.visitArgument(i) for i in ctx.children if isinstance(i, AsmParser.ArgumentContext)]


def build_ast(input_stream: InputStream, filepath: str):
def build_ast(input_stream: InputStream, filepath: Path):
str_path = filepath.absolute().as_posix()
lexer = AsmLexer(input_stream)
lexer.removeErrorListeners()
lexer.addErrorListener(AntlrErrorListener(CdmExceptionTag.ASM, filepath))
lexer.addErrorListener(AntlrErrorListener(CdmExceptionTag.ASM, str_path))
token_stream = CommonTokenStream(lexer)
token_stream.fill()
parser = AsmParser(token_stream)
parser.removeErrorListeners()
parser.addErrorListener(AntlrErrorListener(CdmExceptionTag.ASM, filepath))
parser.addErrorListener(AntlrErrorListener(CdmExceptionTag.ASM, str_path))
cst = parser.program()
bav = BuildAstVisitor(filepath)
bav = BuildAstVisitor(str_path)
result = bav.visit(cst)
return result
24 changes: 12 additions & 12 deletions cocas/assembler/macro_processor.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import re
from base64 import b64encode
from dataclasses import dataclass
from pathlib import Path

from antlr4 import CommonTokenStream, FileStream, InputStream
from antlr4.TokenStreamRewriter import TokenStreamRewriter
Expand Down Expand Up @@ -286,30 +287,29 @@ def visitMacro_piece(self, ctx: MacroParser.Macro_pieceContext):
return MacroNonce()


# filepath should be absolute
def read_mlb(filepath):
input_stream = FileStream(filepath)
def read_mlb(filepath: Path):
str_path = filepath.absolute().as_posix()
input_stream = FileStream(str_path)
lexer = MacroLexer(input_stream)
token_stream = CommonTokenStream(lexer)
parser = MacroParser(token_stream)
cst = parser.mlb()
return ExpandMacrosVisitor(None, dict(), filepath).visit(cst)
return ExpandMacrosVisitor(None, dict(), str_path).visit(cst)


# filepath should be absolute
def process_macros(input_stream: InputStream, library_macros, filepath: str):
def process_macros(input_stream: InputStream, library_macros, filepath: Path):
str_path = filepath.absolute().as_posix()
lexer = MacroLexer(input_stream)
lexer.removeErrorListeners()
# Adds a class that will be called somehow from antlr. And it will raise exceptions with MACRO and filepath
lexer.addErrorListener(AntlrErrorListener(CdmExceptionTag.MACRO, filepath))
lexer.addErrorListener(AntlrErrorListener(CdmExceptionTag.MACRO, str_path))
token_stream = CommonTokenStream(lexer)

parser = MacroParser(token_stream)
parser.removeErrorListeners()
parser.addErrorListener(AntlrErrorListener(CdmExceptionTag.MACRO, filepath))
parser.addErrorListener(AntlrErrorListener(CdmExceptionTag.MACRO, str_path))
cst = parser.program()
rewriter = TokenStreamRewriter(token_stream)
emv = ExpandMacrosVisitor(rewriter, library_macros, filepath)
emv = ExpandMacrosVisitor(rewriter, library_macros, str_path)
emv.visit(cst)
new_test = rewriter.getDefaultText()
return InputStream(new_test)
new_text = rewriter.getDefaultText()
return InputStream(new_text)
6 changes: 2 additions & 4 deletions cocas/assembler/object_generator.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from dataclasses import dataclass
from pathlib import Path
from typing import Type

from cocas.assembler.targets import IVaryingLengthSegment
Expand Down Expand Up @@ -84,7 +83,7 @@ def update_varying_length(sections: list[Section], known_labels: dict[str, int],
changed = True


def generate_object_module(pn: ProgramNode, target_instructions, debug_info_path: Path) -> ObjectModule:
def generate_object_module(pn: ProgramNode, target_instructions) -> ObjectModule:
templates = [Template(t, target_instructions) for t in pn.template_sections]
template_fields = dict([(t.name, t.labels) for t in templates])

Expand All @@ -98,6 +97,5 @@ def generate_object_module(pn: ProgramNode, target_instructions, debug_info_path
update_varying_length([rsect], asects_labels, template_fields)

obj = ObjectModule([asect.to_object_section_record(asects_labels, template_fields) for asect in asects],
[rsect.to_object_section_record(asects_labels, template_fields) for rsect in rsects],
debug_info_path)
[rsect.to_object_section_record(asects_labels, template_fields) for rsect in rsects])
return obj
25 changes: 13 additions & 12 deletions cocas/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import argparse
import pathlib
from pathlib import Path
from typing import Union

import colorama
Expand All @@ -8,6 +8,7 @@
from cocas.error import CdmException, log_error
from cocas.linker import link, write_debug_export, write_image
from cocas.object_file import list_object_targets, read_object_files, write_object_file
from cocas.object_module import ObjectModule


def handle_os_error(e: OSError):
Expand All @@ -23,18 +24,18 @@ def main():
available_targets = list_assembler_targets() & list_object_targets()

parser = argparse.ArgumentParser('cocas')
parser.add_argument('sources', type=pathlib.Path, nargs='*', help='source files')
parser.add_argument('sources', type=Path, nargs='*', help='source files')
parser.add_argument('-t', '--target', type=str, default='cdm-16', help='target processor, CdM-16 is default')
parser.add_argument('-T', '--list-targets', action='count', help='list available targets and exit')
parser.add_argument('-c', '--compile', action='store_true', help='compile into object files without linking')
parser.add_argument('-m', '--merge', action='store_true', help='merge object files into one')
parser.add_argument('-o', '--output', type=str, help='specify output file name')
parser.add_argument('-o', '--output', type=Path, help='specify output file name')
debug_group = parser.add_argument_group('debug')
debug_group.add_argument('--debug', type=str, nargs='?', const=True, help='export debug information')
debug_group.add_argument('--debug', type=Path, nargs='?', const=True, help='export debug information')
debug_path_group = debug_group.add_mutually_exclusive_group()
debug_path_group.add_argument('--relative-path', type=pathlib.Path,
debug_path_group.add_argument('--relative-path', type=Path,
help='convert source files paths to relative in debug info and object files')
debug_path_group.add_argument('--absolute-path', type=pathlib.Path,
debug_path_group.add_argument('--absolute-path', type=Path,
help='convert all debug paths to absolute, concatenating with given path')
debug_group.add_argument('--realpath', action='store_true',
help='canonicalize paths by following symlinks and resolving . and ..')
Expand All @@ -55,23 +56,23 @@ def main():
print('Error: cannot use --compile and --merge options at same time')
return 2

objects = []
objects: list[tuple[Path, ObjectModule]] = []

realpath = bool(args.realpath)
if args.relative_path:
relative_path: Union[pathlib.Path, None] = args.relative_path.absolute()
relative_path: Union[Path, None] = args.relative_path.absolute()
if realpath:
relative_path = relative_path.resolve()
else:
relative_path = None
if args.absolute_path:
absolute_path: Union[pathlib.Path, None] = args.absolute_path.absolute()
absolute_path: Union[Path, None] = args.absolute_path.absolute()
if realpath:
absolute_path = absolute_path.resolve()
else:
absolute_path = None

filepath: pathlib.Path
filepath: Path
for filepath in args.sources:
try:
filetype = filepath.suffix
Expand Down Expand Up @@ -114,9 +115,9 @@ def main():
if args.debug:
if args.debug is True:
if args.output:
filename = pathlib.Path(args.output).with_suffix('.dbg.json')
filename = Path(args.output).with_suffix('.dbg.json')
else:
filename = 'out.dbg.json'
filename = Path('out.dbg.json')
else:
filename = args.debug
write_debug_export(filename, code_locations)
Expand Down
4 changes: 2 additions & 2 deletions cocas/object_file/object_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ def export_object(objs: list[ObjectModule], target: str, debug: bool) -> list[st
for obj in objs:
if len(objs) > 1:
result.append('\n')
if debug and obj.debug_info_path:
result.append(f'FILE {Path(obj.debug_info_path).as_posix()}\n')
if debug and obj.source_file_path:
result.append(f'FILE {Path(obj.source_file_path).as_posix()}\n')

for asect in obj.asects:
s = data_to_str(asect.data)
Expand Down
35 changes: 18 additions & 17 deletions cocas/object_file/object_import.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import bisect
import codecs
from pathlib import Path
from typing import List, Optional
from typing import List, Optional, Union

import antlr4
from antlr4 import CommonTokenStream, InputStream
Expand Down Expand Up @@ -224,24 +224,25 @@ def visitMinus(self, ctx: ObjectFileParser.MinusContext):
pass


def import_object(input_stream: InputStream, filepath: str,
def import_object(input_stream: InputStream, filepath: Path,
target: str) -> List[ObjectModule]:
str_path = filepath.absolute().as_posix()
lexer = ObjectFileLexer(input_stream)
lexer.removeErrorListeners()
lexer.addErrorListener(AntlrErrorListener(CdmExceptionTag.OBJ, filepath))
lexer.addErrorListener(AntlrErrorListener(CdmExceptionTag.OBJ, str_path))
token_stream = CommonTokenStream(lexer)
token_stream.fill()
parser = ObjectFileParser(token_stream)
parser.removeErrorListeners()
parser.addErrorListener(AntlrErrorListener(CdmExceptionTag.OBJ, filepath))
parser.addErrorListener(AntlrErrorListener(CdmExceptionTag.OBJ, str_path))
ctx = parser.object_file()
visitor = ImportObjectFileVisitor(filepath, target)
visitor = ImportObjectFileVisitor(str_path, target)
result = visitor.visit(ctx)
return result


def read_object_files(target: str,
files: list[Path],
files: list[Union[str, Path]],
debug: bool,
relative_path: Optional[Path],
absolute_path: Optional[Path],
Expand All @@ -257,40 +258,40 @@ def read_object_files(target: str,
_ = debug
objects = []
for filepath in files:
with filepath.open('rb') as file:
with open(filepath, 'rb') as file:
data = file.read()
data = codecs.decode(data, 'utf8', 'strict')
if not data.endswith('\n'):
data += '\n'

input_stream = antlr4.InputStream(data)
for obj in import_object(input_stream, str(filepath), target):
for obj in import_object(input_stream, Path(filepath), target):
if realpath:
dip = obj.debug_info_path
obj.debug_info_path = obj.debug_info_path.resolve()
dip = obj.source_file_path
obj.source_file_path = obj.source_file_path.resolve()
for i in obj.asects + obj.rsects:
for j in i.code_locations.values():
f = Path(j.file)
if f == dip:
j.file = obj.debug_info_path.as_posix()
j.file = obj.source_file_path.as_posix()
else:
j.file = Path(j.file).resolve().as_posix()
if relative_path:
dip = obj.debug_info_path
if obj.debug_info_path.is_absolute():
obj.debug_info_path = obj.debug_info_path.absolute().relative_to(relative_path)
dip = obj.source_file_path
if obj.source_file_path.is_absolute():
obj.source_file_path = obj.source_file_path.absolute().relative_to(relative_path)
for i in obj.asects + obj.rsects:
for j in i.code_locations.values():
f = Path(j.file)
if f == dip:
j.file = obj.debug_info_path.as_posix()
j.file = obj.source_file_path.as_posix()
else:
if f.is_absolute():
j.file = f.absolute().relative_to(relative_path).as_posix()
elif absolute_path:
obj.debug_info_path = absolute_path / obj.debug_info_path
obj.source_file_path = absolute_path / obj.source_file_path
if realpath:
obj.debug_info_path = obj.debug_info_path.resolve()
obj.source_file_path = obj.source_file_path.resolve()
for i in obj.asects + obj.rsects:
for j in i.code_locations.values():
f = absolute_path / Path(j.file)
Expand Down
2 changes: 1 addition & 1 deletion cocas/object_module/object_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ class ObjectSectionRecord:
class ObjectModule:
asects: list[ObjectSectionRecord]
rsects: list[ObjectSectionRecord]
debug_info_path: Union[Path, None]
source_file_path: Union[Path, None] = field(default=None)

0 comments on commit 6f3815c

Please sign in to comment.