diff --git a/src/parseTestRecord.py b/src/parseTestRecord.py index 22d5664..6982540 100644 --- a/src/parseTestRecord.py +++ b/src/parseTestRecord.py @@ -6,79 +6,41 @@ # TODO: resolve differences with common.py and unify into one file. -import logging -import optparse +from __future__ import print_function + import os -from os import path -import platform import re -import subprocess -import sys -import tempfile -import time import imp from _monkeyYaml import load as yamlLoad -headerPatternStr = r"(?:(?:\s*\/\/.*)?\s*\n)*" -captureCommentPatternStr = r"\/\*\*?((?:\s|\S)*?)\*\/\s*\n" -anyPatternStr = r"(?:\s|\S)*" - -headerPattern = re.compile("^" + headerPatternStr) - -# Should match anything -testRecordPattern = re.compile(r"^(" + headerPatternStr + - r")(?:" + captureCommentPatternStr + - r")?(" + anyPatternStr + - r")$") - -stars = re.compile(r"\s*\n\s*\*\s?") -atattrs = re.compile(r"\s*\n\s*\*\s*@") - -yamlPattern = re.compile(r"---((?:\s|\S)*)---") -newlinePattern = re.compile(r"\n") - -def stripStars(text): - return stars.sub('\n', text).strip() - -def stripHeader(src): - header = headerPattern.match(src).group(0) - return src[len(header):] - -def matchParts(src, name): - match = testRecordPattern.match(src) - if match == None: - raise Exception('unrecognized: ' + name) - return match - -def hasYAML(text): - match = yamlPattern.match(text) - if match == None: - return False - return True - -def oldAttrParser(testRecord, body, name): - propTexts = atattrs.split(body) - testRecord['commentary'] = stripStars(propTexts[0]) - del propTexts[0] - for propText in propTexts: - propMatch = re.match(r"^\w+", propText) - if propMatch == None: - raise Exception('Malformed "@" attribute: ' + name) - propName = propMatch.group(0) - propVal = stripStars(propText[len(propName):]) - - if propName in testRecord: - raise Exception('duplicate: ' + propName) - testRecord[propName] = propVal; - -def yamlAttrParser(testRecord, attrs, name): - match = yamlPattern.match(attrs) - body = match.group(1) - parsed = yamlLoad(body) - - if (parsed is None): - print "Failed to parse yaml in name %s"%(name) +#def onerror(message): +# print(message) + +# Matches trailing whitespace and any following blank lines. +_BLANK_LINES = r"([ \t]*[\r\n]{1,2})*" + +# Matches the YAML frontmatter block. +_YAML_PATTERN = re.compile(r"/\*---(.*)---\*/" + _BLANK_LINES, re.DOTALL) + +# Matches all known variants for the license block. +_LICENSE_PATTERN = re.compile( + r'// Copyright( \(C\))? (\w+) .+\. {1,2}All rights reserved\.[\r\n]{1,2}' + + r'(' + + r'// This code is governed by the( BSD)? license found in the LICENSE file\.' + + r'|' + + r'// See LICENSE for details\.' + + r'|' + + r'// Use of this source code is governed by a BSD-style license that can be[\r\n]{1,2}' + + r'// found in the LICENSE file\.' + + r'|' + + r'// See LICENSE or https://github\.com/tc39/test262/blob/master/LICENSE' + + r')[\r\n]{1,2}' + _BLANK_LINES, re.IGNORECASE) + +def yamlAttrParser(testRecord, attrs, name, onerror = print): + parsed = yamlLoad(attrs) + if parsed is None: + onerror("Failed to parse yaml in name %s" % name) return for key in parsed: @@ -91,17 +53,60 @@ def yamlAttrParser(testRecord, attrs, name): for flag in testRecord['flags']: testRecord[flag] = "" -def parseTestRecord(src, name): +def findLicense(src): + match = _LICENSE_PATTERN.search(src) + if not match: + return None + + return match.group(0) + +def findAttrs(src): + match = _YAML_PATTERN.search(src) + if not match: + return (None, None) + + return (match.group(0), match.group(1).strip()) + +def parseTestRecord(src, name, onerror = print): + # Find the license block. + header = findLicense(src) + + # Find the YAML frontmatter. + (frontmatter, attrs) = findAttrs(src) + + # YAML frontmatter is required for all tests. + if frontmatter is None: + onerror("Missing frontmatter: %s" % name) + + # The license shuold be placed before the frontmatter and there shouldn't be + # any extra content between the license and the frontmatter. + if header is not None and frontmatter is not None: + headerIdx = src.index(header) + frontmatterIdx = src.index(frontmatter) + if headerIdx > frontmatterIdx: + onerror("Unexpected license after frontmatter: %s" % name) + + # Search for any extra test content, but ignore whitespace only or comment lines. + extra = src[headerIdx + len(header) : frontmatterIdx] + if extra and any(line.strip() and not line.lstrip().startswith("//") for line in extra.split("\n")): + onerror("Unexpected test content between license and frontmatter: %s" % name) + + # Remove the license and YAML parts from the actual test content. + test = src + if frontmatter is not None: + test = test.replace(frontmatter, '') + if header is not None: + test = test.replace(header, '') + testRecord = {} - match = matchParts(src, name) - testRecord['header'] = match.group(1).strip() - testRecord['test'] = match.group(3) # do not trim + testRecord['header'] = header.strip() if header else '' + testRecord['test'] = test - attrs = match.group(2) if attrs: - if hasYAML(attrs): - yamlAttrParser(testRecord, attrs, name) - else: - oldAttrParser(testRecord, attrs, name) + yamlAttrParser(testRecord, attrs, name, onerror) + + # Report if the license block is missing in non-generated tests. + if header is None and "generated" not in testRecord and "hashbang" not in name: + onerror("No license found in: %s" % name) return testRecord