module Main where import Monad import System.Environment import Control.Monad.Error import Text.ParserCombinators.Parsec import Debug.Trace -- ghc --make p.hs && echo blah | ./p /dev/stdin main :: IO () main = do args <- getArgs filename <- return $ args !! 0 guts <- readFile $ filename putStrLn $ translateGo guts filename return () translateGo :: String -> String -> String translateGo input what = case parse parseGo what input of Left err -> "***** ERROR\n***** " ++ show err ++ "\n*****" Right s -> "GOOD{" ++ show s ++ "}" parseGo :: Parser String parseGo = do skipJunk x <- parseGoPackage ys <- parseGoStanzas return $ show $ x : ys parseGoStanzas :: Parser [GoStanza] parseGoStanzas = do x <- try parseGoEof <|> parseGoStanza case x of GoEof -> return [GoEof] _ -> do xs <- parseGoStanzas return $ x : xs data GoStanza = GoPackage String | GoImports [String] | GoConsts [(String, String)] | GoVars [(String, String)] | GoTypes [(String, String)] | GoFunc String | GoEof deriving (Show) parseGoStanza :: Parser GoStanza parseGoStanza = do x <- try parseGoPackage <|> try parseGoImports <|> try parseGoConsts <|> try parseGoVars <|> try parseGoTypes <|> try parseGoFunc <|> fail "stanza???" --return $ trace $ show x return $ x parseGoEof :: Parser GoStanza parseGoEof = do eof "parseGoEof" return $ GoEof keyword :: String -> Parser () keyword needed = do kw <- parseKeyword let Keyword k = kw if k == needed then return () else fail $ "keyword:" ++ needed ident :: Parser String ident = do id <- parseIdent "ident" let Ident name = id return name symbol :: String -> Parser () symbol needed = do sym <- parseSymbol let Symbol c = sym if c == needed then return () else fail $ "symbol:" ++ needed parseGoPackage :: Parser GoStanza parseGoPackage = do keyword "package" ident <- parseIdent let Ident name = ident return (GoPackage name) parseGoImports :: Parser GoStanza parseGoImports = do keyword "import" char '(' skipJunk char ')' skipJunk return (GoImports []) parseGoConsts :: Parser GoStanza parseGoConsts = do keyword "const" char '(' skipJunk char ')' skipJunk return (GoConsts []) parseGoVars :: Parser GoStanza parseGoVars = do keyword "var" char '(' skipJunk char ')' skipJunk return (GoVars []) parseGoTypes :: Parser GoStanza parseGoTypes = do keyword "type" char '(' skipJunk char ')' skipJunk return (GoTypes []) parseGoFunc :: Parser GoStanza parseGoFunc = do keyword "func" name <- ident symbol "(" arg1 <- ident symbol ")" symbol "{" symbol "}" return (GoFunc name) data Token = Comment String | Symbol String | Keyword String | Ident String | LitInt Integer | LitStr String | NewLine deriving (Show) parseToken :: Parser Token parseToken = try parseComment <|> try parseKeyword <|> try parseIdent <|> try parseLitInt <|> try parseLitStr <|> try parseSymbol <|> parseNewLine alphaz = "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" numz = "0123456789" whitez = " \t\r\v" skipJunk :: Parser () skipJunk = do many (try skipWhite1 <|> try skipComment <|> skipNewLine) return () where skipWhite1 = (many1 (oneOf whitez)) >> return () skipComment = parseComment >> return () skipNewLine = parseNewLine >> return () eofStr = do eof "eofStr" return "" skipWhite :: Parser () skipWhite = do eofStr <|> many (oneOf whitez) "skipWhite" return () parseComment :: Parser Token parseComment = do char '/' "parseComment/" char '/' "parseComment//" z <- many (noneOf "\n") char '\n' skipJunk return $ Comment z parseSymbol :: Parser Token parseSymbol = do z <- oneOf "!$%|*+-/:<=?>@#,^()[]{}" skipJunk return $ Symbol [z] parseAlphanumz :: Parser String parseAlphanumz = do y <- oneOf alphaz z <- many $ oneOf (alphaz ++ numz) skipJunk return ([y] ++ z) keywordz = [ "if", "then", "else", "var", "return", "package", "import", "const", "var", "type" ] parseKeyword = do x <- parseAlphanumz "parseKeyword" if memberp keywordz x then return $ Keyword x else fail $x parseIdent = do x <- parseAlphanumz return $ Ident x parseNatural :: Parser Integer parseNatural = do s <- many1 $ oneOf numz skipJunk return $ read s parseNegative = do char '-' x <- parseNatural return $ 0 - x parseLitInt = do z <- (try parseNegative) <|> parseNatural return $ LitInt z parseLitStr = do char '\"' z <- many (noneOf "\"") char '\"' skipJunk return $ LitStr z parseNewLine = do char '\n' skipJunk return $ NewLine memberp :: Eq a => [a] -> a -> Bool memberp [] _ = False --memberp (x:xs) x = True --memberp (x:xs) y = memberp xs y memberp (x:xs) y = if x==y then True else memberp xs y