test262/tools/packaging/monkeyYaml.py

127 lines
3.6 KiB
Python

#!/usr/bin/env python
# Copyright 2014 by Sam Mikes. All rights reserved.
# This code is governed by the BSD license found in the LICENSE file.
# This code provides a fallback parser that can handle the subset of
# YAML used in test262 frontmatter
import re
mYamlKV = re.compile(r"(.*?):(.*)")
mYamlIntDigits = re.compile(r"^[-0-9]*$")
mYamlFloatDigits = re.compile(r"^[-.0-9eE]*$")
mYamlListPattern = re.compile(r"^\[(.*)\]$")
mYamlMultilineList = re.compile(r"^ *- (.*)$")
def load(str):
return myReadDict(str.splitlines())[1]
def myReadDict(lines, indent=""):
dict = None
key = None
emptyLines = 0
while lines:
if not lines[0].startswith(indent):
break
line = lines.pop(0)
if myIsAllSpaces(line):
emptyLines += 1
continue
result = mYamlKV.match(line)
if result:
if not dict:
dict = {}
key = result.group(1).strip()
value = result.group(2).strip()
(lines, value) = myReadValue(lines, value, indent)
dict[key] = value
else:
if dict and key and key in dict:
c = " " if emptyLines == 0 else "\n" * emptyLines
dict[key] += c + line.strip()
else:
raise Exception("monkeyYaml is confused at " + line)
emptyLines = 0
return lines, dict
def myReadValue(lines, value, indent):
if value == ">" or value == "|":
(lines, value) = myMultiline(lines, value)
value = value + "\n"
return (lines, value)
if lines and not value:
if myMaybeList(lines[0]):
return myMultilineList(lines, value)
indentMatch = re.match("(" + indent + r"\s+)", lines[0])
if indentMatch:
return myReadDict(lines, indentMatch.group(1))
return lines, myReadOneLine(value)
def myMaybeList(value):
return mYamlMultilineList.match(value)
def myMultilineList(lines, value):
# assume no explcit indentor (otherwise have to parse value)
value = []
indent = None
while lines:
line = lines.pop(0)
leading = myLeadingSpaces(line)
if myIsAllSpaces(line):
pass
elif indent is not None and leading < indent:
lines.insert(0, line)
break;
else:
indent = indent or leading
value += [myReadOneLine(myRemoveListHeader(indent, line))]
return (lines, value)
def myRemoveListHeader(indent, line):
line = line[indent:]
return mYamlMultilineList.match(line).group(1)
def myReadOneLine(value):
if mYamlListPattern.match(value):
return myFlowList(value)
elif mYamlIntDigits.match(value):
try:
value = int(value)
except ValueError:
pass
elif mYamlFloatDigits.match(value):
try:
value = float(value)
except ValueError:
pass
return value
def myFlowList(value):
result = mYamlListPattern.match(value)
values = result.group(1).split(",")
return [myReadOneLine(v.strip()) for v in values]
def myMultiline(lines, value):
# assume no explcit indentor (otherwise have to parse value)
value = []
indent = myLeadingSpaces(lines[0])
while lines:
line = lines.pop(0)
if myIsAllSpaces(line):
value += ["\n"]
elif myLeadingSpaces(line) < indent:
lines.insert(0, line)
break;
else:
value += [line[(indent):]]
value = " ".join(value)
return (lines, value)
def myIsAllSpaces(line):
return len(line.strip()) == 0
def myLeadingSpaces(line):
return len(line) - len(line.lstrip(' '))