Allow omitting length in `file` array initalizers (fixes #35)

This commit is contained in:
Karol Stasiak 2020-01-10 18:37:49 +01:00
parent 17e02b9b13
commit 0333b339ca
3 changed files with 28 additions and 5 deletions

View File

@ -175,6 +175,7 @@ An array is initialized with either:
array b = "----" scr
array c = ["hello world!" ascii, 13]
array d = file("d.bin")
array d1 = file("d.bin", 128)
array e = file("d.bin", 128, 256)
array f = for x,0,until,8 [x * 3 + 5] // equivalent to [5, 8, 11, 14, 17, 20, 23, 26]
array(point) g = [point(2,3), point(5,6)]
@ -183,7 +184,10 @@ An array is initialized with either:
Trailing commas (`[1, 2,]`) are not allowed.
The parameters for `file` are: file path, optional start offset, optional length
(start offset and length have to be either both present or both absent).
(if only two parameters are present, then the second one is assumed to be the start offset).
The `file` expression is expanded at the compile time to an array of bytes equal to the bytes contained in the file.
If the start offset is present, then that many bytes at the start of the file are skipped.
If the length is present, then only that many bytes are taken, otherwise, all bytes until the end of the file are taken.
The `for`-style expression has a variable, a starting index, a direction, a final index,
and a parameterizable array initializer.

View File

@ -627,4 +627,4 @@ const array attribute = [
// *CHARACTER ROM (GRAPHICS)*
segment(chrrom) const array graphics @ $0000 = file("tiles.chr")
segment(chrrom) const array graphics @ $0000 = file("tiles.chr", 0)

View File

@ -229,12 +229,31 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri
val arrayFileContents: P[ArrayContents] = for {
p <- "file" ~ HWS ~/ "(" ~/ HWS ~/ position("file name")
filePath <- doubleQuotedString ~/ HWS
optSlice <- ("," ~/ HWS ~/ literalAtom ~/ HWS ~/ "," ~/ HWS ~/ literalAtom ~/ HWS ~/ Pass).?
optStart <- ("," ~/ HWS ~/ literalAtom ~/ HWS ~/ Pass).?
optLength <- ("," ~/ HWS ~/ literalAtom ~/ HWS ~/ Pass).?
_ <- ")" ~/ Pass
} yield {
val data = Files.readAllBytes(Paths.get(currentDirectory, filePath))
val slice = optSlice.fold(data) {
case (start, length) => data.slice(start.value.toInt, start.value.toInt + length.value.toInt)
val slice: Array[Byte] = (optStart.map(_.value.toInt), optLength.map(_.value.toInt)) match {
case (Some(start), Some(length)) =>
if (data.length < start) {
log.error(s"File $filePath is shorter (${data.length} B) that the start offset $start", Some(p))
Array.fill(length)(0.toByte)
} else if (data.length < start + length) {
log.error(s"File $filePath is shorter (${data.length} B) that the start offset plus length ${start + length}", Some(p))
Array.fill(length)(0.toByte)
} else {
data.slice(start, start + length)
}
case (Some(start), None) =>
if (data.length < start) {
log.error(s"File $filePath is shorter (${data.length} B) that the start offset $start", Some(p))
Array[Byte](0)
} else {
data.drop(start)
}
case (None, None) => data
case _ => throw new IllegalStateException("error parsing file()")
}
LiteralContents(slice.map(c => LiteralExpression(c & 0xff, 1)).toList)
}