def type_to_ehlit(typ: Type) -> ast.Node: res: Optional[ast.Node] = None if typ.kind in uint_types: res = ast.CompoundIdentifier( [ast.Identifier(0, '@uint' + str(typ.get_size() * 8))]) elif typ.kind in int_types: res = ast.CompoundIdentifier( [ast.Identifier(0, '@int' + str(typ.get_size() * 8))]) elif typ.kind in decimal_types: res = ast.CompoundIdentifier( [ast.Identifier(0, decimal_types[typ.kind])]) else: try: res = globals()['type_' + typ.kind.name](typ) except KeyError: logging.debug('c_compat: unimplemented: type_%s' % typ.kind.name) if res is None: return ast.CompoundIdentifier([ast.Identifier(0, '@any')]) elif not isinstance(res, ast.Symbol): return res if typ.is_const_qualified(): res.qualifiers = res.qualifiers | ast.Qualifier.CONST if typ.is_volatile_qualified(): res.qualifiers = res.qualifiers | ast.Qualifier.VOLATILE if typ.is_restrict_qualified(): res.qualifiers = res.qualifiers | ast.Qualifier.RESTRICT return res
def _macro_var_type(tokens: List[Token]) -> ast.Symbol: for tok in tokens: if tok.kind == TokenKind.LITERAL: if tok.spelling[0] == '"': return ast.CompoundIdentifier([ast.Identifier(0, '@str')]) if all(x in '0123456789' for x in tok.spelling): return ast.CompoundIdentifier([ast.Identifier(0, '@int32')]) if all(x in '0123456789.' for x in tok.spelling): return ast.CompoundIdentifier([ast.Identifier(0, '@float')]) return CAnyType.make_symbol()
def type_POINTER(typ: Type) -> ast.Node: subtype: Type = typ.get_pointee() builtin_type: Optional[ast.Symbol] = { TypeKind.CHAR_S: ast.CompoundIdentifier([ast.Identifier(0, '@str')]), TypeKind.SCHAR: ast.CompoundIdentifier([ast.Identifier(0, '@str')]), TypeKind.VOID: ast.CompoundIdentifier([ast.Identifier(0, '@any')]) }.get(subtype.kind) if builtin_type is not None: return builtin_type res = type_to_ehlit(subtype) if isinstance(res, ast.TemplatedIdentifier) and res.name == '@func': return res assert isinstance(res, ast.Symbol) return ast.Reference(res)
def type_RECORD(typ: Type) -> ast.Node: decl: Cursor = typ.get_declaration() # If the type do not have a name, it may not be referenced. In the case, we have to embed # the type definition in its usage. Otherwise, we reference it with its identifier. if decl.spelling == '': res: Optional[ast.Node] = cursor_to_ehlit(decl) if res is None: # The underlying type is not handled, so make this elaborated type unhandled too raise KeyError return res return ast.CompoundIdentifier([ast.Identifier(0, decl.spelling)])
def _macro_alias_value(tokens: List[Token]) -> Optional[ast.Symbol]: name: str = tokens[0].spelling tokens = tokens[2:] if tokens[1].spelling == '(' else tokens[1:] if tokens[0].kind == TokenKind.KEYWORD: typ: Optional[ast.Symbol] = _macro_alias_type(tokens) if type is not None: return typ elif len(tokens) == 1 or (len(tokens) == 2 and tokens[1].spelling == ')'): return ast.CompoundIdentifier([ast.Identifier(0, tokens[0].spelling)]) logging.debug('c_parser: failed to parse macro: {}'.format(name)) return None
def visit_function_arguments(self, node: ParseTreeNode, children: Tuple[ast.VariableDeclaration] ) -> Tuple[List[ast.VariableDeclaration], Optional[ast.Symbol]]: args: List[ast.VariableDeclaration] = [] variadic_type: Optional[ast.Symbol] = None for child in children[::2]: arg = child if isinstance(arg, ast.VariableDeclaration): args.append(arg) else: if arg == '...': variadic_type = ast.CompoundIdentifier([ast.Identifier(0, '@any')]) else: assert isinstance(arg, ast.Symbol) variadic_type = arg return args, variadic_type
def visit_destructor(self, node: ParseTreeNode, children: Tuple[str, ast.UnparsedContents] ) -> ast.Dtor: qualifiers: ast.Qualifier = ast.Qualifier.NONE i: int = 0 while isinstance(children[i], str): if children[i] == 'inline': qualifiers |= ast.Qualifier.INLINE elif children[i] == 'priv': qualifiers |= ast.Qualifier.PRIVATE elif children[i] == 'dtor': break i += 1 i += 1 body = None if len(children) > i: body = children[i] typ = ast.TemplatedIdentifier(node.position, '@func', [ast.FunctionType( ast.CompoundIdentifier([ast.Identifier(node.position, '@void')]), [] )]) assert(body is None or isinstance(body, ast.UnparsedContents)) return ast.Dtor(node.position, qualifiers, typ, body)
def visit_constructor(self, node: ParseTreeNode, children: Tuple[str, Tuple[List[ast.VariableDeclaration], Optional[ast.Symbol]], ast.UnparsedContents] ) -> ast.Ctor: qualifiers: ast.Qualifier = ast.Qualifier.NONE i: int = 0 while isinstance(children[i], str): if children[i] == 'inline': qualifiers |= ast.Qualifier.INLINE elif children[i] == 'priv': qualifiers |= ast.Qualifier.PRIVATE elif children[i] == 'ctor': break i += 1 i += 1 args: List[ast.VariableDeclaration] variadic_type: Optional[ast.Symbol] body = None if len(children) < i or isinstance(children[i], ast.UnparsedContents): args = [] variadic_type = None if len(children) > i: body = children[i] else: child_i = children[i] assert(isinstance(child_i, tuple)) args, variadic_type = child_i if len(children) > i + 1: body = children[i + 1] typ = ast.TemplatedIdentifier(node.position, '@func', [ast.FunctionType( ast.CompoundIdentifier([ast.Identifier(node.position, '@void')]), args, variadic_type is not None, variadic_type )]) assert(body is None or isinstance(body, ast.UnparsedContents)) return ast.Ctor(node.position, qualifiers, typ, body)
def visit_function_type(self, node: ParseTreeNode, children: Tuple[StrMatch, ast.Symbol, Tuple[ast.Symbol, ...]] ) -> ast.TemplatedIdentifier: args: List[ast.VariableDeclaration] = [] variadic: bool = False variadic_type: Optional[ast.Symbol] = ast.CompoundIdentifier([ast.Identifier(0, '@any')]) if len(children) > 2: i = 0 while i < len(children[2]): arg = children[2][i] if arg == '...': variadic = True elif len(children[2]) > i + 1 and children[2][i + 1] == '...': assert isinstance(arg, ast.Symbol) variadic_type = arg variadic = True else: args.append(ast.VariableDeclaration(arg, None)) i += 2 return ast.TemplatedIdentifier( node.position, '@func', [ast.FunctionType(children[1], args, variadic, variadic_type)] )
def type_TYPEDEF(typ: Type) -> ast.Node: return ast.CompoundIdentifier( [ast.Identifier(0, typ.get_declaration().spelling)])
def type_VOID(typ: Type) -> ast.Symbol: return ast.CompoundIdentifier([ast.Identifier(0, '@void')])
def make_symbol() -> ast.Symbol: return ast.CompoundIdentifier([ast.Identifier(0, '@c_any')])
def __init__(self, sym: ast.Identifier) -> None: super().__init__(0, ast.CompoundIdentifier([ast.Identifier(0, '@any')]), sym, ast.Qualifier.NONE) self.declaration_type = ast.DeclarationType.C
def visit_compound_identifier(self, node: ParseTreeNode, children: List[ast.Identifier] ) -> ast.CompoundIdentifier: return ast.CompoundIdentifier(children)