Skip to content

Commit 29c3009

Browse files
committed
refactoring doc lexer & parser
1 parent 10eb0f1 commit 29c3009

4 files changed

Lines changed: 348 additions & 284 deletions

File tree

src/comment.js

Lines changed: 3 additions & 284 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
var tunic = require('tunic');
77
var util = require('util');
8+
var parser = require('./comment/parser');
89
var grammar = require('../node_modules/tunic/dist/grammars/javascript');
910
grammar.namedTags = [
1011
'return', 'var', 'property', 'throws', 'param'
@@ -227,288 +228,6 @@ var tag = function(name, description) {
227228
};
228229
tag.prototype.export = function() { return this; };
229230

230-
231-
/**
232-
* @private
233-
*/
234-
var annotationLexer = function(text) {
235-
this._input = text;
236-
this.offset = 0;
237-
this.text = "";
238-
};
239-
240-
var T_EOF = 1, T_WHITESPACE = 2, T_TEXT = 3, T_STRING = 4, T_NUM = 5;
241-
var lexerSymbols = [
242-
',', '=', ':', '(', ')', '[', ']', '{', '}', '@'
243-
];
244-
var lexerWhiteSpace = [' ', '\t', '\r', '\n'];
245-
246-
annotationLexer.prototype.input = function() {
247-
if (this.offset < this._input.length) {
248-
this.ch = this._input[this.offset++];
249-
this.text += this.ch;
250-
return this.ch;
251-
} else {
252-
return null;
253-
}
254-
};
255-
256-
annotationLexer.prototype.unput = function() {
257-
this.offset--;
258-
this.text = this.text.substring(0, this.text.length - 1);
259-
};
260-
261-
annotationLexer.prototype.unlex = function() {
262-
this.offset = this.__offset;
263-
this.text = this.__text;
264-
this.token = this.__token;
265-
return this.token;
266-
};
267-
268-
annotationLexer.prototype.lex = function() {
269-
// backup
270-
this.__offset = this.offset;
271-
this.__text = this.text;
272-
this.__token = this.token;
273-
// scan
274-
this.token = this.next();
275-
while(this.token === T_WHITESPACE) {
276-
// ignore white space
277-
this.token = this.next();
278-
}
279-
return this.token;
280-
};
281-
282-
annotationLexer.prototype.next = function() {
283-
this.text = "";
284-
var ch = this.input();
285-
if (ch === null) return T_EOF;
286-
if (ch === '"' || ch === "'") {
287-
var tKey = ch;
288-
do {
289-
ch = this.input();
290-
if (ch === '\\') {
291-
this.input();
292-
}
293-
} while(ch !== tKey && this.offset < this._input.length);
294-
return T_TEXT;
295-
} else if (lexerSymbols.indexOf(ch) > -1) {
296-
if (ch === ':') ch = '=>'; // alias
297-
if (ch === '=' && this.text[this.offset] === '>') ch += this.input();
298-
return ch;
299-
} else if (lexerWhiteSpace.indexOf(ch) > -1) {
300-
ch = this.input();
301-
while(lexerWhiteSpace.indexOf(ch) > -1) {
302-
ch = this.input();
303-
}
304-
if (ch !== null) this.unput();
305-
return T_WHITESPACE;
306-
} else {
307-
ch = ch.charCodeAt(0);
308-
if (ch > 47 && ch < 58) {
309-
while(ch > 47 && ch < 58 && ch !== null) {
310-
ch = this.input();
311-
if (ch !== null) ch = ch.charCodeAt(0);
312-
}
313-
if (ch !== null) this.unput();
314-
return T_NUM;
315-
} else {
316-
do {
317-
ch = this.input();
318-
if (
319-
lexerSymbols.indexOf(ch) > -1 ||
320-
lexerWhiteSpace.indexOf(ch) > -1
321-
) {
322-
this.unput();
323-
break;
324-
}
325-
} while(this.offset < this._input.length);
326-
return T_STRING;
327-
}
328-
}
329-
};
330-
331-
var annotationParser = function(input) {
332-
this.lexer = new annotationLexer(input);
333-
this.ast = [];
334-
this.token = this.lexer.lex();
335-
while(this.token !== T_EOF) {
336-
var node = this.body();
337-
if (node) this.ast.push(node);
338-
this.token = this.lexer.lex();
339-
}
340-
};
341-
342-
annotationParser.prototype.body = function() {
343-
if (this.token === T_STRING) {
344-
if (this.lexer.text === 'true') {
345-
return ['boolean', true];
346-
} else if (this.lexer.text === 'false') {
347-
return ['boolean', false];
348-
} else if (this.lexer.text === 'null') {
349-
return ['null'];
350-
} else if (this.lexer.text === 'array') {
351-
this.token = this.lexer.lex();
352-
if (this.token === '(') {
353-
var result = ['array'];
354-
result.push(this.read_array(')'));
355-
return result;
356-
} else {
357-
this.token = this.lexer.unlex();
358-
}
359-
return ['type', this.lexer.text];
360-
} else {
361-
var name = this.lexer.text;
362-
this.token = this.lexer.lex();
363-
if (this.token === '=' || this.token === '=>') {
364-
// key value
365-
this.token = this.lexer.lex();
366-
return [
367-
'key',
368-
name,
369-
this.get_json_value(this.body())
370-
];
371-
} else if (this.token === '(') {
372-
// method
373-
var result = ['method', name, []];
374-
do {
375-
this.token = this.lexer.lex();
376-
var item = this.body();
377-
if (item !== null) {
378-
result[2].push(item);
379-
}
380-
} while(this.token !== ')' && this.token !== T_EOF);
381-
return result;
382-
} else {
383-
this.token = this.lexer.unlex();
384-
}
385-
return ['type', name];
386-
}
387-
} else if (this.token === T_TEXT) {
388-
return ['text', this.lexer.text];
389-
} else if (this.token === T_NUM) {
390-
return ['number', this.lexer.text];
391-
} else if (this.token === '[') {
392-
// can be an Array
393-
var result = ['array'];
394-
result.push(this.read_array(']'));
395-
return result;
396-
} else if (this.token === '{') {
397-
// can be a JSON
398-
var result = ['json'];
399-
result.push(this.read_json());
400-
return result;
401-
} else if (this.token === '@') {
402-
this.token = this.lexer.lex();
403-
if (this.token === T_STRING) {
404-
// inner annotation
405-
var result = ['annotation', this.lexer.text, []];
406-
this.token = this.lexer.lex();
407-
if (this.token === '(') {
408-
// with args
409-
do {
410-
this.token = this.lexer.lex();
411-
var item = this.body();
412-
if (item !== null) {
413-
result[2].push(item);
414-
}
415-
} while(this.token !== ')' && this.token !== T_EOF);
416-
} else {
417-
this.token = this.lexer.unlex();
418-
}
419-
return result;
420-
} else {
421-
// ignore it
422-
this.token = this.lexer.unlex();
423-
return null;
424-
}
425-
} else {
426-
// ignore it
427-
return null;
428-
}
429-
};
430-
431-
annotationParser.prototype.read_array = function(endChar) {
432-
var result = [];
433-
do {
434-
this.token = this.lexer.lex(); // consume start char
435-
var item = this.body();
436-
if (item !== null) { // ignore
437-
this.token = this.lexer.lex();
438-
if (this.token === '=>') {
439-
this.token = this.lexer.lex(); // eat
440-
item = ['key', item, this.body()];
441-
this.token = this.lexer.lex(); // eat
442-
}
443-
if ( this.token !== ',') {
444-
this.token = this.lexer.unlex();
445-
}
446-
result.push(item);
447-
}
448-
} while(this.token !== endChar && this.token !== T_EOF);
449-
return result;
450-
};
451-
452-
annotationParser.prototype.read_json = function(endChar) {
453-
var result = {};
454-
do {
455-
this.token = this.lexer.lex();
456-
var item = this.body();
457-
if (item !== null) { // ignore
458-
this.token = this.lexer.lex(); // eat
459-
if (this.token === '=>') {
460-
item = this.get_json_key(item);
461-
if (item !== null) {
462-
this.token = this.lexer.lex();
463-
result[item] = this.get_json_value(this.body());
464-
}
465-
this.token = this.lexer.lex();
466-
}
467-
if ( this.token !== ',') {
468-
this.token = this.lexer.unlex();
469-
}
470-
}
471-
} while(this.token !== '}' && this.token !== T_EOF);
472-
this.token = this.lexer.lex();
473-
return result;
474-
};
475-
476-
annotationParser.prototype.get_json_value = function(ast) {
477-
if (!ast) return null;
478-
var result = this.get_json_key(ast);
479-
if (result === null) {
480-
if (ast[0] === 'json') {
481-
result = ast[1];
482-
} else if (ast[0] === 'array') {
483-
result = [];
484-
ast[1].forEach(function(item) {
485-
result.push(this.get_json_value(item));
486-
}.bind(this));
487-
} else {
488-
result = ast;
489-
}
490-
}
491-
return result;
492-
};
493-
494-
// converts an ast node to a scalar key
495-
annotationParser.prototype.get_json_key = function(ast) {
496-
if (ast[0] === 'text') {
497-
var result = ast[1].substring(1, ast[1].length - 1);
498-
try {
499-
return JSON.parse('"' + result + '"');
500-
} catch(e) {
501-
return result;
502-
}
503-
} else if (ast[0] === 'number') {
504-
return JSON.parse(ast[1]);
505-
} else if (ast[0] === 'type' || ast[0] === 'boolean') {
506-
return ast[1];
507-
} else {
508-
return null;
509-
}
510-
};
511-
512231
/**
513232
* @private
514233
* @constructor annotation
@@ -522,8 +241,8 @@ var annotation = function(name, args) {
522241
var methodEnd = args.lastIndexOf(')');
523242
if (methodEnd > -1) {
524243
this.description = args.substring(methodEnd + 1);
525-
var parser = new annotationParser(args.substring(1, methodEnd));
526-
this.arguments = parser.ast;
244+
var doc = new parser(args.substring(1, methodEnd));
245+
this.arguments = doc.ast;
527246
}
528247
};
529248
annotation.prototype.export = function() { return this; };

0 commit comments

Comments
 (0)