Bug 1645459: Add numbering systems processing to the standard Intl python script. r=jwalden

Handle numbering systems similar to measurement units:
- Add a central list of all supported numbering systems in a yaml file.
- Verify these numbering systems are supported by ICU.
- Also verify ICU supports no additional simple numbering systems. (ECMA-402
  should support all numbering systems with simple digit mappings defined in
  CLDR.)
- Generate source and test files from this list of numbering systems.

Differential Revision: https://phabricator.services.mozilla.com/D81717
This commit is contained in:
André Bargull 2020-07-10 17:19:42 +00:00
parent f2005724b4
commit 9f3944b5b4
7 changed files with 726 additions and 175 deletions

View File

@ -271,3 +271,18 @@ Second, use ``make_intl_data.py``\ s ``units`` mode to update unit handling a
$ # make_intl_data.py requires yaml.
$ export PYTHONPATH="$topsrcdir/third_party/python/PyYAML/lib3/"
$ python3 ./make_intl_data.py units
Updating SpiderMonkey numbering systems support
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``Intl`` API also supports formatting numbers in various numbering systems (for example, “123“ using Latin numbers or “一二三“ using Han decimal numbers). The list of numbering systems that we must support is stored in ``js/src/builtin/intl/NumberingSystems.yaml``. We verify these numbering systems are supported by ICU and generate supporting files from it.
When the list of supported numbering systems needs to be updated, run ``make_intl_data.py`` with the ``numbering`` mode to update it and associated tests in SpiderMonkey:
.. code:: bash
$ cd "$topsrcdir/js/src/builtin/intl"
$ # make_intl_data.py requires yaml.
$ export PYTHONPATH="$topsrcdir/third_party/python/PyYAML/lib3/"
$ python3 ./make_intl_data.py numbering

View File

@ -4,6 +4,8 @@
/* Portions Copyright Norbert Lindenberg 2011-2012. */
#include "NumberingSystemsGenerated.h"
/**
* NumberFormat internal properties.
*
@ -573,72 +575,7 @@ function getNumberingSystems(locale) {
var defaultNumberingSystem = intl_numberingSystem(locale);
return [
defaultNumberingSystem,
"adlm",
"ahom",
"arab",
"arabext",
"bali",
"beng",
"bhks",
"brah",
"cakm",
"cham",
"deva",
"diak",
"fullwide",
"gong",
"gonm",
"gujr",
"guru",
"hanidec",
"hmng",
"hmnp",
"java",
"kali",
"khmr",
"knda",
"lana",
"lanatham",
"laoo",
"latn",
"lepc",
"limb",
"mathbold",
"mathdbl",
"mathmono",
"mathsanb",
"mathsans",
"mlym",
"modi",
"mong",
"mroo",
"mtei",
"mymr",
"mymrshan",
"mymrtlng",
"newa",
"nkoo",
"olck",
"orya",
"osma",
"rohg",
"saur",
"segment",
"shrd",
"sind",
"sinh",
"sora",
"sund",
"takr",
"talu",
"tamldec",
"telu",
"thai",
"tibt",
"tirh",
"vaii",
"wara",
"wcho",
NUMBERING_SYSTEMS_WITH_SIMPLE_DIGIT_MAPPINGS
];
}

View File

@ -0,0 +1,79 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# 12.1.7 PartitionNotationSubPattern ( numberFormat, x, n, exponent )
#
# Numbering systems with simple digit mappings
#
# https://tc39.es/ecma402/#table-numbering-system-digits
# Run |make_intl_data numbering| to regenerate all files which reference this list
# of numbering systems.
- adlm
- ahom
- arab
- arabext
- bali
- beng
- bhks
- brah
- cakm
- cham
- deva
- diak
- fullwide
- gong
- gonm
- gujr
- guru
- hanidec
- hmng
- hmnp
- java
- kali
- khmr
- knda
- lana
- lanatham
- laoo
- latn
- lepc
- limb
- mathbold
- mathdbl
- mathmono
- mathsanb
- mathsans
- mlym
- modi
- mong
- mroo
- mtei
- mymr
- mymrshan
- mymrtlng
- newa
- nkoo
- olck
- orya
- osma
- rohg
- saur
- segment
- shrd
- sind
- sinh
- sora
- sund
- takr
- talu
- tamldec
- telu
- thai
- tibt
- tirh
- vaii
- wara
- wcho

View File

@ -0,0 +1,80 @@
// Generated by make_intl_data.py. DO NOT EDIT.
/**
* The list of numbering systems with simple digit mappings.
*/
#ifndef builtin_intl_NumberingSystemsGenerated_h
#define builtin_intl_NumberingSystemsGenerated_h
// clang-format off
#define NUMBERING_SYSTEMS_WITH_SIMPLE_DIGIT_MAPPINGS \
"adlm", \
"ahom", \
"arab", \
"arabext", \
"bali", \
"beng", \
"bhks", \
"brah", \
"cakm", \
"cham", \
"deva", \
"diak", \
"fullwide", \
"gong", \
"gonm", \
"gujr", \
"guru", \
"hanidec", \
"hmng", \
"hmnp", \
"java", \
"kali", \
"khmr", \
"knda", \
"lana", \
"lanatham", \
"laoo", \
"latn", \
"lepc", \
"limb", \
"mathbold", \
"mathdbl", \
"mathmono", \
"mathsanb", \
"mathsans", \
"mlym", \
"modi", \
"mong", \
"mroo", \
"mtei", \
"mymr", \
"mymrshan", \
"mymrtlng", \
"newa", \
"nkoo", \
"olck", \
"orya", \
"osma", \
"rohg", \
"saur", \
"segment", \
"shrd", \
"sind", \
"sinh", \
"sora", \
"sund", \
"takr", \
"talu", \
"tamldec", \
"telu", \
"thai", \
"tibt", \
"tirh", \
"vaii", \
"wara", \
"wcho"
// clang-format on
#endif // builtin_intl_NumberingSystemsGenerated_h

