multiline string literals
This commit is contained in:
parent
ed0a21cb06
commit
63de82393a
@ -48,6 +48,7 @@ $$ \ln(1+x)=x-{\dfrac {x^{2}}{2}}+{\dfrac {x^{3}}{3}}-\cdots =\sum \limits _{n=0
|
|||||||
}
|
}
|
||||||
assert( почти_равны( 0.0005, 0.000501 ) )
|
assert( почти_равны( 0.0005, 0.000501 ) )
|
||||||
|
|
||||||
Во многих случаях вычисление $n+1$ члена значительно проще cчитается от предыдущего члена, в нашем случае это можно было бы записать через итератор, что мы вскоре добавим.
|
Во многих случаях вычисление $n+1$ члена значительно проще cчитается от предыдущего члена, в нашем случае это можно было бы записать через итератор, см [Iterable] и `flow` в [parallelism].
|
||||||
|
|
||||||
(продолжение следует)
|
[Iterable]: ../Iterable.md
|
||||||
|
[parallelism]: ../parallelism.md
|
||||||
|
@ -1259,7 +1259,19 @@ String literal could be multiline:
|
|||||||
"Hello
|
"Hello
|
||||||
World"
|
World"
|
||||||
|
|
||||||
though multiline literals is yet work in progress.
|
In this case, it will be passed literally ot "hello\n World". But, if there are
|
||||||
|
several lines with common left indent, it will be removed, also, forst and last lines,
|
||||||
|
if blank, will be removed too, for example:
|
||||||
|
|
||||||
|
println("
|
||||||
|
This is a multiline text.
|
||||||
|
This is a second line.
|
||||||
|
")
|
||||||
|
>>> This is a multiline text.
|
||||||
|
>>> This is a second line.
|
||||||
|
>>> void
|
||||||
|
|
||||||
|
- as expected, empty lines and common indent were removed. It is much like kotlin's `""" ... """.trimIndent()` technique, but simpler ;)
|
||||||
|
|
||||||
# Built-in functions
|
# Built-in functions
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
|
|||||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
group = "net.sergeych"
|
group = "net.sergeych"
|
||||||
version = "0.8.4-SNAPSHOT"
|
version = "0.8.5-SNAPSHOT"
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
|
@ -375,6 +375,32 @@ private class Parser(fromPos: Pos) {
|
|||||||
|
|
||||||
private val currentChar: Char get() = pos.currentChar
|
private val currentChar: Char get() = pos.currentChar
|
||||||
|
|
||||||
|
private fun fixMultilineStringLiteral(source: String): String {
|
||||||
|
val sizes = mutableListOf<Int>()
|
||||||
|
val lines = source.lines().toMutableList()
|
||||||
|
if( lines.size == 0 ) return ""
|
||||||
|
if( lines[0].isBlank() ) lines.removeFirst()
|
||||||
|
if( lines.isEmpty()) return ""
|
||||||
|
if( lines.last().isBlank() ) lines.removeLast()
|
||||||
|
|
||||||
|
val normalized = lines.map { l ->
|
||||||
|
if( l.isBlank() ) {
|
||||||
|
sizes.add(-1)
|
||||||
|
""
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val margin = leftMargin(l)
|
||||||
|
sizes += margin
|
||||||
|
" ".repeat(margin) + l.trim()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val commonMargin = sizes.filter { it >= 0 }.min()
|
||||||
|
val fixed = if( commonMargin < 1 ) lines else normalized.map {
|
||||||
|
if( it.isBlank() ) "" else it.drop(commonMargin)
|
||||||
|
}
|
||||||
|
return fixed.joinToString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadStringToken(): Token {
|
private fun loadStringToken(): Token {
|
||||||
val start = currentPos
|
val start = currentPos
|
||||||
|
|
||||||
@ -383,6 +409,7 @@ private class Parser(fromPos: Pos) {
|
|||||||
// start = start.back()
|
// start = start.back()
|
||||||
|
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
|
var newlineDetected = false
|
||||||
while (currentChar != '"') {
|
while (currentChar != '"') {
|
||||||
if (pos.end) throw ScriptError(start, "unterminated string started there")
|
if (pos.end) throw ScriptError(start, "unterminated string started there")
|
||||||
when (currentChar) {
|
when (currentChar) {
|
||||||
@ -397,6 +424,12 @@ private class Parser(fromPos: Pos) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
'\n', '\r'-> {
|
||||||
|
newlineDetected = true
|
||||||
|
sb.append(currentChar)
|
||||||
|
pos.advance()
|
||||||
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
sb.append(currentChar)
|
sb.append(currentChar)
|
||||||
pos.advance()
|
pos.advance()
|
||||||
@ -404,7 +437,10 @@ private class Parser(fromPos: Pos) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pos.advance()
|
pos.advance()
|
||||||
return Token(sb.toString(), start, Token.Type.STRING)
|
|
||||||
|
val result = sb.toString().let { if( newlineDetected ) fixMultilineStringLiteral(it) else it }
|
||||||
|
|
||||||
|
return Token(result, start, Token.Type.STRING)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package net.sergeych.lyng
|
||||||
|
|
||||||
|
fun leftMargin(s: String): Int {
|
||||||
|
var cnt = 0
|
||||||
|
for (c in s) {
|
||||||
|
when (c) {
|
||||||
|
' ' -> cnt++
|
||||||
|
'\t' -> cnt = (cnt / 4.0 + 0.9).toInt() * 4
|
||||||
|
else -> break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cnt
|
||||||
|
}
|
@ -2794,4 +2794,45 @@ class ScriptTest {
|
|||||||
println(y.list)
|
println(y.list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMultilineStrings() = runTest {
|
||||||
|
assertEquals(
|
||||||
|
"""
|
||||||
|
This is a multiline text.
|
||||||
|
This is a second line.
|
||||||
|
""".trimIndent(), eval(
|
||||||
|
"""
|
||||||
|
"
|
||||||
|
This is a multiline text.
|
||||||
|
This is a second line.
|
||||||
|
"
|
||||||
|
""".trimIndent()
|
||||||
|
).toString()
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
"""
|
||||||
|
This is a multiline text.
|
||||||
|
""".trimIndent(), eval(
|
||||||
|
"""
|
||||||
|
"
|
||||||
|
This is a multiline text.
|
||||||
|
"
|
||||||
|
""".trimIndent()
|
||||||
|
).toString()
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
"""
|
||||||
|
|
||||||
|
This is a multiline text.
|
||||||
|
""".trimIndent(), eval(
|
||||||
|
"""
|
||||||
|
"
|
||||||
|
|
||||||
|
This is a multiline text.
|
||||||
|
"
|
||||||
|
""".trimIndent()
|
||||||
|
).toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -6,6 +6,7 @@ import kotlinx.coroutines.runBlocking
|
|||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import net.sergeych.lyng.Scope
|
import net.sergeych.lyng.Scope
|
||||||
import net.sergeych.lyng.Script
|
import net.sergeych.lyng.Script
|
||||||
|
import net.sergeych.lyng.leftMargin
|
||||||
import net.sergeych.lyng.obj.ObjVoid
|
import net.sergeych.lyng.obj.ObjVoid
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Files.readAllLines
|
import java.nio.file.Files.readAllLines
|
||||||
@ -16,18 +17,6 @@ import kotlin.test.Test
|
|||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.fail
|
import kotlin.test.fail
|
||||||
|
|
||||||
fun leftMargin(s: String): Int {
|
|
||||||
var cnt = 0
|
|
||||||
for (c in s) {
|
|
||||||
when (c) {
|
|
||||||
' ' -> cnt++
|
|
||||||
'\t' -> cnt = (cnt / 4.0 + 0.9).toInt() * 4
|
|
||||||
else -> break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cnt
|
|
||||||
}
|
|
||||||
|
|
||||||
data class DocTest(
|
data class DocTest(
|
||||||
val fileName: String,
|
val fileName: String,
|
||||||
val line: Int,
|
val line: Int,
|
||||||
|
@ -13,7 +13,6 @@ dependencyResolutionManagement {
|
|||||||
maven("https://maven.universablockchain.com/")
|
maven("https://maven.universablockchain.com/")
|
||||||
maven("https://gitea.sergeych.net/api/packages/SergeychWorks/maven")
|
maven("https://gitea.sergeych.net/api/packages/SergeychWorks/maven")
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
maven("https://gitea.sergeych.net/api/packages/SergeychWorks/maven")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user