Comparing version 0.0.12 to 0.1.0
@@ -18,5 +18,16 @@ | ||
/** | ||
* Error thrown if something goes wrong during tokenization. | ||
*/ | ||
function TokenError(name, line, column, ch, opt_msg) { | ||
Error.captureStackTrace(this, TokenError) | ||
this.message = 'Unexpected characters in "' + name + '" at line: ' + line + | ||
', column: ' + column + ', char: ' + ch + (opt_msg ? ('. ' + opt_msg) : '') | ||
} | ||
TokenError.prototype = Object.create(Error.prototype) | ||
module.exports = { | ||
ParseError: ParseError | ||
ParseError: ParseError, | ||
TokenError: TokenError | ||
} |
@@ -38,3 +38,3 @@ | ||
module.exports = function parser(identifier, string) { | ||
var tokensIncludingComments = tokenize(string) | ||
var tokensIncludingComments = tokenize(string, identifier) | ||
var tokens = tokensIncludingComments.filter(function (t) { | ||
@@ -131,10 +131,8 @@ return !isComment(t) | ||
function parseField(parent) { | ||
var type = expect(Token.Type.WORD).content | ||
var typeToken = expect(Token.Type.WORD) | ||
var type = typeToken.content | ||
var name = expect(Token.Type.WORD) | ||
expect(Token.Type.OPERATOR) | ||
var tag = expect(Token.Type.WORD) | ||
var tag = expect(Token.Type.NUMBER) | ||
if (isNaN(tag.content)) { | ||
throw new ParseError(identifier, tag, 'invalid tag "' + tag.content + '"') | ||
} | ||
if (parent.getField(name.content)) { | ||
@@ -147,3 +145,3 @@ throw new ParseError(identifier, name, 'duplicate tag name in "' + parent.getName() + '"') | ||
if ((type in fieldTypeValues) && !(type in FieldType)) { | ||
throw new ParseError(identifier, type, 'invalid type "' + type + '"') | ||
throw new ParseError(identifier, typeToken, 'invalid type "' + type + '"') | ||
} | ||
@@ -187,6 +185,3 @@ | ||
expect(Token.Type.OPERATOR) | ||
var number = expect(Token.Type.WORD) | ||
if (isNaN(number.content)) { | ||
throw new ParseError(identifier, index, 'invalid enum "' + number.content + '"') | ||
} | ||
var number = expect(Token.Type.NUMBER) | ||
expect(Token.Type.TERMINATOR) | ||
@@ -202,3 +197,3 @@ enumeration.addValue(name, Number(number.content)) | ||
expect(Token.Type.OPERATOR) | ||
var value = expect([Token.Type.WORD, Token.Type.STRING]).content | ||
var value = expect([Token.Type.WORD, Token.Type.STRING, Token.Type.NUMBER]).content | ||
parent.addOption(name, value) | ||
@@ -205,0 +200,0 @@ if (peek().type == Token.Type.DELIMITER) expect(Token.Type.DELIMITER) |
@@ -39,3 +39,4 @@ | ||
START_OPTION: 10, | ||
END_OPTION: 11 | ||
END_OPTION: 11, | ||
NUMBER: 12 | ||
} | ||
@@ -62,2 +63,3 @@ | ||
case Token.Type.END_OPTION: return '] (close option)' | ||
case Token.Type.NUMBER: return 'number' | ||
default: | ||
@@ -64,0 +66,0 @@ return 'Token Value=' + value |
@@ -8,8 +8,10 @@ | ||
var Token = require('./Token') | ||
var TokenError = require('./errors').TokenError | ||
/** | ||
* @param {string} string | ||
* @param {string} fileName | ||
* @return {Array.<Token>} | ||
*/ | ||
module.exports = function tokenize(string) { | ||
module.exports = function tokenize(string, fileName) { | ||
var pos = 0 | ||
@@ -22,2 +24,8 @@ var currentLine = 1 | ||
fileName = fileName || '[Unknown file]' | ||
function throwTokenError(opt_msg) { | ||
throw new TokenError(fileName, currentLine, currentColumn, currentChar, opt_msg) | ||
} | ||
while (currentChar) { | ||
@@ -35,4 +43,6 @@ if (lookingAt('//') || lookingAt('#')) consumeLineComment() | ||
else if (lookingAt(']')) consumeChar(Token.Type.END_OPTION) | ||
else if (lookingAtWordCharacter()) consumeWord() | ||
else nextChar() | ||
else if (lookingAtNumberFirstCharacter()) consumeNumber() | ||
else if (lookingAtWordFirstCharacter()) consumeWord() | ||
else if (lookingAtRe(/\s/)) nextChar() | ||
else throwTokenError() | ||
} | ||
@@ -50,4 +60,16 @@ | ||
function lookingAtNumberFirstCharacter() { | ||
return lookingAtRe(/[-0-9]/) | ||
} | ||
function lookingAtNumberCharacter() { | ||
return lookingAtNumberFirstCharacter() || currentChar == '.' | ||
} | ||
function lookingAtWordFirstCharacter() { | ||
return lookingAtRe(/[a-zA-Z_]/) | ||
} | ||
function lookingAtWordCharacter() { | ||
return lookingAtRe(/[a-zA-Z0-9_\.]/) | ||
return lookingAtWordFirstCharacter() || lookingAtRe(/[0-9\.]/) | ||
} | ||
@@ -73,3 +95,3 @@ | ||
case undefined: | ||
throw Error('Unterminated string') | ||
throwTokenError('Unterminated string') | ||
@@ -119,2 +141,15 @@ case '\n': | ||
function consumeNumber() { | ||
var line = currentLine | ||
var column = currentColumn | ||
while (lookingAtNumberCharacter()) { | ||
currentToken += currentChar | ||
nextChar() | ||
} | ||
var token = addToken(Token.Type.NUMBER, line, column) | ||
if (isNaN(token.content)) { | ||
throwTokenError('Malformed number ' + token.content) | ||
} | ||
} | ||
function consumeToken(type, until) { | ||
@@ -143,4 +178,6 @@ var line = currentLine | ||
function addToken(type, line, column) { | ||
tokens.push(new Token(type, currentToken, line, column)) | ||
var token = new Token(type, currentToken, line, column) | ||
tokens.push(token) | ||
currentToken = '' | ||
return token | ||
} | ||
@@ -147,0 +184,0 @@ |
{ | ||
"name": "pbnj", | ||
"version": "0.0.12", | ||
"version": "0.1.0", | ||
"keywords": ["protocol", "buffer", "proto", "protobuf", "parser", "codegen"], | ||
@@ -5,0 +5,0 @@ "description": "JavaScript protocol buffer schema parser and template based code generator", |
@@ -43,3 +43,3 @@ | ||
var msg = proto.getMessage('ThisIsTheKitchenSink') | ||
test.equal(msg.getFields().length, 4) | ||
test.equal(msg.getFields().length, 6) | ||
test.ok(msg.getField('optional_field').isOptional()) | ||
@@ -56,2 +56,4 @@ test.ok(!msg.getField('required_field').isOptional()) | ||
test.equal(msg.getField('using_another_message').getType(), 'AnotherMessage') | ||
test.equal(-1, msg.getField('negative_field').getOption('default')) | ||
test.equal('string', msg.getField('string_field').getOption('default')) | ||
@@ -88,2 +90,18 @@ test.done() | ||
exports.testBadProto_badTag = function (test) { | ||
assertFails('message BadTag { required string first = 1-1; }', | ||
'Malformed number 1-1', | ||
'Malformed number 1-1', | ||
test) | ||
} | ||
exports.testBadProto_unexpectedChars = function (test) { | ||
assertFails('message BadTag { required string first = $1; }', | ||
'Unexpected characters in "test.proto" at line: 1, column: 42, char: $', | ||
'Bad characters', | ||
test) | ||
} | ||
function assertFails(protoString, expectedError, message, test) { | ||
@@ -90,0 +108,0 @@ try { |
Sorry, the diff of this file is not supported yet
58428
1379