# Path: rbc/codegen/astnode.py
# def ast_node(cls):
#     """Class decorator which registers the AST node in the _NODE_CLASSES map."""
#     _NODE_CLASSES[cls.__name__] = cls
#     return cls
# 
# def needs_builder(emit):
#     """A decorator for emit() methods which make use of the context's builder
#     attribute. If the builder attribute is None, an InternalCompilerError is
#     raised.
# 
#     """
#     @functools.wraps(emit)
#     def _wrapped_emit(self, context):
#         if context.builder is None:
#             raise exc.InternalCompilerError('AST node requires builder.')
#         return emit(self, context)
#     return _wrapped_emit
# 
# class ASTNode(object):
#     """An AST node with parameters directly accessible as attributes."""
#     def __init__(self, **kwargs):
#         # Set attributes on ourself directly from the keyword args.
#         for k, v in kwargs.items():
#             setattr(self, k, v)
# 
# Path: rbc/codegen/context.py
# def address_to_llvm_ptr(context, address_val, ptr_type):
#     """Cast a llvm Value representing a word into a pointer. Performs the
#     appropriate conversion from word-oriented addresses to llvm's
#     byte-oriented addresses. Requires builder to be not None.
# 
#     This method will arrange that
# 
#         address_to_llvm_ptr(llvm_ptr_to_address(ptr_val), ptr_type)
# 
#     is elided into a simple bitcast. This implies that ptr_val must be word
#     aligned. It's the responsibility of the code generator to make sure
#     that's the case.
# 
#     """
#     # If this address came from a pointer, just return the punned pointer.
#     if hasattr(address_val, 'b_ptr'):
#         return context.builder.bitcast(address_val.b_ptr, ptr_type)
# 
#     bpw_const = ir.Constant(context.word_type, context.bytes_per_word)
#     byte_address = context.builder.mul(address_val, bpw_const,
#                                        flags=['nuw', 'nsw'])
#     ptr_val = context.builder.inttoptr(byte_address, ptr_type)
# 
#     # HACK: we tag the value with a 'b_address' attribute so that
#     # llvm_ptr_to_address() can elide address to pointer followed by pointer
#     # to address conversion.
#     ptr_val.b_address = address_val
# 
#     return ptr_val
# 
# def llvm_ptr_to_address(context, ptr_val):
#     """Cast a llvm Value representing a byte-oriented pointer to a word
#     representing a word-oriented address. Requires builder to be not None.
# 
#     This method will arrange that
# 
#         llvm_ptr_to_address(address_to_llvm_ptr(address_val, ptr_type))
# 
#     is elided to address_val irrespective of ptr_type.
# 
#     """
#     # If this pointer came from an address, just return the original address
#     # value.
#     if hasattr(ptr_val, 'b_address'):
#         return ptr_val.b_address
# 
#     bpw_const = ir.Constant(context.word_type, context.bytes_per_word)
#     byte_address = context.builder.ptrtoint(ptr_val, context.word_type)
#     address_val = context.builder.udiv(byte_address, bpw_const,
#                                        flags=['exact'])
# 
#     # HACK: we tag the value with a 'b_ptr' attribute so that
#     # address_to_llvm_ptr() can elide pointer to address followed by address
#     # to pointer conversion.
#     address_val.b_ptr = ptr_val
# 
#     return address_val
# 
# def create_aligned_global(module, type_, name):
#     """Construct and return an ir.GlobalVariable instance which is guaranteed to
#     have a word-aligned pointer. The symbol name is automatically mangled to
#     avoid collision with C symbols.
# 
#     """
#     return _ModifiedGlobalVariable(module, type_, mangle_symbol_name(name))
# 
# def if_else(context, cond):
#     """Convenience wrapper around llvm.ir.Builder.if_else. Takes a single AST
#     node representing an expression which should be treated as a condition and
#     evaluates that node.
# 
#     """
#     cond_val = cond.emit(context)
#     zero = ir.Constant(context.word_type, 0)
#     bool_val = context.builder.icmp_signed('!=', cond_val, zero)
#     return context.builder.if_else(bool_val)


from llvmlite import ir
from .astnode import ast_node, needs_builder, ASTNode
from .context import (
    address_to_llvm_ptr, llvm_ptr_to_address, create_aligned_global, if_else
)
import rbc.exception as exc
    str_ptr = create_aligned_global(
        context.module, str_type, context.module.get_unique_name(str_name))
    str_ptr.modifiers = ['align {}'.format(context.bytes_per_word)]

    # The string constant shouldn't be modified and merge it with any other
    # symbols with the same content. They're also local to the module.
    str_ptr.global_constant = True
    str_ptr.unnamed_addr = True
    str_ptr.linkage = 'private'

    # Initialise the variable with the terminated contents
    str_ptr.initializer = ir.Constant(str_type, str_contents)

    # Record the pointer and return
    context.string_constants[string_bytes] = (str_type, str_ptr)

    return str_ptr

# lvalues and rvalues
# ===================
#
# B divides values into two categories: lvalue and rvalue. The essential
# difference is that an lvalue represents the address in memory of some other
# value. Thus each lvalue has an associated rvalue (the value pointed to by the
# address) but each rvalue does not have an associated lvalue. If an rvalue
# *does* have some address associated with it the address may be obtained via
# the "&" or "reference" operator. This address is itself an rvalue. An rvalue
# may not be referenced. Both lvalues and rvalues may be "dereferenced" via the
# "*" operator to yield an lvalue.


