# 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 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
# class LLVMPointerValue(RValue):
#     """An RValue corresponding to an llvm pointer type punned to the machine
#     word type. The pointer value is divided by the machine word length in bytes
#     to yield a value which is word-oriented.
# 
#     It is a Bad Idea (TM) to pass this AST node a pointer which is not
#     word-aligned. There is no runtime check for alignment. So, "caveat caller".
# 
#     This class is not marked as an AST node and so cannot be constructed via the
#     make_node() function. This reflects the fact that this is an "internal" node
#     not intended for construction by the semantics.
# 
#     """
#     @needs_builder
#     def emit(self, context):
#         return llvm_ptr_to_address(context, self.value)


from llvmlite import ir
from .astnode import ast_node, needs_builder, ASTNode
from .context import create_aligned_global, if_else
from .expression import LLVMPointerValue
import rbc.exception as exc
from __future__ import print_function




def get_or_create_global(context, name):
    """Retrieve the LValue and llvm GlobalValue associated with an external
    variable with the specified name. If there is no defined external variable,
    a new uninitialised global variable is created which must be resolved at
    link time.

    """
    # Return the existing extern if present.
    if name in context.externals:
        return context.externals[name]

    # Create a new variable in the module and add it to the externals.
    value = create_aligned_global(context.module, context.word_type, name)
    value.modifiers = ['align {}'.format(context.bytes_per_word)]

    lvalue = LLVMPointerValue(value=value).dereference()
    context.externals[name] = lvalue
    return lvalue

# Statements
# ==========
#
# Statements, unlike rvalues or lvalues, do not return llvm Values when emitted.


# 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 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
# class LLVMPointerValue(RValue):
#     """An RValue corresponding to an llvm pointer type punned to the machine
#     word type. The pointer value is divided by the machine word length in bytes
#     to yield a value which is word-oriented.
# 
#     It is a Bad Idea (TM) to pass this AST node a pointer which is not
#     word-aligned. There is no runtime check for alignment. So, "caveat caller".
# 
#     This class is not marked as an AST node and so cannot be constructed via the
#     make_node() function. This reflects the fact that this is an "internal" node
#     not intended for construction by the semantics.
# 
#     """
#     @needs_builder
#     def emit(self, context):
#         return llvm_ptr_to_address(context, self.value)


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

from __future__ import print_function




def get_or_create_global(context, name):
    """Retrieve the LValue and llvm GlobalValue associated with an external
    variable with the specified name. If there is no defined external variable,
    a new uninitialised global variable is created which must be resolved at
    link time.

    """
    # Return the existing extern if present.
    if name in context.externals:
        return context.externals[name]

    # Create a new variable in the module and add it to the externals.
    value = create_aligned_global(context.module, context.word_type, name)
    value.modifiers = ['align {}'.format(context.bytes_per_word)]

    lvalue = LLVMPointerValue(value=value).dereference()
    context.externals[name] = lvalue
    return lvalue

# Statements
# ==========
#
# Statements, unlike rvalues or lvalues, do not return llvm Values when emitted.


@ast_node