"""Provides data structures that represent parsed Modelverse bytecode graphs."""

class Instruction(object):
    """Represents a Modelverse bytecode instruction."""
    def __init__(self):
        self.next_instruction = None
        self.debug_information = None

class VariableNode(object):
    """Represents a variable node, which has an identifier and an optional name."""
    def __init__(self, node_id, name):
        self.node_id = node_id
        self.name = name

class SelectInstruction(Instruction):
    """Represents an 'if/else' instruction."""
    def __init__(self, condition, if_clause, else_clause):
        Instruction.__init__(self)
        self.condition = condition
        self.if_clause = if_clause
        self.else_clause = else_clause

    constructor_parameters = (
        ('cond', Instruction),
        ('then', Instruction),
        ('else', Instruction))

class WhileInstruction(Instruction):
    """Represents a 'while' instruction."""
    def __init__(self, condition, body):
        Instruction.__init__(self)
        self.condition = condition
        self.body = body

    constructor_parameters = (
        ('cond', Instruction),
        ('body', Instruction))

class BreakInstruction(Instruction):
    """Represents a 'break' instruction."""
    def __init__(self, loop):
        Instruction.__init__(self)
        self.loop = loop

    constructor_parameters = (('while', WhileInstruction),)

class ContinueInstruction(Instruction):
    """Represents a 'continue' instruction."""
    def __init__(self, loop):
        Instruction.__init__(self)
        self.loop = loop

    constructor_parameters = (('while', WhileInstruction),)

class ReturnInstruction(Instruction):
    """Represents a 'return' instruction, which terminates the current function
       and optionally returns a value."""
    def __init__(self, value):
        Instruction.__init__(self)
        self.value = value

    constructor_parameters = (('value', Instruction),)

class CallInstruction(Instruction):
    """Represents a 'call' instruction, which calls a function with an argument
       list, encoded as a list of name-instruction tuples."""
    def __init__(self, target, argument_list):
        Instruction.__init__(self)
        self.target = target
        self.argument_list = argument_list

class ConstantInstruction(Instruction):
    """Represents a 'constant' instruction, which produces a reference
       to a constant node."""
    def __init__(self, constant_id):
        Instruction.__init__(self)
        self.constant_id = constant_id

    constructor_parameters = (('node', int),)

class InputInstruction(Instruction):
    """Represents an 'input' instruction, which pops a node from the input
       queue."""
    def __init__(self):
        Instruction.__init__(self)

    constructor_parameters = ()

class OutputInstruction(Instruction):
    """Represents an 'output' instruction, which pushes a node onto the output
       queue."""
    def __init__(self, value):
        Instruction.__init__(self)
        self.value = value

    constructor_parameters = (('value', Instruction),)

class DeclareInstruction(Instruction):
    """Represents a 'declare' instruction, which declares a local variable."""
    def __init__(self, variable):
        Instruction.__init__(self)
        self.variable = variable

    constructor_parameters = (('var', VariableNode),)

class GlobalInstruction(Instruction):
    """Represents a 'global' instruction, which declares a global variable."""
    def __init__(self, variable):
        Instruction.__init__(self)
        self.variable = variable

    constructor_parameters = (('var', VariableNode),)

class ResolveInstruction(Instruction):
    """Represents a 'resolve' instruction, which resolves a variable node/name as
       either a local or global variable."""
    def __init__(self, variable):
        Instruction.__init__(self)
        self.variable = variable

    constructor_parameters = (('var', VariableNode),)

class AccessInstruction(Instruction):
    """Represents an 'access' instruction, which loads the node pointed to by a
       pointer node."""
    def __init__(self, pointer):
        Instruction.__init__(self)
        self.pointer = pointer

    constructor_parameters = (('var', Instruction),)

class AssignInstruction(Instruction):
    """Represents an 'assign' instruction, which sets the node pointed to by a
       pointer node to the given node."""
    def __init__(self, pointer, value):
        Instruction.__init__(self)
        self.pointer = pointer
        self.value = value

    constructor_parameters = (
        ('var', Instruction),
        ('value', Instruction))

INSTRUCTION_TYPE_MAPPING = {
    'if' : SelectInstruction,
    'while' : WhileInstruction,
    'return' : ReturnInstruction,
    'constant' : ConstantInstruction,
    'resolve' : ResolveInstruction,
    'declare' : DeclareInstruction,
    'global' : GlobalInstruction,
    'assign' : AssignInstruction,
    'access' : AccessInstruction,
    'output' : OutputInstruction,
    'input' : InputInstruction,
    'call' : CallInstruction,
    'break' : BreakInstruction,
    'continue' : ContinueInstruction
}
"""Maps instruction names to types."""
