Skip to content
This repository has been archived by the owner on May 28, 2019. It is now read-only.

Commit

Permalink
Merge pull request #33 from cucumber/broken-boolean-logic
Browse files Browse the repository at this point in the history
Broken boolean logic branch is ready for merge I hope. see #32
  • Loading branch information
mattwynne committed Feb 22, 2013
2 parents 4218945 + 055d351 commit 8c7375d
Show file tree
Hide file tree
Showing 13 changed files with 250 additions and 8 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ mingw/
bison-2.7/
flex-2.5.37/
.project
*~
3 changes: 2 additions & 1 deletion c/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ typedef void* yyscan_t;
%token TOKEN_LPAREN
%token TOKEN_RPAREN

%left TOKEN_AND TOKEN_OR
%left TOKEN_OR
%left TOKEN_AND
%left UNOT

%type <node> expr
Expand Down
2 changes: 2 additions & 0 deletions java/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
*.iml
.idea
target
.classpath
.settings
3 changes: 2 additions & 1 deletion java/src/main/bison/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ import java.io.IOException;
%token TOKEN_LPAREN
%token TOKEN_RPAREN

%left TOKEN_AND TOKEN_OR
%left TOKEN_OR
%left TOKEN_AND
%left UNOT

%%
Expand Down
31 changes: 31 additions & 0 deletions java/src/main/java/bool/Renderer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package bool;

import java.util.List;

public class Renderer implements Visitor< String, List<String>> {

@Override
public String var(Var var, List<String> notused) {
return var.name;
}

@Override
public String and(And and, List<String> notused) {
return "(" + explicit(and.left) + " && " + explicit(and.right) + ")";
}

@Override
public String or(Or or, List<String> notused) {
return "(" + explicit(or.left) + " || " + explicit(or.right) + ")";
}

@Override
public String not(Not not, List<String> notused) {
return "!" + explicit(not.operand);
}

private String explicit (Expr expr) {
return expr.describeTo(this, null);
}

}
37 changes: 37 additions & 0 deletions java/src/test/java/bool/EvaluatorTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package bool;

import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.CoreMatchers.*;
import org.junit.Test;

import java.io.IOException;

import static java.util.Arrays.asList;
import static org.junit.Assert.assertTrue;



public class EvaluatorTest {
@Test
public void test_and_or_expression() throws IOException {
Parser parser = new Parser(new Lexer("a && b || c"));
Expr expr = parser.parseExpr();
assertTrue("a && b || c given a, b should be true",
expr.describeTo(new Evaluator(), asList("a", "b")));
assertTrue("a && b || c given a, c should be true",
expr.describeTo(new Evaluator(), asList("a", "c")));

}

@Test
public void test_or_and_expression() throws IOException {
Parser parser = new Parser(new Lexer("a || b && c"));
Expr expr = parser.parseExpr();
assertTrue("a || b && c given a, b should be true",
expr.describeTo(new Evaluator(), asList("a","b")));
assertTrue("a || b && c given a, c should be true",
expr.describeTo(new Evaluator(), asList("a","c")));
}


}
42 changes: 42 additions & 0 deletions java/src/test/java/bool/RendererTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package bool;

import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.CoreMatchers.*;
import org.junit.Test;

import java.io.IOException;

import static java.util.Arrays.asList;
import static org.junit.Assert.assertTrue;



public class RendererTest {
@Test
public void test_and_or_expression() throws IOException {
Parser parser = new Parser(new Lexer("a && b || c"));
Expr expr = parser.parseExpr();
assertThat("a && b || c should explicitly be ((a && b) || c)",
expr.describeTo(new Renderer(),null),
is ("((a && b) || c)"));

}

@Test
public void test_or_and_expression() throws IOException {
Parser parser = new Parser(new Lexer("a || b && c"));
Expr expr = parser.parseExpr();
assertThat("a || b && c should explicitly be (a || (b && c))",
expr.describeTo(new Renderer(),null),
is ("(a || (b && c))"));
}

@Test
public void test_not_expression() throws IOException {
Parser parser = new Parser(new Lexer("!(a || b && !c)"));
Expr expr = parser.parseExpr();
assertThat("!(a || b && !c) should explicitly be !(a || (b && !c))",
expr.describeTo(new Renderer(),null),
is ("!(a || (b && !c))"));
}
}
5 changes: 3 additions & 2 deletions javascript/lib/parser.jison
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
%token TOKEN_LPAREN
%token TOKEN_RPAREN

