Match complete structure in Jison grammar

I'm new to Jison.

I've got the following node program that doesn't give me the output I want. I see that the issue is that "expression" gets a match when "statement" contains only one "WORD", but I don't see how to fix it.

The output of the script below is:

$ ./test.js
ABC
Result: { foo: 'ABC' }

What I'd like to get out of it is something like this structure:

// input: "ABC !aa DEF @b GHI !cc"

Result: {
  words: ["ABC"],
  bangs: {
    aa: "DEF",
    cc: null
  }, 
  ats: {
    b: "GHI"
  }
}

I don't really understand how to build something cumulatively in the grammar. I read through some Bison/Jison stuff online, but it was pretty opaque to me. My experience with grammars is generally from Perl6, a while ago.

The script...

#!/usr/bin/env node

// mygenerator.js
var Parser = require("jison").Parser;

var grammar = {
  "lex": {
    "rules": [
      ["\\s+"            , "/* skip whitespace */"] ,
      ["![a-zA-Z0-9_-]+" , "return 'BANG';"   ] ,
      ["@[a-zA-Z0-9_-]"  , "return 'AT';"  ] ,
      ["[a-zA-Z0-9_-]+"  , "return 'WORD';"       ] ,
      ["$"               , "return 'EOF';"        ]
    ]
  },

  "bnf": {

    "expressions": [
      [ "statement EOF", "console.log($1); return {foo:$1}" ]
    ],

    "statement": [
      "words",
      "words tags"
    ],

    "words": [
      "words WORD",
      "WORD"
    ],

    "tag": [
      "BANG WORD",
      "AT WORD",
      "BANG",
      "AT"
    ],

    "tags": [
      "tags tag",
      "tag"
    ]

  }
};

var parser = new Parser(grammar);

// generate source, ready to be written to disk
var parserSource = parser.generate();
//console.log(parserSource);

// you can also use the parser directly from memory

// returns true
var result = parser.parse("ABC !aa DEF @b GHI !cc");

console.log("Result:", result);