#ifndef __LAMBDA_HPP__
#define __LAMBDA_HPP__

#include <string>
#include <iostream>
using namespace std;

class LambdaExpression {
 public:
	virtual ~LambdaExpression() {}
	virtual void print() const = 0;
};

class LambdaAbstraction : public LambdaExpression {
 public:
	LambdaAbstraction(string var, LambdaExpression* expression) 
		: _var(var), _expression(expression) {
	}

	~LambdaAbstraction() {
		delete _expression;
	}

	void print() const {
		cout << "(%" << _var << ". ";
		_expression->print();
		cout << ")";
	}
 private:
	string _var;
	LambdaExpression* _expression;	
};

class Application : public LambdaExpression {
 public:
	Application(LambdaExpression* op1, LambdaExpression* op2) 
		: _op1(op1), _op2(op2) {
	}
	
	~Application() {
		delete _op1;
		delete _op2;
	}

	void print() const {
		cout << "(";
		_op1->print();
		cout << " ";
		_op2->print();
		cout << ")";
	}

 private:
	LambdaExpression *_op1, *_op2;
};

class Plus : public LambdaExpression {
 public:
	Plus(LambdaExpression* op1, LambdaExpression* op2) 
		:_op1(op1), _op2(op2) {
	}

	~Plus() {
		delete _op1;
		delete _op2;
	}

	void print() const {
		_op1->print();
		cout << " + ";
		_op2->print();
	}

 private:
    LambdaExpression *_op1, *_op2;
};

class Variable : public LambdaExpression {
 public:
	Variable(string name) 
		: _name(name) {
	}

	void print() const {
		cout << _name;
	}

 private:
	string _name;
};

class Constant : public LambdaExpression {
  public:
	Constant(int value)
		: _value(value) {
	}

	void print() const {
		cout << _value;
	}
	
  private:
	int _value;
};

#endif
