-- | -- Module : Language.Go.Parser.Parser -- Copyright : (c) 2011 Andrew Robbins -- License : GPLv3 (see COPYING) -- -- y {- LANGUAGE CPP -} module Language.Go.Parser.Parser where import Language.Go.Parser.Tokens import Language.Go.Parser.Tokens (GoTokenPos(..)) import Language.Go.Parser.Lexer (alexScanTokens) import Language.Go.Syntax.AST import Control.Monad import Data.Maybe (isJust) import Text.Parsec.Prim import Text.Parsec.Error (ParseError) import Text.Parsec.Combinator import Data.Function {- | Tokenize Go Language source code TODO: * [X] Semicolon insertion (currently ';' is required) - DONE! * [ ] Unicode identifiers (currently '#[...]' can be used) -} goTokenize :: String -> [GoTokenPos] goTokenize s = filter whitespace (goRecognize (alexScanTokens s)) where whitespace (GoTokenPos _ x) = nonnull x && nonsemi x && comment x comment x = (not (goTokenEq x (GoTokComment False ""))) nonsemi = (/= GoTokSemicolonAuto) nonnull = (/= GoTokNone) goSemiNeeded :: GoToken -> Bool goSemiNeeded token = case token of GoTokId _ -> True GoTokInteger _ _ -> True GoTokFloat _ _ -> True GoTokFloatI _ _ -> True GoTokChar _ _ -> True GoTokString _ _ -> True GoTokBreak -> True GoTokContinue -> True GoTokFallthrough -> True GoTokReturn -> True GoTokDec -> True GoTokInc -> True GoTokRParen -> True GoTokRBrace -> True GoTokRBracket -> True _ -> False goRecognize :: [GoTokenPos] -> [GoTokenPos] goRecognize [] = [] goRecognize ((xt@(GoTokenPos xp x)):[]) = (xt:repl:[]) where cond = if goSemiNeeded x then GoTokSemicolon else GoTokNone repl = GoTokenPos xp cond goRecognize ((xt@(GoTokenPos _ x)):(yt@(GoTokenPos yp y)):zs) = xt:(goRecognize ((repl y):zs)) where cond = if goSemiNeeded x then GoTokSemicolon else GoTokNone repl GoTokSemicolonAuto = GoTokenPos yp cond repl _ = yt --goBrace --goParen --goBracket -- | Parse Go Language source code into AST goParse :: String -> String -> Either ParseError GoSource goParse filename s = goParseTokens filename $ goTokenize s -- | Parse Go Language token list into AST goParseTokens :: String -> [GoTokenPos] -> Either ParseError GoSource goParseTokens filename toks = parse goSource filename toks goParseFileWith :: GoParser a -> String -> String -> Either ParseError a goParseFileWith start filename s = parse start filename (goTokenize s) goParseTestWith :: GoParser a -> String -> Either ParseError a goParseTestWith start s = parse start "" (goTokenize s) -- | Go @Source@ production goSource :: GoParser GoSource goSource = do pkg <- goSemi goPackageClause imp <- many $ goSemi goTopLevelPrel top <- many $ goSemi goTopLevelDecl goSourceRest return $ GoSource pkg [] top goSourceRest :: GoParser () goSourceRest = do rest <- many anyToken case length rest of 0 -> return () _ -> fail "language-go: Source not consumed" -- | Go @PackageClase@ production goPackageClause :: GoParser GoId goPackageClause = do goTokPackage goIdentifier {- | Nonstandard @TopLevelPrel@ production This is not part of the standard, but is here to abstract away some of the details of possible extensions to the language. -} goTopLevelPrel :: GoParser GoPrel goTopLevelPrel = goImportDecl -- | Go @TopLevelDecl@ production goTopLevelDecl :: GoParser GoDecl goTopLevelDecl = goConstDecl <|> goTypeDecl <|> goVarDecl <|> goFunctionDecl <|> goMethodDecl -- <|> fail "TopLevelDecl what?" goImportDecl :: GoParser GoPrel goImportDecl = goTokImport >> liftM GoImportDecl goImportSpec goImportSpec :: GoParser [GoImpSpec] goImportSpec = goImpSpecs' <|> goImpSpecs'' where goImpSpecs' = do spec <- goImpSpec return $ [spec] goImpSpecs'' = do goTokLParen specs <- many $ goSemi goImpSpec goTokRParen return $ specs goImpSpec :: GoParser GoImpSpec goImpSpec = do ty <- goImpType ip <- goString return $ GoImpSpec ty ip goImpType :: GoParser GoImpType goImpType = lookAhead anyToken >>= \(GoTokenPos _ tok) -> case tok of --GoTokId _ -> fail "ident" --GoTokFullStop -> fail "period" --GoTokString _ _ -> fail "string" GoTokId _ -> liftM GoImpQual goIdentifier GoTokFullStop -> liftM GoImpDot goOperator GoTokString _ _ -> return GoImp _ -> fail "language-go: bad import" -- tokens goTokenEq :: GoToken -> GoToken -> Bool goTokenEq (GoTokComment _ _) (GoTokComment _ _) = True goTokenEq (GoTokInteger _ _) (GoTokInteger _ _) = True goTokenEq (GoTokFloat _ _) (GoTokFloat _ _) = True goTokenEq (GoTokFloatI _ _) (GoTokFloatI _ _) = True goTokenEq (GoTokId _) (GoTokId _) = True goTokenEq (GoTokOp _) (GoTokOp _) = True goTokenEq a b = a == b goToken :: GoToken -> GoParser GoToken goToken tok = token showTok posnTok testTok where showTok (GoTokenPos pos t) = show t posnTok (GoTokenPos pos t) = pos testTok (GoTokenPos pos t) = if goTokenEq tok t then Just t else Nothing goIdentifier :: GoParser GoId goIdentifier = do GoTokId name <- goToken $ GoTokId "" return $ GoId name goOperator :: GoParser GoOp goOperator = do GoTokOp name <- goToken $ GoTokOp "" return $ GoOp name goTokAsterisk = try $ do (GoOp "*") <- goOperator return () goTokLParen = try $ goToken $ GoTokLParen goTokRParen = try $ goToken $ GoTokRParen goTokLBrace = try $ goToken $ GoTokLBrace goTokRBrace = try $ goToken $ GoTokRBrace goTokLBracket = try $ goToken $ GoTokLBracket goTokRBracket = try $ goToken $ GoTokRBracket goTokSemicolon= try $ goToken $ GoTokSemicolon goTokColon = try $ goToken $ GoTokColon goTokComma = try $ goToken $ GoTokComma goTokFullStop = try $ goToken $ GoTokFullStop --goTokAsterisk = try $ goToken $ GoTokAsterisk goTokElipsis = try $ goToken $ GoTokElipsis goTokDec = try $ goToken $ GoTokDec goTokInc = try $ goToken $ GoTokInc goTokBreak = try $ goToken $ GoTokBreak goTokCase = try $ goToken $ GoTokCase goTokChan = try $ goToken $ GoTokChan goTokConst = try $ goToken $ GoTokConst goTokContinue = try $ goToken $ GoTokContinue goTokDefault = try $ goToken $ GoTokDefault goTokDefer = try $ goToken $ GoTokDefer goTokElse = try $ goToken $ GoTokElse goTokFallthrough = try $ goToken $ GoTokFallthrough goTokFor = try $ goToken $ GoTokFor goTokFunc = try $ goToken $ GoTokFunc goTokGo = try $ goToken $ GoTokGo goTokGoto = try $ goToken $ GoTokGoto goTokIf = try $ goToken $ GoTokIf goTokImport = try $ goToken $ GoTokImport goTokInterface= try $ goToken $ GoTokInterface goTokMap = try $ goToken $ GoTokMap goTokPackage = try $ goToken $ GoTokPackage goTokRange = try $ goToken $ GoTokRange goTokReturn = try $ goToken $ GoTokReturn goTokSelect = try $ goToken $ GoTokSelect goTokStruct = try $ goToken $ GoTokStruct goTokSwitch = try $ goToken $ GoTokSwitch goTokType = try $ goToken $ GoTokType goTokVar = try $ goToken $ GoTokVar --goTokBinaryOps = goOperator --goTokAssignOps = goOperator goUnaryOp :: GoParser GoOp goUnaryOp = goOperator goBinaryOp :: GoParser GoOp goBinaryOp = do op <- goOperator case op of (GoOp "=") -> fail "BinaryOp what?" _ -> return op goAssignOp :: GoParser GoOp goAssignOp = goOperator goTokArrowOp :: GoParser () goTokArrowOp = do op <- goOperator case op of GoOp "<-" -> return () _ -> fail "language-go: Expected '<-' token" goTokColonEq :: GoParser () goTokColonEq = do op <- goOperator case op of GoOp ":=" -> return () _ -> fail "language-go: Expected ':=' token" goTokEq :: GoParser () goTokEq = do op <- goOperator case op of GoOp "=" -> return () _ -> fail "language-go: Expected '=' token" -- combinators goAfter :: GoParser b -> GoParser a -> GoParser a goAfter y x = do z <- x ; y ; return z goSemi :: GoParser a -> GoParser a goSemi = goAfter goTokSemicolon -- literals goString :: GoParser String goString = do (GoTokenPos _ tok) <- anyToken -- goToken $ GoTokString Nothing " " case tok of (GoTokString rep uni) -> return uni _ -> fail "String: what?" -- parsers goBuiltinCall :: GoParser GoPrim goBuiltinCall = do id <- goIdentifier goTokLParen tj <- optionMaybe goType ar <- option [] goBuiltinArgs goTokRParen case (id, tj) of (GoId "new", Just ty) -> return $ GoNew ty (GoId "make", Just ty) -> return $ GoMake ty ar _ -> fail "BuiltinCall what?" goBuiltinArgs :: GoParser [GoExpr] goBuiltinArgs = do goTokComma goExpressionList goType = goTypeName <|> goTypeLit <|> goTypeParen goTypeParen = do goTokLParen t <- goType goTokRParen return t goTypeName :: GoParser GoType goTypeName = do (GoQual q n) <- goQualifiedIdent return $ GoTypeName q n goTypeLit :: GoParser GoType goTypeLit = (try goSliceType) <|> goArrayType <|> goStructType <|> goPointerType <|> goFunctionType <|> goInterfaceType <|> goMapType <|> goChannelType goArrayType :: GoParser GoType goArrayType = do goTokLBracket l <- goExpression goTokRBracket t <- goType return $ GoArrayType l t goSliceType :: GoParser GoType goSliceType = do goTokLBracket goTokRBracket t <- goType return $ GoSliceType t goStructType :: GoParser GoType goStructType = do goTokStruct goTokLBrace d <- many (goSemi goFieldDecl) goTokRBrace return $ GoStructType d goFieldTag :: GoParser String goFieldTag = goString -- "struct documentation" goFieldDecl = goFieldDecl'' <|> goFieldDecl' goFieldDecl' = do ids <- goIdentifierList t <- goType tag <- option "" (try goFieldTag) return $ GoFieldType tag ids t goFieldDecl'' = do goTokAsterisk -- "*" t <- goTypeName -- TypeName tag <- option "" (try goFieldTag) return $ GoFieldAnon tag t goPointerType :: GoParser GoType goPointerType = do goTokAsterisk t <- goType return $ GoPointerType t goFunctionType :: GoParser GoType goFunctionType = do goTokFunc s <- goSignature return $ GoFunctionType s goSignature :: GoParser GoSig goSignature = do par <- goParameters res <- option [] goResult return $ GoSig par res goResult :: GoParser [GoParam] goResult = goParameters <|> do ty <- goType ; return [GoParam [] ty] goParameters :: GoParser [GoParam] goParameters = do goTokLParen params <- option [] $ do ps <- goParameterList optional goTokComma return ps goTokRParen return params goParameterList :: GoParser [GoParam] goParameterList = sepBy goParameterDecl goTokComma goParameterDecl :: GoParser GoParam goParameterDecl = (try goParameterDecl') <|> goParameterDecl'' goParameterDecl' :: GoParser GoParam goParameterDecl' = do is <- option [] goIdentifierList optional goTokElipsis t <- goType return $ GoParam is t -- return $ flip map is (\i -> GoParam (Just i) t) goParameterDecl'' :: GoParser GoParam goParameterDecl'' = do t <- goType return $ GoParam [] t goInterfaceType :: GoParser GoType goInterfaceType = do goTokInterface goTokLBrace xs <- many (goSemi goMethodSpec) goTokRBrace return $ GoInterfaceType xs goMethodSpec = goMethodSpec' <|> goMethodSpec'' where goMethodSpec' = do n <- goIdentifier s <- goSignature return $ GoMethSpec n s goMethodSpec'' = liftM GoInterface goIdentifier -- TypeName goMapType :: GoParser GoType goMapType = do goTokMap goTokLBracket ktype <- goType goTokRBracket etype <- goType return $ GoMapType ktype etype goChannelQuip :: GoParser GoChanKind goChannelQuip = do goTokArrowOp ; goTokChan ; return GoIChan -- 1=RecvDir <|> (try $ do goTokChan ; goTokArrowOp ; return GoOChan) -- 2=SendDir <|> (try $ do goTokChan ; return GoIOChan) -- 3=BothDir goChannelType :: GoParser GoType goChannelType = do qi <- goChannelQuip ty <- goType return $ GoChannelType qi ty goDeclaration :: GoParser GoDecl goDeclaration = goConstDecl <|> goTypeDecl <|> goVarDecl "declaration" goStatement :: GoParser GoStmt goStatement = (liftM GoStmtDecl goDeclaration) -- 'Statement/Declaration' <|> (liftM GoStmtSimple goSimple) -- 'Statement/SimpleStmt' <|> goLabeledStmt <|> goGoStmt <|> goReturnStmt <|> goBreakStmt <|> goContinueStmt -- <|> goGotoStmt -- <|> goFallthroughStmt -- <|> liftM GoStmtBlock goBlock <|> goIfStmt -- <|> goSwitchStmt -- DONE -- <|> goSelectStmt <|> goForStmt -- DONE -- <|> goDeferStmt "statement" goLabeledStmt :: GoParser GoStmt goLabeledStmt = do id <- goIdentifier goTokColon st <- goStatement return $ GoStmtLabeled id st goSimple :: GoParser GoSimp goSimple = (liftM GoSimpExpr goExpression) -- 'SimpleStmt/ExpressionStmt' -- <|> goIncDecStmt -- 'SimpleStmt/IncDecStmt' -- <|> goAssignment -- 'SimpleStmt/Assignment' -- <|> goShortVarDecl -- 'SimpleStmt/ShortVarDecl' goIncDecStmt :: GoParser GoSimp goIncDecStmt = try $ do ex <- goExpression op <- goOperator case op of GoOp "++" -> return $ GoSimpInc ex GoOp "--" -> return $ GoSimpDec ex _ -> fail "IncDecStmt What?" -- | Go @Assignment@ production goAssignment :: GoParser GoSimp goAssignment = try $ do lv <- goExpressionList op <- goOperator rv <- goExpressionList let failure = fail "Assignment What?" case op of GoOp opname -> if last opname == '=' then return $ GoSimpAsn lv op rv else failure -- _ -> failure -- | Go @ShortVarDecl@ production goShortVarDecl :: GoParser GoSimp goShortVarDecl = do ids <- goIdentifierList goTokColonEq exs <- goExpressionList return $ GoSimpVar ids exs goBlock :: GoParser GoBlock goBlock = liftM GoBlock $ between goTokLBrace goTokRBrace $ many $ goSemi goStatement goIdentifierList :: GoParser [GoId] goIdentifierList = sepBy goIdentifier goTokComma goExpressionList :: GoParser [GoExpr] goExpressionList = sepBy goExpression goTokComma goCVSpecs :: GoParser [GoCVSpec] goCVSpecs = try goCVSpecs' <|> goCVSpecs'' where goCVSpecs' = do spec <- goCVSpec return $ [spec] goCVSpecs'' = do goTokLParen specs <- many $ goSemi goCVSpec goTokRParen return $ specs goCVSpec :: GoParser GoCVSpec goCVSpec = do ids <- goIdentifierList try (goCVSpec' ids) <|> goCVSpec'' ids where goCVSpec' :: [GoId] -> GoParser GoCVSpec goCVSpec' ids = do goTokEq exs <- goExpressionList return $ GoCVSpec ids Nothing exs goCVSpec'' :: [GoId] -> GoParser GoCVSpec goCVSpec'' ids = do typ <- goType goTokEq exs <- goExpressionList return $ GoCVSpec ids (Just typ) exs goConstDecl :: GoParser GoDecl goConstDecl = goTokConst >> goCVSpecs >>= (return . GoConst) goVarDecl :: GoParser GoDecl goVarDecl = goTokVar >> goCVSpecs >>= (return . GoVar) goTypeDecl :: GoParser GoDecl goTypeDecl = goTokType >> goTypeSpecs >>= (return . GoType) goTypeSpecs :: GoParser [GoTypeSpec] goTypeSpecs = try goTypeDecl' <|> goTypeDecl'' where goTypeDecl' = do spec <- goTypeSpec return $ [spec] goTypeDecl'' = do goTokLParen specs <- many $ goSemi goTypeSpec goTokRParen return $ specs goTypeSpec :: GoParser GoTypeSpec goTypeSpec = do id <- goIdentifier ty <- goType return $ GoTypeSpec id ty goFunctionDecl :: GoParser GoDecl goFunctionDecl = try $ do goTokFunc id <- goIdentifier sg <- goSignature bk <- option GoNoBlock goBlock return $ GoFunc $ GoFuncDecl id sg bk goMethodDecl :: GoParser GoDecl goMethodDecl = try $ do goTokFunc rc <- goReceiver id <- goIdentifier sg <- goSignature bk <- option GoNoBlock goBlock return $ GoMeth $ GoMethDecl rc id sg bk goReceiver :: GoParser GoRec goReceiver = between goTokLParen goTokRParen recspec where recspec = do id <- optionMaybe goIdentifier pt <- optionMaybe goOperator -- Asterisk ty <- goTypeName return $ GoRec (isJust pt) id ty goQualifiedIdent :: GoParser GoPrim goQualifiedIdent = do ns <- sepBy1 goIdentifier goTokFullStop let qual = init ns name = last ns return $ GoQual qual name goOperand :: GoParser GoPrim goOperand = (try goLiteralPrim) <|> goQualifiedIdent -- <|> goMethodExpr -- <|> between goTokLParen goTokRParen $ goExpression goLiteralPrim :: GoParser GoPrim goLiteralPrim = liftM GoLiteral goLiteral goLiteral :: GoParser GoLit goLiteral = goBasicLit <|> goCompositeLit <|> goFunctionLit "literal" goBasicLit :: GoParser GoLit goBasicLit = try $ do (GoTokenPos _ tok) <- anyToken case tok of (GoTokInteger (Just s) t) -> return $ GoLitInt s t (GoTokFloat (Just s) t) -> return $ GoLitReal s t (GoTokFloatI (Just s) t) -> return $ GoLitImag s t (GoTokChar (Just s) t) -> return $ GoLitChar s t (GoTokString (Just s) t) -> return $ GoLitStr s t _ -> fail "BasicLit: What?" {- was goBasicLit = goLitInteger <|> goLitFloat <|> goLitFloatI <|> goLitChar <|> goLitString -} goCompositeLit :: GoParser GoLit goCompositeLit = do ty <- goLiteralType va <- goLiteralValue return $ GoLitComp ty va goArrayElipsisType :: GoParser GoType goArrayElipsisType = do goTokLBracket goTokElipsis goTokRBracket goType -- only in TypeLit: -- Pointer -- InterfaceType -- ChannelType -- FunctionType (available as FunctionLit) -- only in LiteralType: -- goArrayElipsisType goLiteralType :: GoParser GoType goLiteralType = (try goArrayType) <|> (try goArrayElipsisType) <|> goSliceType <|> goStructType <|> goMapType <|> goTypeName goLiteralValue :: GoParser GoComp goLiteralValue = do goTokLBrace el <- goElementList -- optional goTokComma goTokRBrace return $ GoComp el goElementList :: GoParser [GoElement] goElementList = sepBy1 goElement goTokComma goElement :: GoParser GoElement goElement = do key <- goElementKey val <- goValue return $ GoElement key val goElementKey :: GoParser GoKey goElementKey = option GoKeyNone (try keyed) where keyed = do k <- goKey goTokColon return k goKey :: GoParser GoKey goKey = liftM GoKeyField goIdentifier -- FieldName <|> liftM GoKeyIndex goExpression -- ElementIndex "literal key" goValue :: GoParser GoValue goValue = liftM GoValueExpr goExpression <|> liftM GoValueComp goLiteralValue "literal value" goFunctionLit :: GoParser GoLit goFunctionLit = liftM GoLitFunc goFuncLambda --goFuncLambda :: GoParser GoLitFunc goFuncLambda = do goTokFunc sg <- goSignature bk <- goBlock return $ GoFuncExpr sg bk -- | Standard @Expression@ -- -- Technically, the Go spec says -- -- * @Expression@ = @UnaryExpr@ | @Expression@ @binary_op@ @UnaryExpr@ . -- -- * @UnaryExpr@ = @PrimaryExpr@ | @unary_op@ @UnaryExpr@ . -- -- but we combine these into one production here. goExpression :: GoParser GoExpr goExpression = goUnaryExpr >>= goBinaryExpr' -- | Standard @PrimaryExpr@ -- -- @PrimaryExpr@ is occurs in many places: -- -- * @Expression@, -- -- * @TypeSwitchGuard@, -- -- * and in its own definition. -- -- Therefore, it is useful to have a separate datatype for it, -- since otherwise we would have to repeat ourselves. This is -- the responsibility @goPrimary@ below. The only thing we do -- here is convert the AST one level, so it's an expression. goPrimaryExpr :: GoParser GoExpr goPrimaryExpr = liftM GoPrim (goPrimary) -- | Nonstandard primary expressions (self-contained) goPrimary :: GoParser GoPrim goPrimary = goPrimary' >>= goPrimary''' -- THANK YOU ski ... goPrimary''' :: GoPrim -> GoParser GoPrim goPrimary''' ex = (goPrimary'' ex >>= goPrimary''') <|> return ex -- this is the right-associative parts of 'PrimaryExpr' goPrimary'' :: GoPrim -> GoParser GoPrim goPrimary'' ex = goIndex ex <|> goSlice ex <|> goTypeAssertion ex <|> goCall ex -- <|> goSelector ex -- how to distinguish from qualified identifiers? -- "primary expression component" -- this is the beginning of 'PrimaryExpr' goPrimary' :: GoParser GoPrim goPrimary' = (try goBuiltinCall) <|> (try goConversion) <|> goOperand -- "primary expression start" goConversion :: GoParser GoPrim goConversion = do ty <- goType goTokLParen ex <- goExpression goTokRParen return $ GoCast ty ex goUnaryExpr :: GoParser GoExpr goUnaryExpr = goPrimaryExpr <|> do op <- goUnaryOp ex <- goUnaryExpr return $ Go1Op op ex -- we cheat here and make them right-associative -- even though the standard indicates left-associative -- this could be reversed later during processing goBinaryExpr :: GoExpr -> GoParser GoExpr goBinaryExpr ex = do op <- goBinaryOp e2 <- goExpression return $ Go2Op op ex e2 goBinaryExpr' :: GoExpr -> GoParser GoExpr goBinaryExpr' ex = (goBinaryExpr ex >>= goBinaryExpr') <|> return ex goSelector :: GoPrim -> GoParser GoPrim goSelector ex = do goTokFullStop id <- goIdentifier return $ GoSelect ex id goIndex :: GoPrim -> GoParser GoPrim goIndex ex = do goTokLBracket ix <- goExpression goTokRBracket return $ GoIndex ex ix goSlice :: GoPrim -> GoParser GoPrim goSlice ex = do goTokLBracket ix <- optionMaybe goExpression goTokColon iy <- optionMaybe goExpression goTokRBracket let zero = GoPrim (GoLiteral (GoLitInt "0" 0)) return $ case (ix, iy) of (Just x, Just y) -> GoSlice ex [x, y] (Just x, Nothing) -> GoSlice ex [x] (Nothing, Just y) -> GoSlice ex [zero, y] (Nothing, Nothing) -> GoSlice ex [zero] goTypeAssertion :: GoPrim -> GoParser GoPrim goTypeAssertion ex = do goTokFullStop goTokLParen ty <- goType goTokRParen return $ GoTA ex ty goCall :: GoPrim -> GoParser GoPrim goCall ex = do goTokLParen ar <- goExpressionList rs <- optionMaybe goTokElipsis goTokRParen return $ case rs of (Just _) -> GoCallV ex ar Nothing -> GoCall ex ar {- goMethodExpr = () goReceiverType = goTypeName -- <|> goReceiverParen -} goIfStmt :: GoParser GoStmt goIfStmt = do goTokIf s <- optionMaybe (goSemi goSimple) c <- optionMaybe goExpression b <- goBlock e <- optionMaybe (goTokElse >> goStatement) return $ GoStmtIf s c b e goSwitchStmt = goExprSwitchStmt -- <|> goTypeSwitchStmt goExprSwitchStmt :: GoParser GoStmt goExprSwitchStmt = do goTokSwitch s <- optionMaybe (goSemi goSimple) e <- optionMaybe goExpression goTokLBrace c <- many1 goExprCaseClause goTokRBrace return $ GoStmtSwitch s e c goExprCaseClause :: GoParser GoCase goExprCaseClause = do j <- goExprSwitchCase goTokColon m <- many1 (goSemi goStatement) return $ case j of Just ex -> GoCase ex m Nothing -> GoDefault m goExprSwitchCase :: GoParser (Maybe [GoExpr]) goExprSwitchCase = goExprSwitchCase' <|> goExprSwitchCase'' goExprSwitchCase' = goTokCase >> liftM Just goExpressionList goExprSwitchCase'' = goTokDefault >> return Nothing {- goTypeSwitchStmt :: GoParser GoStmt goTypeSwitchStmt = () goTypeSwitchGuard = () goTypeCaseClause = () goTypeSwitchCase = () goTypeList = () -} goForStmt = do goTokFor h <- (goCondition <|> goForClause <|> goRangeClause) b <- goBlock return $ GoStmtFor h b goCondition :: GoParser GoForClause goCondition = liftM GoForWhile goExpression goForClause :: GoParser GoForClause goForClause = do i <- option GoSimpEmpty goSimple goTokSemicolon c <- optionMaybe goExpression goTokSemicolon p <- option GoSimpEmpty goSimple return $ GoForThree i c p goRangeClause :: GoParser GoForClause goRangeClause = do k <- goExpression v <- goExpressionList -- TODO: optionMaybe (goTokComma >> goExpression) p <- goOperator goTokRange e <- goExpression return $ GoForRange (k:v) e -- goEmpty = (GoStmtSimple GoSimpEmpty) -- goCondition -- goForClause -- goInitStmt -- goPostStmt -- goRangeClause goGoStmt :: GoParser GoStmt goGoStmt = do goTokGo liftM GoStmtGo goExpression goReturnStmt :: GoParser GoStmt goReturnStmt = goReturnStmt' <|> goReturnStmt'' goReturnStmt' = try $ do goTokReturn rv <- goExpressionList --(liftM (\x -> [x]) goExpression) --List return $ GoStmtReturn rv goReturnStmt'' = do goTokReturn return $ GoStmtReturn [] goBreakStmt = do goTokBreak id <- optionMaybe goIdentifier return $ GoStmtBreak id goContinueStmt = do goTokContinue id <- optionMaybe goIdentifier return $ GoStmtContinue id