builtins are built in

This commit is contained in:
Mirek Kratochvil 2022-11-13 00:46:38 +01:00
parent 9d78684317
commit 8d5353dc8c
8 changed files with 80 additions and 50 deletions

View file

@ -1,15 +1,19 @@
module Builtins where module Builtins where
import Code import Code
import Control.Monad.IO.Class
import Control.Monad.Trans.State.Lazy import Control.Monad.Trans.State.Lazy
import qualified Data.Map as M import qualified Data.Map as M
import Env import Env hiding (PrlgEnv)
import Interpreter (backtrack)
import qualified Operators as O import qualified Operators as O
import Debug.Trace bi = Builtin
hello :: BuiltinFunc hello =
hello = BuiltinFunc $ trace "hllo prlg" bi $ do
liftIO $ putStrLn "hllo prlg"
return Nothing
addBuiltins :: PrlgEnv () addBuiltins :: PrlgEnv ()
addBuiltins = do addBuiltins = do
@ -21,6 +25,9 @@ addBuiltins = do
any1 <- findStruct "any" 1 any1 <- findStruct "any" 1
eq2 <- findStruct "=" 2 eq2 <- findStruct "=" 2
hello0 <- findStruct "hello" 0 hello0 <- findStruct "hello" 0
fail0 <- findStruct "fail" 0
true0 <- findStruct "true" 0
prlgstate0 <- findStruct "prlgstate" 0
modify $ \s -> modify $ \s ->
s s
{ defs = { defs =
@ -32,7 +39,11 @@ addBuiltins = do
, [Goal, U (Struct a1), U (Atom b), LastCall] , [Goal, U (Struct a1), U (Atom b), LastCall]
]) ])
, (any1, [[U (VoidRef Nothing), NoGoal]]) , (any1, [[U (VoidRef Nothing), NoGoal]])
, (hello0, [[Builtin hello]]) , (hello0, [[Invoke hello]])
, (fail0, [[Invoke $ bi backtrack]])
, (true0, [[Invoke $ bi (pure Nothing)]])
, ( prlgstate0
, [[Invoke $ bi (get >>= liftIO . print >> pure Nothing)]])
] ]
, ops = [(O.xfy "," 1000), (O.xfx "=" 700)] , ops = [(O.xfy "," 1000), (O.xfx "=" 700)]
} }

View file

@ -1,8 +1,10 @@
module Code where module Code where
import Control.Monad.Trans.State.Lazy
import qualified Data.Map as M import qualified Data.Map as M
import IR (Id(..), StrTable) import IR (Id(..), StrTable)
import Operators (Ops) import Operators (Ops)
import System.Console.Haskeline
data Datum data Datum
= Atom Int -- unifies a constant = Atom Int -- unifies a constant
@ -12,16 +14,10 @@ data Datum
| HeapRef Int (Maybe Int) -- heap structure idx | HeapRef Int (Maybe Int) -- heap structure idx
deriving (Show, Eq, Ord) deriving (Show, Eq, Ord)
data BuiltinFunc =
BuiltinFunc (Interp -> Interp)
instance Show BuiltinFunc where
show _ = "BuiltinFunc _"
data Instr data Instr
= U Datum -- something unifiable = U Datum -- something unifiable
| NoGoal -- trivial goal (directly after head) | NoGoal -- trivial goal (directly after head)
| Builtin BuiltinFunc -- trivial goal (directly after head) | Invoke Builtin -- also directly after head
| Goal -- a new goal (set head) | Goal -- a new goal (set head)
| Call -- all seems okay, call the head's hoal | Call -- all seems okay, call the head's hoal
| LastCall -- tail call the head's goal | LastCall -- tail call the head's goal
@ -64,3 +60,13 @@ data Interp =
, strtable :: StrTable -- string table , strtable :: StrTable -- string table
} }
deriving (Show) deriving (Show)
type PrlgEnv a = StateT Interp (InputT IO) a
type BuiltinFn = PrlgEnv (Maybe (Either String Bool))
data Builtin =
Builtin BuiltinFn
instance Show Builtin where
show _ = "Builtin _"

