Skip to content

Commit

Permalink
Fixes object literal and block ambiguity
Browse files Browse the repository at this point in the history
- Follows the requirements in 12.4
- Additions to the grammar test suite.
- Repairs older grammar tests and adds a test-grammar to the Makefile.
- All the examples from the WAT talk should now work as expected
  (well, according to spec. They're not really what I'd call expected ;)
  • Loading branch information
ndreynolds committed Feb 15, 2013
1 parent f88c754 commit 197a6ee
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 31 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ test-sm:
test-rhino:
node test/runner.js --exec rhino --timeout 10000 --args "-f test/harness.js -f [test]"

test-grammar:
mocha test/grammar

archive:
git archive --format=tar.gz --prefix="flathead-$(VERSION)/" \
--output="flathead-$(VERSION).tar.gz" master .
40 changes: 37 additions & 3 deletions src/grammar.y
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@
%type<node> LeftHSExpression
%type<node> LeftHSExpressionNoFn
%type<node> Literal
%type<node> LiteralNoObj
%type<node> LogicalANDExpression
%type<node> LogicalANDExpressionNoIn
%type<node> LogicalANDExpressionNoFn
Expand All @@ -228,6 +229,7 @@
%type<node> PostfixExpression
%type<node> PostfixExpressionNoFn
%type<node> PrimaryExpression
%type<node> PrimaryExpressionNoObj
%type<node> Program
%type<node> PropertyAssignment
%type<node> PropertyName
Expand Down Expand Up @@ -264,11 +266,17 @@
* declaration and a named function expression. Expression statements cannot
* begin with the 'function' keyword (Ecma-252 12.4). These productions
* prevent that.
*
* 'NoObj' rides the 'NoFn' train, forking at 'MemberExpressionNoFn' to ensure
* that 'PrimaryExpression' cannot be an object literal. Like the function
* declaration and expression, object literals must be disambiguated from
* blocks, and therefore may not be used to start an expression statement
* (Ecma-252 12.4).
*/

%%

Program : SourceElements
Program : SourceElements
{ root = $1; }
;

Expand Down Expand Up @@ -314,7 +322,9 @@ Statement : Block
{ $$ = $1; }
;

Block : '{' StatementList '}'
Block : '{' '}'
{ $$ = NEW_BLOCK(NULL); }
| '{' StatementList '}'
{ $$ = NEW_BLOCK($2); }
;

Expand Down Expand Up @@ -501,6 +511,18 @@ Literal : NullLiteral
{ $$ = $1; }
;

LiteralNoObj : NullLiteral
{ $$ = $1; }
| BooleanLiteral
{ $$ = $1; }
| NumericLiteral
{ $$ = $1; }
| StringLiteral
{ $$ = $1; }
| RegularExpressionLiteral
{ $$ = $1; }
;

ArrayLiteral : '[' ']'
{ $$ = NEW_ARR(NULL); }
| '[' Elision ']'
Expand Down Expand Up @@ -630,6 +652,18 @@ PrimaryExpression : THIS
{ $$ = $2; }
;

PrimaryExpressionNoObj : THIS
{ $$ = NEW_THIS(); }
| Identifier
{ $$ = $1; }
| LiteralNoObj
{ $$ = $1; }
| ArrayLiteral
{ $$ = $1; }
| '(' Expression ')'
{ $$ = $2; }
;

ConditionalExpression : LogicalORExpression
{ $$ = $1; }
| LogicalORExpression '?' AssignmentExpression ':' AssignmentExpression
Expand Down Expand Up @@ -1056,7 +1090,7 @@ MemberExpression : PrimaryExpression
{ $$ = NEW_NEW(NEW_MEMBER($3, $2, false)); }
;

