content: module TokenSpec where
  
  import Parser
  import Test.Hspec (Spec, describe, it, shouldBe)
  import Token
  
  spec :: Spec
  spec = describe "scanning" $ do
    -- single
    it "scans single" $ do
      let input = ("(", 0)
      parse single input `shouldBe` Just (LeftParen, ("", 0))
  
    -- multi
    it "scans multi" $ do
      let input = ("!=", 0)
      parse multi input `shouldBe` Just (BangEqual, ("", 0))
  
    -- comment
    it "scans comment" $ do
      let input = ("//you are not expected to understand this\n", 0)
      parse comment input `shouldBe` Just ("you are not expected to understand this", ("", 1))
  
    -- whitespace
    it "scans whitespace" $ do
      let input = ("\t", 0)
      parse whitespace input `shouldBe` Just (Tab, ("", 0))
  
    -- newline
    it "scans newline" $ do
      let input = ("\n", 0)
      parse (char '\n') input `shouldBe` Just ('\n', ("", 1))
  
    -- NumberLiteral
    it "scans whole number" $ do
      let input = ("123", 0)
      parse number input `shouldBe` Just (Number 123 0, ("", 0))
  
    it "scans decimal number" $ do
      let input = ("123.123", 0)
      parse number input `shouldBe` Just (Number 123 123, ("", 0))
  
    it "scans negative number" $ do
      let input = ("-123", 0)
      parse number input `shouldBe` Just (Number (negate 123) 0, ("", 0))
  
    -- keyword
    it "scans keywords" $ do
      let input = ("class ", 0) -- gotta add whitespace as it could be an identifier
      parse keyword input `shouldBe` Just (Class, (" ", 0)) -- leaves whitespace alone
  
    -- code
    it "scans code" $ do
      let code =
            "print \"Hello, world!\";\n\
            \var a = -20.25;\n\
            \while (a < 10) {\n\
            \  print a;\n\
            \  a = a + 1;\n\
            \}\n\
            \fun printSum(a, b) {\n\
            \  print a + b; //comment\n\
            \}\n\
            \"
          input = (code, 0)
      tokenise input `shouldBe` Just [Token {line = 0, ty = KeywordToken Print}, Token {line = 0, ty = LiteralToken (StringLiteral "Hello, world!")}, Token {line = 0, ty = SingleToken Semicolon}, Token {line = 0, ty = SingleToken Newline}, Token {line = 1, ty = KeywordToken Var}, Token {line = 1, ty = IdentifierToken "a"}, Token {line = 1, ty = MultiToken Equal}, Token {line = 1, ty = LiteralToken (NumberLiteral (Number {wholePart = -20, fractionalPart = 25}))}, Token {line = 1, ty = SingleToken Semicolon}, Token {line = 1, ty = SingleToken Newline}, Token {line = 2, ty = KeywordToken While}, Token {line = 2, ty = SingleToken LeftParen}, Token {line = 2, ty = IdentifierToken "a"}, Token {line = 2, ty = MultiToken Less}, Token {line = 2, ty = LiteralToken (NumberLiteral (Number {wholePart = 10, fractionalPart = 0}))}, Token {line = 2, ty = SingleToken RightParen}, Token {line = 2, ty = SingleToken LeftBrace}, Token {line = 2, ty = SingleToken Newline}, Token {line = 3, ty = KeywordToken Print}, Token {line = 3, ty = IdentifierToken "a"}, Token {line = 3, ty = SingleToken Semicolon}, Token {line = 3, ty = SingleToken Newline}, Token {line = 4, ty = IdentifierToken "a"}, Token {line = 4, ty = MultiToken Equal}, Token {line = 4, ty = IdentifierToken "a"}, Token {line = 4, ty = SingleToken Plus}, Token {line = 4, ty = LiteralToken (NumberLiteral (Number {wholePart = 1, fractionalPart = 0}))}, Token {line = 4, ty = SingleToken Semicolon}, Token {line = 4, ty = SingleToken Newline}, Token {line = 5, ty = SingleToken RightBrace}, Token {line = 5, ty = SingleToken Newline}, Token {line = 6, ty = KeywordToken Fun}, Token {line = 6, ty = IdentifierToken "printSum"}, Token {line = 6, ty = SingleToken LeftParen}, Token {line = 6, ty = IdentifierToken "a"}, Token {line = 6, ty = SingleToken Comma}, Token {line = 6, ty = IdentifierToken "b"}, Token {line = 6, ty = SingleToken RightParen}, Token {line = 6, ty = SingleToken LeftBrace}, Token {line = 6, ty = SingleToken Newline}, Token {line = 7, ty = KeywordToken Print}, Token {line = 7, ty = IdentifierToken "a"}, Token {line = 7, ty = SingleToken Plus}, Token {line = 7, ty = IdentifierToken "b"}, Token {line = 7, ty = SingleToken Semicolon}, Token {line = 7, ty = CommentToken "comment"}, Token {line = 8, ty = SingleToken RightBrace}, Token {line = 8, ty = SingleToken Newline}]
  