From 40f86f4b5901ad125468a4ab67791d297aea7b04 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 7 Jun 2017 15:57:39 -0400 Subject: [PATCH] Define type synonyms for Ruby and Python assignment so as to not have to keep editing every type signature. --- src/Language/Python/Syntax.hs | 97 ++++++++++++++++++----------------- src/Language/Ruby/Syntax.hs | 45 ++++++++-------- 2 files changed, 72 insertions(+), 70 deletions(-) diff --git a/src/Language/Python/Syntax.hs b/src/Language/Python/Syntax.hs index b56345f5e..f208fd581 100644 --- a/src/Language/Python/Syntax.hs +++ b/src/Language/Python/Syntax.hs @@ -13,7 +13,7 @@ import Data.Functor.Classes.Show.Generic import Data.Functor.Union import Data.Record import qualified Data.Syntax as Syntax -import Data.Syntax.Assignment hiding (Error) +import Data.Syntax.Assignment hiding (Assignment, Error) import qualified Data.Syntax.Assignment as Assignment import qualified Data.Syntax.Comment as Comment import qualified Data.Syntax.Declaration as Declaration @@ -65,6 +65,7 @@ type Syntax = type Error = Assignment.Error Grammar type Term = Term.Term (Union Syntax) (Record Location) +type Assignment = Assignment.Assignment Grammar Term -- | Ellipsis (used in splice expressions and alternatively can be used as a fill in expression, like `undefined` in Haskell) data Ellipsis a = Ellipsis @@ -81,13 +82,13 @@ instance Eq1 Redirect where liftEq = genericLiftEq instance Show1 Redirect where liftShowsPrec = genericLiftShowsPrec -- | Assignment from AST in Python's grammar onto a program in Python's syntax. -assignment :: HasCallStack => Assignment Grammar Term +assignment :: HasCallStack => Assignment assignment = makeTerm <$> symbol Module <*> children (many declaration) -declaration :: HasCallStack => Assignment Grammar Term +declaration :: HasCallStack => Assignment declaration = handleError $ comment <|> statement <|> expression -statement :: HasCallStack => Assignment Grammar Term +statement :: HasCallStack => Assignment statement = assertStatement <|> assignment' <|> augmentedAssignment @@ -100,10 +101,10 @@ statement = assertStatement <|> printStatement <|> returnStatement -expressionStatement :: HasCallStack => Assignment Grammar Term +expressionStatement :: HasCallStack => Assignment expressionStatement = symbol ExpressionStatement *> children expression -expression :: HasCallStack => Assignment Grammar Term +expression :: HasCallStack => Assignment expression = await <|> binaryOperator <|> booleanOperator @@ -123,13 +124,13 @@ expression = await <|> tuple <|> unaryOperator -dottedName :: HasCallStack => Assignment Grammar Term +dottedName :: HasCallStack => Assignment dottedName = makeTerm <$> symbol DottedName <*> children (Expression.ScopeResolution <$> many expression) -ellipsis :: HasCallStack => Assignment Grammar Term +ellipsis :: HasCallStack => Assignment ellipsis = makeTerm <$> symbol Grammar.Ellipsis <*> (Language.Python.Syntax.Ellipsis <$ source) -comparisonOperator :: HasCallStack => Assignment Grammar Term +comparisonOperator :: HasCallStack => Assignment comparisonOperator = symbol ComparisonOperator >>= \ loc -> children (expression >>= \ lexpression -> makeComparison loc lexpression) where makeComparison loc lexpression = makeTerm loc <$ symbol AnonLAngle <*> (Expression.LessThan lexpression <$> expression) @@ -144,26 +145,26 @@ comparisonOperator = symbol ComparisonOperator >>= \ loc -> children (expression <|> symbol AnonIs *> source *> (symbol AnonNot *> (makeTerm loc <$> Expression.Not <$> (makeTerm <$> location <*> (Expression.Equal lexpression <$> expression))) <|> (makeTerm loc <$> Expression.Equal lexpression <$> expression)) -notOperator :: HasCallStack => Assignment Grammar Term +notOperator :: HasCallStack => Assignment notOperator = makeTerm <$> symbol NotOperator <*> children (Expression.Not <$> expression) -keywordIdentifier :: HasCallStack => Assignment Grammar Term +keywordIdentifier :: HasCallStack => Assignment keywordIdentifier = makeTerm <$> symbol KeywordIdentifier <*> children (Syntax.Identifier <$> source) -tuple :: HasCallStack => Assignment Grammar Term +tuple :: HasCallStack => Assignment tuple = makeTerm <$> symbol Tuple <*> children (Literal.Tuple <$> (many expression)) -- TODO: Consider flattening single element lists -expressionList :: HasCallStack => Assignment Grammar Term +expressionList :: HasCallStack => Assignment expressionList = makeTerm <$> symbol ExpressionList <*> children (many expression) -unaryOperator :: HasCallStack => Assignment Grammar Term +unaryOperator :: HasCallStack => Assignment unaryOperator = symbol UnaryOperator >>= \ location -> arithmetic location <|> bitwise location <|> children ( symbol AnonPlus *> expression ) where arithmetic location = makeTerm location . Expression.Negate <$> children ( symbol AnonMinus *> expression ) bitwise location = makeTerm location . Expression.Complement <$> children ( symbol AnonTilde *> expression ) -binaryOperator :: HasCallStack => Assignment Grammar Term +binaryOperator :: HasCallStack => Assignment binaryOperator = symbol BinaryOperator >>= \ location -> children (expression >>= \ lexpression -> makeTerm location <$> arithmetic lexpression <|> makeTerm location <$> bitwise lexpression) @@ -181,17 +182,17 @@ binaryOperator = symbol BinaryOperator >>= \ location -> children (expression >> <|> symbol AnonLAngleLAngle *> (Expression.LShift lexpression <$> expression) <|> symbol AnonRAngleRAngle *> (Expression.RShift lexpression <$> expression) -booleanOperator :: HasCallStack => Assignment Grammar Term +booleanOperator :: HasCallStack => Assignment booleanOperator = makeTerm <$> symbol BooleanOperator <*> children ( expression >>= booleanOperator' ) where booleanOperator' lexpression = symbol AnonAnd *> (Expression.And lexpression <$> expression) <|> symbol AnonOr *> (Expression.Or lexpression <$> expression) -assignment' :: HasCallStack => Assignment Grammar Term +assignment' :: HasCallStack => Assignment assignment' = makeTerm <$> symbol Assignment <*> children (Statement.Assignment <$> expressionList <*> rvalue) -augmentedAssignment :: HasCallStack => Assignment Grammar Term +augmentedAssignment :: HasCallStack => Assignment augmentedAssignment = makeTerm <$> symbol AugmentedAssignment <*> children (expressionList >>= \ lvalue -> Statement.Assignment lvalue <$> (makeTerm <$> symbol AnonPlusEqual <*> (Expression.Plus lvalue <$> rvalue) <|> makeTerm <$> symbol AnonMinusEqual <*> (Expression.Minus lvalue <$> rvalue) @@ -206,56 +207,56 @@ augmentedAssignment = makeTerm <$> symbol AugmentedAssignment <*> children (expr <|> makeTerm <$> symbol AnonLAngleLAngleEqual <*> (Expression.LShift lvalue <$> rvalue) <|> makeTerm <$> symbol AnonCaretEqual <*> (Expression.BXOr lvalue <$> rvalue))) -yield :: HasCallStack => Assignment Grammar Term +yield :: HasCallStack => Assignment yield = makeTerm <$> symbol Yield <*> (Statement.Yield <$> children ( expression <|> expressionList <|> emptyTerm )) -rvalue :: HasCallStack => Assignment Grammar Term +rvalue :: HasCallStack => Assignment rvalue = expressionList <|> assignment' <|> augmentedAssignment <|> yield -identifier :: HasCallStack => Assignment Grammar Term +identifier :: HasCallStack => Assignment identifier = makeTerm <$> symbol Identifier <*> (Syntax.Identifier <$> source) -literal :: HasCallStack => Assignment Grammar Term +literal :: HasCallStack => Assignment literal = string <|> integer <|> float <|> boolean <|> none <|> concatenatedString <|> list' <|> dictionary <|> set -set :: HasCallStack => Assignment Grammar Term +set :: HasCallStack => Assignment set = makeTerm <$> symbol Set <*> children (Literal.Set <$> many expression) -dictionary :: HasCallStack => Assignment Grammar Term +dictionary :: HasCallStack => Assignment dictionary = makeTerm <$> symbol Dictionary <*> children (Literal.Hash <$> many pairs) where pairs = makeTerm <$> symbol Pair <*> children (Literal.KeyValue <$> expression <*> expression) -list' :: HasCallStack => Assignment Grammar Term +list' :: HasCallStack => Assignment list' = makeTerm <$> symbol List <*> children (Literal.Array <$> many expression) -- TODO: Wrap `Literal.TextElement` with a `Literal.String` -string :: HasCallStack => Assignment Grammar Term +string :: HasCallStack => Assignment string = makeTerm <$> symbol String <*> (Literal.TextElement <$> source) -concatenatedString :: HasCallStack => Assignment Grammar Term +concatenatedString :: HasCallStack => Assignment concatenatedString = makeTerm <$> symbol ConcatenatedString <*> children (Literal.TextElement . mconcat <$> many (symbol String *> source)) -float :: HasCallStack => Assignment Grammar Term +float :: HasCallStack => Assignment float = makeTerm <$> symbol Float <*> (Literal.Float <$> source) -integer :: HasCallStack => Assignment Grammar Term +integer :: HasCallStack => Assignment integer = makeTerm <$> symbol Integer <*> (Literal.Integer <$> source) -comment :: HasCallStack => Assignment Grammar Term +comment :: HasCallStack => Assignment comment = makeTerm <$> symbol Comment <*> (Comment.Comment <$> source) -- TODO Possibly match against children for dotted name and identifiers -import' :: HasCallStack => Assignment Grammar Term +import' :: HasCallStack => Assignment import' = makeTerm <$> symbol ImportStatement <*> children (Declaration.Import <$> many expression) -- TODO Possibly match against children nodes -importFrom :: HasCallStack => Assignment Grammar Term +importFrom :: HasCallStack => Assignment importFrom = makeTerm <$> symbol ImportFromStatement <*> children (Declaration.Import <$> many expression) -assertStatement :: HasCallStack => Assignment Grammar Term +assertStatement :: HasCallStack => Assignment assertStatement = makeTerm <$ symbol AssertStatement <*> location <*> children (Expression.Call <$> (makeTerm <$> symbol AnonAssert <*> (Syntax.Identifier <$> source)) <*> many expression) -printStatement :: HasCallStack => Assignment Grammar Term +printStatement :: HasCallStack => Assignment printStatement = do location <- symbol PrintStatement children $ do @@ -266,47 +267,47 @@ printStatement = do redirectCallTerm location keyword = makeTerm location <$ symbol Chevron <*> (flip Redirect <$> children expression <*> printCallTerm location keyword) printCallTerm location keyword = makeTerm location . Expression.Call keyword <$> many expression -globalStatement :: HasCallStack => Assignment Grammar Term +globalStatement :: HasCallStack => Assignment globalStatement = makeTerm <$> symbol GlobalStatement <*> children (Expression.Call <$> (makeTerm <$> symbol AnonGlobal <*> (Syntax.Identifier <$> source)) <*> many identifier) -await :: HasCallStack => Assignment Grammar Term +await :: HasCallStack => Assignment await = makeTerm <$> symbol Await <*> children (Expression.Call <$> (makeTerm <$> symbol AnonAwait <*> (Syntax.Identifier <$> source)) <*> many expression) -returnStatement :: HasCallStack => Assignment Grammar Term +returnStatement :: HasCallStack => Assignment returnStatement = makeTerm <$> symbol ReturnStatement <*> (Statement.Return <$> children expressionList) -ifStatement :: HasCallStack => Assignment Grammar Term +ifStatement :: HasCallStack => Assignment ifStatement = makeTerm <$> symbol IfStatement <*> children (Statement.If <$> expression <*> statement <*> (flip (foldr makeElif) <$> many elifClause <*> optionalElse)) where elseClause = symbol ElseClause *> children statement elifClause = (,) <$ symbol ElifClause <*> location <*> children (Statement.If <$> expression <*> statement) optionalElse = fromMaybe <$> emptyTerm <*> optional elseClause makeElif (loc, makeIf) rest = makeTerm loc (makeIf rest) -memberAccess :: HasCallStack => Assignment Grammar Term +memberAccess :: HasCallStack => Assignment memberAccess = makeTerm <$> symbol Attribute <*> children (Expression.MemberAccess <$> expression <*> expression) -subscript :: HasCallStack => Assignment Grammar Term +subscript :: HasCallStack => Assignment subscript = makeTerm <$> symbol Subscript <*> children (Expression.Subscript <$> expression <*> many expression) -call :: HasCallStack => Assignment Grammar Term +call :: HasCallStack => Assignment call = makeTerm <$> symbol Call <*> children (Expression.Call <$> identifier <*> (symbol ArgumentList *> children (many expression) <|> some comprehension)) -boolean :: HasCallStack => Assignment Grammar Term +boolean :: HasCallStack => Assignment boolean = makeTerm <$> symbol Grammar.True <*> (Literal.true <$ source) <|> makeTerm <$> symbol Grammar.False <*> (Literal.false <$ source) -none :: HasCallStack => Assignment Grammar Term +none :: HasCallStack => Assignment none = makeTerm <$> symbol None <*> (Literal.Null <$ source) -lambda :: HasCallStack => Assignment Grammar Term +lambda :: HasCallStack => Assignment lambda = makeTerm <$> symbol Lambda <*> children (Declaration.Function <$> lambdaIdentifier <*> lambdaParameters <*> lambdaBody) where lambdaIdentifier = makeTerm <$> symbol AnonLambda <*> (Syntax.Identifier <$> source) lambdaParameters = many identifier lambdaBody = expression -comprehension :: HasCallStack => Assignment Grammar Term +comprehension :: HasCallStack => Assignment comprehension = makeTerm <$> symbol GeneratorExpression <*> children (comprehensionDeclaration expression) <|> makeTerm <$> symbol ListComprehension <*> children (comprehensionDeclaration expression) <|> makeTerm <$> symbol SetComprehension <*> children (comprehensionDeclaration expression) @@ -317,16 +318,16 @@ comprehension = makeTerm <$> symbol GeneratorExpression <*> children (comprehen makeComprehension (loc, makeRest) rest = makeTerm loc (makeRest rest) nestedComprehension = (,) <$> location <*> (Declaration.Comprehension <$> expression <* symbol Variables <*> children (many expression)) -conditionalExpression :: HasCallStack => Assignment Grammar Term +conditionalExpression :: HasCallStack => Assignment conditionalExpression = makeTerm <$> symbol ConditionalExpression <*> children (expression >>= \ thenBranch -> expression >>= \ conditional -> Statement.If conditional thenBranch <$> (expression <|> emptyTerm)) makeTerm :: (HasCallStack, InUnion fs f) => a -> f (Term.Term (Union fs) a) -> Term.Term (Union fs) a makeTerm a f = cofree (a :< inj f) -emptyTerm :: HasCallStack => Assignment Grammar Term +emptyTerm :: HasCallStack => Assignment emptyTerm = makeTerm <$> location <*> pure Syntax.Empty -handleError :: HasCallStack => Assignment Grammar Term -> Assignment Grammar Term +handleError :: HasCallStack => Assignment -> Assignment handleError = flip catchError $ \ error -> case errorCause error of UnexpectedEndOfInput _ -> throwError error _ -> makeTerm <$> location <*> (Syntax.Error error <$ source) diff --git a/src/Language/Ruby/Syntax.hs b/src/Language/Ruby/Syntax.hs index 8e1efc82c..4270f224f 100644 --- a/src/Language/Ruby/Syntax.hs +++ b/src/Language/Ruby/Syntax.hs @@ -10,7 +10,7 @@ module Language.Ruby.Syntax import Data.Functor.Union import Data.Record import qualified Data.Syntax as Syntax -import Data.Syntax.Assignment hiding (Error) +import Data.Syntax.Assignment hiding (Assignment, Error) import qualified Data.Syntax.Assignment as Assignment import qualified Data.Syntax.Comment as Comment import qualified Data.Syntax.Declaration as Declaration @@ -55,33 +55,34 @@ type Syntax = type Error = Assignment.Error Grammar type Term = Term.Term (Union Syntax) (Record Location) +type Assignment = Assignment.Assignment Grammar Term -- | Assignment from AST in Ruby’s grammar onto a program in Ruby’s syntax. -assignment :: HasCallStack => Assignment Grammar Term +assignment :: HasCallStack => Assignment assignment = makeTerm <$> symbol Program <*> children (many declaration) -declaration :: HasCallStack => Assignment Grammar Term +declaration :: HasCallStack => Assignment declaration = handleError $ comment <|> class' <|> method -class' :: HasCallStack => Assignment Grammar Term +class' :: HasCallStack => Assignment class' = makeTerm <$> symbol Class <*> children (Declaration.Class <$> (constant <|> scopeResolution) <*> (superclass <|> pure []) <*> many declaration) where superclass = pure <$ symbol Superclass <*> children constant scopeResolution = symbol ScopeResolution *> children (constant <|> identifier) -constant :: HasCallStack => Assignment Grammar Term +constant :: HasCallStack => Assignment constant = makeTerm <$> symbol Constant <*> (Syntax.Identifier <$> source) -identifier :: HasCallStack => Assignment Grammar Term +identifier :: HasCallStack => Assignment identifier = makeTerm <$> symbol Identifier <*> (Syntax.Identifier <$> source) -method :: HasCallStack => Assignment Grammar Term +method :: HasCallStack => Assignment method = makeTerm <$> symbol Method <*> children (Declaration.Method <$> identifier <*> pure [] <*> statements) -statements :: HasCallStack => Assignment Grammar Term +statements :: HasCallStack => Assignment statements = makeTerm <$> location <*> many statement -statement :: HasCallStack => Assignment Grammar Term +statement :: HasCallStack => Assignment statement = handleError $ exit Statement.Return Return <|> exit Statement.Yield Yield @@ -96,36 +97,36 @@ statement = handleError <|> assignment' where exit construct sym = makeTerm <$> symbol sym <*> children ((construct .) . fromMaybe <$> emptyTerm <*> optional (symbol ArgumentList *> children statement)) -lvalue :: HasCallStack => Assignment Grammar Term +lvalue :: HasCallStack => Assignment lvalue = identifier -expression :: HasCallStack => Assignment Grammar Term +expression :: HasCallStack => Assignment expression = identifier <|> statement -comment :: HasCallStack => Assignment Grammar Term +comment :: HasCallStack => Assignment comment = makeTerm <$> symbol Comment <*> (Comment.Comment <$> source) -if' :: HasCallStack => Assignment Grammar Term +if' :: HasCallStack => Assignment if' = ifElsif If <|> makeTerm <$> symbol IfModifier <*> children (flip Statement.If <$> statement <*> statement <*> (makeTerm <$> location <*> pure Syntax.Empty)) where ifElsif s = makeTerm <$> symbol s <*> children (Statement.If <$> statement <*> statements <*> (fromMaybe <$> emptyTerm <*> optional (ifElsif Elsif <|> makeTerm <$> symbol Else <*> children (many statement)))) -unless :: HasCallStack => Assignment Grammar Term +unless :: HasCallStack => Assignment unless = makeTerm <$> symbol Unless <*> children (Statement.If <$> invert statement <*> statements <*> (fromMaybe <$> emptyTerm <*> optional (makeTerm <$> symbol Else <*> children (many statement)))) <|> makeTerm <$> symbol UnlessModifier <*> children (flip Statement.If <$> statement <*> invert statement <*> (makeTerm <$> location <*> pure Syntax.Empty)) -while :: HasCallStack => Assignment Grammar Term +while :: HasCallStack => Assignment while = makeTerm <$> symbol While <*> children (Statement.While <$> statement <*> statements) <|> makeTerm <$> symbol WhileModifier <*> children (flip Statement.While <$> statement <*> statement) -until :: HasCallStack => Assignment Grammar Term +until :: HasCallStack => Assignment until = makeTerm <$> symbol Until <*> children (Statement.While <$> invert statement <*> statements) <|> makeTerm <$> symbol UntilModifier <*> children (flip Statement.While <$> statement <*> invert statement) -for :: HasCallStack => Assignment Grammar Term +for :: HasCallStack => Assignment for = makeTerm <$> symbol For <*> children (Statement.ForEach <$> identifier <*> statement <*> statements) -assignment' :: HasCallStack => Assignment Grammar Term +assignment' :: HasCallStack => Assignment assignment' = makeTerm <$> symbol Assignment <*> children (Statement.Assignment <$> lvalue <*> expression) <|> makeTerm <$> symbol OperatorAssignment <*> children (lvalue >>= \ var -> Statement.Assignment var <$> @@ -143,23 +144,23 @@ assignment' <|> makeTerm <$> symbol AnonLAngleLAngleEqual <*> (Expression.LShift var <$> expression) <|> makeTerm <$> symbol AnonCaretEqual <*> (Expression.BXOr var <$> expression))) -literal :: HasCallStack => Assignment Grammar Term +literal :: HasCallStack => Assignment literal = makeTerm <$> symbol Grammar.True <*> (Literal.true <$ source) <|> makeTerm <$> symbol Grammar.False <*> (Literal.false <$ source) <|> makeTerm <$> symbol Grammar.Integer <*> (Literal.Integer <$> source) <|> makeTerm <$> symbol Symbol <*> (Literal.Symbol <$> source) <|> makeTerm <$> symbol Range <*> children (Literal.Range <$> statement <*> statement) -- FIXME: represent the difference between .. and ... -invert :: (InUnion fs Expression.Boolean, HasCallStack) => Assignment grammar (Term.Term (Union fs) (Record Location)) -> Assignment grammar (Term.Term (Union fs) (Record Location)) +invert :: (InUnion fs Expression.Boolean, HasCallStack) => Assignment.Assignment grammar (Term.Term (Union fs) (Record Location)) -> Assignment.Assignment grammar (Term.Term (Union fs) (Record Location)) invert term = makeTerm <$> location <*> fmap Expression.Not term makeTerm :: (InUnion fs f, HasCallStack) => a -> f (Term.Term (Union fs) a) -> Term.Term (Union fs) a makeTerm a f = cofree $ a :< inj f -emptyTerm :: HasCallStack => Assignment Grammar Term +emptyTerm :: HasCallStack => Assignment emptyTerm = makeTerm <$> location <*> pure Syntax.Empty -handleError :: HasCallStack => Assignment Grammar Term -> Assignment Grammar Term +handleError :: HasCallStack => Assignment -> Assignment handleError = flip catchError $ \ error -> case errorCause error of UnexpectedEndOfInput _ -> throwError error _ -> makeTerm <$> location <*> (Syntax.Error error <$ source)