Skip to content

Commit

Permalink
implement type, text & tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ichiriac committed Jan 8, 2017
1 parent 6216fe0 commit 7ff0b34
Show file tree
Hide file tree
Showing 2 changed files with 236 additions and 11 deletions.
199 changes: 193 additions & 6 deletions src/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ var Parser = function (lexer, grammar) {
{
property: 'description',
parser: 'text',
optional: true
optional: true,
default: ''
}],
return: [{
property: 'what',
Expand All @@ -75,7 +76,8 @@ var Parser = function (lexer, grammar) {
{
property: 'description',
parser: 'text',
optional: true
optional: true,
default: ''
}],
throws: [{
property: 'what',
Expand Down Expand Up @@ -293,9 +295,11 @@ Parser.prototype.parseGrammar = function (name) {
*/
Parser.prototype.parseRule = function (rule) {
if (typeof this.parsers[rule.parser] === 'function') {
var backup = this.lexer.state();
var result = this.parsers[rule.parser].apply(this, []);
if (result === null) {
if (rule.default) {
this.lexer.unlex(backup);
if (typeof rule.default !== 'undefined') {
return rule.default;
}
}
Expand All @@ -304,6 +308,189 @@ Parser.prototype.parseRule = function (rule) {
return null;
};

/**
* Check if current token can be a type
* ```ebnf
* type ::= '\\'? T_STRING ('\\' T_STRING) *
* parseType ::= type |
* type '[' (type (',' type)*)? ']' |
* type '<' (type (',' type)*)? '>'
* ```
*/
Parser.prototype.parseType = function () {
var result = {
kind: 'type',
fqn: false,
name: ''
};
if (this.token === '\\') {
result.fqn = true;
this.token = this.lexer.lex();
}
if (this.token !== this.lexer._t.T_STRING) {
return null;
}
while (this.token === this.lexer._t.T_STRING) {
result.name += this.lexer.text;
this.token = this.lexer.lex(); // eat
if (this.token === '\\') {
result.name += '\\';
this.token = this.lexer.lex(); // eat && continue
} else if (this.token === '[') {
// collection
result = {
kind: 'collection',
value: result,
index: this.parseListOfTypes(']')
};
if (result.index === null) {
return null;
}
break;
} else if (this.token === '<') {
// template class
result = {
kind: 'class',
class: result,
parameters: this.parseListOfTypes('>')
};
if (result.parameters === null) {
return null;
}
break;
} else {
break;
}
}
return result;
};

/**
* Parse a list of type
* @private
*/
Parser.prototype.parseListOfTypes = function (charEnd) {
var result = [];
this.token = this.lexer.lex(); // eat && continue
if (this.token === charEnd) {
this.token = this.lexer.lex(); // eat && continue
} else {
var indexType = this.parseType();
if (indexType !== null) {
result.push(indexType);
while (this.token === ',') {
this.token = this.lexer.lex(); // eat && continue
indexType = this.parseType();
if (indexType === null) {
break;
} else {
result.push(indexType);
}
}
}
if (this.token !== charEnd) {
return null;
}
}
return result;
};

Parser.prototype.parseVarName = function () {

};

/**
* Parsing an entire line string
*/
Parser.prototype.parseText = function () {
if (this.token !== this.lexer._t.T_STRING) {
return null;
}
var line = this.lexer.backup.line;
var offset = this.lexer.backup.offset;
while (this.token !== this.lexer._t.EOF) {
this.token = this.lexer.lex(); // eat && continue
if (this.lexer.line !== line) {
this.lexer.unlex();
break;
}
}
var result = this.lexer._input.substring(offset, this.lexer.offset).trim();
this.token = this.lexer.lex(); // eat && continue
return result;
};

/**
* Reads a version informations
* ```ebnf
* parseVersion ::= T_NUM ('.' T_NUM ('.' T_NUM ('-' T_STRING)?)?)?
* ```
*/
Parser.prototype.parseVersion = function () {
var version = {
major: 0,
minor: 0,
patch: 0,
label: null
};

if (this.token !== this.lexer._t.T_NUM) {
return null;
}

// PARSE THE NUMERIC PART
var v = this.lexer.text;
this.token = this.lexer.lex(); // eat && continue
if (this.token === this.lexer._t.T_NUM) {
v += this.lexer.text;
this.token = this.lexer.lex(); // eat && continue
}

// EAT THE LABEL
if (this.token === '-') {
this.token = this.lexer.lex(); // eat && continue
if (this.token === this.lexer._t.T_STRING) {
version.label = this.lexer.text;
this.token = this.lexer.lex(); // eat && continue
if (this.token === this.lexer._t.T_NUM) {
version.label += this.lexer.text;
this.token = this.lexer.lex(); // eat && continue
}
}
}

// READ THE VERSION
v = v.split('\\.');
version.major = v[0];
if (v.length > 1) {
version.minor = v[1];
if (v.length > 2) {
version.patch = v[2];
}
}
return version;
};

Parser.prototype.parseArray = function () {

};

Parser.prototype.parseObject = function () {

};

Parser.prototype.parseBoolean = function () {

};

Parser.prototype.parseNumber = function () {

};

Parser.prototype.parseString = function () {

};

/**
* Parses a T_STRING statement
*/
Expand Down Expand Up @@ -347,7 +534,7 @@ Parser.prototype.parseStatement = function () {
return {
kind: 'key',
name: name,
value: this.getJsonValue(this.body())
value: this.getJsonValue(this.parseTopStatement())
};
} else if (this.token === '(') {
// method
Expand Down Expand Up @@ -376,7 +563,7 @@ Parser.prototype.readArray = function (endChar) {
var result = [];
do {
this.token = this.lexer.lex(); // consume start char
var item = this.body();
var item = this.parseTopStatement();
if (item !== null) { // ignore
this.token = this.lexer.lex();
item = this.getJsonValue(item);
Expand Down Expand Up @@ -457,7 +644,7 @@ Parser.prototype.getJsonKey = function (ast) {
} catch (err) {
}
} else if (ast.kind === 'number') {
result = JSON.parse(ast[1]);
result = JSON.parse(ast.value);
} else if (ast.kind === 'word' || ast.kind === 'boolean') {
result = ast.value;
}
Expand Down
48 changes: 43 additions & 5 deletions test/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,63 @@ describe('Test parser', function () {
var ast = doc.parse([
'/**',
' * Description',
' * @test 123 1.23',
' * @test 123 1.23 null',
' */'
].join('\n'));
].join('\r\n'));
ast.body[0].type.should.be.exactly('test');
ast.body[0].options.length.should.be.exactly(2);
ast.body[0].options.length.should.be.exactly(3);
ast.body[0].options[0].kind.should.be.exactly('number');
ast.body[0].options[0].value.should.be.exactly('123');
ast.body[0].options[1].kind.should.be.exactly('number');
ast.body[0].options[1].value.should.be.exactly('1.23');
ast.body[0].options[2].kind.should.be.exactly('null');
});

it('test rule', function () {
it('test array', function () {
var ast = doc.parse([
'/**',
' * @test [1, 2, a => b]',
' */'
].join('\r\n'));
ast.body[0].type.should.be.exactly('test');
ast.body[0].options.length.should.be.exactly(1);
ast.body[0].options[0].kind.should.be.exactly('array');
console.log(ast.body[0].options[0]);
});

it('test boolean', function () {
var ast = doc.parse([
'/**',
' * @test true false',
' */'
].join('\r\n'));
ast.body[0].type.should.be.exactly('test');
ast.body[0].options.length.should.be.exactly(2);
ast.body[0].options[0].kind.should.be.exactly('boolean');
ast.body[0].options[0].value.should.be.exactly(true);
ast.body[0].options[1].kind.should.be.exactly('boolean');
ast.body[0].options[1].value.should.be.exactly(false);
});

it('test return rule', function () {
var ast = doc.parse([
'/**',
' * Description',
' * @return void Some extra informations',
' */'
].join('\n'));
ast.body[0].kind.should.be.exactly('return');
console.log(ast.body[0]);
ast.body[0].what.kind.should.be.exactly('type');
ast.body[0].what.name.should.be.exactly('void');
ast.body[0].description.should.be.exactly('Some extra informations');
});
it('test return optional values', function () {
var ast = doc.parse('/* @return \\Foo\\Bar[] */');
ast.body[0].kind.should.be.exactly('return');
ast.body[0].what.kind.should.be.exactly('collection');
ast.body[0].what.value.kind.should.be.exactly('type');
ast.body[0].what.value.name.should.be.exactly('Foo\\Bar');
ast.body[0].what.value.fqn.should.be.exactly(true);
ast.body[0].description.should.be.exactly('');
});
});

0 comments on commit 7ff0b34

Please sign in to comment.