1
1
mirror of https://github.com/github/semantic.git synced 2024-12-22 14:21:31 +03:00

Stub typescript syntax

This commit is contained in:
joshvera 2017-08-08 12:13:44 -04:00
parent 5f1925cc3d
commit a5bb117c35

View File

@ -1,9 +1,352 @@
{-# LANGUAGE TemplateHaskell #-}
module Language.TypeScript.Syntax where
{-# LANGUAGE DataKinds, RankNTypes, TypeOperators #-}
import Language.Haskell.TH
import Text.Parser.TreeSitter.Language
import Text.Parser.TreeSitter.TypeScript
module Language.TypeScript.Syntax
( assignment
, Syntax
, Grammar
, Term
) where
-- | Statically-known rules corresponding to symbols in the grammar.
mkSymbolDatatype (mkName "Grammar") tree_sitter_typescript
import Control.Comonad.Cofree (Cofree(..))
import Data.Maybe (fromMaybe)
import Data.Record
import qualified Data.Syntax as Syntax
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
import qualified Data.Syntax.Expression as Expression
import qualified Data.Syntax.Literal as Literal
import qualified Data.Syntax.Statement as Statement
import qualified Data.Syntax.Type as Type
import Data.Union
import GHC.Stack
import Language.TypeScript.Grammar as Grammar
import qualified Term
-- | The type of TypeScript syntax.
type Syntax = '[
Comment.Comment
, Declaration.Class
, Declaration.Function
, Declaration.Method
, Declaration.Module
, Expression.Arithmetic
, Expression.Bitwise
, Expression.Boolean
, Expression.Call
, Expression.Comparison
, Expression.Enumeration
, Expression.MemberAccess
, Expression.ScopeResolution
, Expression.Subscript
, Literal.Array
, Literal.Boolean
, Literal.Float
, Literal.Hash
, Literal.Integer
, Literal.KeyValue
, Literal.Null
, Literal.String
, Literal.Symbol
, Literal.TextElement
, Statement.Assignment
, Statement.Break
, Statement.Catch
, Statement.Continue
, Statement.Else
, Statement.Finally
, Statement.ForEach
, Statement.If
, Statement.Match
, Statement.Pattern
, Statement.Retry
, Statement.Return
, Statement.ScopeEntry
, Statement.ScopeExit
, Statement.Try
, Statement.While
, Statement.Yield
, Syntax.Empty
, Syntax.Error
, Syntax.Identifier
, Syntax.Program
, Type.Annotation
, []
]
type Term = Term.Term (Union Syntax) (Record Location)
type Assignment = HasCallStack => Assignment.Assignment (AST Grammar) Grammar Term
-- | Assignment from AST in Rubys grammar onto a program in TypeScripts syntax.
assignment :: Assignment
assignment =
makeTerm <$> symbol Program <*> children (Syntax.Program <$> many expression)
<|> parseError
expression :: Assignment
expression =
comment
<|> if'
<|> while'
<|> until'
<|> case'
<|> emptyStatement
<|> assignment'
<|> unary
<|> binary
<|> literal
<|> mk Return Statement.Return
<|> mk Yield Statement.Yield
<|> mk Break Statement.Break
<|> mk Next Statement.Continue
<|> mk Retry Statement.Retry
<|> for
<|> class'
<|> method
<|> lambda
<|> module'
<|> identifier
<|> conditional
<|> methodCall
<|> call
<|> subscript
<|> begin
<|> rescue
<|> block
<|> parseError
where mk s construct = makeTerm <$> symbol s <*> children ((construct .) . fromMaybe <$> emptyTerm <*> optional (symbol ArgumentList *> children expression))
expressions :: Assignment
expressions = makeTerm <$> location <*> many expression
identifier :: Assignment
identifier =
mk Identifier
<|> mk Constant
<|> mk InstanceVariable
<|> mk ClassVariable
<|> mk GlobalVariable
<|> mk Operator
<|> mk Self
<|> mk Super
<|> mk Setter
<|> mk ReservedIdentifier
<|> mk Uninterpreted
where mk s = makeTerm <$> symbol s <*> (Syntax.Identifier <$> source)
literal :: Assignment
literal =
makeTerm <$> symbol Grammar.True <*> (Literal.true <$ source)
<|> makeTerm <$> symbol Grammar.False <*> (Literal.false <$ source)
<|> makeTerm <$> symbol Grammar.Number <*> (Literal.Float <$> source)
<|> makeTerm <$> symbol Grammar.Null <*> (Literal.Null <$ source)
-- TODO: Do we want to represent the difference between .. and ...
<|> makeTerm <$> symbol Range <*> children (Expression.Enumeration <$> expression <*> expression <*> emptyTerm)
<|> makeTerm <$> symbol Array <*> children (Literal.Array <$> many expression)
<|> makeTerm <$> symbol Hash <*> children (Literal.Hash <$> many pair)
-- TODO: Give subshell it's own literal and allow interpolation
<|> makeTerm <$> symbol Subshell <*> (Literal.TextElement <$> source)
-- TODO: Handle interpolation
<|> makeTerm <$> symbol String <*> (Literal.TextElement <$> source)
-- TODO: this isn't quite right `"a" "b"` ends up as TextElement {textElementContent = "\"a\"\"b\""}
<|> makeTerm <$> symbol ChainedString <*> children (Literal.TextElement . mconcat <$> many (symbol String *> source))
-- TODO: Handle interpolation, dedicated literal?
<|> makeTerm <$> symbol Regex <*> (Literal.TextElement <$> source)
-- TODO: Handle interpolation
<|> makeTerm <$> symbol Symbol <*> (Literal.Symbol <$> source)
class' :: Assignment
class' = makeTerm <$> symbol Class <*> children (Declaration.Class <$> expression <*> (superclass <|> pure []) <*> many expression)
where superclass = pure <$ symbol Superclass <*> children expression
module' :: Assignment
module' = makeTerm <$> symbol Module <*> children (Declaration.Module <$> expression <*> many expression)
parameter :: Assignment
parameter =
mk SplatParameter
<|> mk HashSplatParameter
<|> mk BlockParameter
<|> mk KeywordParameter
<|> mk OptionalParameter
<|> makeTerm <$> symbol DestructuredParameter <*> children (many parameter)
<|> expression
<|> parseError
where mk s = makeTerm <$> symbol s <*> (Syntax.Identifier <$> source)
method :: Assignment
method = makeTerm <$> symbol Method <*> children (Declaration.Method <$> emptyTerm <*> expression <*> params <*> expressions)
where params = symbol MethodParameters *> children (many parameter) <|> pure []
lambda :: Assignment
lambda = symbol Lambda >>= \ loc -> children $ do
name <- makeTerm loc <$> (Syntax.Identifier <$> source)
params <- (symbol BlockParameters <|> symbol LambdaParameters) *> children (many parameter) <|> pure []
body <- expressions
pure $ makeTerm loc (Declaration.Function name params body)
block :: Assignment
block = makeTerm <$> symbol DoBlock <*> children (Declaration.Function <$> emptyTerm <*> params <*> expressions)
<|> makeTerm <$> symbol Block <*> children (Declaration.Function <$> emptyTerm <*> params <*> expressions)
where params = (symbol BlockParameters) *> children (many parameter) <|> pure []
comment :: Assignment
comment = makeTerm <$> symbol Comment <*> (Comment.Comment <$> source)
if' :: Assignment
if' =
ifElsif If
<|> makeTerm <$> symbol IfModifier <*> children (flip Statement.If <$> expression <*> expression <*> emptyTerm)
where ifElsif s = makeTerm <$> symbol s <*> children (Statement.If <$> expression <*> expressions <*> (fromMaybe <$> emptyTerm <*> optional (ifElsif Elsif <|> else')))
else' :: Assignment
else' = makeTerm <$> symbol Else <*> children (many expression)
while' :: Assignment
while' =
makeTerm <$> symbol While <*> children (Statement.While <$> expression <*> expressions)
<|> makeTerm <$> symbol WhileModifier <*> children (flip Statement.While <$> expression <*> expression)
until' :: Assignment
until' =
makeTerm <$> symbol Until <*> children (Statement.While <$> invert expression <*> expressions)
<|> makeTerm <$> symbol UntilModifier <*> children (flip Statement.While <$> expression <*> invert expression)
for :: Assignment
for = makeTerm <$> symbol For <*> children (Statement.ForEach <$> vars <*> expression <*> expressions)
where vars = makeTerm <$> location <*> some expression
case' :: Assignment
case' = makeTerm <$> symbol Case <*> children (Statement.Match <$> expression <*> when')
where
when' = makeTerm <$> symbol When <*> children (Statement.Pattern <$> (makeTerm <$> location <*> some pattern) <*> (when' <|> else' <|> expressions))
pattern = symbol Pattern *> children ((symbol SplatArgument *> children expression) <|> expression)
subscript :: Assignment
subscript = makeTerm <$> symbol ElementReference <*> children (Expression.Subscript <$> expression <*> many argument)
pair :: Assignment
pair = makeTerm <$> symbol Pair <*> children (Literal.KeyValue <$> expression <*> expression)
argument :: Assignment
argument =
mk SplatArgument
<|> mk HashSplatArgument
<|> mk BlockArgument
<|> pair
<|> expression
where mk s = makeTerm <$> symbol s <*> (Syntax.Identifier <$> source)
methodCall :: Assignment
methodCall = makeTerm <$> symbol MethodCall <*> children (Expression.Call <$> expression <*> args <*> (block <|> emptyTerm))
where
args = (symbol ArgumentList <|> symbol ArgumentListWithParens) *> children (many argument) <|> pure []
call :: Assignment
call = makeTerm <$> symbol Call <*> children (Expression.MemberAccess <$> expression <*> expression)
rescue :: Assignment
rescue = rescue'
<|> makeTerm <$> symbol RescueModifier <*> children (Statement.Try <$> expression <*> many (makeTerm <$> location <*> (Statement.Catch <$> expression <*> emptyTerm)))
<|> makeTerm <$> symbol Ensure <*> children (Statement.Finally <$> expressions)
<|> makeTerm <$> symbol Else <*> children (Statement.Else <$> emptyTerm <*> expressions)
where
rescue' = makeTerm <$> symbol Rescue <*> children (Statement.Catch <$> exceptions <*> (rescue' <|> expressions))
exceptions = makeTerm <$> location <*> many ex
ex = makeTerm <$> symbol Exceptions <*> children (many expression)
<|> makeTerm <$> symbol ExceptionVariable <*> children (many expression)
begin :: Assignment
begin = makeTerm <$> symbol Begin <*> children (Statement.Try <$> expressions <*> many rescue)
assignment' :: Assignment
assignment'
= makeTerm <$> symbol Assignment <*> children (Statement.Assignment <$> lhs <*> rhs)
<|> makeTerm <$> symbol OperatorAssignment <*> children (lhs >>= \ var -> Statement.Assignment var <$>
(makeTerm <$> symbol AnonPlusEqual <*> (Expression.Plus var <$> expression)
<|> makeTerm <$> symbol AnonMinusEqual <*> (Expression.Minus var <$> expression)
<|> makeTerm <$> symbol AnonStarEqual <*> (Expression.Times var <$> expression)
<|> makeTerm <$> symbol AnonStarStarEqual <*> (Expression.Power var <$> expression)
<|> makeTerm <$> symbol AnonSlashEqual <*> (Expression.DividedBy var <$> expression)
<|> makeTerm <$> symbol AnonPipePipeEqual <*> (Expression.And var <$> expression)
<|> makeTerm <$> symbol AnonPipeEqual <*> (Expression.BOr var <$> expression)
<|> makeTerm <$> symbol AnonAmpersandAmpersandEqual <*> (Expression.And var <$> expression)
<|> makeTerm <$> symbol AnonAmpersandEqual <*> (Expression.BAnd var <$> expression)
<|> makeTerm <$> symbol AnonPercentEqual <*> (Expression.Modulo var <$> expression)
<|> makeTerm <$> symbol AnonRAngleRAngleEqual <*> (Expression.RShift var <$> expression)
<|> makeTerm <$> symbol AnonLAngleLAngleEqual <*> (Expression.LShift var <$> expression)
<|> makeTerm <$> symbol AnonCaretEqual <*> (Expression.BXOr var <$> expression)))
where
lhs = makeTerm <$> symbol LeftAssignmentList <*> children (many expr) <|> expr
rhs = makeTerm <$> symbol RightAssignmentList <*> children (many expr) <|> expr
expr =
makeTerm <$> symbol RestAssignment <*> (Syntax.Identifier <$> source)
<|> makeTerm <$> symbol DestructuredLeftAssignment <*> children (many expr)
<|> argument
unary :: Assignment
unary = symbol Unary >>= \ location ->
makeTerm location . Expression.Complement <$> children ( symbol AnonTilde *> expression )
<|> makeTerm location . Expression.Not <$> children ( symbol AnonBang *> expression )
<|> makeTerm location . Expression.Not <$> children ( symbol AnonNot *> expression )
<|> makeTerm location <$> children (Expression.Call <$> (makeTerm <$> symbol AnonDefinedQuestion <*> (Syntax.Identifier <$> source)) <*> some expression <*> emptyTerm)
<|> children ( symbol AnonPlus *> expression )
<|> makeTerm location . Expression.Negate <$> children expression -- Unary minus (e.g. `-a`). HiddenUnaryMinus nodes are hidden, so we can't match on the symbol.
binary :: Assignment
binary = symbol Binary >>= \ loc -> children $ expression >>= \ lexpression -> go loc lexpression
where
go loc lexpression
= mk AnonAnd Expression.And
<|> mk AnonAmpersandAmpersand Expression.And
<|> mk AnonOr Expression.Or
<|> mk AnonPipePipe Expression.Or
<|> mk AnonLAngleLAngle Expression.LShift
<|> mk AnonRAngleRAngle Expression.RShift
<|> mk AnonEqualEqual Expression.Equal
<|> mkNot AnonBangEqual Expression.Equal
-- TODO: Distinguish `===` from `==` ?
<|> mk AnonEqualEqualEqual Expression.Equal
<|> mk AnonLAngleEqualRAngle Expression.Comparison
-- TODO: Distinuish `=~` and `!~` ?
<|> mk AnonEqualTilde Expression.Equal
<|> mkNot AnonBangTilde Expression.Equal
<|> mk AnonLAngle Expression.LessThan
<|> mk AnonLAngleEqual Expression.LessThanEqual
<|> mk AnonRAngle Expression.GreaterThan
<|> mk AnonRAngleEqual Expression.GreaterThanEqual
<|> mk AnonAmpersand Expression.BAnd
<|> mk AnonCaret Expression.BXOr
<|> mk AnonPipe Expression.BOr
-- TODO: binary minus (hidden node). Doesn't work b/c we can't match hidden nodes (they aren't in the tree).
-- <|> mk HiddenBinaryMinus Expression.Minus
<|> mk AnonPlus Expression.Plus
-- TODO: binary star (hidden node)
<|> mk AnonSlash Expression.DividedBy
<|> mk AnonPercent Expression.Modulo
<|> mk AnonStarStar Expression.Power
where mk s constr = makeTerm loc <$> (symbol s *> (constr lexpression <$> expression))
mkNot s constr = makeTerm loc <$ symbol s <*> (Expression.Not <$> (makeTerm <$> location <*> (constr lexpression <$> expression)))
conditional :: Assignment
conditional = makeTerm <$> symbol Conditional <*> children (Statement.If <$> expression <*> expression <*> expression)
emptyStatement :: Assignment
emptyStatement = makeTerm <$> symbol EmptyStatement <*> (Syntax.Empty <$ source <|> pure Syntax.Empty)
-- Helper functions
makeTerm :: (f :< fs, HasCallStack) => a -> f (Term.Term (Union fs) a) -> Term.Term (Union fs) a
makeTerm a f = a :< inj f
emptyTerm :: Assignment
emptyTerm = makeTerm <$> location <*> pure Syntax.Empty
invert :: (Expression.Boolean :< fs, HasCallStack) => Assignment.Assignment ast grammar (Term.Term (Union fs) (Record Location)) -> Assignment.Assignment ast grammar (Term.Term (Union fs) (Record Location))
invert term = makeTerm <$> location <*> fmap Expression.Not term
parseError :: Assignment
parseError = makeTerm <$> symbol ParseError <*> (Syntax.Error [] <$ source)