module CirruParser ( parse , pare ) where import Cirru import Debug.Trace isEmpty :: String -> Bool isEmpty [] = True isEmpty _ = False emptyList = CirruList [] parse :: String -> String -> CirruValue parse code filename = parseState emptyList buffer startState code where buffer = CirruBuffer "" 1 1 startState = CirruState "indent" 1 1 1 0 0 0 filename cr :: CirruValue -> CrValue cr (CirruToken x _ _ _ _ _) = CrString x cr (CirruList xs) = CrList (map cr xs) pare :: String -> String -> CrValue pare code filename = cr (parse code filename) newState x = x log2 :: CirruValue -> CirruBuffer -> CirruState -> String -> String log2 xs buffer state code = "\nstate:\t" ++ (show state) ++ "\ncode:\t" ++ (show code) ++ "\nxs:\t" ++ (show xs) ++ "\nbuffer:\t" ++ (show buffer) parseState2 :: CirruValue -> CirruBuffer -> CirruState -> String -> CirruValue parseState2 xs buffer state code = trace (log2 xs buffer state code) $ parseState xs buffer state code parseState :: CirruValue -> CirruBuffer -> CirruState -> String -> CirruValue parseState xs buffer state code = if (isEmpty code) then case (sName state) of ("escape") -> escapeEof xs buffer state code ("string") -> stringEof xs buffer state code ("space") -> spaceEof xs buffer state code ("token") -> tokenEof xs buffer state code ("indent") -> indentEof xs buffer state code else case (sName state) of ("escape") -> case (head code) of ('\n') -> escapeNewline xs buffer state code ('n') -> escapeN xs buffer state code ('t') -> escapeT xs buffer state code _ -> escapeElse xs buffer state code ("string") -> case (head code) of ('\\') -> stringBackslash xs buffer state code ('\n') -> stringNewline xs buffer state code ('\"') -> stringQuote xs buffer state code _ -> stringElse xs buffer state code ("space") -> case (head code) of (' ') -> spaceSpace xs buffer state code ('\n') -> spaceNewline xs buffer state code ('(') -> spaceOpen xs buffer state code (')') -> spaceClose xs buffer state code ('"') -> spaceQuote xs buffer state code _ -> spaceElse xs buffer state code ("token") -> case (head code) of (' ') -> tokenSpace xs buffer state code ('\n') -> tokenNewline xs buffer state code ('(') -> tokenOpen xs buffer state code (')') -> tokenClose xs buffer state code ('"') -> tokenQuote xs buffer state code _ -> tokenElse xs buffer state code ("indent") -> case (head code) of (' ') -> indentSpace xs buffer state code ('\n') -> indentNewline xs buffer state code (')') -> indentClose xs buffer state code _ -> indentElse xs buffer state code _ -> error ("unknown state: " ++ (sName state)) escapeEof xs buffer state code = error "EOF in escape state" stringEof xs buffer state code = error "EOF in string state" spaceEof xs buffer state code = xs tokenEof xs b s code = let newToken = CirruToken (bText b) (bX b) (bY b) (sX s) (sY s) (sPath s) newXs = appendItem xs (sLevel s) newToken in newXs indentEof xs buffer state code = xs escapeNewline xs buffer state code = error "new line while escape" escapeN :: CirruValue -> CirruBuffer -> CirruState -> String -> CirruValue escapeN xs b s code = let newState = CirruState "string" ((sX s)+1) (sY s) (sLevel s) (sIndent s) (sIndented s) (sNest s) (sPath s) newBuffer = CirruBuffer ((bText b) ++ "\n") (bX b) (bY b) in parseState xs newBuffer newState (tail code) escapeT xs b s code = let newState = CirruState "string" ((sX s)+1) (sY s) (sLevel s) (sIndent s) (sIndented s) (sNest s) (sPath s) newBuffer = CirruBuffer ((bText b) ++ "\t") (bX b) (bY b) in parseState xs newBuffer newState (tail code) escapeElse xs b s code = let newState = CirruState "string" ((sX s)+1) (sY s) (sLevel s) (sIndent s) (sIndented s) (sNest s) (sPath s) newBuffer = CirruBuffer ((bText b) ++ [head code]) (bX b) (bY b) in parseState xs newBuffer newState (tail code) stringBackslash xs b s code = let newState = CirruState "escape" ((sX s)+1) (sY s) (sLevel s) (sIndent s) (sIndented s) (sNest s) (sPath s) in parseState xs b newState (tail code) stringNewline xs buffer state code = error "newline in a string" stringQuote xs b s code = let newState = CirruState "token" ((sX s)+1) (sY s) (sLevel s) (sIndent s) (sIndented s) (sNest s) (sPath s) in parseState xs b newState (tail code) stringElse xs b s code = let newState = CirruState (sName s) ((sX s)+1) (sY s) (sLevel s) (sIndent s) (sIndented s) (sNest s) (sPath s) newBuffer = CirruBuffer ((bText b) ++ [head code]) (bX b) (bY b) in parseState xs newBuffer newState (tail code) spaceSpace xs b s code = let newState = CirruState (sName s) ((sX s)+1) (sY s) (sLevel s) (sIndent s) (sIndented s) (sNest s) (sPath s) in parseState xs b newState (tail code) spaceNewline xs b s code = if (mod (sNest s) 2) == 1 then error "incorrect nesting" else let newState = CirruState "indent" 1 ((sY s)+1) (sLevel s) (sIndent s) 0 (sNest s) (sPath s) in parseState xs b newState (tail code) spaceOpen xs b s code = let nesting = createNesting 1 newXs = appendItem xs (sLevel s) nesting newState = CirruState (sName s) ((sX s)+1) (sY s) ((sLevel s)+1) (sIndent s) (sIndented s) ((sNest s)+1) (sPath s) in parseState newXs b newState (tail code) spaceClose xs b s code = if ((sNest s) < 1) then error "close at space" else let newState = CirruState (sName s) ((sX s)+1) (sY s) ((sLevel s)-1) (sIndent s) (sIndented s) ((sNest s)-1) (sPath s) in parseState xs b newState (tail code) spaceQuote xs b s code = let newState = CirruState "string" ((sX s)+1) (sY s) (sLevel s) (sIndent s) (sIndented s) (sNest s) (sPath s) newBuffer = CirruBuffer "" (sX s) (sY s) in parseState xs newBuffer newState (tail code) spaceElse xs b s code = let newState = CirruState "token" ((sX s)+1) (sY s) (sLevel s) (sIndent s) (sIndented s) (sNest s) (sPath s) newBuffer = CirruBuffer [head code] (sX s) (sY s) in parseState xs newBuffer newState (tail code) tokenSpace xs b s code = let newState = CirruState "space" ((sX s)+1) (sY s) (sLevel s) (sIndent s) (sIndented s) (sNest s) (sPath s) newToken = CirruToken (bText b) (bX b) (bY b) (sX s) (sY s) (sPath s) newXs = appendItem xs (sLevel s) newToken in parseState newXs b newState (tail code) tokenNewline xs b s code = let newState = CirruState "indent" 1 ((sY s)+1) (sLevel s) (sIndent s) 0 (sNest s) (sPath s) newToken = CirruToken (bText b) (bX b) (bY b) (sX s) (sY s) (sPath s) newXs = appendItem xs (sLevel s) newToken in parseState newXs b newState (tail code) tokenOpen xs buffer state code = error "open parenthesis in token" tokenClose xs b s code = let newState = CirruState "space" (sX s) (sY s) (sLevel s) (sIndent s) (sIndented s) (sNest s) (sPath s) newToken = CirruToken (bText b) (bX b) (bY b) (sX s) (sY s) (sPath s) newXs = appendItem xs (sLevel s) newToken in parseState newXs b newState code tokenQuote xs b s code = let newState = CirruState "string" ((sX s)+1) (sY s) (sLevel s) (sIndent s) (sIndented s) (sNest s) (sPath s) in parseState xs b newState (tail code) tokenElse xs b s code = let newState = CirruState (sName s) ((sX s)+1) (sY s) (sLevel s) (sIndent s) (sIndented s) (sNest s) (sPath s) newBuffer = CirruBuffer ((bText b) ++ [head code]) ((sX s)+1) (sY s) in parseState xs newBuffer newState (tail code) indentSpace xs b s code = let newState = CirruState (sName s) ((sX s)+1) (sY s) (sLevel s) (sIndent s) ((sIndented s)+1) (sNest s) (sPath s) in parseState xs b newState (tail code) indentNewline xs b s code = let newState = CirruState (sName s) 1 ((sY s)+1) (sLevel s) (sIndent s) 0 (sNest s) (sPath s) in parseState xs b newState (tail code) indentClose xs buffer state code = error "close parenthesis at indent" indentElse xs b s code = if (mod (sIndented s) 2) == 1 then error ("odd indentation: " ++ (show (sIndented s))) else let indented = div (sIndented s) 2 diff = indented - (sIndent s) nesting = createNesting 1 newState = CirruState "space" (sX s) (sY s) ((sLevel s)+diff) indented (sIndented s) (sNest s) (sPath s) in if diff <= 0 then let newXs = appendItem xs ((sLevel s) + diff - 1) nesting in parseState newXs b newState code else if diff > 0 then let newXs = appendItem xs (sLevel s) nesting in parseState newXs b newState code else parseState xs b newState code