# AST.py
# Stephanie Taylor
# Definitions for nodes of Abstract Syntax Tree
# For a language with dynamic typing, no side effects, and only one scope
# Note: this version if for Expressions only (no statements)

# Abstract syntax 
# 
# Statement = Assignment | Conditional | While | Pass
# Assignment = target (Identifier), source (Expression)
# Expression = BinaryExpression | Identifier | Value
# BinaryExpression = string op (+,-,*,/,<,>,==,!=,AND,OR), Expression left, Expression right
# Variable = string name
# Value = a literal integer or boolean

class Pass:
    def printTree( self, spaces ):
        print( spaces + "Pass" )
        
class Conditional:
    def __init__( self, condition, thenbranch, elsebranch ):
        self.condition = condition
        self.thenbranch = thenbranch
        self.elsebranch = elsebranch
        
    def printTree( self, spaces ):
        print( spaces + "Condition" )
        self.condition.printTree( spaces + "  " ) 
        self.thenbranch.printTree( spaces + "  " ) 
        self.elsebranch.printTree( spaces + "  " ) 

class Block:
    def __init__( self, statements ):
        self.statements = statements    
        
    def printTree( self, spaces ):
        print( spaces + "Block" )
        for s in self.statements:
            s.printTree( spaces + "  " )
        
class Assignment:
    def __init__( self, target, source ):
        self.target = target
        self.source = source
        
    def printTree( self, spaces ):
        print( spaces + "Assignment" )
        self.target.printTree( spaces + "  " )
        self.source.printTree( spaces + "  " )
        
class While:
    def __init__( self, test, body ):
        self.test = test
        self.body = body
        
    def printTree( self, spaces ):
        print( spaces + "While Loop " )
        self.test.printTree( spaces + "  " )
        self.body.printTree( spaces + "  " )

class ForLoop:
    # For = init (Assignment), test (Expression), update (Assignment), body (Statement)
    def __init__( self, initial, test, post, body ):
        self.initial = initial
        self.test = test
        self.post = post
        self.body = body
        
    def printTree( self, spaces ):
        print( spaces + "For Loop " )
        self.initial.printTree( spaces + "  " )
        self.test.printTree( spaces + "  " )
        self.post.printTree( spaces + "  " )
        self.body.printTree( spaces + "  " )
 
class BinaryExpression:
    def __init__( self, left, operator, right ):
        self.left = left
        self.operator = operator
        self.right = right
        
    def printTree( self, spaces ):
        print( spaces + "Binary Operation: " + self.operator )
        self.left.printTree( spaces + "  " )
        self.right.printTree( spaces + "  " )

class Variable:
    def __init__( self, name ):
        self.name = name
        
    def printTree( self, spaces ):
        print( spaces + "Id: " + self.name )
        
class Value:
    def __init__( self, value ):
        self.value = value # should be a boolean or integer
        
    def printTree( self, spaces ):
        if self.value is True or self.value is False:
            print( spaces + "Bool: " + str(self.value) )
        else:
            print( spaces + "Int: " + str(self.value) )

    def __str__( self ):
        return str(self.value)
                                        
