UNPKG

3.44 kBJavaScriptView Raw
1/**
2 * @overview The simple command parser used by AdvTxt
3 *
4 * @since 0.0.4
5 * @author Nathan Wittstock <code@fardogllc.com>
6 * @license MIT License - See file 'LICENSE' in this project.
7 */
8
9var natural = require('natural');
10var tokenizer = new natural.WordTokenizer();
11var _ = require('underscore');
12var Hoek = require('hoek');
13var debug = require('debug')('parser');
14
15var COMMANDS = {
16 en: {
17 GO: 'go'
18 , GET: 'get'
19 , RESET: 'reset'
20 , LOOK: 'look'
21 , EXITS: 'exits'
22 }
23}
24var ALIASES = {
25 en: {
26 'walk': COMMANDS.en.GO
27 , 'move': COMMANDS.en.GO
28 , 'head': COMMANDS.en.GO
29 , 'grab': COMMANDS.en.GET
30 , 'take': COMMANDS.en.GET
31 , 'pick': COMMANDS.en.GET
32 , 'see': COMMANDS.en.LOOK
33 , 'peep': COMMANDS.en.LOOK
34 }
35}
36var OPERATORS = {
37 en: ['in', 'on', 'up', 'if']
38}
39var LINKERS = {
40 en: ['and', 'or', 'then']
41}
42var FLUFF = {
43 en: ['the']
44}
45
46var advtxt = {};
47
48/**
49 * Constructs a new AdvTxt Parser. This is a single-use class that should be
50 * reinstantiated each time it parses a new command.
51 *
52 * @since 0.0.4
53 * @constructor
54 *
55 * @param {command} command - The command object.
56 * @param {string} lang - The language to be used, defaults to 'en'.
57 *
58 * @returns {boolean} If the parse was successful or not.
59 */
60exports = module.exports = advtxt.Parser = function(command, lang) {
61 var self = this;
62
63
64 if (typeof lang === 'undefined' || !lang) {
65 debug("Setting lang to 'en'.");
66 lang = 'en';
67 }
68
69 // parse the command, if we have a parser for that language defined
70 if (typeof self.parse[lang] !== 'undefined')
71 return self.parse[lang](command.command);
72 else
73 throw "advtxt.Parser: language " + lang + " does not have an appropriate parser defined.";
74}
75
76advtxt.Parser.prototype.parse = {};
77
78/**
79 * The English command parser. Parses the command at self.command, and alters
80 * it for consumption outside this class.
81 *
82 * @returns {boolean} If the parse passed or not.
83 */
84advtxt.Parser.prototype.parse["en"] = function(cmd) {
85 var self = this;
86
87 debug("Starting to parse English.");
88
89 var tokenized = tokenizer.tokenize(cmd.toLowerCase());
90 var original_verb = null;
91 var verb = null;
92 var object = null;
93 var operator = null;
94
95 // Get rid of fluff words like "the"
96 tokenized = _.difference(tokenized, FLUFF);
97
98 // We don't handle compound statements, so fail if we see one.
99 if (_.intersection(tokenized, LINKERS).length > 0) {
100 debug("Got a linker word.");
101 self.fail = true;
102 return self;
103 }
104
105 // If we see a operator word after the verb, we can throw it out.
106 if (tokenized.length > 2 && _.contains(OPERATORS["en"], tokenized[1])) {
107 debug("Command contains operator in position 1");
108 verb = tokenized[0];
109 operator = tokenized[1];
110 object = tokenized.slice(2).join("_");
111 }
112 // otherwise, we can just split it up
113 else {
114 verb = tokenized[0];
115 object = tokenized.slice(1).join("_");
116 }
117
118 // now see if we have an alias
119 if (typeof ALIASES.en[verb] !== 'undefined' && ALIASES.en[verb]) {
120 debug("Parser saw an alias.");
121 original_verb = Hoek.clone(verb);
122 verb = ALIASES.en[verb];
123 debug(verb);
124 }
125 else {
126 debug("Setting verb");
127 verb = COMMANDS.en[verb.toUpperCase()];
128 if (typeof verb === 'undefined' || !verb) {
129 verb = tokenized[0];
130 }
131 debug(verb);
132 }
133
134 cmd = {
135 original: cmd,
136 original_verb: original_verb,
137 lang: self.lang,
138 verb: verb,
139 object: object
140 }
141
142 self.fail = false;
143 self.command = cmd;
144 self.commands = COMMANDS.en;
145 debug(JSON.stringify(cmd));
146
147 return self;
148};