MemberExpressionNoFn : PrimaryExpression
MemberExpressionNoFn : PrimaryExpressionNoObj
{ $$ = $1; }
| MemberExpressionNoFn '[' Expression ']'
{ $$ = NEW_MEMBER($3, $1, 42); }
Expand Down
45 changes: 36 additions & 9 deletions test/grammar/expressions.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,56 @@ describe('Expressions', function() {
describe('Arithmetic', function() {

it('should handle 2+2', function(done) {
withParseTree("2+2;", function(tree) {
assert.equal(tree, fixture("expression1"));
withParseTree('2+2;', function(tree) {
assert.equal(tree, fixture('expression1'));
done();
});
});

it('should handle 6%(12-2*7)*3+9/1', function(done) {
withParseTree("6%(12-2*7)*3+9/1;", function(tree) {
assert.equal(tree, fixture("expression2"));
withParseTree('6%(12-2*7)*3+9/1;', function(tree) {
assert.equal(tree, fixture('expression2'));
done();
});
});

it('should give * precedence over /', function(done) {
withParseTree("1*2/3;", function(tree) {
assert.equal(tree, fixture("expression3"));
withParseTree('1*2/3;', function(tree) {
assert.equal(tree, fixture('expression3'));
done();
});
})
});

it('should give + precedence over -', function(done) {
withParseTree("1+2-3;", function(tree) {
assert.equal(tree, fixture("expression4"));
withParseTree('1+2-3;', function(tree) {
assert.equal(tree, fixture('expression4'));
done();
});
});
});

describe('12.4 Ambiguities', function() {

it('should properly distinguish object literals from blocks', function(done) {
// block and unary + operator on an object literal
withParseTree('{}+{};', function(tree) {
assert.equal(tree, fixture('block-object1'));
done();
});
});

it('should properly distinguish object literals from blocks (2)', function(done) {
// block and unary + operator on an array literal
withParseTree('{}+[];', function(tree) {
assert.equal(tree, fixture('block-object2'));
done();
});
});

it('should properly distinguish object literals from blocks (3)', function(done) {
// binary + operator on array literal and object literal
withParseTree('[]+{};', function(tree) {
assert.equal(tree, fixture('block-object3'));
done();
});
});
Expand Down
7 changes: 7 additions & 0 deletions test/grammar/fixtures/block-object1
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
source list
expression statement
expression (unary prefix)
+
object
source list
block
7 changes: 7 additions & 0 deletions test/grammar/fixtures/block-object2
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
source list
expression statement
expression (unary prefix)
+
array literal
source list
block
6 changes: 6 additions & 0 deletions test/grammar/fixtures/block-object3
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
source list
expression statement
expression (binary)
+
array literal
object
4 changes: 2 additions & 2 deletions test/grammar/fixtures/expression1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
statement list
source list
expression statement
expression
expression (binary)
+
number (2.000000)
number (2.000000)
14 changes: 7 additions & 7 deletions test/grammar/fixtures/expression2
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
statement list
source list
expression statement
expression
expression (binary)
+
expression
expression (binary)
*
expression
expression (binary)
%
number (6.000000)
expression
expression (binary)
-
number (12.000000)
expression
expression (binary)
*
number (2.000000)
number (7.000000)
number (3.000000)
expression
expression (binary)
/
number (9.000000)
number (1.000000)
6 changes: 3 additions & 3 deletions test/grammar/fixtures/expression3
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
statement list
source list
expression statement
expression
expression (binary)
/
expression
expression (binary)
*
number (1.000000)
number (2.000000)
Expand Down
6 changes: 3 additions & 3 deletions test/grammar/fixtures/expression4
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
statement list
source list
expression statement
expression
expression (binary)
-
expression
expression (binary)
+
number (1.000000)
number (2.000000)
Expand Down
8 changes: 4 additions & 4 deletions test/grammar/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@

var exec = require('child_process').exec,
fs = require('fs'),
cmd = __dirname + '/../../bin/fh',
cmd = __dirname + '/../../bin/flat',
fixtures = __dirname + '/fixtures/';

exports.withParseTree = function(evalString, cb) {
var parseTree;
var child = exec(cmd + ' -p', function(err, stdout, stderr) {
var child = exec(cmd + ' -n', function(err, stdout, stderr) {
cb(stdout);
});
child.stdin.write(evalString);
child.stdin.end();
}
};

exports.fixture = function(name) {
return fs.readFileSync(fixtures + name, 'utf8');
}
};

0 comments on commit 197a6ee

Please sign in to comment.