View File

@ -10,6 +10,7 @@
make_intl_data.py tzdata
make_intl_data.py currency
make_intl_data.py units
make_intl_data.py numbering
Target "langtags":
@ -32,6 +33,11 @@
Target "units":
Generate source and test files using the list of so-called "sanctioned unit
identifiers" and verifies that the ICU data filter includes these units.
Target "numbering":
Generate source and test files using the list of numbering systems with
simple digit mappings and verifies that it's in sync with ICU/CLDR.
"""
from __future__ import print_function
@ -1329,6 +1335,25 @@ if (typeof reportCompare === "function")
reportCompare(0, 0);""")
def readCLDRVersionFromICU():
icuDir = os.path.join(topsrcdir, "intl/icu/source")
if not os.path.isdir(icuDir):
raise RuntimeError("not a directory: {}".format(icuDir))
reVersion = re.compile(r'\s*cldrVersion\{"(\d+(?:\.\d+)?)"\}')
for line in flines(os.path.join(icuDir, "data/misc/supplementalData.txt")):
m = reVersion.match(line)
if m:
version = m.group(1)
break
if version is None:
raise RuntimeError("can't resolve CLDR version")
return version
def updateCLDRLangTags(args):
""" Update the LanguageTagGenerated.cpp file. """
version = args.version
@ -1338,20 +1363,7 @@ def updateCLDRLangTags(args):
# Determine current CLDR version from ICU.
if version is None:
icuDir = os.path.join(topsrcdir, "intl/icu/source")
if not os.path.isdir(icuDir):
raise RuntimeError("not a directory: {}".format(icuDir))
reVersion = re.compile(r'\s*cldrVersion\{"(\d+(?:\.\d+)?)"\}')
for line in flines(os.path.join(icuDir, "data/misc/supplementalData.txt")):
m = reVersion.match(line)
if m:
version = m.group(1)
break
if version is None:
raise RuntimeError("can't resolve CLDR version")
version = readCLDRVersionFromICU()
url = url.replace("<VERSION>", version)
@ -1390,7 +1402,8 @@ def updateCLDRLangTags(args):
writeCLDRLanguageTagData(println, data, url)
print("Writing Intl test data...")
test_file = os.path.join(os.path.dirname(os.path.abspath(__file__)),
js_src_builtin_intl_dir = os.path.dirname(os.path.abspath(__file__))
test_file = os.path.join(js_src_builtin_intl_dir,
"../../tests/non262/Intl/Locale/likely-subtags-generated.js")
with io.open(test_file, mode="w", encoding="utf-8", newline="") as f:
println = partial(print, file=f)
@ -2455,9 +2468,9 @@ def readICUUnitResourceFile(filepath):
Returns {("length", "meter"), ("duration", "day"), ("duration", "day-person")}
"""
start_table_re = re.compile(r"^([\w\-%:\"]+){$")
end_table_re = re.compile(r"^}$")
table_entry_re = re.compile(r"^([\w\-%:\"]+){\"(.*?)\"}$")
start_table_re = re.compile(r"^([\w\-%:\"]+)\{$")
end_table_re = re.compile(r"^\}$")
table_entry_re = re.compile(r"^([\w\-%:\"]+)\{\"(.*?)\"\}$")
# The current resource table.
table = {}
@ -2509,7 +2522,7 @@ def readICUUnitResourceFile(filepath):
table[entry_key] = entry_value
continue
raise Exception("unexpected line: '{}' in {}".format(line, file_name))
raise Exception("unexpected line: '{}' in {}".format(line, filepath))
assert len(parents) == 0, "Not all tables closed"
assert len(table) == 1, "More than one root table"
@ -2576,14 +2589,15 @@ def readICUDataFilterForUnits(data_filter_file):
def writeSanctionedSimpleUnitIdentifiersFiles(all_units, sanctioned_units):
intl_dir = os.path.dirname(os.path.abspath(__file__))
js_src_builtin_intl_dir = os.path.dirname(os.path.abspath(__file__))
def find_unit_type(unit):
result = [unit_type for (unit_type, unit_name) in all_units if unit_name == unit]
assert result and len(result) == 1
return result[0]
sanctioned_js_file = os.path.join(intl_dir, "SanctionedSimpleUnitIdentifiersGenerated.js")
sanctioned_js_file = os.path.join(js_src_builtin_intl_dir,
"SanctionedSimpleUnitIdentifiersGenerated.js")
with io.open(sanctioned_js_file, mode="w", encoding="utf-8", newline="") as f:
println = partial(print, file=f)
@ -2601,7 +2615,7 @@ def writeSanctionedSimpleUnitIdentifiersFiles(all_units, sanctioned_units):
println(u"var sanctionedSimpleUnitIdentifiers = {};".format(sanctioned_units_object))
sanctioned_cpp_file = os.path.join(intl_dir, "MeasureUnitGenerated.h")
sanctioned_cpp_file = os.path.join(js_src_builtin_intl_dir, "MeasureUnitGenerated.h")
with io.open(sanctioned_cpp_file, mode="w", encoding="utf-8", newline="") as f:
println = partial(print, file=f)
@ -2634,8 +2648,8 @@ inline constexpr MeasureUnit simpleMeasureUnits[] = {
def writeUnitTestFiles(all_units, sanctioned_units):
""" Generate test files for unit number formatters. """
test_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)),
"../../tests/non262/Intl/NumberFormat")
js_src_builtin_intl_dir = os.path.dirname(os.path.abspath(__file__))
test_dir = os.path.join(js_src_builtin_intl_dir, "../../tests/non262/Intl/NumberFormat")
def write_test(file_name, test_content, indent=4):
file_path = os.path.join(test_dir, file_name)
@ -2773,6 +2787,188 @@ def updateUnits(topsrcdir, args):
writeSanctionedSimpleUnitIdentifiersFiles(all_units, sanctioned_units)
def readICUNumberingSystemsResourceFile(filepath):
""" Returns a dictionary of numbering systems where the key denotes the numbering system name
and the value a dictionary with additional numbering system data.
Example:
numberingSystems:table(nofallback){
numberingSystems{
latn{
algorithmic:int{0}
desc{"0123456789"}
radix:int{10}
}
roman{
algorithmic:int{1}
desc{"%roman-upper"}
radix:int{10}
}
}
}
Returns {"latn": {"digits": "0123456789", "algorithmic": False},
"roman": {"algorithmic": True}}
"""
start_table_re = re.compile(r"^(\w+)(?:\:[\w\(\)]+)?\{$")
end_table_re = re.compile(r"^\}$")
table_entry_re = re.compile(r"^(\w+)(?:\:[\w\(\)]+)?\{(?:(?:\"(.*?)\")|(\d+))\}$")
# The current resource table.
table = {}
# List of parent tables when parsing.
parents = []
# Track multi-line comments state.
in_multiline_comment = False
for line in flines(filepath, "utf-8-sig"):
# Remove leading and trailing whitespace.
line = line.strip()
# Skip over comments.
if in_multiline_comment:
if line.endswith("*/"):
in_multiline_comment = False
continue
if line.startswith("//"):
continue
if line.startswith("/*"):
in_multiline_comment = True
continue
# Try to match the start of a table, e.g. `latn{`.
match = start_table_re.match(line)
if match:
parents.append(table)
table_name = match.group(1)
new_table = {}
table[table_name] = new_table
table = new_table
continue
# Try to match the end of a table.
match = end_table_re.match(line)
if match:
table = parents.pop()
continue
# Try to match a table entry, e.g. `desc{"0123456789"}`.
match = table_entry_re.match(line)
if match:
entry_key = match.group(1)
entry_value = match.group(2) if match.group(2) is not None else int(match.group(3))
table[entry_key] = entry_value
continue
raise Exception("unexpected line: '{}' in {}".format(line, filepath))
assert len(parents) == 0, "Not all tables closed"
assert len(table) == 1, "More than one root table"
# Remove the two top-level "numberingSystems" tables.
(_, numbering_systems) = table.popitem()
(_, numbering_systems) = numbering_systems.popitem()
# Assert all numbering systems use base 10.
assert all(ns["radix"] == 10 for ns in numbering_systems.values())
# Return the numbering systems.
return {key: {"digits": value["desc"], "algorithmic": False}
if not bool(value["algorithmic"])
else {"algorithmic": True}
for (key, value) in numbering_systems.items()}
def writeNumberingSystemFiles(numbering_systems):
js_src_builtin_intl_dir = os.path.dirname(os.path.abspath(__file__))
numbering_systems_js_file = os.path.join(js_src_builtin_intl_dir,
"NumberingSystemsGenerated.h")
with io.open(numbering_systems_js_file, mode="w", encoding="utf-8", newline="") as f:
println = partial(print, file=f)
println(generatedFileWarning)
println(u"""
/**
* The list of numbering systems with simple digit mappings.
*/
#ifndef builtin_intl_NumberingSystemsGenerated_h
#define builtin_intl_NumberingSystemsGenerated_h
""")
simple_numbering_systems = sorted(name
for (name, value) in numbering_systems.items()
if not value["algorithmic"])
println(u"// clang-format off")
println(u"#define NUMBERING_SYSTEMS_WITH_SIMPLE_DIGIT_MAPPINGS \\")
println(u"{}".format(", \\\n".join(u' "{}"'.format(name)
for name in simple_numbering_systems)))
println(u"// clang-format on")
println(u"")
println(u"#endif // builtin_intl_NumberingSystemsGenerated_h")
js_src_builtin_intl_dir = os.path.dirname(os.path.abspath(__file__))
test_dir = os.path.join(js_src_builtin_intl_dir, "../../tests/non262/Intl")
intl_shell_js_file = os.path.join(test_dir, "shell.js")
with io.open(intl_shell_js_file, mode="w", encoding="utf-8", newline="") as f:
println = partial(print, file=f)
println(generatedFileWarning)
println(u"""
// source: CLDR file common/bcp47/number.xml; version CLDR {}.
// https://github.com/unicode-org/cldr/blob/master/common/bcp47/number.xml
// https://github.com/unicode-org/cldr/blob/master/common/supplemental/numberingSystems.xml
""".format(readCLDRVersionFromICU()).rstrip())
numbering_systems_object = json.dumps(numbering_systems,
indent=2,
separators=(',', ': '),
sort_keys=True,
ensure_ascii=False)
println(u"const numberingSystems = {};".format(numbering_systems_object))
def updateNumberingSystems(topsrcdir, args):
icu_path = os.path.join(topsrcdir, "intl", "icu")
icu_misc_path = os.path.join(icu_path, "source", "data", "misc")
with io.open("NumberingSystems.yaml", mode="r", encoding="utf-8") as f:
numbering_systems = yaml.safe_load(f)
# Read all possible ICU unit identifiers from the "misc/numberingSystems.txt" resource.
misc_ns_file = os.path.join(icu_misc_path, "numberingSystems.txt")
all_numbering_systems = readICUNumberingSystemsResourceFile(misc_ns_file)
all_numbering_systems_simple_digits = {name for (name, value) in all_numbering_systems.items()
if not value["algorithmic"]}
# Assert ICU includes support for all required numbering systems. If this assertion fails,
# something is broken in ICU.
assert all_numbering_systems_simple_digits.issuperset(numbering_systems), (
"{}".format(numbering_systems.difference(all_numbering_systems_simple_digits)))
# Assert the spec requires support for all numbering systems with simple digit mappings. If
# this assertion fails, file a PR at <https://github.com/tc39/ecma402> to include any new
# numbering systems.
assert all_numbering_systems_simple_digits.issubset(numbering_systems), (
"{}".format(all_numbering_systems_simple_digits.difference(numbering_systems)))
writeNumberingSystemFiles(all_numbering_systems)
if __name__ == "__main__":
import argparse
@ -2846,5 +3042,10 @@ if __name__ == "__main__":
help="Update sanctioned unit identifiers mapping")
parser_units.set_defaults(func=partial(updateUnits, topsrcdir))
parser_numbering_systems = subparsers.add_parser("numbering",
help="Update numbering systems with simple "
"digit mappings")
parser_numbering_systems.set_defaults(func=partial(updateNumberingSystems, topsrcdir))
args = parser.parse_args()
args.func(args)

View File

@ -507,6 +507,7 @@ selfhosted_inputs = [
'builtin/WeakMap.js',
'builtin/WeakSet.js'
] + ([
'builtin/intl/NumberingSystemsGenerated.h',
'builtin/intl/Collator.js',
'builtin/intl/CommonFunctions.js',
'builtin/intl/CurrencyDataGenerated.js',

View File

@ -1,90 +1,328 @@
// Generated by make_intl_data.py. DO NOT EDIT.
// source: CLDR file common/bcp47/number.xml; version CLDR 37.
// https://github.com/unicode-org/cldr/blob/master/common/bcp47/number.xml
// https://github.com/unicode-org/cldr/blob/master/common/supplemental/numberingSystems.xml
const numberingSystems = {
"adlm": {digits: "𞥐𞥑𞥒𞥓𞥔𞥕𞥖𞥗𞥘𞥙", algorithmic: false},
"ahom": {digits: "𑜰𑜱𑜲𑜳𑜴𑜵𑜶𑜷𑜸𑜹", algorithmic: false},
"arab": {digits: "٠١٢٣٤٥٦٧٨٩", algorithmic: false},
"arabext": {digits: "۰۱۲۳۴۵۶۷۸۹", algorithmic: false},
"armn": {algorithmic: true},
"armnlow": {algorithmic: true},
"bali": {digits: "᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙", algorithmic: false},
"beng": {digits: "০১২৩৪৫৬৭৮৯", algorithmic: false},
"bhks": {digits: "𑱐𑱑𑱒𑱓𑱔𑱕𑱖𑱗𑱘𑱙", algorithmic: false},
"brah": {digits: "𑁦𑁧𑁨𑁩𑁪𑁫𑁬𑁭𑁮𑁯", algorithmic: false},
"cakm": {digits: "𑄶𑄷𑄸𑄹𑄺𑄻𑄼𑄽𑄾𑄿", algorithmic: false},
"cham": {digits: "꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙", algorithmic: false},
"cyrl": {algorithmic: true},
"deva": {digits: "०१२३४५६७८९", algorithmic: false},
"diak": {digits: "𑥐𑥑𑥒𑥓𑥔𑥕𑥖𑥗𑥘𑥙", algorithmic: false},
"ethi": {algorithmic: true},
"fullwide": {digits: "", algorithmic: false},
"geor": {algorithmic: true},
"gong": {digits: "𑶠𑶡𑶢𑶣𑶤𑶥𑶦𑶧𑶨𑶩", algorithmic: false},
"gonm": {digits: "𑵐𑵑𑵒𑵓𑵔𑵕𑵖𑵗𑵘𑵙", algorithmic: false},
"grek": {algorithmic: true},
"greklow": {algorithmic: true},
"gujr": {digits: "૦૧૨૩૪૫૬૭૮૯", algorithmic: false},
"guru": {digits: "੦੧੨੩੪੫੬੭੮੯", algorithmic: false},
"hanidays": {algorithmic: true},
"hanidec": {digits: "〇一二三四五六七八九", algorithmic: false},
"hans": {algorithmic: true},
"hansfin": {algorithmic: true},
"hant": {algorithmic: true},
"hantfin": {algorithmic: true},
"hebr": {algorithmic: true},
"hmng": {digits: "𖭐𖭑𖭒𖭓𖭔𖭕𖭖𖭗𖭘𖭙", algorithmic: false},
"hmnp": {digits: "𞅀𞅁𞅂𞅃𞅄𞅅𞅆𞅇𞅈𞅉", algorithmic: false},
"java": {digits: "꧐꧑꧒꧓꧔꧕꧖꧗꧘꧙", algorithmic: false},
"jpan": {algorithmic: true},
"jpanfin": {algorithmic: true},
"jpanyear": {algorithmic: true},
"kali": {digits: "꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉", algorithmic: false},
"khmr": {digits: "០១២៣៤៥៦៧៨៩", algorithmic: false},
"knda": {digits: "೦೧೨೩೪೫೬೭೮೯", algorithmic: false},
"lana": {digits: "᪀᪁᪂᪃᪄᪅᪆᪇᪈᪉", algorithmic: false},
"lanatham": {digits: "᪐᪑᪒᪓᪔᪕᪖᪗᪘᪙", algorithmic: false},
"laoo": {digits: "໐໑໒໓໔໕໖໗໘໙", algorithmic: false},
"latn": {digits: "0123456789", algorithmic: false},
"lepc": {digits: "᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉", algorithmic: false},
"limb": {digits: "᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏", algorithmic: false},
"mathbold": {digits: "𝟎𝟏𝟐𝟑𝟒𝟓𝟔𝟕𝟖𝟗", algorithmic: false},
"mathdbl": {digits: "𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡", algorithmic: false},
"mathmono": {digits: "𝟶𝟷𝟸𝟹𝟺𝟻𝟼𝟽𝟾𝟿", algorithmic: false},
"mathsanb": {digits: "𝟬𝟭𝟮𝟯𝟰𝟱𝟲𝟳𝟴𝟵", algorithmic: false},
"mathsans": {digits: "𝟢𝟣𝟤𝟥𝟦𝟧𝟨𝟩𝟪𝟫", algorithmic: false},
"mlym": {digits: "൦൧൨൩൪൫൬൭൮൯", algorithmic: false},
"modi": {digits: "𑙐𑙑𑙒𑙓𑙔𑙕𑙖𑙗𑙘𑙙", algorithmic: false},
"mong": {digits: "᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙", algorithmic: false},
"mroo": {digits: "𖩠𖩡𖩢𖩣𖩤𖩥𖩦𖩧𖩨𖩩", algorithmic: false},
"mtei": {digits: "꯰꯱꯲꯳꯴꯵꯶꯷꯸꯹", algorithmic: false},
"mymr": {digits: "၀၁၂၃၄၅၆၇၈၉", algorithmic: false},
"mymrshan": {digits: "႐႑႒႓႔႕႖႗႘႙", algorithmic: false},
"mymrtlng": {digits: "꧰꧱꧲꧳꧴꧵꧶꧷꧸꧹", algorithmic: false},
"newa": {digits: "𑑐𑑑𑑒𑑓𑑔𑑕𑑖𑑗𑑘𑑙", algorithmic: false},
"nkoo": {digits: "߀߁߂߃߄߅߆߇߈߉", algorithmic: false},
"olck": {digits: "᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙", algorithmic: false},
"orya": {digits: "୦୧୨୩୪୫୬୭୮୯", algorithmic: false},
"osma": {digits: "𐒠𐒡𐒢𐒣𐒤𐒥𐒦𐒧𐒨𐒩", algorithmic: false},
"rohg": {digits: "𐴰𐴱𐴲𐴳𐴴𐴵𐴶𐴷𐴸𐴹", algorithmic: false},
"roman": {algorithmic: true},
"romanlow": {algorithmic: true},
"saur": {digits: "꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙", algorithmic: false},
"segment": {digits: "🯰🯱🯲🯳🯴🯵🯶🯷🯸🯹", algorithmic: false},
"shrd": {digits: "𑇐𑇑𑇒𑇓𑇔𑇕𑇖𑇗𑇘𑇙", algorithmic: false},
"sind": {digits: "𑋰𑋱𑋲𑋳𑋴𑋵𑋶𑋷𑋸𑋹", algorithmic: false},
"sinh": {digits: "෦෧෨෩෪෫෬෭෮෯", algorithmic: false},
"sora": {digits: "𑃰𑃱𑃲𑃳𑃴𑃵𑃶𑃷𑃸𑃹", algorithmic: false},
"sund": {digits: "᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹", algorithmic: false},
"takr": {digits: "𑛀𑛁𑛂𑛃𑛄𑛅𑛆𑛇𑛈𑛉", algorithmic: false},
"talu": {digits: "᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙", algorithmic: false},
"taml": {algorithmic: true},
"tamldec": {digits: "௦௧௨௩௪௫௬௭௮௯", algorithmic: false},
"telu": {digits: "౦౧౨౩౪౫౬౭౮౯", algorithmic: false},
"thai": {digits: "๐๑๒๓๔๕๖๗๘๙", algorithmic: false},
"tibt": {digits: "༠༡༢༣༤༥༦༧༨༩", algorithmic: false},
"tirh": {digits: "𑓐𑓑𑓒𑓓𑓔𑓕𑓖𑓗𑓘𑓙", algorithmic: false},
"vaii": {digits: "꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩", algorithmic: false},
"wara": {digits: "𑣠𑣡𑣢𑣣𑣤𑣥𑣦𑣧𑣨𑣩", algorithmic: false},
"wcho": {digits: "𞋰𞋱𞋲𞋳𞋴𞋵𞋶𞋷𞋸𞋹", algorithmic: false},
"adlm": {
"algorithmic": false,
"digits": "𞥐𞥑𞥒𞥓𞥔𞥕𞥖𞥗𞥘𞥙"
},
"ahom": {
"algorithmic": false,
"digits": "𑜰𑜱𑜲𑜳𑜴𑜵𑜶𑜷𑜸𑜹"
},
"arab": {
"algorithmic": false,
"digits": "٠١٢٣٤٥٦٧٨٩"
},
"arabext": {
"algorithmic": false,
"digits": "۰۱۲۳۴۵۶۷۸۹"
},
"armn": {
"algorithmic": true
},
"armnlow": {
"algorithmic": true
},
"bali": {
"algorithmic": false,
"digits": "᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙"
},
"beng": {
"algorithmic": false,
"digits": "০১২৩৪৫৬৭৮৯"
},
"bhks": {
"algorithmic": false,
"digits": "𑱐𑱑𑱒𑱓𑱔𑱕𑱖𑱗𑱘𑱙"
},
"brah": {
"algorithmic": false,
"digits": "𑁦𑁧𑁨𑁩𑁪𑁫𑁬𑁭𑁮𑁯"
},
"cakm": {
"algorithmic": false,
"digits": "𑄶𑄷𑄸𑄹𑄺𑄻𑄼𑄽𑄾𑄿"
},
"cham": {
"algorithmic": false,
"digits": "꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙"
},
"cyrl": {
"algorithmic": true
},
"deva": {
"algorithmic": false,
"digits": "०१२३४५६७८९"
},
"diak": {
"algorithmic": false,
"digits": "𑥐𑥑𑥒𑥓𑥔𑥕𑥖𑥗𑥘𑥙"
},
"ethi": {
"algorithmic": true
},
"fullwide": {
"algorithmic": false,
"digits": ""
},
"geor": {
"algorithmic": true
},
"gong": {
"algorithmic": false,
"digits": "𑶠𑶡𑶢𑶣𑶤𑶥𑶦𑶧𑶨𑶩"
},
"gonm": {
"algorithmic": false,
"digits": "𑵐𑵑𑵒𑵓𑵔𑵕𑵖𑵗𑵘𑵙"
},
"grek": {
"algorithmic": true
},
"greklow": {
"algorithmic": true
},
"gujr": {
"algorithmic": false,
"digits": "૦૧૨૩૪૫૬૭૮૯"
},
"guru": {
"algorithmic": false,
"digits": "੦੧੨੩੪੫੬੭੮੯"
},
"hanidays": {
"algorithmic": true
},
"hanidec": {
"algorithmic": false,
"digits": "〇一二三四五六七八九"
},
"hans": {
"algorithmic": true
},
"hansfin": {
"algorithmic": true
},
"hant": {
"algorithmic": true
},
"hantfin": {
"algorithmic": true
},
"hebr": {
"algorithmic": true
},
"hmng": {
"algorithmic": false,
"digits": "𖭐𖭑𖭒𖭓𖭔𖭕𖭖𖭗𖭘𖭙"
},
"hmnp": {
"algorithmic": false,
"digits": "𞅀𞅁𞅂𞅃𞅄𞅅𞅆𞅇𞅈𞅉"
},
"java": {
"algorithmic": false,
"digits": "꧐꧑꧒꧓꧔꧕꧖꧗꧘꧙"
},
"jpan": {
"algorithmic": true
},
"jpanfin": {
"algorithmic": true
},
"jpanyear": {
"algorithmic": true
},
"kali": {
"algorithmic": false,
"digits": "꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉"
},
"khmr": {
"algorithmic": false,
"digits": "០១២៣៤៥៦៧៨៩"
},
"knda": {
"algorithmic": false,
"digits": "೦೧೨೩೪೫೬೭೮೯"
},
"lana": {
"algorithmic": false,
"digits": "᪀᪁᪂᪃᪄᪅᪆᪇᪈᪉"
},
"lanatham": {
"algorithmic": false,
"digits": "᪐᪑᪒᪓᪔᪕᪖᪗᪘᪙"
},
"laoo": {
"algorithmic": false,
"digits": "໐໑໒໓໔໕໖໗໘໙"
},
"latn": {
"algorithmic": false,
"digits": "0123456789"
},
"lepc": {
"algorithmic": false,
"digits": "᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉"
},
"limb": {
"algorithmic": false,
"digits": "᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏"
},
"mathbold": {
"algorithmic": false,
"digits": "𝟎𝟏𝟐𝟑𝟒𝟓𝟔𝟕𝟖𝟗"
},
"mathdbl": {
"algorithmic": false,
"digits": "𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡"
},
"mathmono": {
"algorithmic": false,
"digits": "𝟶𝟷𝟸𝟹𝟺𝟻𝟼𝟽𝟾𝟿"
},
"mathsanb": {
"algorithmic": false,
"digits": "𝟬𝟭𝟮𝟯𝟰𝟱𝟲𝟳𝟴𝟵"
},
"mathsans": {
"algorithmic": false,
"digits": "𝟢𝟣𝟤𝟥𝟦𝟧𝟨𝟩𝟪𝟫"
},
"mlym": {
"algorithmic": false,
"digits": "൦൧൨൩൪൫൬൭൮൯"
},
"modi": {
"algorithmic": false,
"digits": "𑙐𑙑𑙒𑙓𑙔𑙕𑙖𑙗𑙘𑙙"
},
"mong": {
"algorithmic": false,
"digits": "᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙"
},
"mroo": {
"algorithmic": false,
"digits": "𖩠𖩡𖩢𖩣𖩤𖩥𖩦𖩧𖩨𖩩"
},
"mtei": {
"algorithmic": false,
"digits": "꯰꯱꯲꯳꯴꯵꯶꯷꯸꯹"
},
"mymr": {
"algorithmic": false,
"digits": "၀၁၂၃၄၅၆၇၈၉"
},
"mymrshan": {
"algorithmic": false,
"digits": "႐႑႒႓႔႕႖႗႘႙"
},
"mymrtlng": {
"algorithmic": false,
"digits": "꧰꧱꧲꧳꧴꧵꧶꧷꧸꧹"
},
"newa": {
"algorithmic": false,
"digits": "𑑐𑑑𑑒𑑓𑑔𑑕𑑖𑑗𑑘𑑙"
},
"nkoo": {
"algorithmic": false,
"digits": "߀߁߂߃߄߅߆߇߈߉"
},
"olck": {
"algorithmic": false,
"digits": "᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙"
},
"orya": {
"algorithmic": false,
"digits": "୦୧୨୩୪୫୬୭୮୯"
},
"osma": {
"algorithmic": false,
"digits": "𐒠𐒡𐒢𐒣𐒤𐒥𐒦𐒧𐒨𐒩"
},
"rohg": {
"algorithmic": false,
"digits": "𐴰𐴱𐴲𐴳𐴴𐴵𐴶𐴷𐴸𐴹"
},
"roman": {
"algorithmic": true
},
"romanlow": {
"algorithmic": true
},
"saur": {
"algorithmic": false,
"digits": "꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙"
},
"segment": {
"algorithmic": false,
"digits": "🯰🯱🯲🯳🯴🯵🯶🯷🯸🯹"
},
"shrd": {
"algorithmic": false,
"digits": "𑇐𑇑𑇒𑇓𑇔𑇕𑇖𑇗𑇘𑇙"
},
"sind": {
"algorithmic": false,
"digits": "𑋰𑋱𑋲𑋳𑋴𑋵𑋶𑋷𑋸𑋹"
},
"sinh": {
"algorithmic": false,
"digits": "෦෧෨෩෪෫෬෭෮෯"
},
"sora": {
"algorithmic": false,
"digits": "𑃰𑃱𑃲𑃳𑃴𑃵𑃶𑃷𑃸𑃹"
},
"sund": {
"algorithmic": false,
"digits": "᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹"
},
"takr": {
"algorithmic": false,
"digits": "𑛀𑛁𑛂𑛃𑛄𑛅𑛆𑛇𑛈𑛉"
},
"talu": {
"algorithmic": false,
"digits": "᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙"
},
"taml": {
"algorithmic": true
},
"tamldec": {
"algorithmic": false,
"digits": "௦௧௨௩௪௫௬௭௮௯"
},
"telu": {
"algorithmic": false,
"digits": "౦౧౨౩౪౫౬౭౮౯"
},
"thai": {
"algorithmic": false,
"digits": "๐๑๒๓๔๕๖๗๘๙"
},
"tibt": {
"algorithmic": false,
"digits": "༠༡༢༣༤༥༦༧༨༩"
},
"tirh": {
"algorithmic": false,
"digits": "𑓐𑓑𑓒𑓓𑓔𑓕𑓖𑓗𑓘𑓙"
},
"vaii": {
"algorithmic": false,
"digits": "꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩"
},
"wara": {
"algorithmic": false,
"digits": "𑣠𑣡𑣢𑣣𑣤𑣥𑣦𑣧𑣨𑣩"
},
"wcho": {
"algorithmic": false,
"digits": "𞋰𞋱𞋲𞋳𞋴𞋵𞋶𞋷𞋸𞋹"
}
};