mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-04-23 11:42:49 -06:00
cleanup, document and export the completion API
This commit is contained in:
@@ -173,21 +173,14 @@ allCommands pgf = Map.fromAscList [
|
|||||||
if s == "q"
|
if s == "q"
|
||||||
then return ()
|
then return ()
|
||||||
else do cpu1 <- getCPUTime
|
else do cpu1 <- getCPUTime
|
||||||
st <- parse pinfo state0 (words s)
|
exps <- return $! Incremental.parse pinfo (mkCId cat) (words s)
|
||||||
let exps = Incremental.extractExps pinfo (mkCId cat) st
|
|
||||||
mapM_ (putStrLn . showExp) exps
|
mapM_ (putStrLn . showExp) exps
|
||||||
cpu2 <- getCPUTime
|
cpu2 <- getCPUTime
|
||||||
putStrLn (show ((cpu2 - cpu1) `div` 1000000000) ++ " msec")
|
putStrLn (show ((cpu2 - cpu1) `div` 1000000000) ++ " msec")
|
||||||
wordCompletion opts
|
wordCompletion opts
|
||||||
where
|
where
|
||||||
parse pinfo st [] = do putStrLnFlush ""
|
|
||||||
return st
|
|
||||||
parse pinfo st (t:ts) = do putStrFlush "."
|
|
||||||
st1 <- return $! (Incremental.nextState pinfo t st)
|
|
||||||
parse pinfo st1 ts
|
|
||||||
|
|
||||||
myCompletion pinfo state0 line prefix p = do
|
myCompletion pinfo state0 line prefix p = do
|
||||||
let ws = words (take (p-length prefix) line)
|
let ws = words (take (p-length prefix) line)
|
||||||
state = foldl (\st t -> Incremental.nextState pinfo t st) state0 ws
|
state = foldl Incremental.nextState state0 ws
|
||||||
compls = Incremental.getCompletions pinfo prefix state
|
compls = Incremental.getCompletions state prefix
|
||||||
return (Map.keys compls)
|
return (Map.keys compls)
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ module PGF(
|
|||||||
|
|
||||||
-- ** Parsing
|
-- ** Parsing
|
||||||
parse, parseAllLang, parseAll,
|
parse, parseAllLang, parseAll,
|
||||||
|
|
||||||
|
-- ** Word Completion (Incremental Parsing)
|
||||||
|
Incremental.ParseState,
|
||||||
|
initState, Incremental.nextState, Incremental.getCompletions, extractExps,
|
||||||
|
|
||||||
-- ** Generation
|
-- ** Generation
|
||||||
generateRandom, generateAll, generateAllDepth
|
generateRandom, generateAll, generateAllDepth
|
||||||
@@ -52,6 +56,7 @@ import PGF.Raw.Convert
|
|||||||
import PGF.Raw.Parse
|
import PGF.Raw.Parse
|
||||||
import PGF.Raw.Print (printTree)
|
import PGF.Raw.Print (printTree)
|
||||||
import PGF.Parsing.FCFG
|
import PGF.Parsing.FCFG
|
||||||
|
import qualified PGF.Parsing.FCFG.Incremental as Incremental
|
||||||
import GF.Text.UTF8
|
import GF.Text.UTF8
|
||||||
|
|
||||||
import GF.Data.ErrM
|
import GF.Data.ErrM
|
||||||
@@ -119,6 +124,16 @@ parseAll :: PGF -> Category -> String -> [[Exp]]
|
|||||||
-- if the grammar is ambiguous.
|
-- if the grammar is ambiguous.
|
||||||
parseAllLang :: PGF -> Category -> String -> [(Language,[Exp])]
|
parseAllLang :: PGF -> Category -> String -> [(Language,[Exp])]
|
||||||
|
|
||||||
|
-- | Creates an initial parsing state for a given language and
|
||||||
|
-- startup category.
|
||||||
|
initState :: PGF -> Language -> Category -> Incremental.ParseState
|
||||||
|
|
||||||
|
-- | This function extracts the list of all completed parse trees
|
||||||
|
-- that spans the whole input consumed so far. The trees are also
|
||||||
|
-- limited by the category specified, which is usually
|
||||||
|
-- the same as the startup category.
|
||||||
|
extractExps :: Incremental.ParseState -> Category -> [Exp]
|
||||||
|
|
||||||
-- | The same as 'generateAllDepth' but does not limit
|
-- | The same as 'generateAllDepth' but does not limit
|
||||||
-- the depth in the generation.
|
-- the depth in the generation.
|
||||||
generateAll :: PGF -> Category -> [Exp]
|
generateAll :: PGF -> Category -> [Exp]
|
||||||
@@ -183,6 +198,16 @@ parseAll mgr cat = map snd . parseAllLang mgr cat
|
|||||||
parseAllLang mgr cat s =
|
parseAllLang mgr cat s =
|
||||||
[(lang,ts) | lang <- languages mgr, let ts = parse mgr lang cat s, not (null ts)]
|
[(lang,ts) | lang <- languages mgr, let ts = parse mgr lang cat s, not (null ts)]
|
||||||
|
|
||||||
|
initState pgf lang cat = Incremental.initState pinfo catCId
|
||||||
|
where
|
||||||
|
langCId = mkCId lang
|
||||||
|
catCId = mkCId cat
|
||||||
|
pinfo = case lookParser pgf langCId of
|
||||||
|
Just pinfo -> pinfo
|
||||||
|
_ -> error ("Unknown language: " ++ lang)
|
||||||
|
|
||||||
|
extractExps state cat = Incremental.extractExps state (mkCId cat)
|
||||||
|
|
||||||
generateRandom pgf cat = do
|
generateRandom pgf cat = do
|
||||||
gen <- newStdGen
|
gen <- newStdGen
|
||||||
return $ genRandom gen pgf (mkCId cat)
|
return $ genRandom gen pgf (mkCId cat)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{-# LANGUAGE BangPatterns #-}
|
{-# LANGUAGE BangPatterns #-}
|
||||||
module PGF.Parsing.FCFG.Incremental
|
module PGF.Parsing.FCFG.Incremental
|
||||||
( State
|
( ParseState
|
||||||
, initState
|
, initState
|
||||||
, nextState
|
, nextState
|
||||||
, getCompletions
|
, getCompletions
|
||||||
@@ -10,7 +10,7 @@ module PGF.Parsing.FCFG.Incremental
|
|||||||
|
|
||||||
import Data.Array
|
import Data.Array
|
||||||
import Data.Array.Base (unsafeAt)
|
import Data.Array.Base (unsafeAt)
|
||||||
import Data.List (isPrefixOf)
|
import Data.List (isPrefixOf, foldl')
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromMaybe)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import qualified Data.IntMap as IntMap
|
import qualified Data.IntMap as IntMap
|
||||||
@@ -26,12 +26,9 @@ import PGF.Parsing.FCFG.Utilities
|
|||||||
import Debug.Trace
|
import Debug.Trace
|
||||||
|
|
||||||
parse :: ParserInfo -> CId -> [FToken] -> [Exp]
|
parse :: ParserInfo -> CId -> [FToken] -> [Exp]
|
||||||
parse pinfo start toks = go (initState pinfo start) toks
|
parse pinfo start toks = extractExps (foldl' nextState (initState pinfo start) toks) start
|
||||||
where
|
|
||||||
go st [] = extractExps pinfo start st
|
|
||||||
go st (t:ts) = go (nextState pinfo t st) ts
|
|
||||||
|
|
||||||
initState :: ParserInfo -> CId -> State
|
initState :: ParserInfo -> CId -> ParseState
|
||||||
initState pinfo start =
|
initState pinfo start =
|
||||||
let items = do
|
let items = do
|
||||||
c <- Map.findWithDefault [] start (startupCats pinfo)
|
c <- Map.findWithDefault [] start (startupCats pinfo)
|
||||||
@@ -46,39 +43,47 @@ initState pinfo start =
|
|||||||
Just ((fid,_), _) -> fid+1
|
Just ((fid,_), _) -> fid+1
|
||||||
Nothing -> 0
|
Nothing -> 0
|
||||||
|
|
||||||
in State (Chart MM.empty [] Map.empty forest max_fid 0)
|
in State pinfo
|
||||||
|
(Chart MM.empty [] Map.empty forest max_fid 0)
|
||||||
(Set.fromList items)
|
(Set.fromList items)
|
||||||
|
|
||||||
nextState :: ParserInfo -> FToken -> State -> State
|
-- | From the current state and the next token
|
||||||
nextState pinfo t (State chart items) =
|
-- 'nextState' computes a new state where the token
|
||||||
|
-- is consumed and the current position shifted by one.
|
||||||
|
nextState :: ParseState -> String -> ParseState
|
||||||
|
nextState (State pinfo chart items) t =
|
||||||
let (items1,chart1) = process add (allRules pinfo) (Set.toList items) (Set.empty,chart)
|
let (items1,chart1) = process add (allRules pinfo) (Set.toList items) (Set.empty,chart)
|
||||||
chart2 = chart1{ active =MM.empty
|
chart2 = chart1{ active =MM.empty
|
||||||
, actives=active chart1 : actives chart1
|
, actives=active chart1 : actives chart1
|
||||||
, passive=Map.empty
|
, passive=Map.empty
|
||||||
, offset =offset chart1+1
|
, offset =offset chart1+1
|
||||||
}
|
}
|
||||||
in State chart2 items1
|
in State pinfo chart2 items1
|
||||||
where
|
where
|
||||||
add tok item set
|
add tok item set
|
||||||
| tok == t = Set.insert item set
|
| tok == t = Set.insert item set
|
||||||
| otherwise = set
|
| otherwise = set
|
||||||
|
|
||||||
getCompletions :: ParserInfo -> FToken -> State -> Map.Map FToken State
|
-- | If the next token is not known but only its prefix (possible empty prefix)
|
||||||
getCompletions pinfo w (State chart items) =
|
-- then the 'getCompletions' function can be used to calculate the possible
|
||||||
|
-- next words and the consequent states. This is used for word completions in
|
||||||
|
-- the GF interpreter.
|
||||||
|
getCompletions :: ParseState -> String -> Map.Map String ParseState
|
||||||
|
getCompletions (State pinfo chart items) w =
|
||||||
let (map',chart1) = process add (allRules pinfo) (Set.toList items) (MM.empty,chart)
|
let (map',chart1) = process add (allRules pinfo) (Set.toList items) (MM.empty,chart)
|
||||||
chart2 = chart1{ active =MM.empty
|
chart2 = chart1{ active =MM.empty
|
||||||
, actives=active chart1 : actives chart1
|
, actives=active chart1 : actives chart1
|
||||||
, passive=Map.empty
|
, passive=Map.empty
|
||||||
, offset =offset chart1+1
|
, offset =offset chart1+1
|
||||||
}
|
}
|
||||||
in fmap (State chart2) map'
|
in fmap (State pinfo chart2) map'
|
||||||
where
|
where
|
||||||
add tok item map
|
add tok item map
|
||||||
| isPrefixOf w tok = fromMaybe map (MM.insert' tok item map)
|
| isPrefixOf w tok = fromMaybe map (MM.insert' tok item map)
|
||||||
| otherwise = map
|
| otherwise = map
|
||||||
|
|
||||||
extractExps :: ParserInfo -> CId -> State -> [Exp]
|
extractExps :: ParseState -> CId -> [Exp]
|
||||||
extractExps pinfo start (State chart items) = exps
|
extractExps (State pinfo chart items) start = exps
|
||||||
where
|
where
|
||||||
(_,st) = process (\_ _ -> id) (allRules pinfo) (Set.toList items) ((),chart)
|
(_,st) = process (\_ _ -> id) (allRules pinfo) (Set.toList items) ((),chart)
|
||||||
|
|
||||||
@@ -160,7 +165,9 @@ data PassiveKey
|
|||||||
deriving (Eq,Ord,Show)
|
deriving (Eq,Ord,Show)
|
||||||
|
|
||||||
|
|
||||||
data State = State Chart (Set.Set Active)
|
-- | An abstract data type whose values represent
|
||||||
|
-- the current state in an incremental parser.
|
||||||
|
data ParseState = State ParserInfo Chart (Set.Set Active)
|
||||||
|
|
||||||
data Chart
|
data Chart
|
||||||
= Chart
|
= Chart
|
||||||
|
|||||||
Reference in New Issue
Block a user