diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c3ae4c9..0cc9d9e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ * Aliases now also support subfields. +* Short functions can be now defined using expression syntax. + * 6502: Fixed optimizations using index registers. * Fixed volatile-related bugs. diff --git a/docs/lang/functions.md b/docs/lang/functions.md index 0a03c55b..ca85dbdc 100644 --- a/docs/lang/functions.md +++ b/docs/lang/functions.md @@ -6,6 +6,8 @@ Syntax: `[segment ()] [] ( ) [align ( )] [@
] { }` +`[segment ()] [] ( ) [align ( )] [@
] = ` + `[segment ()] asm ( ) @
extern` * ``: segment name; if absent, then defaults to `default_code_segment` as defined for the platform (usually `default`) @@ -53,3 +55,5 @@ Such functions should be marked as written in assembly and should have their par * `` is a newline-separated list of either Millfork or assembly statements +* `` is an expression. It is equivalent to a function body of form `{ return }`. + diff --git a/src/main/scala/millfork/parser/MfParser.scala b/src/main/scala/millfork/parser/MfParser.scala index 095000af..4fb04963 100644 --- a/src/main/scala/millfork/parser/MfParser.scala +++ b/src/main/scala/millfork/parser/MfParser.scala @@ -372,6 +372,13 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri def statements: P[List[Statement]] = ("{" ~/ AWS ~ statement.rep(sep = NoCut(EOL) ~ !"}" ~/ Pass) ~/ AWS ~/ "}" ~/ Pass).map(_.flatten.toList) + def mfFunctionSmallBody: P[List[Statement]] = for { + _ <- "=" ~/ AWS + expression <- mfExpression(nonStatementLevel, false) + } yield List(ReturnStatement(Some(expression)).pos(expression.position)) + + def mfFunctionBody: P[List[Statement]] = statements | mfFunctionSmallBody + def executableStatements: P[Seq[ExecutableStatement]] = ("{" ~/ AWS ~/ executableStatement.rep(sep = NoCut(EOL) ~ !"}" ~/ Pass) ~/ AWS ~ "}").map(_.flatten) val dispatchLabel: P[ReturnDispatchLabel] = @@ -449,7 +456,7 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri params <- "(" ~/ AWS ~/ (if (flags("asm")) asmParamDefinition else paramDefinition).rep(sep = AWS ~ "," ~/ AWS) ~ AWS ~ ")" ~/ AWS alignment <- alignmentDeclaration(fastAlignmentForFunctions).? ~/ AWS addr <- ("@" ~/ HWS ~/ mfExpression(1, false)).?.opaque("
") ~/ AWS - statements <- (externFunctionBody | (if (flags("asm")) asmStatements else statements).map(l => Some(l))) ~/ Pass + statements <- (externFunctionBody | (if (flags("asm")) asmStatements else mfFunctionBody).map(l => Some(l))) ~/ Pass } yield { if (flags("interrupt") && flags("macro")) log.error(s"Interrupt function `$name` cannot be macros", Some(p)) if (flags("kernal_interrupt") && flags("macro")) log.error(s"Kernal interrupt function `$name` cannot be macros", Some(p)) diff --git a/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala b/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala index 51f6ec8c..091b26a7 100644 --- a/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala +++ b/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala @@ -135,9 +135,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers { | void main () { | output = f(5) | } - | byte f(byte x) { - | return ((x & $1E) >> 1) + 3 - | } + | byte f(byte x) = ((x & $1E) >> 1) + 3 | """.stripMargin)(_.readByte(0xc000) should equal(5)) } diff --git a/src/test/scala/millfork/test/DerefSuite.scala b/src/test/scala/millfork/test/DerefSuite.scala index bc93c956..38417900 100644 --- a/src/test/scala/millfork/test/DerefSuite.scala +++ b/src/test/scala/millfork/test/DerefSuite.scala @@ -51,7 +51,7 @@ class DerefSuite extends FunSuite with Matchers { | ¥(q) = ¥(p) + ¥(q) | } | - | noinline pointer id(pointer x) { return x } + | noinline pointer id(pointer x) = x """.stripMargin){m => m.readByte(0xc000) should equal (3) m.readByte(0xc001) should equal (6)