1
1
mirror of https://github.com/github/semantic.git synced 2024-12-19 12:51:52 +03:00

Merge branch 'master' into parse-jquery

This commit is contained in:
Rob Rix 2016-08-16 15:12:10 -04:00
commit 538961285a
2 changed files with 46 additions and 36 deletions

View File

@ -21,13 +21,22 @@ type Parser f a = SourceBlob -> IO (Cofree f a)
isOperator :: Category -> Bool
isOperator = flip Set.member (Set.fromList [ Operator, BinaryOperator ])
-- | Given a function that maps production names to sets of categories, produce
-- | a Constructor.
termConstructor :: forall fields. (Show (Record fields), HasField fields Category, HasField fields Range) => Source Char -> SourceSpan -> (Record fields) -> [Term Text (Record fields)] -> Term Text (Record fields)
termConstructor source sourceSpan info = cofree . construct
-- | Construct a term given source, the span covered, the annotation for the term, and its children.
--
-- This is typically called during parsing, building terms up leaf-to-root.
termConstructor :: forall fields. (Show (Record fields), HasField fields Category, HasField fields Range)
=> Source Char -- ^ The source that the term occurs within.
-> IO SourceSpan -- ^ The span that the term occupies. This is passed in 'IO' to guarantee some access constraints & encourage its use only when needed (improving performance).
-> Record fields -- ^ The annotation for the term.
-> [Term Text (Record fields)] -- ^ The child nodes of the term.
-> IO (Term Text (Record fields)) -- ^ The resulting term, in IO.
termConstructor source sourceSpan info = fmap cofree . construct
where
withDefaultInfo syntax = (info :< syntax)
construct :: (Show (Record fields), HasField fields Category, HasField fields Range) => [Term Text (Record fields)] -> CofreeF (S.Syntax Text) (Record fields) (Term Text (Record fields))
withDefaultInfo syntax = pure (info :< syntax)
errorWith children = do
sourceSpan' <- sourceSpan
withDefaultInfo (S.Error sourceSpan' children)
construct :: (Show (Record fields), HasField fields Category, HasField fields Range) => [Term Text (Record fields)] -> IO (CofreeF (S.Syntax Text) (Record fields) (Term Text (Record fields)))
construct [] = case category info of
Return -> withDefaultInfo $ S.Return Nothing -- Map empty return statements to Return Nothing
_ -> withDefaultInfo . S.Leaf . pack . toString $ slice (characterRange info) source
@ -35,16 +44,16 @@ termConstructor source sourceSpan info = cofree . construct
withDefaultInfo $ S.Return (listToMaybe children)
construct children | Assignment == category info = case children of
(identifier:value:[]) -> withDefaultInfo $ S.Assignment identifier value
children -> withDefaultInfo $ S.Error sourceSpan children
children -> errorWith children
construct children | MathAssignment == category info = case children of
(identifier:value:[]) -> withDefaultInfo $ S.MathAssignment identifier value
children -> withDefaultInfo $ S.Error sourceSpan children
children -> errorWith children
construct children | MemberAccess == category info = case children of
(base:property:[]) -> withDefaultInfo $ S.MemberAccess base property
children -> withDefaultInfo $ S.Error sourceSpan children
children -> errorWith children
construct children | SubscriptAccess == category info = case children of
(base:element:[]) -> withDefaultInfo $ S.SubscriptAccess base element
_ -> withDefaultInfo $ S.Error sourceSpan children
_ -> errorWith children
construct children | isOperator (category info) = withDefaultInfo $ S.Operator children
construct children | Function == category info = case children of
(body:[]) -> withDefaultInfo $ S.Function Nothing Nothing body
@ -54,18 +63,18 @@ termConstructor source sourceSpan info = cofree . construct
withDefaultInfo $ S.Function (Just id) Nothing body
(id:params:body:[]) | (info :< _) <- runCofree id, Identifier == category info ->
withDefaultInfo $ S.Function (Just id) (Just params) body
_ -> withDefaultInfo $ S.Error sourceSpan children
_ -> errorWith children
construct children | FunctionCall == category info = case runCofree <$> children of
[ (_ :< S.MemberAccess{..}), params@(_ :< S.Args{}) ] ->
setCategory info MethodCall :< S.MethodCall memberId property (cofree params)
pure $! setCategory info MethodCall :< S.MethodCall memberId property (cofree params)
(x:xs) ->
withDefaultInfo $ S.FunctionCall (cofree x) (cofree <$> xs)
_ -> withDefaultInfo $ S.Error sourceSpan children
_ -> errorWith children
construct children | Ternary == category info = case children of
(condition:cases) -> withDefaultInfo $ S.Ternary condition cases
_ -> withDefaultInfo $ S.Error sourceSpan children
_ -> errorWith children
construct children | Args == category info = withDefaultInfo $ S.Args children
construct children | VarAssignment == category info
, [x, y] <- children = withDefaultInfo $ S.VarAssignment x y
@ -90,12 +99,12 @@ termConstructor source sourceSpan info = cofree . construct
construct children | Pair == (category info) = withDefaultInfo $ S.Fixed children
construct children | C.Error == category info =
withDefaultInfo $ S.Error sourceSpan children
errorWith children
construct children | If == category info, Just (expr, clauses) <- uncons children =
withDefaultInfo $ case clauses of
[clause1, clause2] -> S.If expr clause1 (Just clause2)
[clause] -> S.If expr clause Nothing
_ -> S.Error sourceSpan children
case clauses of
[clause1, clause2] -> withDefaultInfo $ S.If expr clause1 (Just clause2)
[clause] -> withDefaultInfo $ S.If expr clause Nothing
_ -> errorWith children
construct children | For == category info, Just (exprs, body) <- unsnoc children =
withDefaultInfo $ S.For exprs body
construct children | While == category info, [expr, body] <- children =
@ -113,7 +122,7 @@ termConstructor source sourceSpan info = cofree . construct
[body, catch, finally] | Catch <- category (extract catch),
Finally <- category (extract finally) ->
withDefaultInfo $ S.Try body (Just catch) (Just finally)
_ -> withDefaultInfo $ S.Error sourceSpan children
_ -> errorWith children
construct children | ArrayLiteral == category info =
withDefaultInfo $ S.Array children
construct children | Method == category info = case children of
@ -123,14 +132,12 @@ termConstructor source sourceSpan info = cofree . construct
withDefaultInfo $ S.Method identifier params' (toList (unwrap exprs))
[identifier, exprs] ->
withDefaultInfo $ S.Method identifier mempty (toList (unwrap exprs))
_ ->
withDefaultInfo $ S.Error sourceSpan children
_ -> errorWith children
construct children | Class == category info = case children of
[identifier, superclass, definitions] ->
withDefaultInfo $ S.Class identifier (Just superclass) (toList (unwrap definitions))
[identifier, definitions] ->
withDefaultInfo $ S.Class identifier Nothing (toList (unwrap definitions))
_ ->
withDefaultInfo $ S.Error sourceSpan children
_ -> errorWith children
construct children =
withDefaultInfo $ S.Indexed children

View File

@ -2,8 +2,9 @@
module TreeSitter where
import Prologue hiding (Constructor)
import Data.Record
import Control.Monad
import Category
import Data.Record
import Language
import Parser
import Range
@ -55,6 +56,7 @@ categoriesForLanguage language name = case (language, name) of
(Ruby, "hash") -> Object
_ -> defaultCategoryForNodeName name
{-# INLINE categoriesForLanguage #-}
-- | Given a node name from TreeSitter, return the correct categories.
defaultCategoryForNodeName :: Text -> Category
@ -94,6 +96,7 @@ defaultCategoryForNodeName name = case name of
"try_statement" -> Try
"method_definition" -> Method
_ -> Other name
{-# INLINE defaultCategoryForNodeName #-}
-- | Return a parser for a tree sitter language & document.
documentToTerm :: Language -> Ptr Document -> Parser (Syntax.Syntax Text) (Record '[Range, Category])
@ -105,15 +108,15 @@ documentToTerm language document blob = alloca $ \ root -> do
name <- peekCString name
count <- ts_node_p_named_child_count node
children <- traverse (alloca . getChild node) $ take (fromIntegral count) [0..]
let range = Range { start = fromIntegral $ ts_node_p_start_char node, end = fromIntegral $ ts_node_p_end_char node }
let sourceSpan = SourceSpan { spanName = toS (path blob)
, spanStart = SourcePos (fromIntegral $! ts_node_p_start_point_row node) (fromIntegral $! ts_node_p_start_point_column node)
, spanEnd = SourcePos (fromIntegral $! ts_node_p_end_point_row node) (fromIntegral $! ts_node_p_end_point_column node) }
-- Note: The strict application here is semantically important. Without it, we may not evaluate the range until after weve exited the scope that `node` was allocated within, meaning `alloca` will free it & other stack data may overwrite it.
range <- pure $! Range { start = fromIntegral $ ts_node_p_start_char node, end = fromIntegral $ ts_node_p_end_char node }
sourceSpan <- pure $! SourceSpan { spanName = toS (path blob)
, spanStart = SourcePos (fromIntegral $ ts_node_p_start_point_row node) (fromIntegral $ ts_node_p_start_point_column node)
, spanEnd = SourcePos (fromIntegral $ ts_node_p_end_point_row node) (fromIntegral $ ts_node_p_end_point_column node) }
let info = range .: (categoriesForLanguage language (toS name)) .: RNil
pure $! termConstructor (source blob) sourceSpan info children
getChild node n out = do
_ <- ts_node_p_named_child node n out
toTerm out
let info = range `seq` range .: categoriesForLanguage language (toS name) .: RNil
termConstructor (source blob) (sourceSpan `seq` pure sourceSpan) info children
getChild node n out = ts_node_p_named_child node n out >> toTerm out
{-# INLINE getChild #-}