View file

@ -1,25 +1,22 @@
module Env where module Env where
import Code (Interp (..)) import Code (Interp(..), PrlgEnv)
import Control.Monad.IO.Class
import Control.Monad.Trans.State.Lazy import Control.Monad.Trans.State.Lazy
import qualified IR import qualified IR
import qualified Operators
import System.Console.Haskeline
type PrlgEnv a = StateT Code.Interp (InputT IO) a withStrTable :: (IR.StrTable -> (IR.StrTable, a)) -> Env.PrlgEnv a
withStrTable :: (IR.StrTable -> (IR.StrTable, a)) -> PrlgEnv a
withStrTable f = do withStrTable f = do
st <- gets strtable st <- gets strtable
let (st', x) = f st let (st', x) = f st
modify (\s -> s {strtable = st'}) modify (\s -> s {strtable = st'})
return x return x
findStruct :: String -> Int -> PrlgEnv IR.Id findStruct :: String -> Int -> Env.PrlgEnv IR.Id
findStruct str arity = do findStruct str arity = do
stri <- findAtom str stri <- findAtom str
return IR.Id {IR.str = stri, IR.arity = arity} return IR.Id {IR.str = stri, IR.arity = arity}
findAtom :: String -> PrlgEnv Int findAtom :: String -> Env.PrlgEnv Int
findAtom = withStrTable . flip IR.strtablize findAtom = withStrTable . flip IR.strtablize
type PrlgEnv a = Code.PrlgEnv a

View file

@ -87,4 +87,10 @@ interpreter :: InputT IO ()
interpreter = interpreter =
evalStateT evalStateT
interpreterStart interpreterStart
(Interp {defs = M.empty, ops = [], strtable = IR.emptystrtable, cur=error "no cur", cho=[]}) (Interp
{ defs = M.empty
, ops = []
, strtable = IR.emptystrtable
, cur = error "no cur"
, cho = []
})

View file

