2015-12-09 17:58:15 +03:00
|
|
|
module TreeSitter where
|
|
|
|
|
|
|
|
import Diff
|
|
|
|
import Range
|
2015-12-17 00:24:23 +03:00
|
|
|
import Parser
|
2015-12-09 17:58:15 +03:00
|
|
|
import Term
|
2015-12-16 23:49:46 +03:00
|
|
|
import qualified Data.Set as Set
|
2015-12-09 17:58:15 +03:00
|
|
|
import Foreign
|
|
|
|
import Foreign.C
|
|
|
|
import Foreign.C.Types
|
|
|
|
|
|
|
|
data TSLanguage = TsLanguage deriving (Show, Eq)
|
2015-12-09 18:11:30 +03:00
|
|
|
foreign import ccall "prototype/doubt-difftool/doubt-difftool-Bridging-Header.h ts_language_c" ts_language_c :: Ptr TSLanguage
|
|
|
|
foreign import ccall "prototype/doubt-difftool/doubt-difftool-Bridging-Header.h ts_language_javascript" ts_language_javascript :: Ptr TSLanguage
|
2015-12-09 17:58:15 +03:00
|
|
|
|
|
|
|
data TSDocument = TsDocument deriving (Show, Eq)
|
|
|
|
foreign import ccall "prototype/External/tree-sitter/include/tree_sitter/runtime.h ts_document_make" ts_document_make :: IO (Ptr TSDocument)
|
|
|
|
foreign import ccall "prototype/External/tree-sitter/include/tree_sitter/runtime.h ts_document_set_language" ts_document_set_language :: Ptr TSDocument -> Ptr TSLanguage -> IO ()
|
|
|
|
foreign import ccall "prototype/External/tree-sitter/include/tree_sitter/runtime.h ts_document_set_input_string" ts_document_set_input_string :: Ptr TSDocument -> CString -> IO ()
|
|
|
|
foreign import ccall "prototype/External/tree-sitter/include/tree_sitter/runtime.h ts_document_parse" ts_document_parse :: Ptr TSDocument -> IO ()
|
|
|
|
foreign import ccall "prototype/External/tree-sitter/include/tree_sitter/runtime.h ts_document_free" ts_document_free :: Ptr TSDocument -> IO ()
|
|
|
|
|
|
|
|
data TSLength = TsLength { bytes :: CSize, chars :: CSize }
|
|
|
|
deriving (Show, Eq)
|
|
|
|
|
|
|
|
data TSNode = TsNode { _data :: Ptr (), offset :: TSLength }
|
|
|
|
deriving (Show, Eq)
|
|
|
|
|
|
|
|
instance Storable TSNode where
|
2015-12-23 03:06:51 +03:00
|
|
|
alignment _ = 32
|
|
|
|
sizeOf _ = 32
|
2015-12-14 23:52:39 +03:00
|
|
|
peek _ = error "Haskell code should never read TSNode values directly."
|
|
|
|
poke _ _ = error "Haskell code should never write TSNode values directly."
|
2015-12-09 17:58:15 +03:00
|
|
|
|
|
|
|
foreign import ccall "app/bridge.h ts_document_root_node_p" ts_document_root_node_p :: Ptr TSDocument -> Ptr TSNode -> IO ()
|
|
|
|
foreign import ccall "app/bridge.h ts_node_p_name" ts_node_p_name :: Ptr TSNode -> Ptr TSDocument -> IO CString
|
|
|
|
foreign import ccall "app/bridge.h ts_node_p_named_child_count" ts_node_p_named_child_count :: Ptr TSNode -> IO CSize
|
|
|
|
foreign import ccall "app/bridge.h ts_node_p_named_child" ts_node_p_named_child :: Ptr TSNode -> CSize -> Ptr TSNode -> IO CSize
|
2015-12-17 22:56:43 +03:00
|
|
|
foreign import ccall "app/bridge.h ts_node_p_start_char" ts_node_p_start_char :: Ptr TSNode -> CSize
|
|
|
|
foreign import ccall "app/bridge.h ts_node_p_end_char" ts_node_p_end_char :: Ptr TSNode -> CSize
|
2015-12-09 17:58:15 +03:00
|
|
|
|
2015-12-17 02:08:51 +03:00
|
|
|
data Language = Language { getTsLanguage :: Ptr TSLanguage, getConstructor :: Constructor }
|
2015-12-17 00:03:15 +03:00
|
|
|
|
2015-12-17 00:05:24 +03:00
|
|
|
languageForType :: String -> Maybe Language
|
2015-12-15 22:39:54 +03:00
|
|
|
languageForType mediaType = case mediaType of
|
2015-12-17 02:11:23 +03:00
|
|
|
".h" -> c
|
|
|
|
".c" -> c
|
2015-12-17 02:10:39 +03:00
|
|
|
".js" -> Just . Language ts_language_javascript $ constructorForProductions
|
|
|
|
(Set.fromList [ "object" ])
|
|
|
|
(Set.fromList [ "pair", "rel_op", "math_op", "bool_op", "bitwise_op", "type_op", "math_assignment", "assignment", "subscript_access", "member_access", "new_expression", "function_call", "function", "ternary" ])
|
2015-12-15 22:39:54 +03:00
|
|
|
_ -> Nothing
|
2015-12-17 02:22:25 +03:00
|
|
|
where c = Just . Language ts_language_c $ constructorForProductions mempty (Set.fromList [ "assignment_expression", "logical_expression", "pointer_expression", "field_expression", "relational_expression", "designator", "call_expression", "math_expression" ])
|
2015-12-15 22:39:54 +03:00
|
|
|
|
2015-12-17 00:24:23 +03:00
|
|
|
parseTreeSitterFile :: Language -> Parser
|
2015-12-17 02:08:51 +03:00
|
|
|
parseTreeSitterFile (Language language constructor) contents = do
|
2015-12-09 17:58:15 +03:00
|
|
|
document <- ts_document_make
|
|
|
|
ts_document_set_language document language
|
|
|
|
withCString contents (\source -> do
|
|
|
|
ts_document_set_input_string document source
|
|
|
|
ts_document_parse document
|
2015-12-17 00:06:06 +03:00
|
|
|
term <- documentToTerm constructor document contents
|
2015-12-09 17:58:15 +03:00
|
|
|
ts_document_free document
|
|
|
|
return term)
|
|
|
|
|
2015-12-17 00:24:23 +03:00
|
|
|
documentToTerm :: Constructor -> Ptr TSDocument -> Parser
|
2015-12-17 00:06:06 +03:00
|
|
|
documentToTerm constructor document contents = alloca $ \root -> do
|
2015-12-09 17:58:15 +03:00
|
|
|
ts_document_root_node_p document root
|
|
|
|
snd <$> toTerm root where
|
|
|
|
toTerm :: Ptr TSNode -> IO (String, Term String Info)
|
|
|
|
toTerm node = do
|
|
|
|
name <- ts_node_p_name node document
|
|
|
|
name <- peekCString name
|
|
|
|
children <- withNamedChildren node toTerm
|
2015-12-17 22:56:43 +03:00
|
|
|
return (name, constructor contents (Info (range node) $ Set.singleton name) children)
|
2015-12-09 17:58:15 +03:00
|
|
|
|
|
|
|
withNamedChildren :: Ptr TSNode -> (Ptr TSNode -> IO (String, a)) -> IO [(String, a)]
|
|
|
|
withNamedChildren node transformNode = do
|
|
|
|
count <- ts_node_p_named_child_count node
|
|
|
|
if count == 0
|
|
|
|
then return []
|
|
|
|
else mapM (alloca . getChild) [0..pred count] where
|
|
|
|
getChild n out = do
|
2015-12-14 23:52:39 +03:00
|
|
|
_ <- ts_node_p_named_child node n out
|
2015-12-09 17:58:15 +03:00
|
|
|
transformNode out
|
|
|
|
|
2015-12-17 22:56:43 +03:00
|
|
|
range :: Ptr TSNode -> Range
|
|
|
|
range node = Range { start = fromIntegral $ ts_node_p_start_char node, end = fromIntegral $ ts_node_p_end_char node }
|