1
1
mirror of https://github.com/github/semantic.git synced 2024-12-19 21:01:35 +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 :: Category -> Bool
isOperator = flip Set.member (Set.fromList [ Operator, BinaryOperator ]) isOperator = flip Set.member (Set.fromList [ Operator, BinaryOperator ])
-- | Given a function that maps production names to sets of categories, produce -- | Construct a term given source, the span covered, the annotation for the term, and its children.
-- | 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) -- This is typically called during parsing, building terms up leaf-to-root.
termConstructor source sourceSpan info = cofree . construct 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 where
withDefaultInfo syntax = (info :< syntax) withDefaultInfo syntax = pure (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)) 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 construct [] = case category info of
Return -> withDefaultInfo $ S.Return Nothing -- Map empty return statements to Return Nothing Return -> withDefaultInfo $ S.Return Nothing -- Map empty return statements to Return Nothing
_ -> withDefaultInfo . S.Leaf . pack . toString $ slice (characterRange info) source _ -> withDefaultInfo . S.Leaf . pack . toString $ slice (characterRange info) source
@ -35,16 +44,16 @@ termConstructor source sourceSpan info = cofree . construct
withDefaultInfo $ S.Return (listToMaybe children) withDefaultInfo $ S.Return (listToMaybe children)
construct children | Assignment == category info = case children of construct children | Assignment == category info = case children of
(identifier:value:[]) -> withDefaultInfo $ S.Assignment identifier value (identifier:value:[]) -> withDefaultInfo $ S.Assignment identifier value
children -> withDefaultInfo $ S.Error sourceSpan children children -> errorWith children
construct children | MathAssignment == category info = case children of construct children | MathAssignment == category info = case children of
(identifier:value:[]) -> withDefaultInfo $ S.MathAssignment identifier value (identifier:value:[]) -> withDefaultInfo $ S.MathAssignment identifier value
children -> withDefaultInfo $ S.Error sourceSpan children children -> errorWith children
construct children | MemberAccess == category info = case children of construct children | MemberAccess == category info = case children of
(base:property:[]) -> withDefaultInfo $ S.MemberAccess base property (base:property:[]) -> withDefaultInfo $ S.MemberAccess base property
children -> withDefaultInfo $ S.Error sourceSpan children children -> errorWith children
construct children | SubscriptAccess == category info = case children of construct children | SubscriptAccess == category info = case children of
(base:element:[]) -> withDefaultInfo $ S.SubscriptAccess base element (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 | isOperator (category info) = withDefaultInfo $ S.Operator children
construct children | Function == category info = case children of construct children | Function == category info = case children of
(body:[]) -> withDefaultInfo $ S.Function Nothing Nothing body (body:[]) -> withDefaultInfo $ S.Function Nothing Nothing body
@ -54,18 +63,18 @@ termConstructor source sourceSpan info = cofree . construct
withDefaultInfo $ S.Function (Just id) Nothing body withDefaultInfo $ S.Function (Just id) Nothing body
(id:params:body:[]) | (info :< _) <- runCofree id, Identifier == category info -> (id:params:body:[]) | (info :< _) <- runCofree id, Identifier == category info ->
withDefaultInfo $ S.Function (Just id) (Just params) body withDefaultInfo $ S.Function (Just id) (Just params) body
_ -> withDefaultInfo $ S.Error sourceSpan children _ -> errorWith children
construct children | FunctionCall == category info = case runCofree <$> children of construct children | FunctionCall == category info = case runCofree <$> children of
[ (_ :< S.MemberAccess{..}), params@(_ :< S.Args{}) ] -> [ (_ :< 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) -> (x:xs) ->
withDefaultInfo $ S.FunctionCall (cofree x) (cofree <$> xs) withDefaultInfo $ S.FunctionCall (cofree x) (cofree <$> xs)
_ -> withDefaultInfo $ S.Error sourceSpan children _ -> errorWith children
construct children | Ternary == category info = case children of construct children | Ternary == category info = case children of
(condition:cases) -> withDefaultInfo $ S.Ternary condition cases (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 | Args == category info = withDefaultInfo $ S.Args children
construct children | VarAssignment == category info construct children | VarAssignment == category info
, [x, y] <- children = withDefaultInfo $ S.VarAssignment x y , [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 | Pair == (category info) = withDefaultInfo $ S.Fixed children
construct children | C.Error == category info = construct children | C.Error == category info =
withDefaultInfo $ S.Error sourceSpan children errorWith children
construct children | If == category info, Just (expr, clauses) <- uncons children = construct children | If == category info, Just (expr, clauses) <- uncons children =
withDefaultInfo $ case clauses of case clauses of
[clause1, clause2] -> S.If expr clause1 (Just clause2) [clause1, clause2] -> withDefaultInfo $ S.If expr clause1 (Just clause2)
[clause] -> S.If expr clause Nothing [clause] -> withDefaultInfo $ S.If expr clause Nothing
_ -> S.Error sourceSpan children _ -> errorWith children
construct children | For == category info, Just (exprs, body) <- unsnoc children = construct children | For == category info, Just (exprs, body) <- unsnoc children =
withDefaultInfo $ S.For exprs body withDefaultInfo $ S.For exprs body
construct children | While == category info, [expr, body] <- children = 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), [body, catch, finally] | Catch <- category (extract catch),
Finally <- category (extract finally) -> Finally <- category (extract finally) ->
withDefaultInfo $ S.Try body (Just catch) (Just finally) withDefaultInfo $ S.Try body (Just catch) (Just finally)
_ -> withDefaultInfo $ S.Error sourceSpan children _ -> errorWith children
construct children | ArrayLiteral == category info = construct children | ArrayLiteral == category info =
withDefaultInfo $ S.Array children withDefaultInfo $ S.Array children
construct children | Method == category info = case children of 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)) withDefaultInfo $ S.Method identifier params' (toList (unwrap exprs))
[identifier, exprs] -> [identifier, exprs] ->
withDefaultInfo $ S.Method identifier mempty (toList (unwrap exprs)) withDefaultInfo $ S.Method identifier mempty (toList (unwrap exprs))
_ -> _ -> errorWith children
withDefaultInfo $ S.Error sourceSpan children
construct children | Class == category info = case children of construct children | Class == category info = case children of
[identifier, superclass, definitions] -> [identifier, superclass, definitions] ->
withDefaultInfo $ S.Class identifier (Just superclass) (toList (unwrap definitions)) withDefaultInfo $ S.Class identifier (Just superclass) (toList (unwrap definitions))
[identifier, definitions] -> [identifier, definitions] ->
withDefaultInfo $ S.Class identifier Nothing (toList (unwrap definitions)) withDefaultInfo $ S.Class identifier Nothing (toList (unwrap definitions))
_ -> _ -> errorWith children
withDefaultInfo $ S.Error sourceSpan children
construct children = construct children =
withDefaultInfo $ S.Indexed children withDefaultInfo $ S.Indexed children

View File

@ -2,8 +2,9 @@
module TreeSitter where module TreeSitter where
import Prologue hiding (Constructor) import Prologue hiding (Constructor)
import Data.Record import Control.Monad
import Category import Category
import Data.Record
import Language import Language
import Parser import Parser
import Range import Range
@ -55,6 +56,7 @@ categoriesForLanguage language name = case (language, name) of
(Ruby, "hash") -> Object (Ruby, "hash") -> Object
_ -> defaultCategoryForNodeName name _ -> defaultCategoryForNodeName name
{-# INLINE categoriesForLanguage #-}
-- | Given a node name from TreeSitter, return the correct categories. -- | Given a node name from TreeSitter, return the correct categories.
defaultCategoryForNodeName :: Text -> Category defaultCategoryForNodeName :: Text -> Category
@ -94,6 +96,7 @@ defaultCategoryForNodeName name = case name of
"try_statement" -> Try "try_statement" -> Try
"method_definition" -> Method "method_definition" -> Method
_ -> Other name _ -> Other name
{-# INLINE defaultCategoryForNodeName #-}
-- | Return a parser for a tree sitter language & document. -- | Return a parser for a tree sitter language & document.
documentToTerm :: Language -> Ptr Document -> Parser (Syntax.Syntax Text) (Record '[Range, Category]) 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 name <- peekCString name
count <- ts_node_p_named_child_count node count <- ts_node_p_named_child_count node
children <- traverse (alloca . getChild node) $ take (fromIntegral count) [0..] 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. -- 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 } let info = range `seq` range .: categoriesForLanguage language (toS name) .: RNil
termConstructor (source blob) (sourceSpan `seq` pure sourceSpan) info children
sourceSpan <- pure $! SourceSpan { spanName = toS (path blob) getChild node n out = ts_node_p_named_child node n out >> toTerm out
, spanStart = SourcePos (fromIntegral $ ts_node_p_start_point_row node) (fromIntegral $ ts_node_p_start_point_column node) {-# INLINE getChild #-}
, 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