@ -2,11 +2,11 @@
module Interpreter where module Interpreter where
import Code import Code
import qualified Control.Monad.Trans.State.Lazy as St
--import Data.Function --import Data.Function
import qualified Data.Map as M import qualified Data.Map as M
import Env (PrlgEnv(..))
import IR (Id(..)) import IR (Id(..))
import qualified Control.Monad.Trans.State.Lazy as St
prove :: Code -> PrlgEnv (Either String Bool) prove :: Code -> PrlgEnv (Either String Bool)
prove g = do prove g = do
@ -27,32 +27,43 @@ prove g = do
loop loop
where where
loop = do loop = do
i <- St.get x <- proveStep
proveStep cont finish i case x of
cont i = St.put i >> loop Nothing -> loop -- not finished yet
finish i res = St.put i >> return res Just x -> return x
data Dereferenced data Dereferenced
= FreeRef Int = FreeRef Int
| BoundRef Int Datum | BoundRef Int Datum
| NoRef | NoRef
proveStep :: (Interp -> a) -> (Interp -> Either String Bool -> a) -> Interp -> a {- Simple "fail" backtracking -}
proveStep c f i = go i backtrack :: PrlgEnv (Maybe (Either String Bool))
backtrack = do
chos <- St.gets cho
case chos
{- if available, restore the easiest choicepoint -}
of
(c:cs) -> do
St.modify $ \i -> i {cur = c, cho = cs}
pure Nothing
{- if there's no other choice, answer no -}
_ -> pure . Just $ Right False
proveStep :: PrlgEnv (Maybe (Either String Bool))
proveStep = St.get >>= go
where where
ifail msg = f i $ Left msg finish = pure . Just
c i = St.put i >> pure Nothing
ifail msg = finish $ Left msg
tailcut [LastCall] chos _ = Just chos tailcut [LastCall] chos _ = Just chos
tailcut [LastCall, Cut] _ cut = Just cut tailcut [LastCall, Cut] _ cut = Just cut
tailcut _ _ _ = Nothing tailcut _ _ _ = Nothing
withDef fn withDef fn cont = do
| Just d <- defs i M.!? fn = ($ d) d <- St.gets defs
| otherwise = const $ ifail $ "no definition: " ++ show fn case d M.!? fn of
{- Backtracking -} Just d -> cont d
backtrack i@Interp {cho = chos} _ -> ifail $ "no definition: " ++ show fn
{- if available, restore the easiest choicepoint -}
| (cho:chos) <- chos = c i {cur = cho, cho = chos}
{- if there's no other choice, answer no -}
| otherwise = f i $ Right False
{- Unification -} {- Unification -}
go i@Interp {cur = cur@Cho { hed = U h:hs go i@Interp {cur = cur@Cho { hed = U h:hs
, gol = U g:gs , gol = U g:gs
@ -206,7 +217,7 @@ proveStep c f i = go i
} }
} }
_ -> ifail "dangling goal ref" _ -> ifail "dangling goal ref"
unify _ _ = backtrack i unify _ _ = backtrack
{- Resolution -} {- Resolution -}
go i@Interp { cur = cur@Cho { hed = hed go i@Interp { cur = cur@Cho { hed = hed
, hvar = hvar , hvar = hvar
@ -219,14 +230,15 @@ proveStep c f i = go i
, cho = chos , cho = chos
} }
{- invoke a built-in (this gets replaced by NoGoal by default but the {- invoke a built-in (this gets replaced by NoGoal by default but the
- builtin can actually do whatever it wants with the code -} - builtin can actually do whatever it wants with the code) -}
| [Builtin (BuiltinFunc bf)] <- hed = | [Invoke (Builtin bf)] <- hed =
c (bf i {cur = cur {hed = [NoGoal]}}) St.put i {cur = cur {hed = [NoGoal]}} >> bf
{- top-level success -} {- top-level success -}
| [NoGoal] <- hed | [NoGoal] <- hed
, Just nchos <- tailcut gol chos cut , Just nchos <- tailcut gol chos cut
, [] <- stk = , [] <- stk = do
f i {cur = cur {hed = [], gol = []}, cho = nchos} $ Right True St.put i {cur = cur {hed = [], gol = []}, cho = nchos}
finish $ Right True
{- cut before the first goal (this solves all cuts in head) -} {- cut before the first goal (this solves all cuts in head) -}
| Cut:hs <- hed = c i {cur = cur {hed = hs}, cho = cut} | Cut:hs <- hed = c i {cur = cur {hed = hs}, cho = cut}
{- succeed and return to caller -} {- succeed and return to caller -}

View file

@ -1,6 +1,5 @@
module Main where module Main where
import Control.Monad
import Frontend (interpreter) import Frontend (interpreter)
import System.Console.Haskeline import System.Console.Haskeline

View file

@ -6,10 +6,8 @@ module Parser
, shuntPrlg , shuntPrlg
) where ) where
import Control.Applicative (liftA2)
import Control.Monad (void) import Control.Monad (void)
import Data.Char import Data.Char
import Data.List (intercalate)
import Data.List.NonEmpty (NonEmpty(..)) import Data.List.NonEmpty (NonEmpty(..))
import Data.List.Split (splitOn) import Data.List.Split (splitOn)
import Data.Void import Data.Void

View file

@ -3,7 +3,7 @@ name: prlg
version: 0.1.0.0 version: 0.1.0.0
-- A short (one-line) description of the package. -- A short (one-line) description of the package.
-- synopsis: synopsis: A small Vienna-style interpreter.
-- A longer description of the package. -- A longer description of the package.
-- description: -- description:
@ -32,3 +32,4 @@ executable prlg
build-depends: base >=4.16, containers, megaparsec, haskeline, pretty-simple, split, transformers build-depends: base >=4.16, containers, megaparsec, haskeline, pretty-simple, split, transformers
hs-source-dirs: app hs-source-dirs: app
default-language: Haskell2010 default-language: Haskell2010
ghc-options: -Wunused-imports