text: #ifndef AST_H
  #define AST_H
  
  /* INCLUDES */
  #include "llvm/ADT/APFloat.h"
  #include "llvm/ADT/STLExtras.h"
  #include "llvm/IR/BasicBlock.h"
  #include "llvm/IR/Constants.h"
  #include "llvm/IR/DerivedTypes.h"
  #include "llvm/IR/Function.h"
  #include "llvm/IR/IRBuilder.h"
  #include "llvm/IR/Instructions.h"
  #include "llvm/IR/LLVMContext.h"
  #include "llvm/IR/Module.h"
  #include "llvm/IR/Type.h"
  #include "llvm/IR/Verifier.h"
  #include <memory>
  #include <string>
  #include <vector>
  
  /* EXTERNS */
  extern std::unique_ptr <llvm::LLVMContext> TheContext;      // TheContext holds core LLVM data structures, like types and constant value tables. 
  extern std::unique_ptr <llvm::IRBuilder <> > Builder; // Helper object which makes it easy to generate LLVM instructions. 
  extern std::unique_ptr <llvm::Module> TheModule; // TheModule contains functions and global variabels. 
  extern std::map<std::string, llvm::Value *> NamedValues;  // Symbol tables for references (e.x. function parameters)
  //extern std::map <std::string, std::unique_ptr <PrototypeAST>> FunctionProtos;
  
  class BaseExprAST {
      public: 
          virtual ~BaseExprAST () {}
          virtual llvm::Value *codegen() = 0;
  };
  
  // NumberExprAST: Subclass of BaseExprAST used for numeric literals. 
  class NumberExprAST : public BaseExprAST {
      double Val;
  
      public: 
          NumberExprAST ( double Val ) : Val ( Val ) {}
          virtual llvm::Value *codegen();
  };
  
  // VariableExprAST : Subclass of BaseExprAST used for referencing a variable. 
  class VariableExprAST : public BaseExprAST {
      std::string Name;
  
      public:
          VariableExprAST ( const std::string &Name ) : Name ( Name ) {}
          virtual llvm::Value *codegen();
  };
  
  // BinaryExprAST : Subclass of BaseExprAST used for holding the left hand expression, operator, and right hand expression.
  class BinaryExprAST : public BaseExprAST {
      char Op;
      std::unique_ptr <BaseExprAST> LHS, RHS;
  
      public:
          BinaryExprAST ( char op, std::unique_ptr <BaseExprAST> LHS, std::unique_ptr <BaseExprAST> RHS )
              : Op ( op ), LHS ( std::move(LHS) ), RHS ( std::move(RHS) ) {}
  
          virtual llvm::Value *codegen();
  };
  
  // CallExprAST : Subclass of BaseExprAST used for capturing function calls. Keeps track of function name, and its respective arguments. 
  class CallExprAST : public BaseExprAST {
      std::string Callee;
      std::vector <std::unique_ptr <BaseExprAST>> Args;
  
      public:
          CallExprAST (const std::string &Callee, std::vector <std::unique_ptr <BaseExprAST>> Args) : Callee ( Callee ), Args ( std::move(Args) ) {}
          virtual llvm::Value *codegen();
  };
  
  // AST for If/then/else expressions
  class IfExprAST : public BaseExprAST {
      std::unique_ptr <BaseExprAST> Cond, Then, Else;
  
      public: 
      IfExprAST ( std::unique_ptr <BaseExprAST> Cond, std::unique_ptr <BaseExprAST> Then, std::unique_ptr <BaseExprAST> Else  )
          : Cond ( std::move(Cond) ), Then ( std::move(Then) ), Else (std::move(Else) ) {}
      
      virtual llvm::Value *codegen();
  };
  
  // AST for For loops
  class ForExprAST : public BaseExprAST {
      std::string VarName;
      std::unique_ptr <BaseExprAST> Start, End, Step, Body;
  
      public:
          ForExprAST ( std::string VarName, std::unique_ptr <BaseExprAST> Start, std::unique_ptr <BaseExprAST> End,
                 std::unique_ptr <BaseExprAST> Step, std::unique_ptr <BaseExprAST> Body )
              : VarName ( VarName ), Start ( std::move(Start) ), End ( std::move(End) ), Step ( std::move(Step) ), Body ( std::move(Body) ) {}
          
      virtual llvm::Value *codegen();
  };
  
  class UnaryExprAST : public BaseExprAST {
      char Opcode;
      std::unique_ptr <BaseExprAST> Operand;
  
      public:
          UnaryExprAST ( char Opcode, std::unique_ptr <BaseExprAST> Operand ) : Opcode ( Opcode ), Operand ( std::move(Operand) ) {}
  
      virtual llvm::Value *codegen();
  };
  
  class PrototypeAST {
      std::string Name;
      std::vector <std::string> Args;
      bool IsOperator;
      unsigned Precedence;
  
      public:
          PrototypeAST (const std::string &Name, std::vector <std::string> Args, bool IsOperator = false, unsigned Prec = 0)
              : Name( Name ), Args ( std::move(Args) ), IsOperator ( IsOperator ), Precedence ( Prec ) {}
  
          const std::string &getName () const { return Name; }
          llvm::Function *codegen();
  
          bool isUnaryOp () const {
              return IsOperator && Args.size() == 1;
          }
  
          bool isBinaryOp () const {
              return IsOperator && Args.size() == 2;
          }
  
          char getOperatorName () const {
              assert ( isUnaryOp() || isBinaryOp() );
              return Name[Name.size() - 1];
          }
  
          unsigned getBinaryPrecedence() const {
              return Precedence;
          }
  };
  
  class FunctionAST {
      std::unique_ptr <PrototypeAST> Proto;
      std::unique_ptr <BaseExprAST> Body;
  
      public:
          FunctionAST (std::unique_ptr <PrototypeAST> Proto, std::unique_ptr <BaseExprAST> Body) : Proto (std::move(Proto)), Body (std::move(Body)) {}
  
          llvm::Function *codegen();
  };
  
  #endif  /* AST_H */
  