Commit 322c7725 authored by Andrew Gibiansky's avatar Andrew Gibiansky Committed by Adam Vogt

fixing tests and line numbering of code blocks

parent 4ebe3434
...@@ -202,16 +202,31 @@ parserTests = do ...@@ -202,16 +202,31 @@ parserTests = do
layoutChunkerTests = describe "Layout Chunk" $ do layoutChunkerTests = describe "Layout Chunk" $ do
it "chunks 'a string'" $ it "chunks 'a string'" $
layoutChunks "a string" `shouldBe` ["a string"] map unloc (layoutChunks "a string") `shouldBe` ["a string"]
it "chunks 'a\\nstring'" $ it "chunks 'a\\n string'" $
layoutChunks "a\n string" `shouldBe` ["a\n string"] map unloc (layoutChunks "a\n string") `shouldBe` ["a\n string"]
it "chunks 'a\\n string\\nextra'" $ it "chunks 'a\\n string\\nextra'" $
layoutChunks "a\n string\nextra" `shouldBe` ["a\n string","extra"] map unloc (layoutChunks "a\n string\nextra") `shouldBe` ["a\n string","extra"]
it "chunks strings with too many lines" $ it "chunks strings with too many lines" $
layoutChunks "a\n\nstring" `shouldBe` ["a","string"] map unloc (layoutChunks "a\n\nstring") `shouldBe` ["a","string"]
it "parses multiple exprs" $ do
let text = [hereLit|
first
second
third
fourth
|]
layoutChunks text `shouldBe`
[Located 2 "first",
Located 4 "second",
Located 5 "third",
Located 7 "fourth"]
moduleNameTests = describe "Get Module Name" $ do moduleNameTests = describe "Get Module Name" $ do
it "parses simple module names" $ it "parses simple module names" $
...@@ -379,6 +394,6 @@ parseStringTests = describe "Parser" $ do ...@@ -379,6 +394,6 @@ parseStringTests = describe "Parser" $ do
first first
second second
|] >>= (`shouldBe` [Located 1 (Expression "first"), |] >>= (`shouldBe` [Located 2 (Expression "first"),
Located 2 (Expression "second")]) Located 4 (Expression "second")])
...@@ -51,6 +51,8 @@ data CodeBlock ...@@ -51,6 +51,8 @@ data CodeBlock
-- | Store locations along with a value. -- | Store locations along with a value.
data Located a = Located LineNumber a deriving (Eq, Show) data Located a = Located LineNumber a deriving (Eq, Show)
instance Functor Located where
fmap f (Located line a) = Located line $ f a
-- | Directive types. Each directive is associated with a string in the -- | Directive types. Each directive is associated with a string in the
-- directive code block. -- directive code block.
...@@ -83,7 +85,7 @@ parseString codeString = do ...@@ -83,7 +85,7 @@ parseString codeString = do
Failure {} -> Failure {} ->
-- Split input into chunks based on indentation. -- Split input into chunks based on indentation.
let chunks = layoutChunks $ dropComments codeString in let chunks = layoutChunks $ dropComments codeString in
joinFunctions <$> processChunks 1 [] chunks joinFunctions <$> processChunks [] chunks
where where
parseChunk :: GhcMonad m => String -> LineNumber -> m (Located CodeBlock) parseChunk :: GhcMonad m => String -> LineNumber -> m (Located CodeBlock)
parseChunk chunk line = Located line <$> parseChunk chunk line = Located line <$>
...@@ -91,16 +93,16 @@ parseString codeString = do ...@@ -91,16 +93,16 @@ parseString codeString = do
then return $ parseDirective chunk line then return $ parseDirective chunk line
else parseCodeChunk chunk line else parseCodeChunk chunk line
processChunks :: GhcMonad m => LineNumber -> [Located CodeBlock] -> [String] -> m [Located CodeBlock] processChunks :: GhcMonad m => [Located CodeBlock] -> [Located String] -> m [Located CodeBlock]
processChunks line accum remaining = processChunks accum remaining =
case remaining of case remaining of
-- If we have no more remaining lines, return the accumulated results. -- If we have no more remaining lines, return the accumulated results.
[] -> return $ reverse accum [] -> return $ reverse accum
-- If we have more remaining, parse the current chunk and recurse. -- If we have more remaining, parse the current chunk and recurse.
chunk:remaining -> do Located line chunk:remaining -> do
block <- parseChunk chunk line block <- parseChunk chunk line
processChunks (line + nlines chunk) (block : accum) remaining processChunks (block : accum) remaining
-- Test wither a given chunk is a directive. -- Test wither a given chunk is a directive.
isDirective :: String -> Bool isDirective :: String -> Bool
...@@ -248,25 +250,29 @@ parseDirective _ _ = error "Directive must start with colon!" ...@@ -248,25 +250,29 @@ parseDirective _ _ = error "Directive must start with colon!"
-- A chunk is a line and all lines immediately following that are indented -- A chunk is a line and all lines immediately following that are indented
-- beyond the indentation of the first line. This parses Haskell layout -- beyond the indentation of the first line. This parses Haskell layout
-- rules properly, and allows using multiline expressions via indentation. -- rules properly, and allows using multiline expressions via indentation.
layoutChunks :: String -> [String] layoutChunks :: String -> [Located String]
layoutChunks string = filter (not . null) $ map strip $ layoutLines $ lines string layoutChunks = go 1
where where
layoutLines :: [String] -> [String] go :: LineNumber -> String -> [Located String]
go line = filter (not . null . unloc) . map (fmap strip) . layoutLines line . lines
layoutLines :: LineNumber -> [String] -> [Located String]
-- Empty string case. If there's no input, output is empty. -- Empty string case. If there's no input, output is empty.
layoutLines [] = [] layoutLines _ [] = []
-- Use the indent of the first line to find the end of the first block. -- Use the indent of the first line to find the end of the first block.
layoutLines (firstLine:rest) = layoutLines lineIdx all@(firstLine:rest) =
let firstIndent = indentLevel firstLine let firstIndent = indentLevel firstLine
blockEnded line = indentLevel line <= firstIndent in blockEnded line = indentLevel line <= firstIndent in
case findIndex blockEnded rest of case findIndex blockEnded rest of
-- If the first block doesn't end, return the whole string, since -- If the first block doesn't end, return the whole string, since
-- that just means the block takes up the entire string. -- that just means the block takes up the entire string.
Nothing -> [string] Nothing -> [Located lineIdx $ intercalate "\n" all]
-- We found the end of the block. Split this bit out and recurse. -- We found the end of the block. Split this bit out and recurse.
Just idx -> Just idx ->
joinLines (firstLine:take idx rest) : layoutChunks (joinLines $ drop idx rest) let (before, after) = splitAt idx rest in
Located lineIdx (joinLines $ firstLine:before) : go (lineIdx + idx + 1) (joinLines after)
-- Compute indent level of a string as number of leading spaces. -- Compute indent level of a string as number of leading spaces.
indentLevel :: String -> Int indentLevel :: String -> Int
......
{
"metadata": {
"name": ""
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "code",
"collapsed": false,
"input": [
"import \n"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"no Python documentation found for 'PATH'\n",
"\n"
]
}
],
"prompt_number": 4
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
}
],
"metadata": {}
}
]
}
\ No newline at end of file
No preview for this file type
/* /*
Custom IHaskell CSS. Custom IHaskell CSS.
*/ */
table.suggestion-table { .highlight-code {
border: 0px; white-space: pre;
text-align: center; font-family: monospace;
}
tr.suggestion-row {
border: 0px;
}
td.suggestion-cell {
border: 0px;
} }
.suggestion-warning { .suggestion-warning {
font-weight: bold; font-weight: bold;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment