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 ) )
 | 
			
		||||
 | 
			
		||||
Во многих случаях вычисление $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
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
 | 
			
		||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
 | 
			
		||||
 | 
			
		||||
group = "net.sergeych"
 | 
			
		||||
version = "0.8.4-SNAPSHOT"
 | 
			
		||||
version = "0.8.5-SNAPSHOT"
 | 
			
		||||
 | 
			
		||||
buildscript {
 | 
			
		||||
    repositories {
 | 
			
		||||
 | 
			
		||||
@ -375,6 +375,32 @@ private class Parser(fromPos: Pos) {
 | 
			
		||||
 | 
			
		||||
    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 {
 | 
			
		||||
        val start = currentPos
 | 
			
		||||
 | 
			
		||||
@ -383,6 +409,7 @@ private class Parser(fromPos: Pos) {
 | 
			
		||||
//        start = start.back()
 | 
			
		||||
 | 
			
		||||
        val sb = StringBuilder()
 | 
			
		||||
        var newlineDetected = false
 | 
			
		||||
        while (currentChar != '"') {
 | 
			
		||||
            if (pos.end) throw ScriptError(start, "unterminated string started there")
 | 
			
		||||
            when (currentChar) {
 | 
			
		||||
@ -397,6 +424,12 @@ private class Parser(fromPos: Pos) {
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                '\n', '\r'-> {
 | 
			
		||||
                    newlineDetected = true
 | 
			
		||||
                    sb.append(currentChar)
 | 
			
		||||
                    pos.advance()
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                else -> {
 | 
			
		||||
                    sb.append(currentChar)
 | 
			
		||||
                    pos.advance()
 | 
			
		||||
@ -404,7 +437,10 @@ private class Parser(fromPos: Pos) {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        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)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @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 net.sergeych.lyng.Scope
 | 
			
		||||
import net.sergeych.lyng.Script
 | 
			
		||||
import net.sergeych.lyng.leftMargin
 | 
			
		||||
import net.sergeych.lyng.obj.ObjVoid
 | 
			
		||||
import java.nio.file.Files
 | 
			
		||||
import java.nio.file.Files.readAllLines
 | 
			
		||||
@ -16,18 +17,6 @@ import kotlin.test.Test
 | 
			
		||||
import kotlin.test.assertEquals
 | 
			
		||||
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(
 | 
			
		||||
    val fileName: String,
 | 
			
		||||
    val line: Int,
 | 
			
		||||
 | 
			
		||||
@ -13,7 +13,6 @@ dependencyResolutionManagement {
 | 
			
		||||
        maven("https://maven.universablockchain.com/")
 | 
			
		||||
        maven("https://gitea.sergeych.net/api/packages/SergeychWorks/maven")
 | 
			
		||||
        mavenLocal()
 | 
			
		||||
        maven("https://gitea.sergeych.net/api/packages/SergeychWorks/maven")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user