Source code for pepper.abstract_symbol_tree

# This file is a part of the Pepper project, https://github.com/devosoft/Pepper
# (C) Michigan State University, under the MIT License
# See LICENSE.txt for more information

"""
This is the abstract symbol tree for PEPPr.

The parser will build the actual tree, so this is really more of a library of nodes that may
be used within the tree.
"""
import pepper.symbol_table as symtable
import os

from pathlib import Path


[docs]class Node(): def __init__(self, name="Node", children=None): self.name = name if children: self.children = children else: self.children = [] def __str__(self): lines = [f"Node: {self.name}"] for child in self.children: lines.append(f"\t{str(child)}") return "\n".join(lines)
[docs] def preprocess(self, lines): raise NotImplementedError()
[docs]class LinesNode(Node): def __init__(self, children=None): if children is not None: # sometimes whitespace is none, oops children = [child for child in children if child is not None] super(LinesNode, self).__init__("Statements", children)
[docs] def preprocess(self, lines=None): if lines: for child in self.children: child.preprocess(lines) else: return "".join([r.preprocess() for r in self.children])
[docs]class PreprocessorDirectiveNode(Node): def __init__(self, children): super(PreprocessorDirectiveNode, self).__init__("PreprocessorDirective", children)
[docs]class PreprocessorIncludeNode(Node): def __init__(self, children, system_include=False): super(PreprocessorIncludeNode, self).__init__("PreprocessorInclude", children) self.system_include = system_include self.target = children[0][1:-1] def __str__(self): return f"{self.name}: {self.children[0]}"
[docs] def search_system_includes(filename): for system_path in symtable.SYSTEM_INCLUDE_PATHS: candidate = Path(f"{system_path}/{filename}") if candidate.exists() and candidate.is_file(): return candidate raise OSError(f"Could not find file {filename} in defined system include paths: " f"{symtable.SYSTEM_INCLUDE_PATHS}")
[docs] def preprocess(self, lines): "This will be a lie for a while. I'll have to fix it later." lines[-1] = lines[-1] + 'static_assert(false, "include node not properly implemented")' if self.system_include: found_path = PreprocessorIncludeNode.search_system_includes(self.target) symtable.FILE_STACK.append(open(found_path, 'r')) else: symtable.FILE_STACK.append(open(os.path.split(symtable.FILE_STACK[-1].name)[0] + '/' + self.target, 'r'))
[docs]class IdentifierNode(Node): def __init__(self, children, args=None, variadic=False): super(IdentifierNode, self).__init__("Identifier", children) self.args = args self.variadic = variadic def __str__(self): return f"{self.name}: {self.children}"
[docs] def preprocess(self, lines=None): expansion = self.children[0] if self.children[0] in symtable.TABLE.keys(): expansion = symtable.TABLE[self.children[0]].expand( [arg.preprocess() for arg in self.args] if self.args is not None else None) else: if self.args is not None: expansion = f'{self.children[0]}({",".join([arg.preprocess() for arg in self.args])})' # NOQA else: expansion = self.children[0] if lines: lines[-1] = lines[-1] + expansion else: return expansion
[docs]class PrimitiveNode(Node): def __init__(self, name, children): super(PrimitiveNode, self).__init__(name, children) def __str__(self): return f"{self.name}: {self.children[0]}"
[docs] def preprocess(self, lines=None): if lines: lines[-1] += self.children[0] else: return self.children[0]
[docs]class NewlineNode(PrimitiveNode): def __init__(self, children): super(NewlineNode, self).__init__("Newline", children) def __str__(self): return "NewlineNode"
[docs] def preprocess(self, lines): lines.append("")
[docs]class WhiteSpaceNode(PrimitiveNode): def __init__(self, children): super(WhiteSpaceNode, self).__init__("Whitespace", children)
[docs]class ASCIILiteralNode(PrimitiveNode): def __init__(self, children): super(ASCIILiteralNode, self).__init__('ASCIILit', children)
[docs]class StringLiteralNode(PrimitiveNode): def __init__(self, children): super(StringLiteralNode, self).__init__('StringLit', children)
[docs]class PreprocessingNumberNode(PrimitiveNode): def __init__(self, children): super(PreprocessingNumberNode, self).__init__("PreprocessingNumber", children)