src/Tools/Haskell/Haskell.thy
changeset 74211 2ee03f7abd8d
parent 74209 24a2a6ced0ab
child 74213 12152390db34
equal deleted inserted replaced
74210:c14774713d62 74211:2ee03f7abd8d
   226 
   226 
   227   StringLike, STRING (..), TEXT (..), BYTES (..),
   227   StringLike, STRING (..), TEXT (..), BYTES (..),
   228   show_bytes, show_text,
   228   show_bytes, show_text,
   229 
   229 
   230   proper_string, enclose, quote, space_implode, commas, commas_quote, cat_lines,
   230   proper_string, enclose, quote, space_implode, commas, commas_quote, cat_lines,
   231   space_explode, split_lines, trim_line)
   231   space_explode, split_lines, trim_line,
       
   232 
       
   233   getenv, getenv_strict)
   232 where
   234 where
   233 
   235 
       
   236 import System.Environment (lookupEnv)
       
   237 import Data.Maybe (fromMaybe)
   234 import qualified Data.Text as Text
   238 import qualified Data.Text as Text
   235 import Data.Text (Text)
   239 import Data.Text (Text)
   236 import qualified Data.Text.Lazy as Lazy
   240 import qualified Data.Text.Lazy as Lazy
   237 import Data.String (IsString)
   241 import Data.String (IsString)
   238 import qualified Data.List.Split as Split
   242 import qualified Data.List.Split as Split
   394 split_lines :: StringLike a => a -> [a]
   398 split_lines :: StringLike a => a -> [a]
   395 split_lines = space_explode '\n'
   399 split_lines = space_explode '\n'
   396 
   400 
   397 cat_lines :: StringLike a => [a] -> a
   401 cat_lines :: StringLike a => [a] -> a
   398 cat_lines = space_implode "\n"
   402 cat_lines = space_implode "\n"
       
   403 
       
   404 
       
   405 {- getenv -}
       
   406 
       
   407 getenv :: Bytes -> IO Bytes
       
   408 getenv x = do
       
   409   y <- lookupEnv (make_string x)
       
   410   return $ make_bytes $ fromMaybe "" y
       
   411 
       
   412 getenv_strict :: Bytes -> IO Bytes
       
   413 getenv_strict x = do
       
   414   y <- getenv x
       
   415   if Bytes.null y then
       
   416     errorWithoutStackTrace $ make_string ("Undefined Isabelle environment variable: " <> quote x)
       
   417   else return y
   399 \<close>
   418 \<close>
   400 
   419 
   401 
   420 
   402 generate_file "Isabelle/Symbol.hs" = \<open>
   421 generate_file "Isabelle/Symbol.hs" = \<open>
   403 {-  Title:      Isabelle/Symbols.hs
   422 {-  Title:      Isabelle/Symbols.hs
  3128 -}
  3147 -}
  3129 
  3148 
  3130 {-# LANGUAGE OverloadedStrings #-}
  3149 {-# LANGUAGE OverloadedStrings #-}
  3131 
  3150 
  3132 module Isabelle.Server (
  3151 module Isabelle.Server (
  3133   localhost_name, localhost, publish_text, publish_stdout,
  3152   localhost_name, localhost_unprefix, localhost, publish_text, publish_stdout,
  3134   server, connection
  3153   server, connection
  3135 )
  3154 )
  3136 where
  3155 where
  3137 
  3156 
  3138 import Control.Monad (forever, when)
  3157 import Control.Monad (forever, when)
  3152 
  3171 
  3153 {- server address -}
  3172 {- server address -}
  3154 
  3173 
  3155 localhost_name :: Bytes
  3174 localhost_name :: Bytes
  3156 localhost_name = "127.0.0.1"
  3175 localhost_name = "127.0.0.1"
       
  3176 
       
  3177 localhost_prefix :: Bytes
       
  3178 localhost_prefix = localhost_name <> ":"
       
  3179 
       
  3180 localhost_unprefix :: Bytes -> Maybe Bytes
       
  3181 localhost_unprefix address =
       
  3182   if Bytes.isPrefixOf localhost_prefix address
       
  3183   then Just $ Bytes.drop (Bytes.length localhost_prefix) address
       
  3184   else Nothing
  3157 
  3185 
  3158 localhost :: Socket.HostAddress
  3186 localhost :: Socket.HostAddress
  3159 localhost = Socket.tupleToHostAddress (127, 0, 0, 1)
  3187 localhost = Socket.tupleToHostAddress (127, 0, 0, 1)
  3160 
  3188 
  3161 publish_text :: Bytes -> Bytes -> UUID.T -> Bytes
  3189 publish_text :: Bytes -> Bytes -> UUID.T -> Bytes
  3213     resolve = do
  3241     resolve = do
  3214       let hints =
  3242       let hints =
  3215             Socket.defaultHints {
  3243             Socket.defaultHints {
  3216               Socket.addrFlags = [Socket.AI_NUMERICHOST, Socket.AI_NUMERICSERV],
  3244               Socket.addrFlags = [Socket.AI_NUMERICHOST, Socket.AI_NUMERICSERV],
  3217               Socket.addrSocketType = Socket.Stream }
  3245               Socket.addrSocketType = Socket.Stream }
  3218       head <$> Socket.getAddrInfo (Just hints) (Just "127.0.0.1") (Just port)
  3246       head <$> Socket.getAddrInfo (Just hints) (Just $ make_string localhost_name) (Just port)
  3219 
  3247 
  3220     open addr = do
  3248     open addr = do
  3221       socket <- Socket.socket (Socket.addrFamily addr) (Socket.addrSocketType addr)
  3249       socket <- Socket.socket (Socket.addrFamily addr) (Socket.addrSocketType addr)
  3222                   (Socket.addrProtocol addr)
  3250                   (Socket.addrProtocol addr)
  3223       Socket.connect socket $ Socket.addrAddress addr
  3251       Socket.connect socket $ Socket.addrAddress addr
  3345 
  3373 
  3346   Params,
  3374   Params,
  3347   get_script, get_input, get_cwd, get_putenv, get_redirect,
  3375   get_script, get_input, get_cwd, get_putenv, get_redirect,
  3348   get_timeout, get_description,
  3376   get_timeout, get_description,
  3349   script, input, cwd, putenv, redirect, timeout, description,
  3377   script, input, cwd, putenv, redirect, timeout, description,
       
  3378   server_run, server_kill,
       
  3379   server_uuid, server_interrupt, server_failure, server_result
  3350 )
  3380 )
  3351 where
  3381 where
  3352 
  3382 
  3353 import Text.Printf (printf)
  3383 import Text.Printf (printf)
  3354 import qualified Isabelle.Symbol as Symbol
  3384 import qualified Isabelle.Symbol as Symbol
  3433 timeout :: Time -> Params -> Params
  3463 timeout :: Time -> Params -> Params
  3434 timeout timeout params = params { _timeout = timeout }
  3464 timeout timeout params = params { _timeout = timeout }
  3435 
  3465 
  3436 description :: Bytes -> Params -> Params
  3466 description :: Bytes -> Params -> Params
  3437 description description params = params { _description = description }
  3467 description description params = params { _description = description }
       
  3468 
       
  3469 
       
  3470 {- server messages -}
       
  3471 
       
  3472 server_run, server_kill :: Bytes
       
  3473 server_run = \<open>Bash.server_run\<close>;
       
  3474 server_kill = \<open>Bash.server_kill\<close>;
       
  3475 
       
  3476 server_uuid, server_interrupt, server_failure, server_result :: Bytes
       
  3477 server_uuid = \<open>Bash.server_uuid\<close>;
       
  3478 server_interrupt = \<open>Bash.server_interrupt\<close>;
       
  3479 server_failure = \<open>Bash.server_failure\<close>;
       
  3480 server_result = \<open>Bash.server_result\<close>;
  3438 \<close>
  3481 \<close>
  3439 
  3482 
  3440 generate_file "Isabelle/Process_Result.hs" = \<open>
  3483 generate_file "Isabelle/Process_Result.hs" = \<open>
  3441 {-  Title:      Isabelle/Process_Result.hs
  3484 {-  Title:      Isabelle/Process_Result.hs
  3442     Author:     Makarius
  3485     Author:     Makarius
  3633             Decode.pair Decode.properties (Decode.pair Decode.string (Decode.pair Decode.string Decode.string)) body
  3676             Decode.pair Decode.properties (Decode.pair Decode.string (Decode.pair Decode.string Decode.string)) body
  3634         in (name, Opt { _pos = pos, _name = name, _typ = typ, _value = value })
  3677         in (name, Opt { _pos = pos, _name = name, _typ = typ, _value = value })
  3635     in Options . Map.fromList . Decode.list decode_entry
  3678     in Options . Map.fromList . Decode.list decode_entry
  3636 \<close>
  3679 \<close>
  3637 
  3680 
       
  3681 generate_file "Isabelle/Isabelle_System.hs" = \<open>
       
  3682 {-  Title:      Isabelle/Isabelle_System.hs
       
  3683     Author:     Makarius
       
  3684     LICENSE:    BSD 3-clause (Isabelle)
       
  3685 
       
  3686 Isabelle system support.
       
  3687 
       
  3688 See \<^file>\<open>~~/src/Pure/System/isabelle_system.ML\<close>
       
  3689 and \<^file>\<open>~~/src/Pure/System/isabelle_system.scala\<close>
       
  3690 -}
       
  3691 
       
  3692 {-# LANGUAGE OverloadedStrings #-}
       
  3693 
       
  3694 module Isabelle.Isabelle_System (
       
  3695   bash_process, bash_process0
       
  3696 )
       
  3697 where
       
  3698 
       
  3699 import Data.Maybe (fromMaybe)
       
  3700 import Control.Exception (throw, AsyncException (UserInterrupt))
       
  3701 import Network.Socket (Socket)
       
  3702 import Isabelle.Bytes (Bytes)
       
  3703 import qualified Isabelle.Byte_Message as Byte_Message
       
  3704 import qualified Isabelle.Time as Time
       
  3705 import Isabelle.Timing (Timing (..))
       
  3706 import qualified Isabelle.Options as Options
       
  3707 import qualified Isabelle.Bash as Bash
       
  3708 import qualified Isabelle.Process_Result as Process_Result
       
  3709 import qualified Isabelle.XML.Encode as Encode
       
  3710 import qualified Isabelle.YXML as YXML
       
  3711 import qualified Isabelle.Value as Value
       
  3712 import qualified Isabelle.Server as Server
       
  3713 import qualified Isabelle.Isabelle_Thread as Isabelle_Thread
       
  3714 import Isabelle.Library
       
  3715 
       
  3716 
       
  3717 {- bash_process -}
       
  3718 
       
  3719 absolute_path :: Bytes -> Bytes  -- FIXME dummy
       
  3720 absolute_path = id
       
  3721 
       
  3722 bash_process :: Options.T -> Bash.Params -> IO Process_Result.T
       
  3723 bash_process options = bash_process0 address password
       
  3724   where
       
  3725     address = Options.string options "bash_process_address"
       
  3726     password = Options.string options "bash_process_password"
       
  3727 
       
  3728 bash_process0 :: Bytes -> Bytes -> Bash.Params -> IO Process_Result.T
       
  3729 bash_process0 address password params = do
       
  3730   Server.connection port password
       
  3731     (\socket -> do
       
  3732         isabelle_tmp <- getenv "ISABELLE_TMP"
       
  3733         Byte_Message.write_message socket (run isabelle_tmp)
       
  3734         loop Nothing socket)
       
  3735   where
       
  3736     port =
       
  3737       case Server.localhost_unprefix address of
       
  3738         Just port -> make_string port
       
  3739         Nothing -> errorWithoutStackTrace "Bad bash_process server address"
       
  3740 
       
  3741     script = Bash.get_script params
       
  3742     input = Bash.get_input params
       
  3743     cwd = Bash.get_cwd params
       
  3744     putenv = Bash.get_putenv params
       
  3745     redirect = Bash.get_redirect params
       
  3746     timeout = Bash.get_timeout params
       
  3747     description = Bash.get_description params
       
  3748 
       
  3749     run :: Bytes -> [Bytes]
       
  3750     run isabelle_tmp =
       
  3751      [Bash.server_run, script, input,
       
  3752       YXML.string_of_body (Encode.option (Encode.string . absolute_path) cwd),
       
  3753       YXML.string_of_body
       
  3754       (Encode.list (Encode.pair Encode.string Encode.string)
       
  3755         (("ISABELLE_TMP", isabelle_tmp) : putenv)),
       
  3756       Value.print_bool redirect,
       
  3757       Value.print_real (Time.get_seconds timeout),
       
  3758       description]
       
  3759 
       
  3760     kill :: Maybe Bytes -> IO ()
       
  3761     kill maybe_uuid = do
       
  3762       case maybe_uuid of
       
  3763         Just uuid ->
       
  3764           Server.connection port password (\socket ->
       
  3765             Byte_Message.write_message socket [Bash.server_kill, uuid])
       
  3766         Nothing -> return ()
       
  3767 
       
  3768     err = errorWithoutStackTrace "Malformed result from bash_process server"
       
  3769     the = fromMaybe err
       
  3770 
       
  3771     loop :: Maybe Bytes -> Socket -> IO Process_Result.T
       
  3772     loop maybe_uuid socket = do
       
  3773       result <- Isabelle_Thread.bracket_resource (kill maybe_uuid) (Byte_Message.read_message socket)
       
  3774       case result of
       
  3775         Just [head, uuid] | head == Bash.server_uuid -> loop (Just uuid) socket
       
  3776         Just [head] | head == Bash.server_interrupt -> throw UserInterrupt
       
  3777         Just [head, msg] | head == Bash.server_failure -> errorWithoutStackTrace $ make_string msg
       
  3778         Just (head : a : b : c : d : lines) | head == Bash.server_result ->
       
  3779           let
       
  3780             rc = the $ Value.parse_int a
       
  3781             elapsed = Time.ms $ the $ Value.parse_int b
       
  3782             cpu = Time.ms $ the $ Value.parse_int c
       
  3783             timing = Timing elapsed cpu Time.zero
       
  3784             n = the $ Value.parse_int d
       
  3785             out_lines = take n lines
       
  3786             err_lines = drop n lines
       
  3787           in return $ Process_Result.make rc out_lines err_lines timing
       
  3788         _ -> err
       
  3789 \<close>
       
  3790 
  3638 export_generated_files _
  3791 export_generated_files _
  3639 
  3792 
  3640 end
  3793 end