• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# Copyright 2014 by Sam Mikes.  All rights reserved.
3# This code is governed by the BSD license found in the LICENSE file.
4
5# This code provides a fallback parser that can handle the subset of
6# YAML used in test262 frontmatter
7
8import re
9
10mYamlKV = re.compile(r"(.*?):(.*)")
11mYamlIntDigits = re.compile(r"^[-0-9]*$")
12mYamlFloatDigits = re.compile(r"^[-.0-9eE]*$")
13mYamlListPattern = re.compile(r"^\[(.*)\]$")
14mYamlMultilineList = re.compile(r"^ *- (.*)$")
15mYamlStringValue = re.compile(r"^('|\").*\1$")
16
17def load(str):
18    return myReadDict(str.splitlines())[1]
19
20def myReadDict(lines, indent=""):
21    dict = None
22    key = None
23    emptyLines = 0
24
25    while lines:
26        if not lines[0].startswith(indent):
27            break
28
29        line = lines.pop(0)
30        if myIsAllSpaces(line):
31            emptyLines += 1
32            continue
33        result = mYamlKV.match(line)
34
35        if result:
36            if not dict:
37                dict = {}
38            key = result.group(1).strip()
39            value = result.group(2).strip()
40            (lines, value) = myReadValue(lines, value, indent)
41            dict[key] = value
42        else:
43            if dict and key and key in dict:
44                c = " " if emptyLines == 0 else "\n" * emptyLines
45                dict[key] += c + line.strip()
46            else:
47                raise Exception("monkeyYaml is confused at " + line)
48        emptyLines = 0
49    return lines, dict
50
51def myReadValue(lines, value, indent):
52    if value == ">" or value == "|":
53        (lines, value) = myMultiline(lines, value == "|")
54        value = value + "\n"
55        return (lines, value)
56    if lines and not value:
57        if myMaybeList(lines[0]):
58            return myMultilineList(lines, value)
59        indentMatch = re.match("(" + indent + r"\s+)", lines[0])
60        if indentMatch:
61            if ":" in lines[0]:
62                return myReadDict(lines, indentMatch.group(1))
63            return myMultiline(lines, False)
64    return lines, myReadOneLine(value)
65
66def myMaybeList(value):
67    return mYamlMultilineList.match(value)
68
69def myMultilineList(lines, value):
70    # assume no explcit indentor (otherwise have to parse value)
71    value = []
72    indent = 0
73    while lines:
74        line = lines.pop(0)
75        leading = myLeadingSpaces(line)
76        if myIsAllSpaces(line):
77            pass
78        elif leading < indent:
79            lines.insert(0, line)
80            break;
81        else:
82            indent = indent or leading
83            value += [myReadOneLine(myRemoveListHeader(indent, line))]
84    return (lines, value)
85
86def myRemoveListHeader(indent, line):
87    line = line[indent:]
88    return mYamlMultilineList.match(line).group(1)
89
90def myReadOneLine(value):
91    if mYamlListPattern.match(value):
92        return myFlowList(value)
93    elif mYamlIntDigits.match(value):
94        try:
95            value = int(value)
96        except ValueError:
97            pass
98    elif mYamlFloatDigits.match(value):
99        try:
100            value = float(value)
101        except ValueError:
102            pass
103    elif mYamlStringValue.match(value):
104        value = value[1:-1]
105    return value
106
107def myFlowList(value):
108    result = mYamlListPattern.match(value)
109    values = result.group(1).split(",")
110    return [myReadOneLine(v.strip()) for v in values]
111
112def myMultiline(lines, preserveNewlines=False):
113    # assume no explcit indentor (otherwise have to parse value)
114    value = ""
115    indent = myLeadingSpaces(lines[0])
116    wasEmpty = None
117
118    while lines:
119        line = lines.pop(0)
120        isEmpty = myIsAllSpaces(line)
121
122        if isEmpty:
123            if preserveNewlines:
124                value += "\n"
125        elif myLeadingSpaces(line) < indent:
126            lines.insert(0, line)
127            break;
128        else:
129            if preserveNewlines:
130                if wasEmpty != None:
131                    value += "\n"
132            else:
133                if wasEmpty == False:
134                    value += " "
135                elif wasEmpty == True:
136                    value += "\n"
137            value += line[(indent):]
138
139        wasEmpty = isEmpty
140
141    return (lines, value)
142
143def myIsAllSpaces(line):
144    return len(line.strip()) == 0
145
146def myLeadingSpaces(line):
147    return len(line) - len(line.lstrip(' '))
148