mirror of
https://github.com/irmen/prog8.git
synced 2024-07-05 22:29:04 +00:00
+ 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:
parent
c80a15846d
commit
0567168ea9
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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("@")
|
||||
|
@ -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())
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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)
|
||||
|
@ -79,6 +79,9 @@ interface IAstVisitor {
|
||||
fun visit(numLiteral: NumericLiteralValue) {
|
||||
}
|
||||
|
||||
fun visit(char: CharLiteral) {
|
||||
}
|
||||
|
||||
fun visit(string: StringLiteralValue) {
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user