+ add AST node CharLiteral, *without* turning them into ubyte s. This breaks tests, particularly 3 in TestCompilerOnCharLit. I'm comitting this separately since the failure modes might be of interest (compiler says "internal error").

This commit is contained in:
meisl 2021-06-21 20:16:50 +02:00
parent c80a15846d
commit 0567168ea9
10 changed files with 161 additions and 19 deletions

View File

@ -776,10 +776,20 @@ internal class AstChecker(private val program: Program,
super.visit(array)
}
override fun visit(char: CharLiteral) {
try { // just *try* if it can be encoded, don't actually do it
compTarget.encodeString(char.value.toString(), char.altEncoding)
} catch (cx: CharConversionException) {
errors.err(cx.message ?: "can't encode character", char.position)
}
super.visit(char)
}
override fun visit(string: StringLiteralValue) {
checkValueTypeAndRangeString(DataType.STR, string)
try {
try { // just *try* if it can be encoded, don't actually do it
compTarget.encodeString(string.value, string.altEncoding)
} catch (cx: CharConversionException) {
errors.err(cx.message ?: "can't encode string", string.position)

View File

@ -48,6 +48,7 @@ fun assumeReadable(path: Path) {
}
fun assumeReadableFile(path: Path) {
assumeReadable(path)
assertTrue(path.isRegularFile(), "sanity check: should be normal file: ${path.absolute()}")
}
@ -66,7 +67,6 @@ fun sanityCheckDirectories(workingDirName: String? = null) {
assumeDirectory(fixturesDir)
assumeDirectory(resourcesDir)
assumeDirectory(outputDir)
}
@ -97,5 +97,3 @@ val DummyMemsizer = object : IMemSizer {
override fun memorySize(dt: DataType): Int = 0
}

View File

@ -266,6 +266,12 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
output(numLiteral.number.toString())
}
override fun visit(char: CharLiteral) {
if (char.altEncoding)
output("@")
output("'${escape(char.value.toString())}'")
}
override fun visit(string: StringLiteralValue) {
if (string.altEncoding)
output("@")

View File

@ -435,15 +435,7 @@ private fun Prog8ANTLRParser.ExpressionContext.toAst(encoding: IStringEncoding)
}
litval.floatliteral()!=null -> NumericLiteralValue(DataType.FLOAT, litval.floatliteral().toAst(), litval.toPosition())
litval.stringliteral()!=null -> litval.stringliteral().toAst()
litval.charliteral()!=null -> {
try {
NumericLiteralValue(DataType.UBYTE, encoding.encodeString(
unescape(litval.charliteral().SINGLECHAR().text, litval.toPosition()),
litval.charliteral().ALT_STRING_ENCODING()!=null)[0], litval.toPosition())
} catch (ce: CharConversionException) {
throw SyntaxError(ce.message ?: ce.toString(), litval.toPosition())
}
}
litval.charliteral()!=null -> litval.charliteral().toAst()
litval.arrayliteral()!=null -> {
val array = litval.arrayliteral().toAst(encoding)
// the actual type of the arraysize can not yet be determined here (missing namespace & heap)
@ -491,6 +483,9 @@ private fun Prog8ANTLRParser.ExpressionContext.toAst(encoding: IStringEncoding)
throw FatalAstException(text)
}
private fun Prog8ANTLRParser.CharliteralContext.toAst(): CharLiteral =
CharLiteral(unescape(this.SINGLECHAR().text, toPosition())[0], this.ALT_STRING_ENCODING() != null, toPosition())
private fun Prog8ANTLRParser.StringliteralContext.toAst(): StringLiteralValue =
StringLiteralValue(unescape(this.STRING().text, toPosition()), ALT_STRING_ENCODING()!=null, toPosition())

View File

@ -499,6 +499,37 @@ class NumericLiteralValue(val type: DataType, // only numerical types allowed
}
}
class CharLiteral(val value: Char,
val altEncoding: Boolean, // such as: screencodes instead of Petscii for the C64
override val position: Position) : Expression() {
override lateinit var parent: Node
override fun linkParents(parent: Node) {
this.parent = parent
}
override val isSimple = true
override fun replaceChildNode(node: Node, replacement: Node) {
throw FatalAstException("can't replace here")
}
override fun referencesIdentifier(vararg scopedName: String) = false
override fun constValue(program: Program): NumericLiteralValue? = null // TODO: CharLiteral.constValue can't be NumericLiteralValue...
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(walker: AstWalker, parent: Node) = walker.visit(this, parent)
override fun toString(): String = "'${escape(value.toString())}'"
override fun inferType(program: Program): InferredTypes.InferredType = InferredTypes.knownFor(DataType.UNDEFINED) // FIXME: CharLiteral.inferType
operator fun compareTo(other: CharLiteral): Int = value.compareTo(other.value)
override fun hashCode(): Int = Objects.hash(value, altEncoding)
override fun equals(other: Any?): Boolean {
if (other == null || other !is CharLiteral)
return false
return value == other.value && altEncoding == other.altEncoding
}
}
class StringLiteralValue(val value: String,
val altEncoding: Boolean, // such as: screencodes instead of Petscii for the C64
override val position: Position) : Expression() {

View File

@ -110,6 +110,7 @@ abstract class AstWalker {
open fun before(untilLoop: UntilLoop, parent: Node): Iterable<IAstModification> = noModifications
open fun before(returnStmt: Return, parent: Node): Iterable<IAstModification> = noModifications
open fun before(scope: AnonymousScope, parent: Node): Iterable<IAstModification> = noModifications
open fun before(char: CharLiteral, parent: Node): Iterable<IAstModification> = noModifications
open fun before(string: StringLiteralValue, parent: Node): Iterable<IAstModification> = noModifications
open fun before(subroutine: Subroutine, parent: Node): Iterable<IAstModification> = noModifications
open fun before(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> = noModifications
@ -150,6 +151,7 @@ abstract class AstWalker {
open fun after(untilLoop: UntilLoop, parent: Node): Iterable<IAstModification> = noModifications
open fun after(returnStmt: Return, parent: Node): Iterable<IAstModification> = noModifications
open fun after(scope: AnonymousScope, parent: Node): Iterable<IAstModification> = noModifications
open fun after(char: CharLiteral, parent: Node): Iterable<IAstModification> = noModifications
open fun after(string: StringLiteralValue, parent: Node): Iterable<IAstModification> = noModifications
open fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> = noModifications
open fun after(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> = noModifications
@ -300,6 +302,11 @@ abstract class AstWalker {
track(after(numLiteral, parent), numLiteral, parent)
}
fun visit(char: CharLiteral, parent: Node) {
track(before(char, parent), char, parent)
track(after(char, parent), char, parent)
}
fun visit(string: StringLiteralValue, parent: Node) {
track(before(string, parent), string, parent)
track(after(string, parent), string, parent)

View File

@ -79,6 +79,9 @@ interface IAstVisitor {
fun visit(numLiteral: NumericLiteralValue) {
}
fun visit(char: CharLiteral) {
}
fun visit(string: StringLiteralValue) {
}

View File

@ -1,6 +1,5 @@
package prog8tests.helpers
import org.junit.jupiter.api.Test
import kotlin.test.*
import kotlin.io.path.*
@ -25,6 +24,7 @@ fun assumeReadable(path: Path) {
}
fun assumeReadableFile(path: Path) {
assumeReadable(path)
assertTrue(path.isRegularFile(), "sanity check: should be normal file: ${path.absolute()}")
}
@ -43,7 +43,6 @@ fun sanityCheckDirectories(workingDirName: String? = null) {
assumeDirectory(fixturesDir)
assumeDirectory(resourcesDir)
assumeDirectory(outputDir)
}

View File

@ -98,7 +98,6 @@ class TestAstToSourceCode {
}
@Test
@Disabled("TODO: char literals should be kept until code gen - step 4, 'introduce AST node CharLiteral'")
fun testCharLiteral_noAlt() {
val orig = SourceCode.of("""
main {
@ -111,7 +110,6 @@ class TestAstToSourceCode {
}
@Test
@Disabled("TODO: char literals should be kept until code gen - step 4, 'introduce AST node CharLiteral'")
fun testCharLiteral_withAlt() {
val orig = SourceCode.of("""
main {

View File

@ -11,9 +11,10 @@ import kotlin.io.path.*
import prog8.parser.ParseError
import prog8.parser.Prog8Parser.parseModule
import prog8.parser.SourceCode
import prog8.ast.Node
import prog8.ast.base.Position
import prog8.ast.*
import prog8.ast.statements.*
import prog8.ast.base.Position
import prog8.ast.expressions.CharLiteral
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ -336,4 +337,98 @@ class TestProg8Parser {
assertPositionOf(whenStmt.choices[2], mpf, 9, 12) // TODO: endCol wrong!
}
@Test
fun testCharLitAsArg() {
val src = SourceCode.of("""
main {
sub start() {
chrout('\n')
}
}
""")
val module = parseModule(src)
val startSub = module
.statements.filterIsInstance<Block>()[0]
.statements.filterIsInstance<Subroutine>()[0]
val funCall = startSub.statements.filterIsInstance<IFunctionCall>().first()
assertIs<CharLiteral>(funCall.args[0])
val char = funCall.args[0] as CharLiteral
assertEquals('\n', char.value)
}
@Test
fun testBlockLevelVarDeclWithCharLiteral_noAltEnc() {
val src = SourceCode.of("""
main {
ubyte c = 'x'
}
""")
val module = parseModule(src)
val decl = module
.statements.filterIsInstance<Block>()[0]
.statements.filterIsInstance<VarDecl>()[0]
val rhs = decl.value as CharLiteral
assertEquals('x', rhs.value, "char literal's .value")
assertEquals(false, rhs.altEncoding, "char literal's .altEncoding")
}
@Test
fun testBlockLevelConstDeclWithCharLiteral_withAltEnc() {
val src = SourceCode.of("""
main {
const ubyte c = @'x'
}
""")
val module = parseModule(src)
val decl = module
.statements.filterIsInstance<Block>()[0]
.statements.filterIsInstance<VarDecl>()[0]
val rhs = decl.value as CharLiteral
assertEquals('x', rhs.value, "char literal's .value")
assertEquals(true, rhs.altEncoding, "char literal's .altEncoding")
}
@Test
fun testSubRoutineLevelVarDeclWithCharLiteral_noAltEnc() {
val src = SourceCode.of("""
main {
sub start() {
ubyte c = 'x'
}
}
""")
val module = parseModule(src)
val decl = module
.statements.filterIsInstance<Block>()[0]
.statements.filterIsInstance<Subroutine>()[0]
.statements.filterIsInstance<VarDecl>()[0]
val rhs = decl.value as CharLiteral
assertEquals('x', rhs.value, "char literal's .value")
assertEquals(false, rhs.altEncoding, "char literal's .altEncoding")
}
@Test
fun testSubRoutineLevelConstDeclWithCharLiteral_withAltEnc() {
val src = SourceCode.of("""
main {
sub start() {
const ubyte c = @'x'
}
}
""")
val module = parseModule(src)
val decl = module
.statements.filterIsInstance<Block>()[0]
.statements.filterIsInstance<Subroutine>()[0]
.statements.filterIsInstance<VarDecl>()[0]
val rhs = decl.value as CharLiteral
assertEquals('x', rhs.value, "char literal's .value")
assertEquals(true, rhs.altEncoding, "char literal's .altEncoding")
}
}