%left TOKEN_AND TOKEN_OR
%left TOKEN_OR
%left TOKEN_AND
%left UNOT

%start expressions
Expand All @@ -26,4 +27,4 @@ expr

%%
var ast = require('./ast');
var ast = require('./ast');
17 changes: 17 additions & 0 deletions javascript/lib/renderer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module.exports = function Renderer() {
this.var = function(var_node, vars) {
return var_node.name;
};

this.and = function(and_node, vars) {
return "(" + and_node.left.describeTo(this, vars) + " && " + and_node.right.describeTo(this, vars) + ")";
};

this.or = function(or_node, vars) {
return "(" + or_node.left.describeTo(this, vars) + " || " + or_node.right.describeTo(this, vars) + ")";
};

this.not = function(not_node, vars) {
return "!" + not_node.refnode.describeTo(this, vars);
};
};
27 changes: 27 additions & 0 deletions javascript/test/renderer_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
var parser = require('../lib').parser;
var Renderer = require('../lib/renderer');
var assert = require('assert');

describe('Renderer', function() {
it('test and or precedence', function() {
var expr = parser.parse('@a && @b || @c');
assert.equal('((@a && @b) || @c)', expr.describeTo(new Renderer(), null));
});
});

describe('Renderer', function() {
it('test not precedence', function() {
var expr = parser.parse('!(@a && @b || !@c)');
assert.equal('!((@a && @b) || !@c)', expr.describeTo(new Renderer(), null));
});
});


describe('Renderer', function() {
it('test or and precedence', function() {
var expr = parser.parse('@a || @b && @c');
assert.equal('(@a || (@b && @c))', expr.describeTo(new Renderer(), null));
});
});


1 change: 1 addition & 0 deletions ruby/lib/bool.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require 'bool_ext'
require 'bool/ast'
require 'bool/evaluator'
require 'bool/renderer'

module Bool
class SyntaxError < StandardError
Expand Down
35 changes: 35 additions & 0 deletions ruby/lib/bool/renderer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
module Bool
class Renderer
if RUBY_PLATFORM =~ /java/
require 'bool_ext'

def self.new
Java::Bool::Renderer.new
end

else
def var(node, vars)
node.name
end

def and(node, vars)
"(" + renderer(node.left) + " && " + renderer(node.right) + ")"
end

def or(node, vars)
"(" + renderer(node.left) + " || " + renderer(node.right) + ")"
end

def not(node, vars)
"!" + renderer(node.other)
end

private

def renderer(node)
node.describe_to(self, nil)
end
end
end
end

54 changes: 50 additions & 4 deletions ruby/spec/parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ def evaluate(vars)
ast.describe_to(Bool::Evaluator.new, vars)
end

def renderer
ast.describe_to(Bool::Renderer.new, nil)
end

let(:ast) { Bool.parse(expression) }
let(:expression) { raise NotImplementedError }

Expand Down Expand Up @@ -47,11 +51,53 @@ def evaluate(vars)
end
end

describe "ALL expressions" do
let(:expression) { "@a && @b || !@c" }
describe "AND OR expression" do
let(:expression) { "a && b || c" } # (a && b) || c

it "is true when a and b are true" do
evaluate(['a', 'b']).must_equal(true)
end

it "is true when a and c are true" do
evaluate(['a', 'c']).must_equal(true)
end
end

describe "OR AND expression" do
let(:expression) { "c || a && b" } # c || (a && b)

it "is true when all variables are false" do
evaluate([]).must_equal(true)
it "is true when a and b are true" do
evaluate(['a', 'b']).must_equal(true)
end

it "is true when a and c are true" do
evaluate(['a', 'c']).must_equal(true)
end
end


describe "AND OR expression tested by rendering explicitly" do
let(:expression) { "a && b || c" } # (a && b) || c

it "expression should be equivalent to its explicit rendering" do
renderer.must_equal "((a && b) || c)"
end
end

describe "OR AND expression tested by rendering explicitly" do
let(:expression) { "c || a && b" } # c || (a && b)

it "expression should be equivalent to its explicit rendering" do
renderer.must_equal "(c || (a && b))"
end
end


describe "not expression tested by rendering explicitly" do
let(:expression) { "!(c || a && !b)" } # c || (a && b)

it "expression should be equivalent to its explicit rendering" do
renderer.must_equal "!(c || (a && !b))"
end
end

Expand Down

0 comments on commit 8c7375d

Please sign in to comment.