742 строки
28 KiB
Python
Executable File
742 строки
28 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# line-directive.py - Transform line numbers in error messages -*- python -*-
|
|
#
|
|
# This source file is part of the Swift.org open source project
|
|
#
|
|
# Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
# Licensed under Apache License v2.0 with Runtime Library Exception
|
|
#
|
|
# See https://swift.org/LICENSE.txt for license information
|
|
# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
#
|
|
# ----------------------------------------------------------------------------
|
|
from __future__ import print_function
|
|
|
|
import bisect
|
|
import os
|
|
import re
|
|
import shlex
|
|
import subprocess
|
|
import sys
|
|
|
|
usage = '''"#sourceLocation" is a directive used by tools like the Swift
|
|
compiler and debugger to adjust the lines reported in diagnostics and to
|
|
determine what source you see when you're stepping. "#sourceLocation"
|
|
corresponds to "#line" in C/C++ which is inserted by code generators like
|
|
Lex/Flex/Yacc/Bison so that you deal with the actual code you wrote and not the
|
|
generated result. For dealing with errors in the Swift generated by your gyb
|
|
source it's important that your tools can take you to the right line in your
|
|
.gyb file rather than in generated .swift file. If you don't have such a tool,
|
|
manually indirecting through the generated code is tedious, but at least it's
|
|
possible since gyb leaves "#sourceLocation" information behind.
|
|
|
|
But Swift's "#sourceLocation" directive is suboptimal for the purposes of the
|
|
freeform code generation done with gyb because it can only appear between
|
|
grammatically-complete declarations and statements (or something like that). So
|
|
instead of inserting "#sourceLocation" directives, gyb inserts "//
|
|
###sourceLocation" comments (by default---it's tunable). This line-directive
|
|
tool remaps file and line information in the output of your swift compiler (or
|
|
whatever tool you are using to process generated source---gyb is not
|
|
swift-specific) so that the error points to the right place in the .gyb
|
|
source. You invoke it as follows:
|
|
|
|
line-directive <generated-sources> -- <compilation command>
|
|
|
|
e.g., if you have foo.swift.gyb, bar.swift.gyb, and baz.swift, instead of
|
|
|
|
gyb foo.swift.gyb -o foo.swift
|
|
gyb bar.swift.gyb -o bar.swift
|
|
swiftc foo.swift bar.swift baz.swift
|
|
|
|
You do this:
|
|
|
|
gyb foo.swift.gyb -o foo.swift
|
|
gyb bar.swift.gyb -o bar.swift
|
|
line-directive foo.swift bar.swift -- swiftc foo.swift bar.swift baz.swift
|
|
'''
|
|
|
|
line_pattern = re.compile(
|
|
r'^// ###sourceLocation\(file:\s*"([^"]+)",\s*line:\s*([0-9]+)\s*\)')
|
|
|
|
|
|
def _make_line_map(target_filename, stream=None):
|
|
"""
|
|
>>> from StringIO import StringIO
|
|
>>> _make_line_map('box',
|
|
... StringIO('''// ###sourceLocation(file: "foo.bar", line: 3)
|
|
... line 2
|
|
... line 3
|
|
... line 4
|
|
... // ###sourceLocation(file: "baz.txt", line: 20)
|
|
... line 6
|
|
... line 7
|
|
... '''))
|
|
[(0, 'box', 1), (1, 'foo.bar', 3), (5, 'baz.txt', 20)]
|
|
"""
|
|
result = [(0, target_filename, 1)]
|
|
input = stream or open(target_filename)
|
|
for i, l in enumerate(input.readlines()):
|
|
m = line_pattern.match(l)
|
|
if m:
|
|
result.append((i + 1, m.group(1), int(m.group(2))))
|
|
return result
|
|
|
|
|
|
_line_maps = {}
|
|
|
|
|
|
def fline_map(target_filename):
|
|
map = _line_maps.get(target_filename)
|
|
if map is None:
|
|
map = _make_line_map(target_filename)
|
|
_line_maps[target_filename] = map
|
|
return map
|
|
|
|
|
|
def map_line_to_source_file(target_filename, target_line_num):
|
|
"""
|
|
>>> from tempfile import *
|
|
>>> # On Windows, the name of a NamedTemporaryFile cannot be used to open
|
|
>>> # the file for a second time if delete=True. Therefore, we have to
|
|
>>> # manually handle closing and deleting this file to allow us to open
|
|
>>> # the file by its name across all platforms.
|
|
>>> t = NamedTemporaryFile(delete=False)
|
|
>>> t.write('''line 1
|
|
... line 2
|
|
... // ###sourceLocation(file: "foo.bar", line: 20)
|
|
... line 4
|
|
... line 5
|
|
... // ###sourceLocation(file: "baz.txt", line: 5)
|
|
... line 7
|
|
... line 8
|
|
... ''')
|
|
>>> t.flush()
|
|
>>> (t2, l) = map_line_to_source_file(t.name, 1)
|
|
>>> t2 == t.name, l
|
|
(True, 1)
|
|
>>> (t2, l) = map_line_to_source_file(t.name, 2)
|
|
>>> t2 == t.name, l
|
|
(True, 2)
|
|
>>> (t2, l) = map_line_to_source_file(t.name, 3)
|
|
>>> t2 == t.name, l
|
|
(True, 3)
|
|
>>> map_line_to_source_file(t.name, 4)
|
|
('foo.bar', 20)
|
|
>>> map_line_to_source_file(t.name, 5)
|
|
('foo.bar', 21)
|
|
>>> map_line_to_source_file(t.name, 6)
|
|
('foo.bar', 22)
|
|
>>> map_line_to_source_file(t.name, 7)
|
|
('baz.txt', 5)
|
|
>>> map_line_to_source_file(t.name, 8)
|
|
('baz.txt', 6)
|
|
>>> map_line_to_source_file(t.name, 42)
|
|
('baz.txt', 40)
|
|
>>> t.close()
|
|
>>> os.remove(t.name)
|
|
"""
|
|
assert(target_line_num > 0)
|
|
map = fline_map(target_filename)
|
|
index = bisect.bisect_left(map, (target_line_num, '', 0))
|
|
base = map[index - 1]
|
|
return base[1], base[2] + (target_line_num - base[0] - 1)
|
|
|
|
|
|
def map_line_from_source_file(source_filename, source_line_num,
|
|
target_filename):
|
|
"""
|
|
>>> from tempfile import *
|
|
>>> # On Windows, the name of a NamedTemporaryFile cannot be used to open
|
|
>>> # the file for a second time if delete=True. Therefore, we have to
|
|
>>> # manually handle closing and deleting this file to allow us to open
|
|
>>> # the file by its name across all platforms.
|
|
>>> t = NamedTemporaryFile(delete=False)
|
|
>>> t.write('''line 1
|
|
... line 2
|
|
... // ###sourceLocation(file: "foo.bar", line: 20)
|
|
... line 4
|
|
... line 5
|
|
... // ###sourceLocation(file: "baz.txt", line: 5)
|
|
... line 7
|
|
... line 8
|
|
... ''')
|
|
>>> t.flush()
|
|
>>> map_line_from_source_file(t.name, 1, t.name)
|
|
1
|
|
>>> map_line_from_source_file(t.name, 2, t.name)
|
|
2
|
|
>>> map_line_from_source_file(t.name, 3, t.name)
|
|
3
|
|
>>> try: map_line_from_source_file(t.name, 4, t.name)
|
|
... except RuntimeError: pass
|
|
>>> try: map_line_from_source_file('foo.bar', 19, t.name)
|
|
... except RuntimeError: pass
|
|
>>> map_line_from_source_file('foo.bar', 20, t.name)
|
|
4
|
|
>>> map_line_from_source_file('foo.bar', 21, t.name)
|
|
5
|
|
>>> map_line_from_source_file('foo.bar', 22, t.name)
|
|
6
|
|
>>> try: map_line_from_source_file('foo.bar', 23, t.name)
|
|
... except RuntimeError: pass
|
|
>>> map_line_from_source_file('baz.txt', 5, t.name)
|
|
7
|
|
>>> map_line_from_source_file('baz.txt', 6, t.name)
|
|
8
|
|
>>> map_line_from_source_file('baz.txt', 33, t.name)
|
|
35
|
|
>>> try: map_line_from_source_file(t.name, 33, t.name)
|
|
... except RuntimeError: pass
|
|
>>> try: map_line_from_source_file('foo.bar', 2, t.name)
|
|
... except RuntimeError: pass
|
|
>>> t.close()
|
|
>>> os.remove(t.name)
|
|
"""
|
|
assert(source_line_num > 0)
|
|
map = fline_map(target_filename)
|
|
|
|
for i, (target_line_num, found_source_filename,
|
|
found_source_line_num) in enumerate(map):
|
|
if found_source_filename != source_filename:
|
|
continue
|
|
if found_source_line_num > source_line_num:
|
|
continue
|
|
result = target_line_num + (source_line_num - found_source_line_num)
|
|
if i + 1 == len(map) or map[i + 1][0] > result:
|
|
return result + 1
|
|
raise RuntimeError("line not found")
|
|
|
|
|
|
def read_response_file(file_path):
|
|
with open(file_path, 'r') as files:
|
|
# "Make an iterator out of shlex.shlex.get_token, then consume items
|
|
# until it returns None." (Then eagerly convert the result to a list so
|
|
# that we can close the file.)
|
|
return list(iter(shlex.shlex(files, file_path, posix=True).get_token,
|
|
None))
|
|
|
|
|
|
def expand_response_files(files):
|
|
expanded_files = []
|
|
for file_path in files:
|
|
# Read a list of files from a response file.
|
|
if file_path[0] == '@':
|
|
expanded_files.extend(read_response_file(file_path[1:]))
|
|
else:
|
|
expanded_files.append(file_path)
|
|
|
|
return expanded_files
|
|
|
|
|
|
def run():
|
|
"""Simulate a couple of gyb-generated files
|
|
|
|
>>> from tempfile import *
|
|
>>> # On Windows, the name of a NamedTemporaryFile cannot be used to open
|
|
>>> # the file for a second time if delete=True. Therefore, we have to
|
|
>>> # manually handle closing and deleting this file to allow us to open
|
|
>>> # the file by its name across all platforms.
|
|
>>> target1 = NamedTemporaryFile(delete=False)
|
|
>>> target1.write('''line 1
|
|
... line 2
|
|
... // ###sourceLocation(file: "foo.bar", line: 20)
|
|
... line 4
|
|
... line 5
|
|
... // ###sourceLocation(file: "baz.txt", line: 5)
|
|
... line 7
|
|
... line 8
|
|
... ''')
|
|
>>> target1.flush()
|
|
>>> # On Windows, the name of a NamedTemporaryFile cannot be used to open
|
|
>>> # the file for a second time if delete=True. Therefore, we have to
|
|
>>> # manually handle closing and deleting this file to allow us to open
|
|
>>> # the file by its name across all platforms.
|
|
>>> target2 = NamedTemporaryFile(delete=False)
|
|
>>> target2.write('''// ###sourceLocation(file: "foo.bar", line: 7)
|
|
... line 2
|
|
... line 3
|
|
... // ###sourceLocation(file: "fox.box", line: 11)
|
|
... line 5
|
|
... line 6
|
|
... ''')
|
|
>>> target2.flush()
|
|
|
|
Simulate the raw output of compilation
|
|
|
|
>>> # On Windows, the name of a NamedTemporaryFile cannot be used to open
|
|
>>> # the file for a second time if delete=True. Therefore, we have to
|
|
>>> # manually handle closing and deleting this file to allow us to open
|
|
>>> # the file by its name across all platforms.
|
|
>>> raw_output = NamedTemporaryFile(delete=False)
|
|
>>> target1_name, target2_name = target1.name, target2.name
|
|
>>> raw_output.write('''A
|
|
... %(target1_name)s:2:111: error one
|
|
... B
|
|
... %(target1_name)s:4:222: error two
|
|
... C
|
|
... %(target1_name)s:8:333: error three
|
|
... D
|
|
... glitch in file %(target2_name)s:1 assert one
|
|
... E
|
|
... glitch in file %(target2_name)s, line 2 assert two
|
|
... glitch at %(target2_name)s, line 3 assert three
|
|
... glitch at %(target2_name)s:4 assert four
|
|
... glitch in [%(target2_name)s, line 5 assert five
|
|
... glitch in [%(target2_name)s:22 assert six
|
|
... ''' % locals())
|
|
>>> raw_output.flush()
|
|
|
|
Run this tool on the two targets, using a portable version of Unix 'cat' to
|
|
dump the output file.
|
|
|
|
>>> import subprocess
|
|
>>> output = subprocess.check_output([sys.executable,
|
|
... __file__, target1.name, target2.name, '--',
|
|
... sys.executable, '-c',
|
|
... 'import sys;sys.stdout.write(open(sys.argv[1]).read())',
|
|
... raw_output.name], universal_newlines=True)
|
|
|
|
Replace temporary filenames and check it.
|
|
|
|
>>> print(output.replace(target1.name,'TARGET1-NAME')
|
|
... .replace(target2.name,'TARGET2-NAME') + 'EOF')
|
|
A
|
|
TARGET1-NAME:2:111: error one
|
|
B
|
|
foo.bar:20:222: error two
|
|
C
|
|
baz.txt:6:333: error three
|
|
D
|
|
glitch in file TARGET2-NAME:1 assert one
|
|
E
|
|
glitch in file foo.bar, line 7 assert two
|
|
glitch at foo.bar, line 8 assert three
|
|
glitch at foo.bar:9 assert four
|
|
glitch in [fox.box, line 11 assert five
|
|
glitch in [fox.box:28 assert six
|
|
EOF
|
|
>>> print(subprocess.check_output([sys.executable, __file__, 'foo.bar',
|
|
... '21', target1.name],
|
|
... universal_newlines=True), end='')
|
|
5
|
|
>>> print(subprocess.check_output([sys.executable, __file__, 'foo.bar',
|
|
... '8', target2.name],
|
|
... universal_newlines=True), end='')
|
|
3
|
|
|
|
Simulate errors on different line numbers
|
|
>>> # On Windows, the name of a NamedTemporaryFile cannot be used to open
|
|
>>> # the file for a second time if delete=True. Therefore, we have to
|
|
>>> # manually handle closing and deleting this file to allow us to open
|
|
>>> # the file by its name across all platforms.
|
|
>>> long_output = NamedTemporaryFile(delete=False)
|
|
>>> long_output.write('''
|
|
... // ###sourceLocation(file: "/public/core/Map.swift.gyb", line: 1)
|
|
... // ###sourceLocation(file: "/public/core/Map.swift.gyb", line: 1)
|
|
... //===--- Map.swift.gyb - Lazily map over a Sequence -----------*- swif
|
|
... //
|
|
... // This source file is part of the Swift.org open source project
|
|
... //
|
|
... // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
... // Licensed under Apache License v2.0 with Runtime Library Exception
|
|
... //
|
|
... // See https://swift.org/LICENSE.txt for license information
|
|
... // See https://swift.org/CONTRIBUTORS.txt for the list of Swift projec
|
|
... //
|
|
... //===-----------------------------------------------------------------
|
|
...
|
|
... // ###sourceLocation(file: "/public/core/Map.swift.gyb", line: 20)
|
|
...
|
|
... /// The `IteratorProtocol` used by `MapSequence` and `MapCollection`.
|
|
... /// Produces each element by passing the output of the `Base`
|
|
... /// `IteratorProtocol` through a transform function returning
|
|
... @_fixed_layout
|
|
... public struct LazyMapIterator<
|
|
... Base : IteratorProtocol, Element
|
|
... > : IteratorProtocol, Sequence {
|
|
... /// Advances to the next element and returns it, or `nil` if no
|
|
... /// exists.
|
|
... ///
|
|
... /// Once `nil` has been returned, all subsequent calls return `nil`.
|
|
... ///
|
|
... /// - Precondition: `next()` has not been applied to a copy.
|
|
... /// since the copy was made.
|
|
... @_inlineable
|
|
... public mutating func next() -> Element? {
|
|
... return _base.next().map(_transform)
|
|
... }
|
|
...
|
|
... @_inlineable
|
|
... public var base: Base { return _base }
|
|
...
|
|
... @_versioned
|
|
... internal var _base: Base
|
|
... @_versioned
|
|
... internal let _transform: (Base.Element) -> Element
|
|
...
|
|
... @_inlineable
|
|
... @_versioned
|
|
... internal init(_base: Base, _transform: @escaping (Base.Element)
|
|
... self._base = _base
|
|
... self._transform = _transform
|
|
... }
|
|
... }
|
|
...
|
|
... /// A `Sequence` whose elements consist of those in a `Base`
|
|
... /// `Sequence` passed through a transform function returning.
|
|
... /// These elements are computed lazily, each time they're read, by
|
|
... /// calling the transform function on a base element.
|
|
... @_fixed_layout
|
|
... public struct LazyMapSequence<Base : Sequence, Element>
|
|
... : LazySequenceProtocol {
|
|
...
|
|
... public typealias Elements = LazyMapSequence
|
|
...
|
|
... /// Returns an iterator over the elements of this sequence.
|
|
... ///
|
|
... /// - Complexity: O(1).
|
|
... @_inlineable
|
|
... public func makeIterator() -> LazyMapIterator<Base.Iterator, Element
|
|
... return LazyMapIterator(_base: _base.makeIterator(), _transform: _t
|
|
... }
|
|
...
|
|
... /// Returns a value less than or equal to the number of elements in
|
|
... /// `self`, **nondestructively**.
|
|
... ///
|
|
... /// - Complexity: O(*n*)
|
|
... @_inlineable
|
|
... public var underestimatedCount: Int {
|
|
... return _base.underestimatedCount
|
|
... }
|
|
...
|
|
... /// Creates an instance with elements `transform(x)` for each elemen
|
|
... /// `x` of base.
|
|
... @_inlineable
|
|
... @_versioned
|
|
... internal init(_base: Base, transform: @escaping (Base.Iterator.Eleme
|
|
... self._base = _base
|
|
... self._transform = transform
|
|
... }
|
|
...
|
|
... @_versioned
|
|
... internal var _base: Base
|
|
... @_versioned
|
|
... internal let _transform: (Base.Iterator.Element) -> Element
|
|
... }
|
|
...
|
|
... //===--- Collections -------------------------------------------------
|
|
...
|
|
... // FIXME(ABI)#45 (Conditional Conformance): `LazyMap*Collection` types
|
|
... // collapsed into one `LazyMapCollection` using conditional conformanc
|
|
... // Maybe even combined with `LazyMapSequence`.
|
|
... // rdar://problem/17144340
|
|
...
|
|
... // ###sourceLocation(file: "/public/core/Map.swift.gyb", line: 108)
|
|
...
|
|
... /// A `Collection` whose elements consist of those in a `Base`
|
|
... /// `Collection` passed through a transform function returning `Elemen
|
|
... /// These elements are computed lazily, each time they're read, by
|
|
... /// calling the transform function on a base element.
|
|
... @_fixed_layout
|
|
... public struct LazyMapCollection<
|
|
... Base : Collection, Element
|
|
... > : LazyCollectionProtocol,
|
|
... _CollectionWrapper
|
|
... {
|
|
... public typealias Base = Base_
|
|
... public typealias Index = Base.Index
|
|
... public typealias _Element = Base._Element
|
|
... public typealias SubSequence = Base.SubSequence
|
|
... typealias Indices = Base.Indices
|
|
...
|
|
... @_inlineable
|
|
... public subscript(position: Base.Index) -> Element {
|
|
... return _transform(_base[position])
|
|
... }
|
|
...
|
|
... /// Create an instance with elements `transform(x)` for each element
|
|
... /// `x` of base.
|
|
... @_inlineable
|
|
... @_versioned
|
|
... internal init(_base: Base, transform: @escaping (Base.Iterator.Eleme
|
|
... self._base = _base
|
|
... self._transform = transform
|
|
... }
|
|
...
|
|
... @_versioned
|
|
... internal var _base: Base
|
|
... @_versioned
|
|
... internal let _transform: (Base.Iterator.Element) -> Element
|
|
... }
|
|
...
|
|
... // ###sourceLocation(file: "/public/core/Map.swift.gyb", line: 108)
|
|
...
|
|
... /// A `Collection` whose elements consist of those in a `Base`
|
|
... /// `Collection` passed through a transform function returning `Elemen
|
|
... /// These elements are computed lazily, each time they're read, by
|
|
... /// calling the transform function on a base element.
|
|
... @_fixed_layout
|
|
... public struct LazyMapBidirectionalCollection<
|
|
... Base : BidirectionalCollection, Element
|
|
... > : LazyCollectionProtocol,
|
|
... _BidirectionalCollectionWrapper
|
|
... {
|
|
... public typealias Base = Base_
|
|
... public typealias Index = Base.Index
|
|
... public typealias _Element = Base._Element
|
|
... public typealias SubSequence = Base.SubSequence
|
|
... typealias Indices = Base.Indices
|
|
...
|
|
... @_inlineable
|
|
... public subscript(position: Base.Index) -> Element {
|
|
... return _transform(_base[position])
|
|
... }
|
|
...
|
|
... /// Create an instance with elements `transform(x)` for each element
|
|
... /// `x` of base.
|
|
... @_inlineable
|
|
... @_versioned
|
|
... internal init(_base: Base, transform: @escaping (Base.Iterator.Eleme
|
|
... self._base = _base
|
|
... self._transform = transform
|
|
... }
|
|
...
|
|
... @_versioned
|
|
... internal var _base: Base
|
|
... @_versioned
|
|
... internal let _transform: (Base.Iterator.Element) -> Element
|
|
... }
|
|
...
|
|
... // ###sourceLocation(file: "/public/core/Map.swift.gyb", line: 108)
|
|
...
|
|
... /// A `Collection` whose elements consist of those in a `Base`
|
|
... /// `Collection` passed through a transform function returning `Elemen
|
|
... /// These elements are computed lazily, each time they're read, by
|
|
... /// calling the transform function on a base element.
|
|
... @_fixed_layout
|
|
... public struct LazyMapRandomAccessCollection<
|
|
... Base : RandomAccessCollection, Element
|
|
... > : LazyCollectionProtocol,
|
|
... _RandomAccessCollectionWrapper
|
|
... {
|
|
... public typealias Base = Base_
|
|
... public typealias Index = Base.Index
|
|
... public typealias _Element = Base._Element
|
|
... public typealias SubSequence = Base.SubSequence
|
|
... typealias Indices = Base.Indices
|
|
...
|
|
... @_inlineable
|
|
... public subscript(position: Base.Index) -> Element {
|
|
... return _transform(_base[position])
|
|
... }
|
|
...
|
|
... /// Create an instance with elements `transform(x)` for each element
|
|
... /// `x` of base.
|
|
... @_inlineable
|
|
... @_versioned
|
|
... internal init(_base: Base, transform: @escaping (Base.Iterator.Eleme
|
|
... self._base = _base
|
|
... self._transform = transform
|
|
... }
|
|
...
|
|
... @_versioned
|
|
... internal var _base: Base
|
|
... @_versioned
|
|
... internal let _transform: (Base.Iterator.Element) -> Element
|
|
... }
|
|
...
|
|
... // ###sourceLocation(file: "/public/core/Map.swift.gyb", line: 146)
|
|
...
|
|
... //===--- Support for s.lazy ------------------------------------------
|
|
...
|
|
... extension LazySequenceProtocol {
|
|
... /// Returns a `LazyMapSequence` over this `Sequence`. The elements
|
|
... /// the result are computed lazily, each time they are read, by
|
|
... /// calling `transform` function on a base element.
|
|
... @_inlineable
|
|
... public func map<U>(
|
|
... _ transform: @escaping (Elements.Iterator.Element) -> U
|
|
... ) -> LazyMapSequence<Self.Elements, U> {
|
|
... return LazyMapSequence(_base: self.elements, transform: transform)
|
|
... }
|
|
... }
|
|
...
|
|
... // ###sourceLocation(file: "/public/core/Map.swift.gyb", line: 162)
|
|
...
|
|
... extension LazyCollectionProtocol
|
|
... // ###sourceLocation(file: "/public/core/Map.swift.gyb", line: 169)
|
|
... {
|
|
... /// Returns a `LazyMapCollection` over this `Collection`. The eleme
|
|
... /// the result are computed lazily, each time they are read, by
|
|
... /// calling `transform` function on a base element.
|
|
... @_inlineable
|
|
... public func map<U>(
|
|
... _ transform: @escaping (Elements.Iterator.Element) -> U
|
|
... ) -> LazyMapCollection<Self.Elements, U> {
|
|
... return LazyMapCollection(
|
|
... _base: self.elements,
|
|
... transform: transform)
|
|
... }
|
|
... }
|
|
...
|
|
... // ###sourceLocation(file: "/public/core/Map.swift.gyb", line: 162)
|
|
...
|
|
... extension LazyCollectionProtocol
|
|
... // ###sourceLocation(file: "/public/core/Map.swift.gyb", line: 165)
|
|
... where
|
|
... Self : BidirectionalCollection,
|
|
... Elements : BidirectionalCollection
|
|
... // ###sourceLocation(file: "/public/core/Map.swift.gyb", line: 169)
|
|
... {
|
|
... /// Returns a `LazyMapCollection` over this `Collection`. The eleme
|
|
... /// the result are computed lazily, each time they are read, by
|
|
... /// calling `transform` function on a base element.
|
|
... @_inlineable
|
|
... public func map<U>(
|
|
... _ transform: @escaping (Elements.Iterator.Element) -> U
|
|
... ) -> LazyMapBidirectionalCollection<Self.Elements, U> {
|
|
... return LazyMapBidirectionalCollection(
|
|
... _base: self.elements,
|
|
... transform: transform)
|
|
... }
|
|
... }
|
|
...
|
|
... // ###sourceLocation(file: "/public/core/Map.swift.gyb", line: 162)
|
|
...
|
|
... extension LazyCollectionProtocol
|
|
... // ###sourceLocation(file: "/public/core/Map.swift.gyb", line: 165)
|
|
... where
|
|
... Self : RandomAccessCollection,
|
|
... Elements : RandomAccessCollection
|
|
... // ###sourceLocation(file: "/public/core/Map.swift.gyb", line: 169)
|
|
... {
|
|
... /// Returns a `LazyMapCollection` over this `Collection`. The eleme
|
|
... /// the result are computed lazily, each time they are read, by
|
|
... /// calling `transform` function on a base element.
|
|
... @_inlineable
|
|
... public func map<U>(
|
|
... _ transform: @escaping (Elements.Iterator.Element) -> U
|
|
... ) -> LazyMapRandomAccessCollection<Self.Elements, U> {
|
|
... return LazyMapRandomAccessCollection(
|
|
... _base: self.elements,
|
|
... transform: transform)
|
|
... }
|
|
... }
|
|
...
|
|
... // ###sourceLocation(file: "/public/core/Map.swift.gyb", line: 184)
|
|
...
|
|
... @available(*, unavailable, renamed: "LazyMapIterator")
|
|
... public struct LazyMapGenerator<Base : IteratorProtocol, Element> {}
|
|
...
|
|
... extension LazyMapSequence {
|
|
... @available(*, unavailable, message: "use '.lazy.map' on the sequence
|
|
... public init(_ base: Base, transform: (Base.Iterator.Element) -> Elem
|
|
... Builtin.unreachable()
|
|
... }
|
|
... }
|
|
...
|
|
... extension LazyMapCollection {
|
|
... @available(*, unavailable, message: "use '.lazy.map' on the collecti
|
|
... public init(_ base: Base, transform: (Base.Iterator.Element) -> Elem
|
|
... Builtin.unreachable()
|
|
... }
|
|
... }
|
|
...
|
|
... // Local Variables:
|
|
... // eval: (read-only-mode 1)
|
|
... // End:
|
|
... ''')
|
|
>>> long_output.flush()
|
|
>>> long_output_result = subprocess.check_output([sys.executable,
|
|
... __file__, long_output.name, '--',
|
|
... 'echo', long_output.name + ':112:27: error:']).rstrip()
|
|
>>> print(long_output_result)
|
|
/public/core/Map.swift.gyb:117:27: error:
|
|
>>> target1.close()
|
|
>>> os.remove(target1.name)
|
|
>>> target2.close()
|
|
>>> os.remove(target2.name)
|
|
>>> raw_output.close()
|
|
>>> os.remove(raw_output.name)
|
|
|
|
Lint this file.
|
|
>>> import python_lint
|
|
>>> python_lint.lint([os.path.realpath(__file__)], verbose=False)
|
|
0
|
|
"""
|
|
if len(sys.argv) <= 1:
|
|
import doctest
|
|
failure_count, _ = doctest.testmod()
|
|
sys.exit(failure_count)
|
|
elif len(sys.argv) == 2 and sys.argv[1] == '--help':
|
|
print(usage)
|
|
sys.exit(1)
|
|
elif '--' not in sys.argv:
|
|
source_file = sys.argv[1]
|
|
source_line = int(sys.argv[2])
|
|
target_file = sys.argv[3]
|
|
print(map_line_from_source_file(source_file, source_line, target_file))
|
|
else:
|
|
dashes = sys.argv.index('--')
|
|
sources = expand_response_files(sys.argv[1:dashes])
|
|
|
|
# The first argument of command_args is the process to open.
|
|
# subprocess.Popen doesn't normalize arguments. This means that trying
|
|
# to open a non-normalized file (e.g. C:/swift/./bin/swiftc.exe) on
|
|
# Windows results in file/directory not found errors, as Popen
|
|
# delegates to the Win32 CreateProcess API. Unix systems handle
|
|
# non-normalized paths, so don't have this problem.
|
|
# Arguments passed to the process are normalized by the process.
|
|
command_args = expand_response_files(sys.argv[dashes + 1:])
|
|
command_args[0] = os.path.normpath(command_args[0])
|
|
|
|
command = subprocess.Popen(
|
|
command_args,
|
|
stderr=subprocess.STDOUT,
|
|
stdout=subprocess.PIPE,
|
|
universal_newlines=True
|
|
)
|
|
|
|
sources = '(?P<file>' + '|'.join(re.escape(s) for s in sources) + ')'
|
|
|
|
error_pattern = re.compile(
|
|
'^' + sources +
|
|
':(?P<line>[0-9]+):(?P<column>[0-9]+):(?P<tail>.*?)\n?$')
|
|
|
|
assertion_pattern = re.compile(
|
|
'^(?P<head>.*( file | at |#[0-9]+: |[[]))' +
|
|
sources +
|
|
'(?P<middle>, line |:)(?P<line>[0-9]+)(?P<tail>.*?)\n?$')
|
|
|
|
while True:
|
|
input = command.stdout.readline()
|
|
if input == '':
|
|
break
|
|
output = input
|
|
|
|
def decode_match(p, l):
|
|
m = p.match(l)
|
|
if m is None:
|
|
return ()
|
|
file, line_num = map_line_to_source_file(
|
|
m.group('file'), int(m.group('line')))
|
|
return ((m, file, line_num),)
|
|
|
|
for (m, file, line_num) in decode_match(error_pattern, input):
|
|
output = '%s:%s:%s:%s\n' % (
|
|
file, line_num, int(m.group(3)), m.group(4))
|
|
break
|
|
else:
|
|
for (m, file, line_num) in decode_match(assertion_pattern,
|
|
input):
|
|
output = '%s%s%s%s%s\n' % (
|
|
m.group('head'), file, m.group('middle'), line_num,
|
|
m.group('tail'))
|
|
sys.stdout.write(output)
|
|
|
|
sys.exit(command.wait())
|
|
|
|
|
|
if __name__ == '__main__':
|
|
run()
|