[feaLib] Don’t accept hex/octal numbers everywhere
Only in name, nameid, sizemenuname and Character.
This commit is contained in:
parent
ae239722d4
commit
197b36fef4
@ -6,6 +6,9 @@ import os
|
||||
|
||||
class Lexer(object):
|
||||
NUMBER = "NUMBER"
|
||||
HEXADECIMAL = "HEXADECIMAL"
|
||||
OCTAL = "OCTAL"
|
||||
NUMBERS = (NUMBER, HEXADECIMAL, OCTAL)
|
||||
FLOAT = "FLOAT"
|
||||
STRING = "STRING"
|
||||
NAME = "NAME"
|
||||
@ -123,10 +126,10 @@ class Lexer(object):
|
||||
if cur_char == "0" and next_char in "xX":
|
||||
self.pos_ += 2
|
||||
self.scan_over_(Lexer.CHAR_HEXDIGIT_)
|
||||
return (Lexer.NUMBER, int(text[start:self.pos_], 16), location)
|
||||
return (Lexer.HEXADECIMAL, int(text[start:self.pos_], 16), location)
|
||||
if cur_char == "0" and next_char in Lexer.CHAR_DIGIT_:
|
||||
self.scan_over_(Lexer.CHAR_DIGIT_)
|
||||
return (Lexer.NUMBER, int(text[start:self.pos_], 8), location)
|
||||
return (Lexer.OCTAL, int(text[start:self.pos_], 8), location)
|
||||
if cur_char in Lexer.CHAR_DIGIT_:
|
||||
self.scan_over_(Lexer.CHAR_DIGIT_)
|
||||
if self.pos_ >= limit or text[self.pos_] != ".":
|
||||
|
@ -976,14 +976,14 @@ class Parser(object):
|
||||
def parse_name_(self):
|
||||
platEncID = None
|
||||
langID = None
|
||||
if self.next_token_type_ == Lexer.NUMBER:
|
||||
platformID = self.expect_number_()
|
||||
if self.next_token_type_ in Lexer.NUMBERS:
|
||||
platformID = self.expect_any_number_()
|
||||
location = self.cur_token_location_
|
||||
if platformID not in (1, 3):
|
||||
raise FeatureLibError("Expected platform id 1 or 3", location)
|
||||
if self.next_token_type_ == Lexer.NUMBER:
|
||||
platEncID = self.expect_number_()
|
||||
langID = self.expect_number_()
|
||||
if self.next_token_type_ in Lexer.NUMBERS:
|
||||
platEncID = self.expect_any_number_()
|
||||
langID = self.expect_any_number_()
|
||||
else:
|
||||
platformID = 3
|
||||
location = self.cur_token_location_
|
||||
@ -1006,7 +1006,7 @@ class Parser(object):
|
||||
|
||||
def parse_nameid_(self):
|
||||
assert self.cur_token_ == "nameid", self.cur_token_
|
||||
location, nameID = self.cur_token_location_, self.expect_number_()
|
||||
location, nameID = self.cur_token_location_, self.expect_any_number_()
|
||||
if nameID > 32767:
|
||||
raise FeatureLibError("Name id value cannot be greater than 32767",
|
||||
self.cur_token_location_)
|
||||
@ -1350,7 +1350,7 @@ class Parser(object):
|
||||
|
||||
def parse_cvCharacter_(self, tag):
|
||||
assert self.cur_token_ == "Character", self.cur_token_
|
||||
location, character = self.cur_token_location_, self.expect_decimal_or_hexadecimal_()
|
||||
location, character = self.cur_token_location_, self.expect_any_number_()
|
||||
self.expect_symbol_(";")
|
||||
if not (0xFFFFFF >= character >= 0):
|
||||
raise FeatureLibError("Character value must be between "
|
||||
@ -1556,13 +1556,19 @@ class Parser(object):
|
||||
return self.cur_token_
|
||||
raise FeatureLibError("Expected a name", self.cur_token_location_)
|
||||
|
||||
# TODO: Don't allow this method to accept hexadecimal values
|
||||
def expect_number_(self):
|
||||
self.advance_lexer_()
|
||||
if self.cur_token_type_ is Lexer.NUMBER:
|
||||
return self.cur_token_
|
||||
raise FeatureLibError("Expected a number", self.cur_token_location_)
|
||||
|
||||
def expect_any_number_(self):
|
||||
self.advance_lexer_()
|
||||
if self.cur_token_type_ in Lexer.NUMBERS:
|
||||
return self.cur_token_
|
||||
raise FeatureLibError("Expected a decimal, hexadecimal or octal number",
|
||||
self.cur_token_location_)
|
||||
|
||||
def expect_float_(self):
|
||||
self.advance_lexer_()
|
||||
if self.cur_token_type_ is Lexer.FLOAT:
|
||||
@ -1570,7 +1576,6 @@ class Parser(object):
|
||||
raise FeatureLibError("Expected a floating-point number",
|
||||
self.cur_token_location_)
|
||||
|
||||
# TODO: Don't allow this method to accept hexadecimal values
|
||||
def expect_decipoint_(self):
|
||||
if self.next_token_type_ == Lexer.FLOAT:
|
||||
return self.expect_float_()
|
||||
@ -1580,18 +1585,6 @@ class Parser(object):
|
||||
raise FeatureLibError("Expected an integer or floating-point number",
|
||||
self.cur_token_location_)
|
||||
|
||||
def expect_decimal_or_hexadecimal_(self):
|
||||
# the lexer returns the same token type 'NUMBER' for either decimal or
|
||||
# hexadecimal integers, and casts them both to a `int` type, so it's
|
||||
# impossible to distinguish the two here. This method is implemented
|
||||
# the same as `expect_number_`, only it gives a more informative
|
||||
# error message
|
||||
self.advance_lexer_()
|
||||
if self.cur_token_type_ is Lexer.NUMBER:
|
||||
return self.cur_token_
|
||||
raise FeatureLibError("Expected a decimal or hexadecimal number",
|
||||
self.cur_token_location_)
|
||||
|
||||
def expect_string_(self):
|
||||
self.advance_lexer_()
|
||||
if self.cur_token_type_ is Lexer.STRING:
|
||||
|
@ -67,9 +67,9 @@ class LexerTest(unittest.TestCase):
|
||||
def test_number(self):
|
||||
self.assertEqual(lex("123 -456"),
|
||||
[(Lexer.NUMBER, 123), (Lexer.NUMBER, -456)])
|
||||
self.assertEqual(lex("0xCAFED00D"), [(Lexer.NUMBER, 0xCAFED00D)])
|
||||
self.assertEqual(lex("0xcafed00d"), [(Lexer.NUMBER, 0xCAFED00D)])
|
||||
self.assertEqual(lex("010"), [(Lexer.NUMBER, 0o10)])
|
||||
self.assertEqual(lex("0xCAFED00D"), [(Lexer.HEXADECIMAL, 0xCAFED00D)])
|
||||
self.assertEqual(lex("0xcafed00d"), [(Lexer.HEXADECIMAL, 0xCAFED00D)])
|
||||
self.assertEqual(lex("010"), [(Lexer.OCTAL, 0o10)])
|
||||
|
||||
def test_float(self):
|
||||
self.assertEqual(lex("1.23 -4.5"),
|
||||
|
@ -1117,6 +1117,36 @@ class ParserTest(unittest.TestCase):
|
||||
FeatureLibError, "Expected platform id 1 or 3",
|
||||
self.parse, 'table name { nameid 9 666 "Foo"; } name;')
|
||||
|
||||
def test_nameid_hexadecimal(self):
|
||||
doc = self.parse(
|
||||
r'table name { nameid 0x9 0x3 0x1 0x0409 "Test"; } name;')
|
||||
name = doc.statements[0].statements[0]
|
||||
self.assertEqual(name.nameID, 9)
|
||||
self.assertEqual(name.platformID, 3)
|
||||
self.assertEqual(name.platEncID, 1)
|
||||
self.assertEqual(name.langID, 0x0409)
|
||||
|
||||
def test_nameid_octal(self):
|
||||
doc = self.parse(
|
||||
r'table name { nameid 011 03 012 02011 "Test"; } name;')
|
||||
name = doc.statements[0].statements[0]
|
||||
self.assertEqual(name.nameID, 9)
|
||||
self.assertEqual(name.platformID, 3)
|
||||
self.assertEqual(name.platEncID, 10)
|
||||
self.assertEqual(name.langID, 0o2011)
|
||||
|
||||
def test_cv_hexadecimal(self):
|
||||
doc = self.parse(
|
||||
r'feature cv01 { cvParameters { Character 0x5DDE; }; } cv01;')
|
||||
cv = doc.statements[0].statements[0].statements[0]
|
||||
self.assertEqual(cv.character, 0x5DDE)
|
||||
|
||||
def test_cv_octal(self):
|
||||
doc = self.parse(
|
||||
r'feature cv01 { cvParameters { Character 056736; }; } cv01;')
|
||||
cv = doc.statements[0].statements[0].statements[0]
|
||||
self.assertEqual(cv.character, 0o56736)
|
||||
|
||||
def test_rsub_format_a(self):
|
||||
doc = self.parse("feature test {rsub a [b B] c' d [e E] by C;} test;")
|
||||
rsub = doc.statements[0].statements[0]
|
||||
|
Loading…
x
Reference in New Issue
Block a user