# Path: rbc/codegen/astnode.py
# def ast_node(cls):
#     """Class decorator which registers the AST node in the _NODE_CLASSES map."""
#     _NODE_CLASSES[cls.__name__] = cls
#     return cls
# 
# def needs_builder(emit):
#     """A decorator for emit() methods which make use of the context's builder
#     attribute. If the builder attribute is None, an InternalCompilerError is
#     raised.
# 
#     """
#     @functools.wraps(emit)
#     def _wrapped_emit(self, context):
#         if context.builder is None:
#             raise exc.InternalCompilerError('AST node requires builder.')
#         return emit(self, context)
#     return _wrapped_emit
# 
# class ASTNode(object):
#     """An AST node with parameters directly accessible as attributes."""
#     def __init__(self, **kwargs):
#         # Set attributes on ourself directly from the keyword args.
#         for k, v in kwargs.items():
#             setattr(self, k, v)
# 
# Path: rbc/codegen/context.py
# def address_to_llvm_ptr(context, address_val, ptr_type):
#     """Cast a llvm Value representing a word into a pointer. Performs the
#     appropriate conversion from word-oriented addresses to llvm's
#     byte-oriented addresses. Requires builder to be not None.
# 
#     This method will arrange that
# 
#         address_to_llvm_ptr(llvm_ptr_to_address(ptr_val), ptr_type)
# 
#     is elided into a simple bitcast. This implies that ptr_val must be word
#     aligned. It's the responsibility of the code generator to make sure
#     that's the case.
# 
#     """
#     # If this address came from a pointer, just return the punned pointer.
#     if hasattr(address_val, 'b_ptr'):
#         return context.builder.bitcast(address_val.b_ptr, ptr_type)
# 
#     bpw_const = ir.Constant(context.word_type, context.bytes_per_word)
#     byte_address = context.builder.mul(address_val, bpw_const,
#                                        flags=['nuw', 'nsw'])
#     ptr_val = context.builder.inttoptr(byte_address, ptr_type)
# 
#     # HACK: we tag the value with a 'b_address' attribute so that
#     # llvm_ptr_to_address() can elide address to pointer followed by pointer
#     # to address conversion.
#     ptr_val.b_address = address_val
# 
#     return ptr_val
# 
# def llvm_ptr_to_address(context, ptr_val):
#     """Cast a llvm Value representing a byte-oriented pointer to a word
#     representing a word-oriented address. Requires builder to be not None.
# 
#     This method will arrange that
# 
#         llvm_ptr_to_address(address_to_llvm_ptr(address_val, ptr_type))
# 
#     is elided to address_val irrespective of ptr_type.
# 
#     """
#     # If this pointer came from an address, just return the original address
#     # value.
#     if hasattr(ptr_val, 'b_address'):
#         return ptr_val.b_address
# 
#     bpw_const = ir.Constant(context.word_type, context.bytes_per_word)
#     byte_address = context.builder.ptrtoint(ptr_val, context.word_type)
#     address_val = context.builder.udiv(byte_address, bpw_const,
#                                        flags=['exact'])
# 
#     # HACK: we tag the value with a 'b_ptr' attribute so that
#     # address_to_llvm_ptr() can elide pointer to address followed by address
#     # to pointer conversion.
#     address_val.b_ptr = ptr_val
# 
#     return address_val
# 
# def create_aligned_global(module, type_, name):
#     """Construct and return an ir.GlobalVariable instance which is guaranteed to
#     have a word-aligned pointer. The symbol name is automatically mangled to
#     avoid collision with C symbols.
# 
#     """
#     return _ModifiedGlobalVariable(module, type_, mangle_symbol_name(name))
# 
# def if_else(context, cond):
#     """Convenience wrapper around llvm.ir.Builder.if_else. Takes a single AST
#     node representing an expression which should be treated as a condition and
#     evaluates that node.
# 
#     """
#     cond_val = cond.emit(context)
#     zero = ir.Constant(context.word_type, 0)
#     bool_val = context.builder.icmp_signed('!=', cond_val, zero)
#     return context.builder.if_else(bool_val)


# Path: rbc/codegen/expression.py
from llvmlite import ir
from .astnode import ast_node, needs_builder, ASTNode
from .context import (
    address_to_llvm_ptr, llvm_ptr_to_address, create_aligned_global, if_else
)
import rbc.exception as exc

    str_ptr = create_aligned_global(
        context.module, str_type, context.module.get_unique_name(str_name))
    str_ptr.modifiers = ['align {}'.format(context.bytes_per_word)]

    # The string constant shouldn't be modified and merge it with any other
    # symbols with the same content. They're also local to the module.
    str_ptr.global_constant = True
    str_ptr.unnamed_addr = True
    str_ptr.linkage = 'private'

    # Initialise the variable with the terminated contents
    str_ptr.initializer = ir.Constant(str_type, str_contents)

    # Record the pointer and return
    context.string_constants[string_bytes] = (str_type, str_ptr)

    return str_ptr

# lvalues and rvalues
# ===================
#
# B divides values into two categories: lvalue and rvalue. The essential
# difference is that an lvalue represents the address in memory of some other
# value. Thus each lvalue has an associated rvalue (the value pointed to by the
# address) but each rvalue does not have an associated lvalue. If an rvalue
# *does* have some address associated with it the address may be obtained via
# the "&" or "reference" operator. This address is itself an rvalue. An rvalue
# may not be referenced. Both lvalues and rvalues may be "dereferenced" via the
# "*" operator to yield an lvalue.


class RValue(ASTNode):