diff --git a/.idea/libraries/json_org.xml b/.idea/libraries/json_org.xml
new file mode 100644
index 00000000000..37a4912e679
--- /dev/null
+++ b/.idea/libraries/json_org.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.xml b/build.xml
index 44f24010bef..e4db33970dc 100644
--- a/build.xml
+++ b/build.xml
@@ -65,6 +65,7 @@
+
@@ -385,6 +386,7 @@
+
diff --git a/js/js.parser/js.parser.iml b/js/js.parser/js.parser.iml
index 9add1fd0a16..8066bb12c1a 100644
--- a/js/js.parser/js.parser.iml
+++ b/js/js.parser/js.parser.iml
@@ -10,5 +10,6 @@
+
\ No newline at end of file
diff --git a/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMap.kt b/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMap.kt
new file mode 100644
index 00000000000..e19e90834a5
--- /dev/null
+++ b/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMap.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.js.parser.sourcemaps
+
+class SourceMap {
+ val groups = mutableListOf()
+}
+
+class SourceMapSegment(
+ val generatedColumnNumber: Int,
+ val sourceFileName: String,
+ val sourceLineNumber: Int,
+ val sourceColumnNumber: Int
+)
+
+class SourceMapGroup {
+ val segments = mutableListOf()
+}
+
+sealed class SourceMapParseResult
+
+class SourceMapSuccess(val value: SourceMap) : SourceMapParseResult()
+
+class SourceMapError(val message: String) : SourceMapParseResult()
\ No newline at end of file
diff --git a/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMapLocationRemapper.kt b/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMapLocationRemapper.kt
new file mode 100644
index 00000000000..5adf792e1ce
--- /dev/null
+++ b/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMapLocationRemapper.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.js.parser.sourcemaps
+
+import org.jetbrains.kotlin.js.backend.ast.JsLocation
+import org.jetbrains.kotlin.js.backend.ast.JsNode
+import org.jetbrains.kotlin.js.backend.ast.RecursiveJsVisitor
+import org.jetbrains.kotlin.js.backend.ast.SourceInfoAwareJsNode
+
+class SourceMapLocationRemapper(val sourceMaps: Map) {
+ fun remap(node: JsNode) {
+ node.accept(visitor)
+ }
+
+ private val visitor = object : RecursiveJsVisitor() {
+ private var lastSourceMap: SourceMap? = null
+ private var lastGroup: SourceMapGroup? = null
+ private var lastSegmentIndex = 0
+
+ override fun visitElement(node: JsNode) {
+ if (node is SourceInfoAwareJsNode) {
+ if (!remapNode(node)) {
+ node.source = null
+ }
+ }
+ super.visitElement(node)
+ }
+
+ private fun remapNode(node: SourceInfoAwareJsNode): Boolean {
+ val source = node.source as? JsLocation ?: return false
+
+ val sourceMap = sourceMaps[source.file] ?: return false
+ val group = sourceMap.groups.getOrElse(source.startLine) { return false }
+ if (group.segments.isEmpty()) return false
+
+ if (lastSourceMap != sourceMap || lastGroup != group) {
+ lastSegmentIndex = 0
+ }
+ if (group.segments[lastSegmentIndex].generatedColumnNumber > source.startChar) {
+ if (lastSegmentIndex == 0) return false
+ lastSegmentIndex = 0
+ }
+
+ while (lastSegmentIndex + 1 < group.segments.size) {
+ val nextIndex = lastSegmentIndex + 1
+ if (group.segments[nextIndex].generatedColumnNumber > source.startChar) break
+ lastSegmentIndex = nextIndex
+ }
+
+ val segment = group.segments[lastSegmentIndex]
+ node.source = JsLocation(segment.sourceFileName, segment.sourceLineNumber, segment.sourceColumnNumber)
+
+ return true
+ }
+ }
+}
\ No newline at end of file
diff --git a/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMapParser.kt b/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMapParser.kt
new file mode 100644
index 00000000000..65323b064f1
--- /dev/null
+++ b/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMapParser.kt
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.js.parser.sourcemaps
+
+import org.json.JSONArray
+import org.json.JSONException
+import org.json.JSONObject
+import org.json.JSONTokener
+import java.io.IOException
+import java.io.Reader
+
+object SourceMapParser {
+ @Throws(IOException::class)
+ fun parse(reader: Reader): SourceMapParseResult {
+ val jsonObject = try {
+ JSONObject(JSONTokener(reader))
+ }
+ catch (e: JSONException) {
+ return SourceMapError(e.message ?: "parse error")
+ }
+
+ if (!jsonObject.has("version")) return SourceMapError("Version not defined")
+ jsonObject.get("version").let {
+ if (it != 3) return SourceMapError("Unsupported version: $it")
+ }
+
+ val sourceRoot = if (jsonObject.has("sourceRoot")) {
+ jsonObject.get("sourceRoot") as? String ?: return SourceMapError("'sourceRoot' property is not of string type")
+ }
+ else {
+ ""
+ }
+
+ val sources = if (jsonObject.has("sources")) {
+ val sourcesProperty = jsonObject.get("sources") as? JSONArray ?:
+ return SourceMapError("'sources' property is not of array type")
+ sourcesProperty.map {
+ it as? String ?: return SourceMapError("'sources' array must contain strings")
+ }
+ }
+ else {
+ emptyList()
+ }
+
+ if (!jsonObject.has("mappings")) return SourceMapError("'mappings' property not found")
+ val mappings = jsonObject.get("mappings") as? String ?: return SourceMapError("'mappings' property is not of string type")
+
+ var jsColumn = 0
+ var sourceLine = 0
+ var sourceColumn = 0
+ var sourceIndex = 0
+ val stream = MappingStream(mappings)
+ val sourceMap = SourceMap()
+ var currentGroup = SourceMapGroup().also { sourceMap.groups += it }
+
+ while (!stream.isEof) {
+ if (stream.isGroupTerminator) {
+ currentGroup = SourceMapGroup().also { sourceMap.groups += it }
+ jsColumn = 0
+ stream.skipChar()
+ continue
+ }
+
+ jsColumn += stream.readInt() ?: return stream.createError("VLQ-encoded JS column number expected")
+
+ if (stream.isEncodedInt) {
+ sourceIndex += stream.readInt() ?: return stream.createError("VLQ-encoded source index expected")
+ sourceLine += stream.readInt() ?: return stream.createError("VLQ-encoded source line expected")
+ sourceColumn += stream.readInt() ?: return stream.createError("VLQ-encoded source column expected")
+ if (stream.isEncodedInt) {
+ stream.readInt() ?: return stream.createError("VLQ-encoded name index expected")
+ }
+ }
+
+ if (sourceIndex !in sources.indices) {
+ return stream.createError("Source index $sourceIndex is out of bounds ${sources.indices}")
+ }
+
+ currentGroup.segments += SourceMapSegment(jsColumn, sourceRoot + sources[sourceIndex], sourceLine, sourceColumn)
+
+ when {
+ stream.isEof -> return stream.createError("Unexpected EOF, ',' or ';' expected")
+ stream.isGroupTerminator -> {
+ currentGroup = SourceMapGroup().also { sourceMap.groups += it }
+ jsColumn = 0
+ }
+ !stream.isSegmentTerminator -> return stream.createError("Unexpected char, ',' or ';' expected")
+ }
+ stream.skipChar()
+ }
+
+ return SourceMapSuccess(sourceMap)
+ }
+
+ internal class MappingStream(val string: String) {
+ var position = 0
+
+ val isEof: Boolean get() = position == string.length
+
+ val isSegmentTerminator: Boolean get() = string[position] == ','
+
+ val isGroupTerminator: Boolean get() = string[position] == ';'
+
+ val isEncodedInt: Boolean get() = !isEof && !isSegmentTerminator && !isGroupTerminator
+
+ fun skipChar() {
+ position++
+ }
+
+ fun readInt(): Int? {
+ var value = 0
+ var shift = 0
+ while (true) {
+ if (isEof) return null
+ val digit = base64value(string[position++]) ?: return null
+
+ val digitValue = digit and 0x1F
+ value = value or (digitValue shl shift)
+
+ if ((digit and 0x20) == 0) break
+ shift += 5
+ }
+
+ val unsignedValue = value ushr 1
+ return if ((value and 1) == 0) unsignedValue else -unsignedValue
+ }
+
+ private fun base64value(c: Char): Int? = when (c) {
+ in 'A'..'Z' -> c.toInt() - 'A'.toInt()
+ in 'a'..'z' -> c.toInt() - 'a'.toInt() + 26
+ in '0'..'9' -> c.toInt() - '0'.toInt() + 52
+ '+' -> 62
+ '/' -> 63
+ else -> null
+ }
+
+ fun createError(error: String): SourceMapError = SourceMapError("Error parsing stream at offset $position: $error")
+ }
+}
diff --git a/update_dependencies.xml b/update_dependencies.xml
index 9ed51affeea..e7dfbbba92e 100644
--- a/update_dependencies.xml
+++ b/update_dependencies.xml
@@ -295,6 +295,9 @@
+
+
+