require('should');

const parser = require('../../build/grammar/grammar');

const Assignment = require('../../build/classes/Assignment');
const Identifer = require('../../build/classes/Identifer');
const Primitive = require('../../build/classes/Primitive');
const Sum = require('../../build/classes/Sum');
const Product = require('../../build/classes/Product');
const Comparison = require('../../build/classes/Comparison');
const Disjunction = require('../../build/classes/Disjunction');
const Conjunction = require('../../build/classes/Conjunction');

const __types = require('../../build/constants/types');
const BOOLEAN = __types.BOOLEAN;
const INTEGER = __types.INTEGER;

const __operators = require('../../build/constants/operators');
const PLUS = __operators.PLUS;
const MINUS = __operators.MINUS;
const TIMES = __operators.TIMES;
const DIVIDED_BY = __operators.DIVIDED_BY;
const EQUAL = __operators.EQUAL;
const NOT_EQUAL = __operators.NOT_EQUAL;
const GREATER_THAN = __operators.GREATER_THAN;
const LESS_THAN = __operators.GREATER_THAN;
const GREATER_EQUAL_THAN = __operators.GREATER_EQUAL_THAN;
const LESS_EQUAL_THAN = __operators.GREATER_EQUAL_THAN;

const parseExpression = expr => parser.parse( expr, {
  startRule: [ 'Statement' ],
});

describe('Expression Parser', () => {
  it('should parse basic assignments', () => {
    const actual = parseExpression('var1 := true;');
    const expected = Assignment( Identifer(), Primitive(BOOLEAN) );

    actual.toString().should.be.exactly(expected.toString());
  });

  it('should parse primitives', () => {
    const actual = parseExpression('2;');
    const expected = Primitive(INTEGER);

    actual.toString().should.be.exactly(expected.toString());
  });

  it('should parse sums', () => {
    const actualPlus = parseExpression('2 + 3;');
    const expectedPlus = Sum( PLUS, Primitive(INTEGER), Primitive(INTEGER) );

    actualPlus.toString().should.be.exactly(expectedPlus.toString());

    const actualMinus = parseExpression('5 - 12846;');
    const expectedMinus = Sum( MINUS, Primitive(INTEGER), Primitive(INTEGER) );

    actualMinus.toString().should.be.exactly(expectedMinus.toString());
  });

  it('should parse products', () => {
    const actualTimes = parseExpression('2 * 3;');
    const expectedTimes = Product( TIMES, Primitive(INTEGER), Primitive(INTEGER) );

    actualTimes.toString().should.be.exactly(expectedTimes.toString());

    const actualMinus = parseExpression('12 / 10;');
    const expectedMinus = Product( DIVIDED_BY, Primitive(INTEGER), Primitive(INTEGER) );

    actualMinus.toString().should.be.exactly(expectedMinus.toString());
  });

  it('should parse comparisons', () => {
    var index; // eslint ignore
    const actual = [];
    const expected = [];

    actual.push( parseExpression('2 == 2;') );
    expected.push( Comparison( EQUAL, Primitive(INTEGER), Primitive(INTEGER) ) );

    actual.push( parseExpression('2 != 2;') );
    expected.push( Comparison( NOT_EQUAL, Primitive(INTEGER), Primitive(INTEGER) ) );

    actual.push( parseExpression('2 > 2;') );
    expected.push( Comparison( GREATER_THAN, Primitive(INTEGER), Primitive(INTEGER) ) );

    actual.push( parseExpression('2 < 2;') );
    expected.push( Comparison( LESS_THAN, Primitive(INTEGER), Primitive(INTEGER) ) );

    actual.push( parseExpression('2 >= 2;') );
    expected.push( Comparison( GREATER_EQUAL_THAN, Primitive(INTEGER), Primitive(INTEGER) ) );

    actual.push( parseExpression('2 <= 2;') );
    expected.push( Comparison( LESS_EQUAL_THAN, Primitive(INTEGER), Primitive(INTEGER) ) );

    for ( index = 0; index < expected.length; ++index ) {
      actual[index].toString().should.be.exactly(expected[index].toString());
    }
  });

  it('should parse disjunctions', () => {
    const actual = parseExpression('false || true;');
    const expected = Disjunction( Primitive(BOOLEAN), Primitive(BOOLEAN) );

    actual.toString().should.be.exactly(expected.toString());
  });

  it('should parse conjunctions', () => {
    const expected = parseExpression('true && false;');
    const actual = Conjunction( Primitive(BOOLEAN), Primitive(BOOLEAN) );

    actual.toString().should.be.exactly(expected.toString());
  });
});

@@ -667,16 +667,47 @@
 INTEGER;
+%0Aconst STRING = __types.STRING;
 %0A%0Aconst 
@@ -1573,17 +1573,29 @@
 rse 
-primitive
+expression assignment
 s', 
@@ -1638,17 +1638,37 @@
 ession('
-2
+var1 := true && false
 ;');%0A   
@@ -1685,16 +1685,286 @@
 ected = 
+Assignment(%0A      Identifer(),%0A      Conjunction( Primitive(BOOLEAN), Primitive(BOOLEAN) )%0A    );%0A%0A    actual.toString().should.be.exactly(expected.toString());%0A  %7D);%0A%0A  it('should parse primitives', () =%3E %7B%0A    parseExpression('2;').toString()%0A      .should.be.exactly(
 Primitiv
@@ -1973,29 +1973,58 @@
 INTEGER)
+.toString())
 ;%0A
-%0A
     
-actual
+parseExpression('true;')
 .toStrin
@@ -2018,32 +2018,39 @@
 ue;').toString()
+%0A      
 .should.be.exact
@@ -2048,32 +2048,139 @@
 .be.exactly(
-expected
+Primitive(BOOLEAN).toString());%0A    parseExpression('%22str%22;').toString()%0A      .should.be.exactly(Primitive(STRING)
 .toString())
@@ -2629,32 +2629,323 @@
 ring());%0A  %7D);%0A%0A
+  it('should parse nested sums', () =%3E %7B%0A    const actual = parseExpression('2 + 3 - 4;');%0A    const expected = Sum(%0A      PLUS,%0A      Sum( MINUS, Primitive(INTEGER), Primitive(INTEGER) ),%0A      Primitive(INTEGER)%0A    );%0A%0A    actual.toString().should.be.exactly(expected.toString());%0A  %7D);%0A%0A
   it('should par

add nestet expression test