parent
f616326383
commit
2e96d75b9f
@ -1385,6 +1385,7 @@ Typical set of String functions includes:
|
||||
| trim() | trim space chars from both ends |
|
||||
| startsWith(prefix) | true if starts with a prefix |
|
||||
| endsWith(prefix) | true if ends with a prefix |
|
||||
| last() | get last character of a string or throw |
|
||||
| take(n) | get a new string from up to n first characters |
|
||||
| takeLast(n) | get a new string from up to n last characters |
|
||||
| drop(n) | get a new string dropping n first chars, or empty string |
|
||||
|
||||
@ -213,25 +213,40 @@ private class Parser(fromPos: Pos) {
|
||||
|
||||
'!' -> {
|
||||
if (currentChar == 'i') {
|
||||
// Potentially !in / !is, but only if a word boundary follows
|
||||
pos.advance()
|
||||
when (currentChar) {
|
||||
'n' -> {
|
||||
pos.advance()
|
||||
Token("!in", from, Token.Type.NOTIN)
|
||||
// if next char continues an identifier, it's actually '!'+identifier starting with "in..."
|
||||
if (idNextChars(currentChar)) {
|
||||
// backtrack to right after '!'
|
||||
pos.back()
|
||||
pos.back()
|
||||
Token("!", from, Token.Type.NOT)
|
||||
} else
|
||||
Token("!in", from, Token.Type.NOTIN)
|
||||
}
|
||||
|
||||
's' -> {
|
||||
pos.advance()
|
||||
Token("!is", from, Token.Type.NOTIS)
|
||||
// if next char continues an identifier, it's actually '!'+identifier starting with "is..."
|
||||
if (idNextChars(currentChar)) {
|
||||
// backtrack to right after '!'
|
||||
pos.back()
|
||||
pos.back()
|
||||
Token("!", from, Token.Type.NOT)
|
||||
} else
|
||||
Token("!is", from, Token.Type.NOTIS)
|
||||
}
|
||||
|
||||
else -> {
|
||||
// it was just '!i' followed by something else; revert one step and return '!'
|
||||
pos.back()
|
||||
Token("!", from, Token.Type.NOT)
|
||||
}
|
||||
}
|
||||
} else
|
||||
if (currentChar == '=') {
|
||||
} else if (currentChar == '=') {
|
||||
pos.advance()
|
||||
if (currentChar == '=') {
|
||||
pos.advance()
|
||||
|
||||
@ -173,6 +173,9 @@ data class ObjString(val value: String) : Obj() {
|
||||
thisAs<ObjString>().value.map { ObjChar(it) }.toMutableList()
|
||||
)
|
||||
}
|
||||
addFn("last") {
|
||||
ObjChar(thisAs<ObjString>().value.lastOrNull() ?: raiseNoSuchElement("empty string"))
|
||||
}
|
||||
addFn("encodeUtf8") { ObjBuffer(thisAs<ObjString>().value.encodeToByteArray().asUByteArray()) }
|
||||
addFn("size") { ObjInt(thisAs<ObjString>().value.length.toLong()) }
|
||||
addFn("toReal") {
|
||||
|
||||
@ -4012,4 +4012,41 @@ class ScriptTest {
|
||||
""".trimIndent()).decodeSerializable<TestJson4>()
|
||||
assertEquals( TestJson4(TestEnum.One), x)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLogicalNot() = runTest {
|
||||
eval("""
|
||||
val vf = false
|
||||
fun f() { false }
|
||||
assert( !false )
|
||||
assert( !vf )
|
||||
assert( !f() )
|
||||
|
||||
val vt = true
|
||||
fun ft() { true }
|
||||
if( !true )
|
||||
throw "impossible"
|
||||
|
||||
if( !ft() )
|
||||
throw "impossible"
|
||||
|
||||
if( !vt )
|
||||
throw "impossible"
|
||||
|
||||
// real world sample
|
||||
|
||||
fun isSignedByAdmin() {
|
||||
// just ok
|
||||
true
|
||||
}
|
||||
|
||||
fun requireAdmin() {
|
||||
// this caused compilation error:
|
||||
if( !isSignedByAdmin() )
|
||||
throw "Admin signature required"
|
||||
}
|
||||
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user