diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/IdentifierSpec.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/IdentifierSpec.scala new file mode 100644 index 000000000..3eebf0fa3 --- /dev/null +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/IdentifierSpec.scala @@ -0,0 +1,34 @@ +package org.alephium.ralph.lsp.access.compiler.parser.soft + +import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.Token +import org.alephium.ralph.lsp.access.compiler.parser.soft.TestParser._ +import org.alephium.ralph.lsp.access.util.TestFastParse._ +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec + +class IdentifierSpec extends AnyWordSpec with Matchers { + + "disallow reserved tokens to be used as identifier" when { + val reserved = + Token.reserved.diff(Seq(Token.Hash)) // Remove hash because `let hash = #` is valid + + "tail has space" in { + reserved foreach { + reserved => + assertIsFastParseError { + parseIdentifier(s"${reserved.lexeme} ") + } + } + } + + "tail is end-of-file" in { + reserved foreach { + reserved => + assertIsFastParseError { + parseIdentifier(reserved.lexeme) + } + } + } + } + +} diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TestParser.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TestParser.scala index 495d1ada6..dd00a30fa 100644 --- a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TestParser.scala +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TestParser.scala @@ -60,6 +60,9 @@ object TestParser { def parseReservedTokenOrError(remove: Token.Reserved*)(code: String): Either[Parsed.Failure, Token.Reserved] = runAnyParserOrError(TokenParser.Reserved(remove: _*)(_))(code) + def parseIdentifier(code: String): SoftAST.IdentifierAST = + runSoftParser(IdentifierParser.parseOrFail(_))(code) + def findAnnotation(identifier: String)(code: String): Option[SoftAST.Annotation] = findAnnotation( identifier = identifier, @@ -118,7 +121,8 @@ object TestParser { result match { case Left(error) => // Print a formatted error so it's easier to debug. - fail(CompilerError.FastParseError(error).toFormatter().format(Some(Console.RED))) + val throwable = CompilerError.FastParseError(error) + fail(throwable.toFormatter().format(Some(Console.RED)), throwable) case Right(ast) => ast diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/util/TestFastParse.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/util/TestFastParse.scala new file mode 100644 index 000000000..36873e62f --- /dev/null +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/util/TestFastParse.scala @@ -0,0 +1,18 @@ +package org.alephium.ralph.lsp.access.util + +import org.alephium.ralph.error.CompilerError +import org.scalatest.TryValues._ +import org.scalatest.matchers.should.Matchers._ +import org.scalatest.Assertion + +import scala.util.Try + +object TestFastParse { + + def assertIsFastParseError[A](f: => A): Assertion = + Try(f) + .failure + .exception + .getCause shouldBe a[CompilerError.FastParseError] + +}