fixed 1e-6 type Real literal

This commit is contained in:
Sergey Chernov 2025-06-11 08:57:12 +04:00
parent d482401b15
commit b253eed032
5 changed files with 189 additions and 70 deletions

26
docs/samples/sum.lyng Normal file
View File

@ -0,0 +1,26 @@
/*
Calculate the limit of Sum( f(n) )
until it reaches asymptotic limit 0.00001% change
return null or found limit
*/
fun findSumLimit(f) {
var sum = 0.0
for( n in 1..1000000 ) {
val s0 = sum
sum += f(n)
if( abs(sum - s0) / abs(sum) < 1.0e-6 ) {
println("limit reached after "+n+" rounds")
break sum
}
n++
}
else {
println("limit not reached")
null
}
}
val limit = findSumLimit { n -> 1.0/n/n }
println("Result: "+limit)

View File

@ -11,7 +11,8 @@ data class ArgsDeclaration(val params: List<Item>, val endTokenType: Token.Type)
val start = params.indexOfFirst { it.defaultValue != null } val start = params.indexOfFirst { it.defaultValue != null }
if (start >= 0) if (start >= 0)
for (j in start + 1 until params.size) for (j in start + 1 until params.size)
if (params[j].defaultValue == null) throw ScriptError( // last non-default could be lambda:
if (params[j].defaultValue == null && j != params.size - 1) throw ScriptError(
params[j].pos, params[j].pos,
"required argument can't follow default one" "required argument can't follow default one"
) )
@ -22,7 +23,7 @@ data class ArgsDeclaration(val params: List<Item>, val endTokenType: Token.Type)
*/ */
suspend fun assignToContext( suspend fun assignToContext(
context: Context, context: Context,
fromArgs: Arguments = context.args, _fromArgs: Arguments = context.args,
defaultAccessType: AccessType = AccessType.Var, defaultAccessType: AccessType = AccessType.Var,
defaultVisibility: Visibility = Visibility.Public defaultVisibility: Visibility = Visibility.Public
) { ) {
@ -31,6 +32,9 @@ data class ArgsDeclaration(val params: List<Item>, val endTokenType: Token.Type)
a.visibility ?: defaultVisibility) a.visibility ?: defaultVisibility)
} }
// will be used with last lambda arg fix
val fromArgs = _fromArgs
suspend fun processHead(index: Int): Int { suspend fun processHead(index: Int): Int {
var i = index var i = index
while (i != params.size) { while (i != params.size) {

View File

@ -1330,7 +1330,7 @@ class Compiler(
/** /**
* The keywords that stop processing of expression term * The keywords that stop processing of expression term
*/ */
val stopKeywords = setOf("break", "continue", "return", "if", "when", "do", "while", "for", "class", "struct") val stopKeywords = setOf("do", "break", "continue", "return", "if", "when", "do", "while", "for", "class", "struct")
} }
} }

View File

@ -293,7 +293,19 @@ private class Parser(fromPos: Pos) {
private fun decodeNumber(p1: String, start: Pos): Token = private fun decodeNumber(p1: String, start: Pos): Token =
if (pos.end) if (pos.end)
Token(p1, start, Token.Type.INT) Token(p1, start, Token.Type.INT)
else if (currentChar == '.') { else if( currentChar == 'e' || currentChar == 'E' ) {
pos.advance()
var negative = false
if (currentChar == '+')
pos.advance()
else if (currentChar == '-') {
negative = true
pos.advance()
}
var p3 = loadChars(digits)
if (negative) p3 = "-$p3"
Token("${p1}e$p3", start, Token.Type.REAL)
} else if (currentChar == '.') {
// could be decimal // could be decimal
pos.advance() pos.advance()
if (currentChar in digitsSet) { if (currentChar in digitsSet) {

View File

@ -57,6 +57,8 @@ class ScriptTest {
check("17.2e22", Token.Type.REAL, 0, 0, "17.2E+22") check("17.2e22", Token.Type.REAL, 0, 0, "17.2E+22")
check("17.2e22", Token.Type.REAL, 0, 0, "17.2E22") check("17.2e22", Token.Type.REAL, 0, 0, "17.2E22")
check("17.2e-22", Token.Type.REAL, 0, 0, "17.2E-22") check("17.2e-22", Token.Type.REAL, 0, 0, "17.2E-22")
check("17.2e-22", Token.Type.REAL, 0, 0, "17.2E-22")
check("1e-22", Token.Type.REAL, 0, 0, "1E-22")
// hex // hex
check("1", Token.Type.HEX, 0, 0, "0x1") check("1", Token.Type.HEX, 0, 0, "0x1")
@ -490,11 +492,13 @@ class ScriptTest {
fun testAssignArgumentsNoEllipsis() = runTest { fun testAssignArgumentsNoEllipsis() = runTest {
// equal args, no ellipsis, no defaults, ok // equal args, no ellipsis, no defaults, ok
val ttEnd = Token.Type.RBRACE val ttEnd = Token.Type.RBRACE
var pa = ArgsDeclaration(listOf( var pa = ArgsDeclaration(
listOf(
ArgsDeclaration.Item("a"), ArgsDeclaration.Item("a"),
ArgsDeclaration.Item("b"), ArgsDeclaration.Item("b"),
ArgsDeclaration.Item("c"), ArgsDeclaration.Item("c"),
), ttEnd) ), ttEnd
)
var c = Context(pos = Pos.builtIn, args = Arguments.from(listOf(1, 2, 3).map { it.toObj() })) var c = Context(pos = Pos.builtIn, args = Arguments.from(listOf(1, 2, 3).map { it.toObj() }))
pa.assignToContext(c) pa.assignToContext(c)
assertEquals(ObjInt(1), c["a"]?.value) assertEquals(ObjInt(1), c["a"]?.value)
@ -506,11 +510,13 @@ class ScriptTest {
pa.assignToContext(c) pa.assignToContext(c)
} }
// less args, no ellipsis, defaults, ok // less args, no ellipsis, defaults, ok
pa = ArgsDeclaration(listOf( pa = ArgsDeclaration(
listOf(
ArgsDeclaration.Item("a"), ArgsDeclaration.Item("a"),
ArgsDeclaration.Item("b"), ArgsDeclaration.Item("b"),
ArgsDeclaration.Item("c", defaultValue = statement { ObjInt(100) }), ArgsDeclaration.Item("c", defaultValue = statement { ObjInt(100) }),
), ttEnd) ), ttEnd
)
pa.assignToContext(c) pa.assignToContext(c)
assertEquals(ObjInt(1), c["a"]?.value) assertEquals(ObjInt(1), c["a"]?.value)
assertEquals(ObjInt(2), c["b"]?.value) assertEquals(ObjInt(2), c["b"]?.value)
@ -528,10 +534,12 @@ class ScriptTest {
// equal args, // equal args,
// less args, no ellipsis, defaults, ok // less args, no ellipsis, defaults, ok
val ttEnd = Token.Type.RBRACE val ttEnd = Token.Type.RBRACE
val pa = ArgsDeclaration(listOf( val pa = ArgsDeclaration(
listOf(
ArgsDeclaration.Item("a"), ArgsDeclaration.Item("a"),
ArgsDeclaration.Item("b", isEllipsis = true), ArgsDeclaration.Item("b", isEllipsis = true),
), ttEnd) ), ttEnd
)
var c = Context(args = Arguments.from(listOf(1, 2, 3).map { it.toObj() })) var c = Context(args = Arguments.from(listOf(1, 2, 3).map { it.toObj() }))
pa.assignToContext(c) pa.assignToContext(c)
c.eval("assert( a == 1 ); println(b)") c.eval("assert( a == 1 ); println(b)")
@ -551,11 +559,13 @@ class ScriptTest {
@Test @Test
fun testAssignArgumentsStartEllipsis() = runTest { fun testAssignArgumentsStartEllipsis() = runTest {
val ttEnd = Token.Type.RBRACE val ttEnd = Token.Type.RBRACE
val pa = ArgsDeclaration(listOf( val pa = ArgsDeclaration(
listOf(
ArgsDeclaration.Item("a", isEllipsis = true), ArgsDeclaration.Item("a", isEllipsis = true),
ArgsDeclaration.Item("b"), ArgsDeclaration.Item("b"),
ArgsDeclaration.Item("c"), ArgsDeclaration.Item("c"),
), ttEnd) ), ttEnd
)
var c = Context(args = Arguments.from(listOf(0, 1, 2, 3).map { it.toObj() })) var c = Context(args = Arguments.from(listOf(0, 1, 2, 3).map { it.toObj() }))
pa.assignToContext(c) pa.assignToContext(c)
c.eval("assertEquals( a,[0,1] )") c.eval("assertEquals( a,[0,1] )")
@ -583,12 +593,14 @@ class ScriptTest {
@Test @Test
fun testAssignArgumentsmiddleEllipsis() = runTest { fun testAssignArgumentsmiddleEllipsis() = runTest {
val ttEnd = Token.Type.RBRACE val ttEnd = Token.Type.RBRACE
val pa = ArgsDeclaration(listOf( val pa = ArgsDeclaration(
listOf(
ArgsDeclaration.Item("i"), ArgsDeclaration.Item("i"),
ArgsDeclaration.Item("a", isEllipsis = true), ArgsDeclaration.Item("a", isEllipsis = true),
ArgsDeclaration.Item("b"), ArgsDeclaration.Item("b"),
ArgsDeclaration.Item("c"), ArgsDeclaration.Item("c"),
), ttEnd) ), ttEnd
)
var c = Context(args = Arguments.from(listOf(-1, 0, 1, 2, 3).map { it.toObj() })) var c = Context(args = Arguments.from(listOf(-1, 0, 1, 2, 3).map { it.toObj() }))
pa.assignToContext(c) pa.assignToContext(c)
c.eval("assertEquals( i, -1 )") c.eval("assertEquals( i, -1 )")
@ -1385,7 +1397,8 @@ class ScriptTest {
@Test @Test
fun testSimpleStruct() = runTest { fun testSimpleStruct() = runTest {
val c = Context() val c = Context()
c.eval(""" c.eval(
"""
class Point(x,y) class Point(x,y)
assert( Point::class is Class ) assert( Point::class is Class )
val p = Point(2,3) val p = Point(2,3)
@ -1398,13 +1411,15 @@ class ScriptTest {
val p2 = Point(p.x+1,p.y+1) val p2 = Point(p.x+1,p.y+1)
p.x = 0 p.x = 0
assertEquals( 0, p.x ) assertEquals( 0, p.x )
""".trimIndent()) """.trimIndent()
)
} }
@Test @Test
fun testNonAssignalbeFieldInStruct() = runTest { fun testNonAssignalbeFieldInStruct() = runTest {
val c = Context() val c = Context()
c.eval(""" c.eval(
"""
class Point(x,y) class Point(x,y)
val p = Point("2",3) val p = Point("2",3)
assert(p is Point) assert(p is Point)
@ -1413,13 +1428,15 @@ class ScriptTest {
p.x = 0 p.x = 0
assertEquals( 0, p.x ) assertEquals( 0, p.x )
""".trimIndent()) """.trimIndent()
)
} }
@Test @Test
fun testStructBodyVal() = runTest { fun testStructBodyVal() = runTest {
val c = Context() val c = Context()
c.eval(""" c.eval(
"""
class Point(x,y) { class Point(x,y) {
val length = sqrt(x*x+y*y) val length = sqrt(x*x+y*y)
var foo = "zero" var foo = "zero"
@ -1433,13 +1450,15 @@ class ScriptTest {
assert( p.foo == "bar") assert( p.foo == "bar")
// length is a val, is shoud not change // length is a val, is shoud not change
assert( p.length == 5 ) assert( p.length == 5 )
""".trimIndent()) """.trimIndent()
)
} }
@Test @Test
fun testStructBodyFun() = runTest { fun testStructBodyFun() = runTest {
val c = Context() val c = Context()
c.eval(""" c.eval(
"""
class Point(x,y) { class Point(x,y) {
fun length() { fun length() {
sqrt(x*x+y*y) sqrt(x*x+y*y)
@ -1451,23 +1470,27 @@ class ScriptTest {
p.y = 10 p.y = 10
println(p.length()) println(p.length())
assertEquals(sqrt(109), p.length()) assertEquals(sqrt(109), p.length())
""".trimIndent()) """.trimIndent()
)
} }
@Test @Test
fun testPrivateConstructorParams() = runTest { fun testPrivateConstructorParams() = runTest {
val c = Context() val c = Context()
c.eval(""" c.eval(
"""
class Point(private var x,y) class Point(private var x,y)
val p = Point(1,2) val p = Point(1,2)
p.y = 101 p.y = 101
assertThrows { p.x = 10 } assertThrows { p.x = 10 }
""") """
)
} }
@Test @Test
fun testLBraceMethodCall() = runTest { fun testLBraceMethodCall() = runTest {
eval(""" eval(
"""
class Foo() { class Foo() {
fun cond(block) { fun cond(block) {
block() block()
@ -1475,22 +1498,26 @@ class ScriptTest {
} }
val f = Foo() val f = Foo()
assertEquals( 1, f.cond { 1 } ) assertEquals( 1, f.cond { 1 } )
""".trimIndent()) """.trimIndent()
)
} }
@Test @Test
fun testLBraceFnCall() = runTest { fun testLBraceFnCall() = runTest {
eval(""" eval(
"""
fun cond(block) { fun cond(block) {
block() block()
} }
assertEquals( 1, cond { 1 } ) assertEquals( 1, cond { 1 } )
""".trimIndent()) """.trimIndent()
)
} }
@Test @Test
fun testClasstoString() = runTest { fun testClasstoString() = runTest {
eval(""" eval(
"""
class Point { class Point {
var x var x
var y var y
@ -1499,19 +1526,22 @@ class ScriptTest {
p.x = 1 p.x = 1
p.y = 2 p.y = 2
println(p) println(p)
""".trimIndent()) """.trimIndent()
)
} }
@Test @Test
fun testClassDefaultCompare() = runTest { fun testClassDefaultCompare() = runTest {
eval(""" eval(
"""
class Point(x,y) class Point(x,y)
assert( Point(1,2) == Point(1,2) ) assert( Point(1,2) == Point(1,2) )
assert( Point(1,2) !== Point(1,2) ) assert( Point(1,2) !== Point(1,2) )
assert( Point(1,2) != Point(1,3) ) assert( Point(1,2) != Point(1,3) )
assert( Point(1,2) < Point(2,2) ) assert( Point(1,2) < Point(2,2) )
assert( Point(1,2) < Point(1,3) ) assert( Point(1,2) < Point(1,3) )
""".trimIndent()) """.trimIndent()
)
} }
@Test @Test
@ -1520,4 +1550,51 @@ class ScriptTest {
assertFalse(Visibility.Private.isPublic) assertFalse(Visibility.Private.isPublic)
assertFalse(Visibility.Protected.isPublic) assertFalse(Visibility.Protected.isPublic)
} }
@Test
fun segfault1Test() = runTest {
eval(
"""
fun findSumLimit(f) {
var sum = 0.0
for( n in 1..1000000 ) {
val s0 = sum
sum += f(n)
if( abs(sum - s0) < 0.00001 ) {
println("limit reached after "+n+" rounds")
break sum
}
n++
}
else {
println("limit not reached")
null
}
}
val limit = findSumLimit { n -> 1.0/n/n }
println("Result: "+limit)
"""
)
}
@Test
fun testIntExponentRealForm() = runTest {
assertEquals("1.0E-6", eval("1e-6").toString())
}
// @Test
// fun testLambdaLastArgAfterDetault() = runTest {
// val c = Context()
// eval("""
// // this means last is lambda:
// fun f(e=1, f) {
// "e="+e+"f="+f()
// }
// assertEquals("e=1f=xx", f { "xx" })
// """.trimIndent())
//
// }
} }