wenzelm@69222: (* Title: Tools/Haskell/Haskell.thy wenzelm@69222: Author: Makarius wenzelm@69225: wenzelm@69225: Support for Isabelle tools in Haskell. wenzelm@69222: *) wenzelm@69222: wenzelm@69222: theory Haskell wenzelm@69222: imports Pure wenzelm@69222: begin wenzelm@69222: wenzelm@69490: generate_file "Isabelle/Symbol.hs" = \ wenzelm@69490: {- Title: Isabelle/Symbols.hs wenzelm@69490: Author: Makarius wenzelm@69490: LICENSE: BSD 3-clause (Isabelle) wenzelm@69490: wenzelm@69490: Isabelle text symbols. wenzelm@69490: -} wenzelm@69490: wenzelm@69490: module Isabelle.Symbol where wenzelm@69490: wenzelm@69490: {- ASCII characters -} wenzelm@69490: wenzelm@69490: is_ascii_letter :: Char -> Bool wenzelm@69490: is_ascii_letter c = 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' wenzelm@69490: wenzelm@69490: is_ascii_digit :: Char -> Bool wenzelm@69490: is_ascii_digit c = '0' <= c && c <= '9' wenzelm@69490: wenzelm@69490: is_ascii_hex :: Char -> Bool wenzelm@69490: is_ascii_hex c = '0' <= c && c <= '9' || 'A' <= c && c <= 'F' || 'a' <= c && c <= 'f' wenzelm@69490: wenzelm@69490: is_ascii_quasi :: Char -> Bool wenzelm@69490: is_ascii_quasi c = c == '_' || c == '\'' wenzelm@69490: wenzelm@69490: is_ascii_blank :: Char -> Bool wenzelm@69490: is_ascii_blank c = c `elem` " \t\n\11\f\r" wenzelm@69490: wenzelm@69490: is_ascii_line_terminator :: Char -> Bool wenzelm@69490: is_ascii_line_terminator c = c == '\r' || c == '\n' wenzelm@69490: wenzelm@69490: is_ascii_letdig :: Char -> Bool wenzelm@69490: is_ascii_letdig c = is_ascii_letter c || is_ascii_digit c || is_ascii_quasi c wenzelm@69490: wenzelm@69490: is_ascii_identifier :: String -> Bool wenzelm@69490: is_ascii_identifier s = wenzelm@69490: not (null s) && is_ascii_letter (head s) && all is_ascii_letdig s wenzelm@69490: \ wenzelm@69490: wenzelm@69444: generate_file "Isabelle/Library.hs" = \ wenzelm@69445: {- Title: Isabelle/Library.hs wenzelm@69225: Author: Makarius wenzelm@69225: LICENSE: BSD 3-clause (Isabelle) wenzelm@69225: wenzelm@69225: Basic library of Isabelle idioms. wenzelm@69280: wenzelm@69280: See also \<^file>\$ISABELLE_HOME/src/Pure/General/basics.ML\, \<^file>\$ISABELLE_HOME/src/Pure/library.ML\. wenzelm@69225: -} wenzelm@69225: wenzelm@69240: module Isabelle.Library ( wenzelm@69240: (|>), (|->), (#>), (#->), wenzelm@69240: wenzelm@69240: the, the_default, wenzelm@69240: wenzelm@69240: fold, fold_rev, single, map_index, get_index, wenzelm@69240: wenzelm@69477: proper_string, quote, space_implode, commas, commas_quote, cat_lines, wenzelm@69453: space_explode, split_lines, trim_line, clean_name) wenzelm@69225: where wenzelm@69225: wenzelm@69234: import Data.Maybe wenzelm@69453: import qualified Data.List as List wenzelm@69453: import qualified Data.List.Split as Split wenzelm@69491: import qualified Isabelle.Symbol as Symbol wenzelm@69234: wenzelm@69234: wenzelm@69225: {- functions -} wenzelm@69225: wenzelm@69225: (|>) :: a -> (a -> b) -> b wenzelm@69225: x |> f = f x wenzelm@69225: wenzelm@69225: (|->) :: (a, b) -> (a -> b -> c) -> c wenzelm@69225: (x, y) |-> f = f x y wenzelm@69225: wenzelm@69225: (#>) :: (a -> b) -> (b -> c) -> a -> c wenzelm@69225: (f #> g) x = x |> f |> g wenzelm@69225: wenzelm@69225: (#->) :: (a -> (c, b)) -> (c -> b -> d) -> a -> d wenzelm@69225: (f #-> g) x = x |> f |-> g wenzelm@69225: wenzelm@69225: wenzelm@69234: {- options -} wenzelm@69234: wenzelm@69240: the :: Maybe a -> a wenzelm@69240: the (Just x) = x wenzelm@69240: the Nothing = error "the Nothing" wenzelm@69240: wenzelm@69234: the_default :: a -> Maybe a -> a wenzelm@69234: the_default x Nothing = x wenzelm@69234: the_default _ (Just y) = y wenzelm@69234: wenzelm@69234: wenzelm@69225: {- lists -} wenzelm@69225: wenzelm@69225: fold :: (a -> b -> b) -> [a] -> b -> b wenzelm@69225: fold _ [] y = y wenzelm@69225: fold f (x : xs) y = fold f xs (f x y) wenzelm@69225: wenzelm@69225: fold_rev :: (a -> b -> b) -> [a] -> b -> b wenzelm@69225: fold_rev _ [] y = y wenzelm@69225: fold_rev f (x : xs) y = f x (fold_rev f xs y) wenzelm@69225: wenzelm@69225: single :: a -> [a] wenzelm@69225: single x = [x] wenzelm@69225: wenzelm@69240: map_index :: ((Int, a) -> b) -> [a] -> [b] wenzelm@69240: map_index f = map_aux 0 wenzelm@69240: where wenzelm@69240: map_aux _ [] = [] wenzelm@69240: map_aux i (x : xs) = f (i, x) : map_aux (i + 1) xs wenzelm@69240: wenzelm@69240: get_index :: (a -> Maybe b) -> [a] -> Maybe (Int, b) wenzelm@69240: get_index f = get_aux 0 wenzelm@69240: where wenzelm@69240: get_aux _ [] = Nothing wenzelm@69240: get_aux i (x : xs) = wenzelm@69240: case f x of wenzelm@69240: Nothing -> get_aux (i + 1) xs wenzelm@69240: Just y -> Just (i, y) wenzelm@69240: wenzelm@69225: wenzelm@69225: {- strings -} wenzelm@69225: wenzelm@69477: proper_string :: String -> Maybe String wenzelm@69477: proper_string s = if null s then Nothing else Just s wenzelm@69477: wenzelm@69225: quote :: String -> String wenzelm@69225: quote s = "\"" ++ s ++ "\"" wenzelm@69225: wenzelm@69453: space_implode :: String -> [String] -> String wenzelm@69453: space_implode = List.intercalate wenzelm@69453: wenzelm@69453: commas, commas_quote :: [String] -> String wenzelm@69453: commas = space_implode ", " wenzelm@69453: commas_quote = commas . map quote wenzelm@69453: wenzelm@69453: cat_lines :: [String] -> String wenzelm@69453: cat_lines = space_implode "\n" wenzelm@69453: wenzelm@69453: wenzelm@69453: space_explode :: Char -> String -> [String] wenzelm@69453: space_explode c = Split.split (Split.dropDelims (Split.whenElt (== c))) wenzelm@69453: wenzelm@69453: split_lines :: String -> [String] wenzelm@69453: split_lines = space_explode '\n' wenzelm@69453: wenzelm@69225: trim_line :: String -> String wenzelm@69225: trim_line line = wenzelm@69491: if not (null line) && Symbol.is_ascii_line_terminator (last line) then wenzelm@69486: case reverse line of wenzelm@69486: '\n' : '\r' : rest -> reverse rest wenzelm@69486: '\r' : rest -> reverse rest wenzelm@69486: '\n' : rest -> reverse rest wenzelm@69486: _ -> line wenzelm@69486: else line wenzelm@69288: wenzelm@69288: clean_name :: String -> String wenzelm@69288: clean_name = reverse #> dropWhile (== '_') #> reverse wenzelm@69225: \ wenzelm@69225: wenzelm@69444: generate_file "Isabelle/Value.hs" = \ wenzelm@69233: {- Title: Haskell/Tools/Value.hs wenzelm@69233: Author: Makarius wenzelm@69233: LICENSE: BSD 3-clause (Isabelle) wenzelm@69233: wenzelm@69233: Plain values, represented as string. wenzelm@69280: wenzelm@69280: See also \<^file>\$ISABELLE_HOME/src/Pure/General/value.ML\. wenzelm@69233: -} wenzelm@69233: wenzelm@69233: module Isabelle.Value wenzelm@69452: (print_bool, parse_bool, parse_nat, print_int, parse_int, print_real, parse_real) wenzelm@69233: where wenzelm@69233: wenzelm@69233: import Data.Maybe wenzelm@69233: import qualified Data.List as List wenzelm@69233: import qualified Text.Read as Read wenzelm@69233: wenzelm@69233: wenzelm@69233: {- bool -} wenzelm@69233: wenzelm@69233: print_bool :: Bool -> String wenzelm@69233: print_bool True = "true" wenzelm@69233: print_bool False = "false" wenzelm@69233: wenzelm@69233: parse_bool :: String -> Maybe Bool wenzelm@69233: parse_bool "true" = Just True wenzelm@69233: parse_bool "false" = Just False wenzelm@69233: parse_bool _ = Nothing wenzelm@69233: wenzelm@69233: wenzelm@69452: {- nat -} wenzelm@69452: wenzelm@69452: parse_nat :: String -> Maybe Int wenzelm@69452: parse_nat s = wenzelm@69452: case Read.readMaybe s of wenzelm@69452: Just n | n >= 0 -> Just n wenzelm@69452: _ -> Nothing wenzelm@69452: wenzelm@69452: wenzelm@69233: {- int -} wenzelm@69233: wenzelm@69233: print_int :: Int -> String wenzelm@69233: print_int = show wenzelm@69233: wenzelm@69233: parse_int :: String -> Maybe Int wenzelm@69233: parse_int = Read.readMaybe wenzelm@69233: wenzelm@69233: wenzelm@69233: {- real -} wenzelm@69233: wenzelm@69233: print_real :: Double -> String wenzelm@69233: print_real x = wenzelm@69233: let s = show x in wenzelm@69233: case span (/= '.') s of wenzelm@69233: (a, '.' : b) | List.all (== '0') b -> a wenzelm@69233: _ -> s wenzelm@69233: wenzelm@69233: parse_real :: String -> Maybe Double wenzelm@69233: parse_real = Read.readMaybe wenzelm@69233: \ wenzelm@69233: wenzelm@69444: generate_file "Isabelle/Buffer.hs" = \ wenzelm@69445: {- Title: Isabelle/Buffer.hs wenzelm@69225: Author: Makarius wenzelm@69225: LICENSE: BSD 3-clause (Isabelle) wenzelm@69225: wenzelm@69225: Efficient text buffers. wenzelm@69280: wenzelm@69280: See also \<^file>\$ISABELLE_HOME/src/Pure/General/buffer.ML\. wenzelm@69225: -} wenzelm@69222: wenzelm@69225: module Isabelle.Buffer (T, empty, add, content) wenzelm@69225: where wenzelm@69225: wenzelm@69474: import Isabelle.Library wenzelm@69474: wenzelm@69474: wenzelm@69474: newtype T = Buffer [Char] wenzelm@69225: wenzelm@69225: empty :: T wenzelm@69225: empty = Buffer [] wenzelm@69225: wenzelm@69225: add :: String -> T -> T wenzelm@69474: add s (Buffer cs) = Buffer (fold (:) s cs) wenzelm@69225: wenzelm@69225: content :: T -> String wenzelm@69474: content (Buffer cs) = reverse cs wenzelm@69225: \ wenzelm@69225: wenzelm@69444: generate_file "Isabelle/Properties.hs" = \ wenzelm@69445: {- Title: Isabelle/Properties.hs wenzelm@69225: Author: Makarius wenzelm@69225: LICENSE: BSD 3-clause (Isabelle) wenzelm@69225: wenzelm@69225: Property lists. wenzelm@69280: wenzelm@69280: See also \<^file>\$ISABELLE_HOME/src/Pure/General/properties.ML\. wenzelm@69225: -} wenzelm@69225: wenzelm@69477: module Isabelle.Properties (Entry, T, defined, get, get_value, put, remove) wenzelm@69225: where wenzelm@69225: wenzelm@69225: import qualified Data.List as List wenzelm@69225: wenzelm@69225: wenzelm@69225: type Entry = (String, String) wenzelm@69225: type T = [Entry] wenzelm@69225: wenzelm@69225: defined :: T -> String -> Bool wenzelm@69225: defined props name = any (\(a, _) -> a == name) props wenzelm@69225: wenzelm@69225: get :: T -> String -> Maybe String wenzelm@69225: get props name = List.lookup name props wenzelm@69225: wenzelm@69477: get_value :: (String -> Maybe a) -> T -> String -> Maybe a wenzelm@69477: get_value parse props name = wenzelm@69477: case get props name of wenzelm@69477: Nothing -> Nothing wenzelm@69477: Just s -> parse s wenzelm@69477: wenzelm@69225: put :: Entry -> T -> T wenzelm@69225: put entry props = entry : remove (fst entry) props wenzelm@69225: wenzelm@69225: remove :: String -> T -> T wenzelm@69225: remove name props = wenzelm@69225: if defined props name then filter (\(a, _) -> a /= name) props wenzelm@69225: else props wenzelm@69225: \ wenzelm@69225: wenzelm@69444: generate_file "Isabelle/Markup.hs" = \ wenzelm@69226: {- Title: Haskell/Tools/Markup.hs wenzelm@69225: Author: Makarius wenzelm@69225: LICENSE: BSD 3-clause (Isabelle) wenzelm@69225: wenzelm@69225: Quasi-abstract markup elements. wenzelm@69280: wenzelm@69280: See also \<^file>\$ISABELLE_HOME/src/Pure/PIDE/markup.ML\. wenzelm@69225: -} wenzelm@69225: wenzelm@69234: module Isabelle.Markup ( wenzelm@69234: T, empty, is_empty, properties, wenzelm@69234: wenzelm@69234: nameN, name, xnameN, xname, kindN, wenzelm@69234: wenzelm@69315: bindingN, binding, entityN, entity, defN, refN, wenzelm@69315: wenzelm@69288: completionN, completion, no_completionN, no_completion, wenzelm@69288: wenzelm@69234: lineN, end_lineN, offsetN, end_offsetN, fileN, idN, positionN, position, wenzelm@69234: wenzelm@69291: expressionN, expression, wenzelm@69291: wenzelm@69291: citationN, citation, wenzelm@69291: wenzelm@69291: pathN, urlN, docN, wenzelm@69291: wenzelm@69248: markupN, consistentN, unbreakableN, indentN, widthN, wenzelm@69248: blockN, block, breakN, break, fbreakN, fbreak, itemN, item, wenzelm@69248: wenzelm@69968: wordsN, words, wenzelm@69234: wenzelm@69234: tfreeN, tfree, tvarN, tvar, freeN, free, skolemN, skolem, boundN, bound, varN, var, wenzelm@69234: numeralN, numeral, literalN, literal, delimiterN, delimiter, inner_stringN, inner_string, wenzelm@69320: inner_cartoucheN, inner_cartouche, wenzelm@69234: token_rangeN, token_range, wenzelm@69234: sortingN, sorting, typingN, typing, class_parameterN, class_parameter, wenzelm@69234: wenzelm@69234: antiquotedN, antiquoted, antiquoteN, antiquote, wenzelm@69234: wenzelm@69234: paragraphN, paragraph, text_foldN, text_fold, wenzelm@69234: wenzelm@69234: keyword1N, keyword1, keyword2N, keyword2, keyword3N, keyword3, quasi_keywordN, quasi_keyword, wenzelm@69234: improperN, improper, operatorN, operator, stringN, string, alt_stringN, alt_string, wenzelm@69320: verbatimN, verbatim, cartoucheN, cartouche, commentN, comment, comment1N, comment1, wenzelm@69320: comment2N, comment2, comment3N, comment3, wenzelm@69234: wenzelm@69794: acceptedN, accepted, forkedN, forked, joinedN, joined, runningN, running, finishedN, finished, wenzelm@69794: failedN, failed, canceledN, canceled, initializedN, initialized, finalizedN, finalized, wenzelm@69794: consolidatedN, consolidated, wenzelm@69794: wenzelm@69234: writelnN, writeln, stateN, state, informationN, information, tracingN, tracing, wenzelm@69234: warningN, warning, legacyN, legacy, errorN, error, reportN, report, no_reportN, no_report, wenzelm@69234: wenzelm@69234: intensifyN, intensify, wenzelm@69234: Output, no_output) wenzelm@69225: where wenzelm@69225: wenzelm@69248: import Prelude hiding (words, error, break) wenzelm@69234: wenzelm@69234: import Isabelle.Library wenzelm@69225: import qualified Isabelle.Properties as Properties wenzelm@69248: import qualified Isabelle.Value as Value wenzelm@69225: wenzelm@69225: wenzelm@69234: {- basic markup -} wenzelm@69234: wenzelm@69225: type T = (String, Properties.T) wenzelm@69225: wenzelm@69225: empty :: T wenzelm@69225: empty = ("", []) wenzelm@69225: wenzelm@69225: is_empty :: T -> Bool wenzelm@69225: is_empty ("", _) = True wenzelm@69225: is_empty _ = False wenzelm@69225: wenzelm@69234: properties :: Properties.T -> T -> T wenzelm@69234: properties more_props (elem, props) = wenzelm@69234: (elem, fold_rev Properties.put more_props props) wenzelm@69234: wenzelm@69234: markup_elem name = (name, (name, []) :: T) wenzelm@69291: markup_string name prop = (name, \s -> (name, [(prop, s)]) :: T) wenzelm@69234: wenzelm@69234: wenzelm@69234: {- misc properties -} wenzelm@69234: wenzelm@69234: nameN :: String wenzelm@69234: nameN = \Markup.nameN\ wenzelm@69234: wenzelm@69234: name :: String -> T -> T wenzelm@69234: name a = properties [(nameN, a)] wenzelm@69234: wenzelm@69234: xnameN :: String wenzelm@69234: xnameN = \Markup.xnameN\ wenzelm@69234: wenzelm@69234: xname :: String -> T -> T wenzelm@69234: xname a = properties [(xnameN, a)] wenzelm@69234: wenzelm@69234: kindN :: String wenzelm@69234: kindN = \Markup.kindN\ wenzelm@69234: wenzelm@69234: wenzelm@69315: {- formal entities -} wenzelm@69315: wenzelm@69315: bindingN :: String; binding :: T wenzelm@69315: (bindingN, binding) = markup_elem \Markup.bindingN\ wenzelm@69315: wenzelm@69315: entityN :: String; entity :: String -> String -> T wenzelm@69315: entityN = \Markup.entityN\ wenzelm@69315: entity kind name = wenzelm@69315: (entityN, wenzelm@69315: (if null name then [] else [(nameN, name)]) ++ (if null kind then [] else [(kindN, kind)])) wenzelm@69315: wenzelm@69315: defN :: String wenzelm@69315: defN = \Markup.defN\ wenzelm@69315: wenzelm@69315: refN :: String wenzelm@69315: refN = \Markup.refN\ wenzelm@69315: wenzelm@69315: wenzelm@69288: {- completion -} wenzelm@69288: wenzelm@69288: completionN :: String; completion :: T wenzelm@69288: (completionN, completion) = markup_elem \Markup.completionN\ wenzelm@69288: wenzelm@69288: no_completionN :: String; no_completion :: T wenzelm@69288: (no_completionN, no_completion) = markup_elem \Markup.no_completionN\ wenzelm@69288: wenzelm@69288: wenzelm@69234: {- position -} wenzelm@69234: wenzelm@69234: lineN, end_lineN :: String wenzelm@69234: lineN = \Markup.lineN\ wenzelm@69234: end_lineN = \Markup.end_lineN\ wenzelm@69234: wenzelm@69234: offsetN, end_offsetN :: String wenzelm@69234: offsetN = \Markup.offsetN\ wenzelm@69234: end_offsetN = \Markup.end_offsetN\ wenzelm@69234: wenzelm@69234: fileN, idN :: String wenzelm@69234: fileN = \Markup.fileN\ wenzelm@69234: idN = \Markup.idN\ wenzelm@69234: wenzelm@69234: positionN :: String; position :: T wenzelm@69234: (positionN, position) = markup_elem \Markup.positionN\ wenzelm@69234: wenzelm@69234: wenzelm@69291: {- expression -} wenzelm@69291: wenzelm@69291: expressionN :: String wenzelm@69291: expressionN = \Markup.expressionN\ wenzelm@69291: wenzelm@69291: expression :: String -> T wenzelm@69291: expression kind = (expressionN, if kind == "" then [] else [(kindN, kind)]) wenzelm@69291: wenzelm@69291: wenzelm@69291: {- citation -} wenzelm@69291: wenzelm@69291: citationN :: String; citation :: String -> T wenzelm@69291: (citationN, citation) = markup_string \Markup.citationN\ nameN wenzelm@69291: wenzelm@69291: wenzelm@69291: {- external resources -} wenzelm@69291: wenzelm@69291: pathN :: String; path :: String -> T wenzelm@69291: (pathN, path) = markup_string \Markup.pathN\ nameN wenzelm@69291: wenzelm@69291: urlN :: String; url :: String -> T wenzelm@69291: (urlN, url) = markup_string \Markup.urlN\ nameN wenzelm@69291: wenzelm@69291: docN :: String; doc :: String -> T wenzelm@69291: (docN, doc) = markup_string \Markup.docN\ nameN wenzelm@69291: wenzelm@69291: wenzelm@69248: {- pretty printing -} wenzelm@69248: wenzelm@69248: markupN, consistentN, unbreakableN, indentN :: String wenzelm@69248: markupN = \Markup.markupN\; wenzelm@69248: consistentN = \Markup.consistentN\; wenzelm@69248: unbreakableN = \Markup.unbreakableN\; wenzelm@69248: indentN = \Markup.indentN\; wenzelm@69248: wenzelm@69248: widthN :: String wenzelm@69248: widthN = \Markup.widthN\ wenzelm@69248: wenzelm@69248: blockN :: String wenzelm@69248: blockN = \Markup.blockN\ wenzelm@69248: block :: Bool -> Int -> T wenzelm@69248: block c i = wenzelm@69248: (blockN, wenzelm@69248: (if c then [(consistentN, Value.print_bool c)] else []) ++ wenzelm@69248: (if i /= 0 then [(indentN, Value.print_int i)] else [])) wenzelm@69248: wenzelm@69248: breakN :: String wenzelm@69248: breakN = \Markup.breakN\ wenzelm@69248: break :: Int -> Int -> T wenzelm@69248: break w i = wenzelm@69248: (breakN, wenzelm@69248: (if w /= 0 then [(widthN, Value.print_int w)] else []) ++ wenzelm@69248: (if i /= 0 then [(indentN, Value.print_int i)] else [])) wenzelm@69248: wenzelm@69248: fbreakN :: String; fbreak :: T wenzelm@69248: (fbreakN, fbreak) = markup_elem \Markup.fbreakN\ wenzelm@69248: wenzelm@69248: itemN :: String; item :: T wenzelm@69248: (itemN, item) = markup_elem \Markup.itemN\ wenzelm@69248: wenzelm@69248: wenzelm@69234: {- text properties -} wenzelm@69234: wenzelm@69234: wordsN :: String; words :: T wenzelm@69234: (wordsN, words) = markup_elem \Markup.wordsN\ wenzelm@69234: wenzelm@69234: wenzelm@69234: {- inner syntax -} wenzelm@69234: wenzelm@69234: tfreeN :: String; tfree :: T wenzelm@69234: (tfreeN, tfree) = markup_elem \Markup.tfreeN\ wenzelm@69234: wenzelm@69234: tvarN :: String; tvar :: T wenzelm@69234: (tvarN, tvar) = markup_elem \Markup.tvarN\ wenzelm@69234: wenzelm@69234: freeN :: String; free :: T wenzelm@69234: (freeN, free) = markup_elem \Markup.freeN\ wenzelm@69234: wenzelm@69234: skolemN :: String; skolem :: T wenzelm@69234: (skolemN, skolem) = markup_elem \Markup.skolemN\ wenzelm@69234: wenzelm@69234: boundN :: String; bound :: T wenzelm@69234: (boundN, bound) = markup_elem \Markup.boundN\ wenzelm@69234: wenzelm@69234: varN :: String; var :: T wenzelm@69234: (varN, var) = markup_elem \Markup.varN\ wenzelm@69234: wenzelm@69234: numeralN :: String; numeral :: T wenzelm@69234: (numeralN, numeral) = markup_elem \Markup.numeralN\ wenzelm@69234: wenzelm@69234: literalN :: String; literal :: T wenzelm@69234: (literalN, literal) = markup_elem \Markup.literalN\ wenzelm@69234: wenzelm@69234: delimiterN :: String; delimiter :: T wenzelm@69234: (delimiterN, delimiter) = markup_elem \Markup.delimiterN\ wenzelm@69234: wenzelm@69234: inner_stringN :: String; inner_string :: T wenzelm@69234: (inner_stringN, inner_string) = markup_elem \Markup.inner_stringN\ wenzelm@69234: wenzelm@69234: inner_cartoucheN :: String; inner_cartouche :: T wenzelm@69234: (inner_cartoucheN, inner_cartouche) = markup_elem \Markup.inner_cartoucheN\ wenzelm@69234: wenzelm@69234: wenzelm@69234: token_rangeN :: String; token_range :: T wenzelm@69234: (token_rangeN, token_range) = markup_elem \Markup.token_rangeN\ wenzelm@69234: wenzelm@69234: wenzelm@69234: sortingN :: String; sorting :: T wenzelm@69234: (sortingN, sorting) = markup_elem \Markup.sortingN\ wenzelm@69234: wenzelm@69234: typingN :: String; typing :: T wenzelm@69234: (typingN, typing) = markup_elem \Markup.typingN\ wenzelm@69234: wenzelm@69234: class_parameterN :: String; class_parameter :: T wenzelm@69234: (class_parameterN, class_parameter) = markup_elem \Markup.class_parameterN\ wenzelm@69234: wenzelm@69234: wenzelm@69234: {- antiquotations -} wenzelm@69234: wenzelm@69234: antiquotedN :: String; antiquoted :: T wenzelm@69234: (antiquotedN, antiquoted) = markup_elem \Markup.antiquotedN\ wenzelm@69234: wenzelm@69234: antiquoteN :: String; antiquote :: T wenzelm@69234: (antiquoteN, antiquote) = markup_elem \Markup.antiquoteN\ wenzelm@69234: wenzelm@69234: wenzelm@69234: {- text structure -} wenzelm@69234: wenzelm@69234: paragraphN :: String; paragraph :: T wenzelm@69234: (paragraphN, paragraph) = markup_elem \Markup.paragraphN\ wenzelm@69234: wenzelm@69234: text_foldN :: String; text_fold :: T wenzelm@69234: (text_foldN, text_fold) = markup_elem \Markup.text_foldN\ wenzelm@69234: wenzelm@69234: wenzelm@69234: {- outer syntax -} wenzelm@69234: wenzelm@69234: keyword1N :: String; keyword1 :: T wenzelm@69234: (keyword1N, keyword1) = markup_elem \Markup.keyword1N\ wenzelm@69234: wenzelm@69234: keyword2N :: String; keyword2 :: T wenzelm@69234: (keyword2N, keyword2) = markup_elem \Markup.keyword2N\ wenzelm@69234: wenzelm@69234: keyword3N :: String; keyword3 :: T wenzelm@69234: (keyword3N, keyword3) = markup_elem \Markup.keyword3N\ wenzelm@69234: wenzelm@69234: quasi_keywordN :: String; quasi_keyword :: T wenzelm@69234: (quasi_keywordN, quasi_keyword) = markup_elem \Markup.quasi_keywordN\ wenzelm@69234: wenzelm@69234: improperN :: String; improper :: T wenzelm@69234: (improperN, improper) = markup_elem \Markup.improperN\ wenzelm@69234: wenzelm@69234: operatorN :: String; operator :: T wenzelm@69234: (operatorN, operator) = markup_elem \Markup.operatorN\ wenzelm@69234: wenzelm@69234: stringN :: String; string :: T wenzelm@69234: (stringN, string) = markup_elem \Markup.stringN\ wenzelm@69234: wenzelm@69234: alt_stringN :: String; alt_string :: T wenzelm@69234: (alt_stringN, alt_string) = markup_elem \Markup.alt_stringN\ wenzelm@69234: wenzelm@69234: verbatimN :: String; verbatim :: T wenzelm@69234: (verbatimN, verbatim) = markup_elem \Markup.verbatimN\ wenzelm@69234: wenzelm@69234: cartoucheN :: String; cartouche :: T wenzelm@69234: (cartoucheN, cartouche) = markup_elem \Markup.cartoucheN\ wenzelm@69234: wenzelm@69234: commentN :: String; comment :: T wenzelm@69234: (commentN, comment) = markup_elem \Markup.commentN\ wenzelm@69234: wenzelm@69234: wenzelm@69320: {- comments -} wenzelm@69320: wenzelm@69320: comment1N :: String; comment1 :: T wenzelm@69320: (comment1N, comment1) = markup_elem \Markup.comment1N\ wenzelm@69320: wenzelm@69320: comment2N :: String; comment2 :: T wenzelm@69320: (comment2N, comment2) = markup_elem \Markup.comment2N\ wenzelm@69320: wenzelm@69320: comment3N :: String; comment3 :: T wenzelm@69320: (comment3N, comment3) = markup_elem \Markup.comment3N\ wenzelm@69320: wenzelm@69320: wenzelm@69793: {- command status -} wenzelm@69793: wenzelm@69793: acceptedN, forkedN, joinedN, runningN, finishedN, failedN, canceledN, wenzelm@69793: initializedN, finalizedN, consolidatedN :: String wenzelm@69793: accepted, forked, joined, running, finished, failed, canceled, wenzelm@69793: initialized, finalized, consolidated :: T wenzelm@69793: (acceptedN, accepted) = markup_elem \Markup.acceptedN\ wenzelm@69793: (forkedN, forked) = markup_elem \Markup.forkedN\ wenzelm@69793: (joinedN, joined) = markup_elem \Markup.joinedN\ wenzelm@69793: (runningN, running) = markup_elem \Markup.runningN\ wenzelm@69793: (finishedN, finished) = markup_elem \Markup.finishedN\ wenzelm@69793: (failedN, failed) = markup_elem \Markup.failedN\ wenzelm@69793: (canceledN, canceled) = markup_elem \Markup.canceledN\ wenzelm@69793: (initializedN, initialized) = markup_elem \Markup.initializedN\ wenzelm@69793: (finalizedN, finalized) = markup_elem \Markup.finalizedN\ wenzelm@69793: (consolidatedN, consolidated) = markup_elem \Markup.consolidatedN\ wenzelm@69793: wenzelm@69793: wenzelm@69234: {- messages -} wenzelm@69234: wenzelm@69234: writelnN :: String; writeln :: T wenzelm@69234: (writelnN, writeln) = markup_elem \Markup.writelnN\ wenzelm@69234: wenzelm@69234: stateN :: String; state :: T wenzelm@69234: (stateN, state) = markup_elem \Markup.stateN\ wenzelm@69234: wenzelm@69234: informationN :: String; information :: T wenzelm@69234: (informationN, information) = markup_elem \Markup.informationN\ wenzelm@69234: wenzelm@69234: tracingN :: String; tracing :: T wenzelm@69234: (tracingN, tracing) = markup_elem \Markup.tracingN\ wenzelm@69234: wenzelm@69234: warningN :: String; warning :: T wenzelm@69234: (warningN, warning) = markup_elem \Markup.warningN\ wenzelm@69234: wenzelm@69234: legacyN :: String; legacy :: T wenzelm@69234: (legacyN, legacy) = markup_elem \Markup.legacyN\ wenzelm@69234: wenzelm@69234: errorN :: String; error :: T wenzelm@69234: (errorN, error) = markup_elem \Markup.errorN\ wenzelm@69234: wenzelm@69234: reportN :: String; report :: T wenzelm@69234: (reportN, report) = markup_elem \Markup.reportN\ wenzelm@69234: wenzelm@69234: no_reportN :: String; no_report :: T wenzelm@69234: (no_reportN, no_report) = markup_elem \Markup.no_reportN\ wenzelm@69234: wenzelm@69234: intensifyN :: String; intensify :: T wenzelm@69234: (intensifyN, intensify) = markup_elem \Markup.intensifyN\ wenzelm@69234: wenzelm@69234: wenzelm@69234: {- output -} wenzelm@69225: wenzelm@69225: type Output = (String, String) wenzelm@69225: wenzelm@69225: no_output :: Output wenzelm@69225: no_output = ("", "") wenzelm@69222: \ wenzelm@69222: wenzelm@69444: generate_file "Isabelle/Completion.hs" = \ wenzelm@69445: {- Title: Isabelle/Completion.hs wenzelm@69288: Author: Makarius wenzelm@69288: LICENSE: BSD 3-clause (Isabelle) wenzelm@69288: wenzelm@69288: Completion of names. wenzelm@69288: wenzelm@69288: See also \<^file>\$ISABELLE_HOME/src/Pure/General/completion.ML\. wenzelm@69288: -} wenzelm@69288: wenzelm@69289: module Isabelle.Completion ( wenzelm@69289: Name, T, names, none, make, markup_element, markup_report, make_report wenzelm@69289: ) where wenzelm@69288: wenzelm@69288: import qualified Data.List as List wenzelm@69288: wenzelm@69288: import Isabelle.Library wenzelm@69288: import qualified Isabelle.Properties as Properties wenzelm@69288: import qualified Isabelle.Markup as Markup wenzelm@69288: import qualified Isabelle.XML.Encode as Encode wenzelm@69288: import qualified Isabelle.XML as XML wenzelm@69288: import qualified Isabelle.YXML as YXML wenzelm@69288: wenzelm@69288: wenzelm@69288: type Name = (String, (String, String)) -- external name, kind, internal name wenzelm@69288: data T = Completion Properties.T Int [Name] -- position, total length, names wenzelm@69288: wenzelm@69288: names :: Int -> Properties.T -> [Name] -> T wenzelm@69288: names limit props names = Completion props (length names) (take limit names) wenzelm@69288: wenzelm@69288: none :: T wenzelm@69288: none = names 0 [] [] wenzelm@69288: wenzelm@69288: make :: Int -> (String, Properties.T) -> ((String -> Bool) -> [Name]) -> T wenzelm@69288: make limit (name, props) make_names = wenzelm@69288: if name /= "" && name /= "_" wenzelm@69288: then names limit props (make_names $ List.isPrefixOf $ clean_name name) wenzelm@69288: else none wenzelm@69288: wenzelm@69289: markup_element :: T -> (Markup.T, XML.Body) wenzelm@69289: markup_element (Completion props total names) = wenzelm@69289: if not (null names) then wenzelm@69289: let wenzelm@69289: markup = Markup.properties props Markup.completion wenzelm@69289: body = wenzelm@69289: Encode.pair Encode.int wenzelm@69289: (Encode.list (Encode.pair Encode.string (Encode.pair Encode.string Encode.string))) wenzelm@69289: (total, names) wenzelm@69289: in (markup, body) wenzelm@69289: else (Markup.empty, []) wenzelm@69288: wenzelm@69289: markup_report :: [T] -> String wenzelm@69289: markup_report [] = "" wenzelm@69289: markup_report elems = wenzelm@69290: YXML.string_of $ XML.Elem (Markup.report, map (XML.Elem . markup_element) elems) wenzelm@69289: wenzelm@69289: make_report :: Int -> (String, Properties.T) -> ((String -> Bool) -> [Name]) -> String wenzelm@69289: make_report limit name_props make_names = wenzelm@69289: markup_report [make limit name_props make_names] wenzelm@69288: \ wenzelm@69288: wenzelm@69444: generate_file "Isabelle/File.hs" = \ wenzelm@69445: {- Title: Isabelle/File.hs wenzelm@69278: Author: Makarius wenzelm@69278: LICENSE: BSD 3-clause (Isabelle) wenzelm@69278: wenzelm@69280: File-system operations. wenzelm@69280: wenzelm@69280: See also \<^file>\$ISABELLE_HOME/src/Pure/General/file.ML\. wenzelm@69278: -} wenzelm@69278: wenzelm@69278: module Isabelle.File (setup, read, write, append) where wenzelm@69278: wenzelm@69278: import Prelude hiding (read) wenzelm@69278: import System.IO (IO) wenzelm@69278: import qualified System.IO as IO wenzelm@69278: wenzelm@69278: setup :: IO.Handle -> IO () wenzelm@69278: setup h = do wenzelm@69278: IO.hSetEncoding h IO.utf8 wenzelm@69278: IO.hSetNewlineMode h IO.noNewlineTranslation wenzelm@69278: wenzelm@69278: read :: IO.FilePath -> IO String wenzelm@69278: read path = wenzelm@69278: IO.withFile path IO.ReadMode (\h -> wenzelm@69278: do setup h; IO.hGetContents h >>= \s -> length s `seq` return s) wenzelm@69278: wenzelm@69278: write :: IO.FilePath -> String -> IO () wenzelm@69278: write path s = wenzelm@69278: IO.withFile path IO.WriteMode (\h -> do setup h; IO.hPutStr h s) wenzelm@69278: wenzelm@69278: append :: IO.FilePath -> String -> IO () wenzelm@69278: append path s = wenzelm@69278: IO.withFile path IO.AppendMode (\h -> do setup h; IO.hPutStr h s) wenzelm@69278: \ wenzelm@69278: wenzelm@69444: generate_file "Isabelle/XML.hs" = \ wenzelm@69445: {- Title: Isabelle/XML.hs wenzelm@69225: Author: Makarius wenzelm@69225: LICENSE: BSD 3-clause (Isabelle) wenzelm@69225: wenzelm@69225: Untyped XML trees and representation of ML values. wenzelm@69280: wenzelm@69280: See also \<^file>\$ISABELLE_HOME/src/Pure/PIDE/xml.ML\. wenzelm@69225: -} wenzelm@69225: wenzelm@69225: module Isabelle.XML (Attributes, Body, Tree(..), wrap_elem, unwrap_elem, content_of) wenzelm@69225: where wenzelm@69225: wenzelm@69225: import qualified Data.List as List wenzelm@69225: wenzelm@69225: import Isabelle.Library wenzelm@69225: import qualified Isabelle.Properties as Properties wenzelm@69225: import qualified Isabelle.Markup as Markup wenzelm@69225: import qualified Isabelle.Buffer as Buffer wenzelm@69225: wenzelm@69225: wenzelm@69225: {- types -} wenzelm@69225: wenzelm@69225: type Attributes = Properties.T wenzelm@69225: type Body = [Tree] wenzelm@69290: data Tree = Elem (Markup.T, Body) | Text String wenzelm@69225: wenzelm@69225: wenzelm@69225: {- wrapped elements -} wenzelm@69225: wenzelm@69482: wrap_elem :: ((Markup.T, Body), [Tree]) -> Tree wenzelm@69236: wrap_elem (((a, atts), body1), body2) = wenzelm@69290: Elem ((\XML.xml_elemN\, (\XML.xml_nameN\, a) : atts), Elem ((\XML.xml_bodyN\, []), body1) : body2) wenzelm@69225: wenzelm@69482: unwrap_elem :: Tree -> Maybe ((Markup.T, Body), [Tree]) wenzelm@69236: unwrap_elem wenzelm@69290: (Elem ((\XML.xml_elemN\, (\XML.xml_nameN\, a) : atts), Elem ((\XML.xml_bodyN\, []), body1) : body2)) = wenzelm@69236: Just (((a, atts), body1), body2) wenzelm@69225: unwrap_elem _ = Nothing wenzelm@69225: wenzelm@69225: wenzelm@69225: {- text content -} wenzelm@69225: wenzelm@69482: add_content :: Tree -> Buffer.T -> Buffer.T wenzelm@69225: add_content tree = wenzelm@69225: case unwrap_elem tree of wenzelm@69225: Just (_, ts) -> fold add_content ts wenzelm@69225: Nothing -> wenzelm@69225: case tree of wenzelm@69290: Elem (_, ts) -> fold add_content ts wenzelm@69225: Text s -> Buffer.add s wenzelm@69225: wenzelm@69482: content_of :: Body -> String wenzelm@69225: content_of body = Buffer.empty |> fold add_content body |> Buffer.content wenzelm@69225: wenzelm@69225: wenzelm@69225: {- string representation -} wenzelm@69225: wenzelm@69225: encode '<' = "<" wenzelm@69225: encode '>' = ">" wenzelm@69225: encode '&' = "&" wenzelm@69225: encode '\'' = "'" wenzelm@69225: encode '\"' = """ wenzelm@69225: encode c = [c] wenzelm@69225: wenzelm@69225: instance Show Tree where wenzelm@69225: show tree = wenzelm@69225: Buffer.empty |> show_tree tree |> Buffer.content wenzelm@69225: where wenzelm@69290: show_tree (Elem ((name, atts), [])) = wenzelm@69225: Buffer.add "<" #> Buffer.add (show_elem name atts) #> Buffer.add "/>" wenzelm@69290: show_tree (Elem ((name, atts), ts)) = wenzelm@69225: Buffer.add "<" #> Buffer.add (show_elem name atts) #> Buffer.add ">" #> wenzelm@69225: fold show_tree ts #> wenzelm@69225: Buffer.add " Buffer.add name #> Buffer.add ">" wenzelm@69225: show_tree (Text s) = Buffer.add (show_text s) wenzelm@69225: wenzelm@69225: show_elem name atts = wenzelm@69225: unwords (name : map (\(a, x) -> a ++ "=\"" ++ show_text x ++ "\"") atts) wenzelm@69225: wenzelm@69225: show_text = concatMap encode wenzelm@69225: \ wenzelm@69225: wenzelm@69444: generate_file "Isabelle/XML/Encode.hs" = \ wenzelm@69445: {- Title: Isabelle/XML/Encode.hs wenzelm@69240: Author: Makarius wenzelm@69240: LICENSE: BSD 3-clause (Isabelle) wenzelm@69240: wenzelm@69240: XML as data representation language. wenzelm@69280: wenzelm@69280: See also \<^file>\$ISABELLE_HOME/src/Pure/PIDE/xml.ML\. wenzelm@69240: -} wenzelm@69240: wenzelm@69240: module Isabelle.XML.Encode ( wenzelm@69240: A, T, V, wenzelm@69240: wenzelm@69240: int_atom, bool_atom, unit_atom, wenzelm@69240: wenzelm@69287: tree, properties, string, int, bool, unit, pair, triple, list, variant wenzelm@69240: ) wenzelm@69240: where wenzelm@69240: wenzelm@69240: import Isabelle.Library wenzelm@69240: import qualified Isabelle.Value as Value wenzelm@69240: import qualified Isabelle.Properties as Properties wenzelm@69240: import qualified Isabelle.XML as XML wenzelm@69240: wenzelm@69240: wenzelm@69240: type A a = a -> String wenzelm@69240: type T a = a -> XML.Body wenzelm@69240: type V a = a -> Maybe ([String], XML.Body) wenzelm@69240: wenzelm@69240: wenzelm@69240: -- atomic values wenzelm@69240: wenzelm@69240: int_atom :: A Int wenzelm@69240: int_atom = Value.print_int wenzelm@69240: wenzelm@69240: bool_atom :: A Bool wenzelm@69240: bool_atom False = "0" wenzelm@69240: bool_atom True = "1" wenzelm@69240: wenzelm@69240: unit_atom :: A () wenzelm@69240: unit_atom () = "" wenzelm@69240: wenzelm@69240: wenzelm@69240: -- structural nodes wenzelm@69240: wenzelm@69290: node ts = XML.Elem ((":", []), ts) wenzelm@69240: wenzelm@69240: vector = map_index (\(i, x) -> (int_atom i, x)) wenzelm@69240: wenzelm@69290: tagged (tag, (xs, ts)) = XML.Elem ((int_atom tag, vector xs), ts) wenzelm@69240: wenzelm@69240: wenzelm@69240: -- representation of standard types wenzelm@69240: wenzelm@69240: tree :: T XML.Tree wenzelm@69240: tree t = [t] wenzelm@69240: wenzelm@69240: properties :: T Properties.T wenzelm@69290: properties props = [XML.Elem ((":", props), [])] wenzelm@69240: wenzelm@69240: string :: T String wenzelm@69240: string "" = [] wenzelm@69240: string s = [XML.Text s] wenzelm@69240: wenzelm@69240: int :: T Int wenzelm@69240: int = string . int_atom wenzelm@69240: wenzelm@69240: bool :: T Bool wenzelm@69240: bool = string . bool_atom wenzelm@69240: wenzelm@69240: unit :: T () wenzelm@69240: unit = string . unit_atom wenzelm@69240: wenzelm@69240: pair :: T a -> T b -> T (a, b) wenzelm@69240: pair f g (x, y) = [node (f x), node (g y)] wenzelm@69240: wenzelm@69240: triple :: T a -> T b -> T c -> T (a, b, c) wenzelm@69240: triple f g h (x, y, z) = [node (f x), node (g y), node (h z)] wenzelm@69240: wenzelm@69240: list :: T a -> T [a] wenzelm@69240: list f xs = map (node . f) xs wenzelm@69240: wenzelm@69240: variant :: [V a] -> T a wenzelm@69240: variant fs x = [tagged (the (get_index (\f -> f x) fs))] wenzelm@69240: \ wenzelm@69240: wenzelm@69444: generate_file "Isabelle/XML/Decode.hs" = \ wenzelm@69445: {- Title: Isabelle/XML/Decode.hs wenzelm@69240: Author: Makarius wenzelm@69240: LICENSE: BSD 3-clause (Isabelle) wenzelm@69240: wenzelm@69240: XML as data representation language. wenzelm@69280: wenzelm@69280: See also \<^file>\$ISABELLE_HOME/src/Pure/PIDE/xml.ML\. wenzelm@69240: -} wenzelm@69240: wenzelm@69240: module Isabelle.XML.Decode ( wenzelm@69240: A, T, V, wenzelm@69240: wenzelm@69240: int_atom, bool_atom, unit_atom, wenzelm@69240: wenzelm@69240: tree, properties, string, init, bool, unit, pair, triple, list, variant wenzelm@69240: ) wenzelm@69240: where wenzelm@69240: wenzelm@69240: import Data.List ((!!)) wenzelm@69240: wenzelm@69240: import Isabelle.Library wenzelm@69240: import qualified Isabelle.Value as Value wenzelm@69240: import qualified Isabelle.Properties as Properties wenzelm@69240: import qualified Isabelle.XML as XML wenzelm@69240: wenzelm@69240: wenzelm@69240: type A a = String -> a wenzelm@69240: type T a = XML.Body -> a wenzelm@69240: type V a = ([String], XML.Body) -> a wenzelm@69240: wenzelm@69240: err_atom = error "Malformed XML atom" wenzelm@69240: err_body = error "Malformed XML body" wenzelm@69240: wenzelm@69240: wenzelm@69240: {- atomic values -} wenzelm@69240: wenzelm@69240: int_atom :: A Int wenzelm@69240: int_atom s = wenzelm@69240: case Value.parse_int s of wenzelm@69240: Just i -> i wenzelm@69240: Nothing -> err_atom wenzelm@69240: wenzelm@69240: bool_atom :: A Bool wenzelm@69240: bool_atom "0" = False wenzelm@69240: bool_atom "1" = True wenzelm@69240: bool_atom _ = err_atom wenzelm@69240: wenzelm@69240: unit_atom :: A () wenzelm@69240: unit_atom "" = () wenzelm@69240: unit_atom _ = err_atom wenzelm@69240: wenzelm@69240: wenzelm@69240: {- structural nodes -} wenzelm@69240: wenzelm@69290: node (XML.Elem ((":", []), ts)) = ts wenzelm@69240: node _ = err_body wenzelm@69240: wenzelm@69240: vector atts = wenzelm@69240: map_index (\(i, (a, x)) -> if int_atom a == i then x else err_atom) atts wenzelm@69240: wenzelm@69290: tagged (XML.Elem ((name, atts), ts)) = (int_atom name, (vector atts, ts)) wenzelm@69240: tagged _ = err_body wenzelm@69240: wenzelm@69240: wenzelm@69240: {- representation of standard types -} wenzelm@69240: wenzelm@69240: tree :: T XML.Tree wenzelm@69240: tree [t] = t wenzelm@69240: tree _ = err_body wenzelm@69240: wenzelm@69240: properties :: T Properties.T wenzelm@69290: properties [XML.Elem ((":", props), [])] = props wenzelm@69240: properties _ = err_body wenzelm@69240: wenzelm@69240: string :: T String wenzelm@69240: string [] = "" wenzelm@69240: string [XML.Text s] = s wenzelm@69240: string _ = err_body wenzelm@69240: wenzelm@69240: int :: T Int wenzelm@69240: int = int_atom . string wenzelm@69240: wenzelm@69240: bool :: T Bool wenzelm@69240: bool = bool_atom . string wenzelm@69240: wenzelm@69240: unit :: T () wenzelm@69240: unit = unit_atom . string wenzelm@69240: wenzelm@69240: pair :: T a -> T b -> T (a, b) wenzelm@69240: pair f g [t1, t2] = (f (node t1), g (node t2)) wenzelm@69240: pair _ _ _ = err_body wenzelm@69240: wenzelm@69240: triple :: T a -> T b -> T c -> T (a, b, c) wenzelm@69240: triple f g h [t1, t2, t3] = (f (node t1), g (node t2), h (node t3)) wenzelm@69240: triple _ _ _ _ = err_body wenzelm@69240: wenzelm@69240: list :: T a -> T [a] wenzelm@69240: list f ts = map (f . node) ts wenzelm@69240: wenzelm@69240: option :: T a -> T (Maybe a) wenzelm@69240: option _ [] = Nothing wenzelm@69240: option f [t] = Just (f (node t)) wenzelm@69240: option _ _ = err_body wenzelm@69240: wenzelm@69240: variant :: [V a] -> T a wenzelm@69240: variant fs [t] = (fs !! tag) (xs, ts) wenzelm@69240: where (tag, (xs, ts)) = tagged t wenzelm@69240: variant _ _ = err_body wenzelm@69240: \ wenzelm@69240: wenzelm@69444: generate_file "Isabelle/YXML.hs" = \ wenzelm@69445: {- Title: Isabelle/YXML.hs wenzelm@69288: Author: Makarius wenzelm@69288: LICENSE: BSD 3-clause (Isabelle) wenzelm@69288: wenzelm@69288: Efficient text representation of XML trees. Suitable for direct wenzelm@69288: inlining into plain text. wenzelm@69288: wenzelm@69288: See also \<^file>\$ISABELLE_HOME/src/Pure/PIDE/yxml.ML\. wenzelm@69288: -} wenzelm@69288: wenzelm@69288: module Isabelle.YXML (charX, charY, strX, strY, detect, output_markup, wenzelm@69288: buffer_body, buffer, string_of_body, string_of, parse_body, parse) wenzelm@69288: where wenzelm@69288: wenzelm@69288: import qualified Data.Char as Char wenzelm@69288: import qualified Data.List as List wenzelm@69288: wenzelm@69288: import Isabelle.Library wenzelm@69288: import qualified Isabelle.Markup as Markup wenzelm@69288: import qualified Isabelle.XML as XML wenzelm@69288: import qualified Isabelle.Buffer as Buffer wenzelm@69288: wenzelm@69288: wenzelm@69288: {- markers -} wenzelm@69288: wenzelm@69288: charX, charY :: Char wenzelm@69288: charX = Char.chr 5 wenzelm@69288: charY = Char.chr 6 wenzelm@69288: wenzelm@69288: strX, strY, strXY, strXYX :: String wenzelm@69288: strX = [charX] wenzelm@69288: strY = [charY] wenzelm@69288: strXY = strX ++ strY wenzelm@69288: strXYX = strXY ++ strX wenzelm@69288: wenzelm@69288: detect :: String -> Bool wenzelm@69288: detect = any (\c -> c == charX || c == charY) wenzelm@69288: wenzelm@69288: wenzelm@69288: {- output -} wenzelm@69288: wenzelm@69288: output_markup :: Markup.T -> Markup.Output wenzelm@69288: output_markup markup@(name, atts) = wenzelm@69288: if Markup.is_empty markup then Markup.no_output wenzelm@69288: else (strXY ++ name ++ concatMap (\(a, x) -> strY ++ a ++ "=" ++ x) atts ++ strX, strXYX) wenzelm@69288: wenzelm@69288: buffer_attrib (a, x) = wenzelm@69288: Buffer.add strY #> Buffer.add a #> Buffer.add "=" #> Buffer.add x wenzelm@69288: wenzelm@69288: buffer_body :: XML.Body -> Buffer.T -> Buffer.T wenzelm@69288: buffer_body = fold buffer wenzelm@69288: wenzelm@69288: buffer :: XML.Tree -> Buffer.T -> Buffer.T wenzelm@69290: buffer (XML.Elem ((name, atts), ts)) = wenzelm@69288: Buffer.add strXY #> Buffer.add name #> fold buffer_attrib atts #> Buffer.add strX #> wenzelm@69288: buffer_body ts #> wenzelm@69288: Buffer.add strXYX wenzelm@69288: buffer (XML.Text s) = Buffer.add s wenzelm@69288: wenzelm@69288: string_of_body :: XML.Body -> String wenzelm@69288: string_of_body body = Buffer.empty |> buffer_body body |> Buffer.content wenzelm@69288: wenzelm@69288: string_of :: XML.Tree -> String wenzelm@69288: string_of = string_of_body . single wenzelm@69288: wenzelm@69288: wenzelm@69288: {- parse -} wenzelm@69288: wenzelm@69288: -- split: fields or non-empty tokens wenzelm@69288: wenzelm@69288: split :: Bool -> Char -> String -> [String] wenzelm@69288: split _ _ [] = [] wenzelm@69288: split fields sep str = splitting str wenzelm@69288: where wenzelm@69288: splitting rest = wenzelm@69288: case span (/= sep) rest of wenzelm@69288: (_, []) -> cons rest [] wenzelm@69288: (prfx, _ : rest') -> cons prfx (splitting rest') wenzelm@69288: cons item = if fields || not (null item) then (:) item else id wenzelm@69288: wenzelm@69288: wenzelm@69288: -- structural errors wenzelm@69288: wenzelm@69288: err msg = error ("Malformed YXML: " ++ msg) wenzelm@69288: err_attribute = err "bad attribute" wenzelm@69288: err_element = err "bad element" wenzelm@69288: err_unbalanced "" = err "unbalanced element" wenzelm@69288: err_unbalanced name = err ("unbalanced element " ++ quote name) wenzelm@69288: wenzelm@69288: wenzelm@69288: -- stack operations wenzelm@69288: wenzelm@69288: add x ((elem, body) : pending) = (elem, x : body) : pending wenzelm@69288: wenzelm@69288: push "" _ _ = err_element wenzelm@69288: push name atts pending = ((name, atts), []) : pending wenzelm@69288: wenzelm@69288: pop ((("", _), _) : _) = err_unbalanced "" wenzelm@69290: pop ((markup, body) : pending) = add (XML.Elem (markup, reverse body)) pending wenzelm@69288: wenzelm@69288: wenzelm@69288: -- parsing wenzelm@69288: wenzelm@69288: parse_attrib s = wenzelm@69288: case List.elemIndex '=' s of wenzelm@69288: Just i | i > 0 -> (take i s, drop (i + 1) s) wenzelm@69288: _ -> err_attribute wenzelm@69288: wenzelm@69288: parse_chunk ["", ""] = pop wenzelm@69288: parse_chunk ("" : name : atts) = push name (map parse_attrib atts) wenzelm@69288: parse_chunk txts = fold (add . XML.Text) txts wenzelm@69288: wenzelm@69288: parse_body :: String -> XML.Body wenzelm@69288: parse_body source = wenzelm@69288: case fold parse_chunk chunks [(("", []), [])] of wenzelm@69288: [(("", _), result)] -> reverse result wenzelm@69288: ((name, _), _) : _ -> err_unbalanced name wenzelm@69288: where chunks = split False charX source |> map (split True charY) wenzelm@69288: wenzelm@69288: parse :: String -> XML.Tree wenzelm@69288: parse source = wenzelm@69288: case parse_body source of wenzelm@69288: [result] -> result wenzelm@69288: [] -> XML.Text "" wenzelm@69288: _ -> err "multiple results" wenzelm@69288: \ wenzelm@69288: wenzelm@69444: generate_file "Isabelle/Pretty.hs" = \ wenzelm@69445: {- Title: Isabelle/Pretty.hs wenzelm@69248: Author: Makarius wenzelm@69248: LICENSE: BSD 3-clause (Isabelle) wenzelm@69248: wenzelm@69248: Generic pretty printing module. wenzelm@69280: wenzelm@69280: See also \<^file>\$ISABELLE_HOME/src/Pure/General/pretty.ML\. wenzelm@69248: -} wenzelm@69248: wenzelm@69248: module Isabelle.Pretty ( wenzelm@69248: T, symbolic, formatted, unformatted, wenzelm@69248: wenzelm@69248: str, brk_indent, brk, fbrk, breaks, fbreaks, blk, block, strs, markup, mark, mark_str, marks_str, wenzelm@69248: item, text_fold, keyword1, keyword2, text, paragraph, para, quote, cartouche, separate, wenzelm@69248: commas, enclose, enum, list, str_list, big_list) wenzelm@69248: where wenzelm@69248: wenzelm@69453: import Isabelle.Library hiding (quote, commas) wenzelm@69248: import qualified Data.List as List wenzelm@69248: import qualified Isabelle.Buffer as Buffer wenzelm@69248: import qualified Isabelle.Markup as Markup wenzelm@69248: import qualified Isabelle.XML as XML wenzelm@69248: import qualified Isabelle.YXML as YXML wenzelm@69248: wenzelm@69248: wenzelm@69248: data T = wenzelm@69248: Block Markup.T Bool Int [T] wenzelm@69248: | Break Int Int wenzelm@69248: | Str String wenzelm@69248: wenzelm@69248: wenzelm@69248: {- output -} wenzelm@69248: wenzelm@69248: output_spaces n = replicate n ' ' wenzelm@69248: wenzelm@69248: symbolic_text "" = [] wenzelm@69248: symbolic_text s = [XML.Text s] wenzelm@69248: wenzelm@69248: symbolic_markup markup body = wenzelm@69248: if Markup.is_empty markup then body wenzelm@69290: else [XML.Elem (markup, body)] wenzelm@69248: wenzelm@69248: symbolic :: T -> XML.Body wenzelm@69248: symbolic (Block markup consistent indent prts) = wenzelm@69248: concatMap symbolic prts wenzelm@69248: |> symbolic_markup block_markup wenzelm@69248: |> symbolic_markup markup wenzelm@69248: where block_markup = if null prts then Markup.empty else Markup.block consistent indent wenzelm@69290: symbolic (Break wd ind) = [XML.Elem (Markup.break wd ind, symbolic_text (output_spaces wd))] wenzelm@69248: symbolic (Str s) = symbolic_text s wenzelm@69248: wenzelm@69248: formatted :: T -> String wenzelm@69248: formatted = YXML.string_of_body . symbolic wenzelm@69248: wenzelm@69248: unformatted :: T -> String wenzelm@69248: unformatted prt = Buffer.empty |> out prt |> Buffer.content wenzelm@69248: where wenzelm@69248: out (Block markup _ _ prts) = wenzelm@69248: let (bg, en) = YXML.output_markup markup wenzelm@69248: in Buffer.add bg #> fold out prts #> Buffer.add en wenzelm@69248: out (Break _ wd) = Buffer.add (output_spaces wd) wenzelm@69248: out (Str s) = Buffer.add s wenzelm@69248: wenzelm@69248: wenzelm@69248: {- derived operations to create formatting expressions -} wenzelm@69248: wenzelm@69248: force_nat n | n < 0 = 0 wenzelm@69248: force_nat n = n wenzelm@69248: wenzelm@69248: str :: String -> T wenzelm@69248: str = Str wenzelm@69248: wenzelm@69248: brk_indent :: Int -> Int -> T wenzelm@69248: brk_indent wd ind = Break (force_nat wd) ind wenzelm@69248: wenzelm@69248: brk :: Int -> T wenzelm@69248: brk wd = brk_indent wd 0 wenzelm@69248: wenzelm@69248: fbrk :: T wenzelm@69248: fbrk = str "\n" wenzelm@69248: wenzelm@69248: breaks, fbreaks :: [T] -> [T] wenzelm@69248: breaks = List.intersperse (brk 1) wenzelm@69248: fbreaks = List.intersperse fbrk wenzelm@69248: wenzelm@69248: blk :: (Int, [T]) -> T wenzelm@69248: blk (indent, es) = Block Markup.empty False (force_nat indent) es wenzelm@69248: wenzelm@69248: block :: [T] -> T wenzelm@69248: block prts = blk (2, prts) wenzelm@69248: wenzelm@69248: strs :: [String] -> T wenzelm@69248: strs = block . breaks . map str wenzelm@69248: wenzelm@69248: markup :: Markup.T -> [T] -> T wenzelm@69248: markup m = Block m False 0 wenzelm@69248: wenzelm@69248: mark :: Markup.T -> T -> T wenzelm@69248: mark m prt = if m == Markup.empty then prt else markup m [prt] wenzelm@69248: wenzelm@69248: mark_str :: (Markup.T, String) -> T wenzelm@69248: mark_str (m, s) = mark m (str s) wenzelm@69248: wenzelm@69248: marks_str :: ([Markup.T], String) -> T wenzelm@69248: marks_str (ms, s) = fold_rev mark ms (str s) wenzelm@69248: wenzelm@69248: item :: [T] -> T wenzelm@69248: item = markup Markup.item wenzelm@69248: wenzelm@69248: text_fold :: [T] -> T wenzelm@69248: text_fold = markup Markup.text_fold wenzelm@69248: wenzelm@69248: keyword1, keyword2 :: String -> T wenzelm@69248: keyword1 name = mark_str (Markup.keyword1, name) wenzelm@69248: keyword2 name = mark_str (Markup.keyword2, name) wenzelm@69248: wenzelm@69248: text :: String -> [T] wenzelm@69248: text = breaks . map str . words wenzelm@69248: wenzelm@69248: paragraph :: [T] -> T wenzelm@69248: paragraph = markup Markup.paragraph wenzelm@69248: wenzelm@69248: para :: String -> T wenzelm@69248: para = paragraph . text wenzelm@69248: wenzelm@69248: quote :: T -> T wenzelm@69248: quote prt = blk (1, [str "\"", prt, str "\""]) wenzelm@69248: wenzelm@69248: cartouche :: T -> T wenzelm@69248: cartouche prt = blk (1, [str "\92", prt, str "\92"]) wenzelm@69248: wenzelm@69248: separate :: String -> [T] -> [T] wenzelm@69248: separate sep = List.intercalate [str sep, brk 1] . map single wenzelm@69248: wenzelm@69248: commas :: [T] -> [T] wenzelm@69248: commas = separate "," wenzelm@69248: wenzelm@69248: enclose :: String -> String -> [T] -> T wenzelm@69248: enclose lpar rpar prts = block (str lpar : prts ++ [str rpar]) wenzelm@69248: wenzelm@69248: enum :: String -> String -> String -> [T] -> T wenzelm@69248: enum sep lpar rpar = enclose lpar rpar . separate sep wenzelm@69248: wenzelm@69248: list :: String -> String -> [T] -> T wenzelm@69248: list = enum "," wenzelm@69248: wenzelm@69248: str_list :: String -> String -> [String] -> T wenzelm@69248: str_list lpar rpar = list lpar rpar . map str wenzelm@69248: wenzelm@69248: big_list :: String -> [T] -> T wenzelm@69248: big_list name prts = block (fbreaks (str name : prts)) wenzelm@69248: \ wenzelm@69248: wenzelm@69444: generate_file "Isabelle/Term.hs" = \ wenzelm@69445: {- Title: Isabelle/Term.hs wenzelm@69240: Author: Makarius wenzelm@69240: LICENSE: BSD 3-clause (Isabelle) wenzelm@69240: wenzelm@69240: Lambda terms, types, sorts. wenzelm@69280: wenzelm@69280: See also \<^file>\$ISABELLE_HOME/src/Pure/term.scala\. wenzelm@69240: -} wenzelm@69240: wenzelm@69240: module Isabelle.Term ( wenzelm@69240: Indexname, wenzelm@69240: wenzelm@69240: Sort, dummyS, wenzelm@69240: wenzelm@69240: Typ(..), dummyT, Term(..)) wenzelm@69240: where wenzelm@69240: wenzelm@69240: type Indexname = (String, Int) wenzelm@69240: wenzelm@69240: wenzelm@69240: type Sort = [String] wenzelm@69240: wenzelm@69240: dummyS :: Sort wenzelm@69240: dummyS = [""] wenzelm@69240: wenzelm@69240: wenzelm@69240: data Typ = wenzelm@69240: Type (String, [Typ]) wenzelm@69240: | TFree (String, Sort) wenzelm@69240: | TVar (Indexname, Sort) wenzelm@69240: deriving Show wenzelm@69240: wenzelm@69240: dummyT :: Typ wenzelm@69240: dummyT = Type (\\<^type_name>\dummy\\, []) wenzelm@69240: wenzelm@69240: wenzelm@69240: data Term = wenzelm@69240: Const (String, Typ) wenzelm@69240: | Free (String, Typ) wenzelm@69240: | Var (Indexname, Typ) wenzelm@69240: | Bound Int wenzelm@69240: | Abs (String, Typ, Term) wenzelm@69240: | App (Term, Term) wenzelm@69240: deriving Show wenzelm@69240: \ wenzelm@69240: wenzelm@69444: generate_file "Isabelle/Term_XML/Encode.hs" = \ wenzelm@69445: {- Title: Isabelle/Term_XML/Encode.hs wenzelm@69240: Author: Makarius wenzelm@69240: LICENSE: BSD 3-clause (Isabelle) wenzelm@69240: wenzelm@69240: XML data representation of lambda terms. wenzelm@69280: wenzelm@69280: See also \<^file>\$ISABELLE_HOME/src/Pure/term_xml.ML\. wenzelm@69240: -} wenzelm@69240: wenzelm@69240: {-# LANGUAGE LambdaCase #-} wenzelm@69240: wenzelm@69240: module Isabelle.Term_XML.Encode (sort, typ, term) wenzelm@69240: where wenzelm@69240: wenzelm@69240: import Isabelle.Library wenzelm@69240: import qualified Isabelle.XML as XML wenzelm@69240: import Isabelle.XML.Encode wenzelm@69240: import Isabelle.Term wenzelm@69240: wenzelm@69240: wenzelm@69240: sort :: T Sort wenzelm@69240: sort = list string wenzelm@69240: wenzelm@69240: typ :: T Typ wenzelm@69240: typ ty = wenzelm@69240: ty |> variant wenzelm@69240: [\case { Type (a, b) -> Just ([a], list typ b); _ -> Nothing }, wenzelm@69240: \case { TFree (a, b) -> Just ([a], sort b); _ -> Nothing }, wenzelm@69240: \case { TVar ((a, b), c) -> Just ([a, int_atom b], sort c); _ -> Nothing }] wenzelm@69240: wenzelm@69240: term :: T Term wenzelm@69240: term t = wenzelm@69240: t |> variant wenzelm@69240: [\case { Const (a, b) -> Just ([a], typ b); _ -> Nothing }, wenzelm@69240: \case { Free (a, b) -> Just ([a], typ b); _ -> Nothing }, wenzelm@69240: \case { Var ((a, b), c) -> Just ([a, int_atom b], typ c); _ -> Nothing }, wenzelm@69240: \case { Bound a -> Just ([int_atom a], []); _ -> Nothing }, wenzelm@69240: \case { Abs (a, b, c) -> Just ([a], pair typ term (b, c)); _ -> Nothing }, wenzelm@69240: \case { App a -> Just ([], pair term term a); _ -> Nothing }] wenzelm@69240: \ wenzelm@69240: wenzelm@69444: generate_file "Isabelle/Term_XML/Decode.hs" = \ wenzelm@69445: {- Title: Isabelle/Term_XML/Decode.hs wenzelm@69240: Author: Makarius wenzelm@69240: LICENSE: BSD 3-clause (Isabelle) wenzelm@69240: wenzelm@69240: XML data representation of lambda terms. wenzelm@69280: wenzelm@69280: See also \<^file>\$ISABELLE_HOME/src/Pure/term_xml.ML\. wenzelm@69240: -} wenzelm@69240: wenzelm@69240: module Isabelle.Term_XML.Decode (sort, typ, term) wenzelm@69240: where wenzelm@69240: wenzelm@69240: import Isabelle.Library wenzelm@69240: import qualified Isabelle.XML as XML wenzelm@69240: import Isabelle.XML.Decode wenzelm@69240: import Isabelle.Term wenzelm@69240: wenzelm@69240: wenzelm@69240: sort :: T Sort wenzelm@69240: sort = list string wenzelm@69240: wenzelm@69240: typ :: T Typ wenzelm@69240: typ ty = wenzelm@69240: ty |> variant wenzelm@69240: [\([a], b) -> Type (a, list typ b), wenzelm@69240: \([a], b) -> TFree (a, sort b), wenzelm@69240: \([a, b], c) -> TVar ((a, int_atom b), sort c)] wenzelm@69240: wenzelm@69240: term :: T Term wenzelm@69240: term t = wenzelm@69240: t |> variant wenzelm@69240: [\([a], b) -> Const (a, typ b), wenzelm@69240: \([a], b) -> Free (a, typ b), wenzelm@69240: \([a, b], c) -> Var ((a, int_atom b), typ c), wenzelm@69240: \([a], []) -> Bound (int_atom a), wenzelm@69240: \([a], b) -> let (c, d) = pair typ term b in Abs (a, c, d), wenzelm@69240: \([], a) -> App (pair term term a)] wenzelm@69240: \ wenzelm@69240: wenzelm@69459: generate_file "Isabelle/UUID.hs" = \ wenzelm@69459: {- Title: Isabelle/UUID.hs wenzelm@69459: Author: Makarius wenzelm@69459: LICENSE: BSD 3-clause (Isabelle) wenzelm@69459: wenzelm@69459: Universally unique identifiers. wenzelm@69459: wenzelm@69459: See \<^file>\$ISABELLE_HOME/src/Pure/General/uuid.scala\. wenzelm@69459: -} wenzelm@69459: wenzelm@69465: module Isabelle.UUID ( wenzelm@69465: T, wenzelm@69465: parse_string, parse_bytes, wenzelm@69465: string, bytes, wenzelm@69465: random, random_string, random_bytes wenzelm@69465: ) wenzelm@69459: where wenzelm@69459: wenzelm@69465: import Data.ByteString (ByteString) wenzelm@69465: import qualified Data.ByteString wenzelm@69459: import Data.UUID (UUID) wenzelm@69459: import qualified Data.UUID as UUID wenzelm@69459: import Data.UUID.V4 (nextRandom) wenzelm@69459: wenzelm@69459: wenzelm@69462: type T = UUID wenzelm@69462: wenzelm@69465: wenzelm@69465: {- parse -} wenzelm@69465: wenzelm@69465: parse_string :: String -> Maybe T wenzelm@69465: parse_string = UUID.fromString wenzelm@69465: wenzelm@69465: parse_bytes :: ByteString -> Maybe T wenzelm@69465: parse_bytes = UUID.fromASCIIBytes wenzelm@69465: wenzelm@69465: wenzelm@69465: {- print -} wenzelm@69465: wenzelm@69465: string :: T -> String wenzelm@69465: string = UUID.toString wenzelm@69465: wenzelm@69465: bytes :: T -> ByteString wenzelm@69465: bytes = UUID.toASCIIBytes wenzelm@69465: wenzelm@69465: wenzelm@69465: {- random id -} wenzelm@69465: wenzelm@69462: random :: IO T wenzelm@69459: random = nextRandom wenzelm@69459: wenzelm@69459: random_string :: IO String wenzelm@69465: random_string = string <$> random wenzelm@69459: wenzelm@69465: random_bytes :: IO ByteString wenzelm@69465: random_bytes = bytes <$> random wenzelm@69459: \ wenzelm@69459: wenzelm@69448: generate_file "Isabelle/Byte_Message.hs" = \ wenzelm@69448: {- Title: Isabelle/Byte_Message.hs wenzelm@69446: Author: Makarius wenzelm@69446: LICENSE: BSD 3-clause (Isabelle) wenzelm@69446: wenzelm@69448: Byte-oriented messages. wenzelm@69448: wenzelm@69448: See \<^file>\$ISABELLE_HOME/src/Pure/PIDE/byte_message.ML\ wenzelm@69448: and \<^file>\$ISABELLE_HOME/src/Pure/PIDE/byte_message.scala\. wenzelm@69446: -} wenzelm@69446: wenzelm@69452: module Isabelle.Byte_Message ( wenzelm@69467: write, write_line, wenzelm@69467: read, read_block, trim_line, read_line, wenzelm@69476: make_message, write_message, read_message, wenzelm@69476: make_line_message, write_line_message, read_line_message wenzelm@69452: ) wenzelm@69446: where wenzelm@69446: wenzelm@69449: import Prelude hiding (read) wenzelm@69454: import Data.Maybe wenzelm@69446: import Data.ByteString (ByteString) wenzelm@69446: import qualified Data.ByteString as ByteString wenzelm@69446: import qualified Data.ByteString.UTF8 as UTF8 wenzelm@69446: import Data.Word (Word8) wenzelm@69446: wenzelm@69448: import Control.Monad (when) wenzelm@69446: import Network.Socket (Socket) wenzelm@69446: import qualified Network.Socket as Socket wenzelm@69446: import qualified Network.Socket.ByteString as ByteString wenzelm@69446: wenzelm@69454: import Isabelle.Library hiding (trim_line) wenzelm@69446: import qualified Isabelle.Value as Value wenzelm@69446: wenzelm@69446: wenzelm@69452: {- output operations -} wenzelm@69452: wenzelm@69452: write :: Socket -> [ByteString] -> IO () wenzelm@69452: write = ByteString.sendMany wenzelm@69452: wenzelm@69452: newline :: ByteString wenzelm@69452: newline = ByteString.singleton 10 wenzelm@69452: wenzelm@69467: write_line :: Socket -> ByteString -> IO () wenzelm@69467: write_line socket s = write socket [s, newline] wenzelm@69467: wenzelm@69452: wenzelm@69452: {- input operations -} wenzelm@69452: wenzelm@69449: read :: Socket -> Int -> IO ByteString wenzelm@69452: read socket n = read_body 0 [] wenzelm@69449: where wenzelm@69449: result = ByteString.concat . reverse wenzelm@69452: read_body len ss = wenzelm@69449: if len >= n then return (result ss) wenzelm@69449: else wenzelm@69449: (do wenzelm@69449: s <- ByteString.recv socket (min (n - len) 8192) wenzelm@69449: case ByteString.length s of wenzelm@69449: 0 -> return (result ss) wenzelm@69452: m -> read_body (len + m) (s : ss)) wenzelm@69452: wenzelm@69452: read_block :: Socket -> Int -> IO (Maybe ByteString, Int) wenzelm@69452: read_block socket n = do wenzelm@69452: msg <- read socket n wenzelm@69452: let len = ByteString.length msg wenzelm@69452: return (if len == n then Just msg else Nothing, len) wenzelm@69449: wenzelm@69452: trim_line :: ByteString -> ByteString wenzelm@69452: trim_line s = wenzelm@69452: if n >= 2 && at (n - 2) == 13 && at (n - 1) == 10 then ByteString.take (n - 2) s wenzelm@69452: else if n >= 1 && (at (n - 1) == 13 || at (n - 1) == 10) then ByteString.take (n - 1) s wenzelm@69452: else s wenzelm@69452: where wenzelm@69452: n = ByteString.length s wenzelm@69452: at = ByteString.index s wenzelm@69449: wenzelm@69446: read_line :: Socket -> IO (Maybe ByteString) wenzelm@69452: read_line socket = read_body [] wenzelm@69446: where wenzelm@69452: result = trim_line . ByteString.pack . reverse wenzelm@69452: read_body bs = do wenzelm@69446: s <- ByteString.recv socket 1 wenzelm@69446: case ByteString.length s of wenzelm@69446: 0 -> return (if null bs then Nothing else Just (result bs)) wenzelm@69446: 1 -> wenzelm@69446: case ByteString.head s of wenzelm@69446: 10 -> return (Just (result bs)) wenzelm@69452: b -> read_body (b : bs) wenzelm@69446: wenzelm@69448: wenzelm@69454: {- messages with multiple chunks (arbitrary content) -} wenzelm@69454: wenzelm@69454: make_header :: [Int] -> [ByteString] wenzelm@69454: make_header ns = wenzelm@69454: [UTF8.fromString (space_implode "," (map Value.print_int ns)), newline] wenzelm@69454: wenzelm@69476: make_message :: [ByteString] -> [ByteString] wenzelm@69476: make_message chunks = make_header (map ByteString.length chunks) ++ chunks wenzelm@69476: wenzelm@69454: write_message :: Socket -> [ByteString] -> IO () wenzelm@69476: write_message socket = write socket . make_message wenzelm@69454: wenzelm@69454: parse_header :: ByteString -> [Int] wenzelm@69454: parse_header line = wenzelm@69454: let wenzelm@69454: res = map Value.parse_nat (space_explode ',' (UTF8.toString line)) wenzelm@69454: in wenzelm@69454: if all isJust res then map fromJust res wenzelm@69454: else error ("Malformed message header: " ++ quote (UTF8.toString line)) wenzelm@69454: wenzelm@69454: read_chunk :: Socket -> Int -> IO ByteString wenzelm@69454: read_chunk socket n = do wenzelm@69454: res <- read_block socket n wenzelm@69454: return $ wenzelm@69454: case res of wenzelm@69454: (Just chunk, _) -> chunk wenzelm@69454: (Nothing, len) -> wenzelm@69454: error ("Malformed message chunk: unexpected EOF after " ++ wenzelm@69454: show len ++ " of " ++ show n ++ " bytes") wenzelm@69454: wenzelm@69454: read_message :: Socket -> IO (Maybe [ByteString]) wenzelm@69454: read_message socket = do wenzelm@69454: res <- read_line socket wenzelm@69454: case res of wenzelm@69454: Just line -> Just <$> mapM (read_chunk socket) (parse_header line) wenzelm@69454: Nothing -> return Nothing wenzelm@69454: wenzelm@69454: wenzelm@69448: -- hybrid messages: line or length+block (with content restriction) wenzelm@69448: wenzelm@69448: is_length :: ByteString -> Bool wenzelm@69452: is_length msg = wenzelm@69452: not (ByteString.null msg) && ByteString.all (\b -> 48 <= b && b <= 57) msg wenzelm@69446: wenzelm@69452: is_terminated :: ByteString -> Bool wenzelm@69452: is_terminated msg = wenzelm@69452: not (ByteString.null msg) && (ByteString.last msg == 13 || ByteString.last msg == 10) wenzelm@69448: wenzelm@69476: make_line_message :: ByteString -> [ByteString] wenzelm@69476: make_line_message msg = wenzelm@69476: let n = ByteString.length msg in wenzelm@69476: if is_length msg || is_terminated msg then wenzelm@69476: error ("Bad content for line message:\n" ++ take 100 (UTF8.toString msg)) wenzelm@69476: else wenzelm@69476: (if n > 100 || ByteString.any (== 10) msg then make_header [n + 1] else []) ++ wenzelm@69476: [msg, newline] wenzelm@69448: wenzelm@69476: write_line_message :: Socket -> ByteString -> IO () wenzelm@69476: write_line_message socket = write socket . make_line_message wenzelm@69448: wenzelm@69448: read_line_message :: Socket -> IO (Maybe ByteString) wenzelm@69448: read_line_message socket = do wenzelm@69446: opt_line <- read_line socket wenzelm@69446: case opt_line of wenzelm@69446: Nothing -> return Nothing wenzelm@69446: Just line -> wenzelm@69452: case Value.parse_nat (UTF8.toString line) of wenzelm@69446: Nothing -> return $ Just line wenzelm@69452: Just n -> fmap trim_line . fst <$> read_block socket n wenzelm@69446: \ wenzelm@69446: wenzelm@69473: generate_file "Isabelle/Standard_Thread.hs" = \ wenzelm@69473: {- Title: Isabelle/Standard_Thread.hs wenzelm@69473: Author: Makarius wenzelm@69473: LICENSE: BSD 3-clause (Isabelle) wenzelm@69473: wenzelm@69473: Standard thread operations. wenzelm@69473: wenzelm@69473: See \<^file>\$ISABELLE_HOME/src/Pure/Concurrent/standard_thread.ML\ wenzelm@69473: and \<^file>\$ISABELLE_HOME/src/Pure/Concurrent/standard_thread.scala\. wenzelm@69473: -} wenzelm@69473: wenzelm@69473: {-# LANGUAGE NamedFieldPuns #-} wenzelm@69473: wenzelm@69473: module Isabelle.Standard_Thread ( wenzelm@69473: ThreadId, Result, wenzelm@69494: find_id, wenzelm@69473: properties, change_properties, wenzelm@69499: add_resource, del_resource, bracket_resource, wenzelm@69497: is_stopped, expose_stopped, stop, wenzelm@69496: my_uuid, stop_uuid, wenzelm@69494: Fork, fork_finally, fork) wenzelm@69473: where wenzelm@69473: wenzelm@69499: import Data.Unique wenzelm@69473: import Data.Maybe wenzelm@69473: import Data.IORef wenzelm@69473: import System.IO.Unsafe wenzelm@69473: wenzelm@69494: import qualified Data.List as List wenzelm@69497: import Control.Monad (when, forM_) wenzelm@69473: import Data.Map.Strict (Map) wenzelm@69473: import qualified Data.Map.Strict as Map wenzelm@69473: import Control.Exception.Base (SomeException) wenzelm@69473: import Control.Exception as Exception wenzelm@69473: import Control.Concurrent (ThreadId) wenzelm@69473: import qualified Control.Concurrent as Concurrent wenzelm@69473: import Control.Concurrent.Thread (Result) wenzelm@69473: import qualified Control.Concurrent.Thread as Thread wenzelm@69494: import qualified Isabelle.UUID as UUID wenzelm@69473: import qualified Isabelle.Properties as Properties wenzelm@69473: wenzelm@69473: wenzelm@69473: {- thread info -} wenzelm@69473: wenzelm@69499: type Resources = Map Unique (IO ()) wenzelm@69499: data Info = Info {uuid :: UUID.T, props :: Properties.T, stopped :: Bool, resources :: Resources} wenzelm@69473: type Infos = Map ThreadId Info wenzelm@69473: wenzelm@69473: lookup_info :: Infos -> ThreadId -> Maybe Info wenzelm@69494: lookup_info infos id = Map.lookup id infos wenzelm@69494: wenzelm@69494: init_info :: ThreadId -> UUID.T -> Infos -> (Infos, ()) wenzelm@69499: init_info id uuid infos = (Map.insert id (Info uuid [] False Map.empty) infos, ()) wenzelm@69473: wenzelm@69473: wenzelm@69473: {- global state -} wenzelm@69473: wenzelm@69473: {-# NOINLINE global_state #-} wenzelm@69473: global_state :: IORef Infos wenzelm@69473: global_state = unsafePerformIO (newIORef Map.empty) wenzelm@69473: wenzelm@69494: find_id :: UUID.T -> IO (Maybe ThreadId) wenzelm@69494: find_id uuid = do wenzelm@69494: state <- readIORef global_state wenzelm@69494: return $ fst <$> List.find (\(_, Info{uuid = uuid'}) -> uuid == uuid') (Map.assocs state) wenzelm@69494: wenzelm@69473: get_info :: ThreadId -> IO (Maybe Info) wenzelm@69473: get_info id = do wenzelm@69473: state <- readIORef global_state wenzelm@69473: return $ lookup_info state id wenzelm@69473: wenzelm@69499: map_info :: ThreadId -> (Info -> Info) -> IO (Maybe Info) wenzelm@69473: map_info id f = wenzelm@69473: atomicModifyIORef' global_state wenzelm@69473: (\infos -> wenzelm@69473: case lookup_info infos id of wenzelm@69499: Nothing -> (infos, Nothing) wenzelm@69499: Just info -> wenzelm@69499: let info' = f info wenzelm@69499: in (Map.insert id info' infos, Just info')) wenzelm@69473: wenzelm@69495: delete_info :: ThreadId -> IO () wenzelm@69495: delete_info id = wenzelm@69495: atomicModifyIORef' global_state (\infos -> (Map.delete id infos, ())) wenzelm@69495: wenzelm@69473: wenzelm@69473: {- thread properties -} wenzelm@69473: wenzelm@69498: my_info :: IO (Maybe Info) wenzelm@69473: my_info = do wenzelm@69473: id <- Concurrent.myThreadId wenzelm@69498: get_info id wenzelm@69473: wenzelm@69473: properties :: IO Properties.T wenzelm@69498: properties = maybe [] props <$> my_info wenzelm@69473: wenzelm@69473: change_properties :: (Properties.T -> Properties.T) -> IO () wenzelm@69473: change_properties f = do wenzelm@69473: id <- Concurrent.myThreadId wenzelm@69473: map_info id (\info -> info {props = f (props info)}) wenzelm@69499: return () wenzelm@69499: wenzelm@69499: wenzelm@69499: {- managed resources -} wenzelm@69499: wenzelm@69499: add_resource :: IO () -> IO Unique wenzelm@69499: add_resource resource = do wenzelm@69499: id <- Concurrent.myThreadId wenzelm@69499: u <- newUnique wenzelm@69499: map_info id (\info -> info {resources = Map.insert u resource (resources info)}) wenzelm@69499: return u wenzelm@69499: wenzelm@69499: del_resource :: Unique -> IO () wenzelm@69499: del_resource u = do wenzelm@69499: id <- Concurrent.myThreadId wenzelm@69499: map_info id (\info -> info {resources = Map.delete u (resources info)}) wenzelm@69499: return () wenzelm@69499: wenzelm@69499: bracket_resource :: IO () -> IO a -> IO a wenzelm@69499: bracket_resource resource body = wenzelm@69499: Exception.bracket (add_resource resource) del_resource (const body) wenzelm@69473: wenzelm@69473: wenzelm@69473: {- stop -} wenzelm@69473: wenzelm@69473: is_stopped :: IO Bool wenzelm@69498: is_stopped = maybe False stopped <$> my_info wenzelm@69473: wenzelm@69497: expose_stopped :: IO () wenzelm@69497: expose_stopped = do wenzelm@69497: stopped <- is_stopped wenzelm@69497: when stopped $ throw ThreadKilled wenzelm@69497: wenzelm@69473: stop :: ThreadId -> IO () wenzelm@69499: stop id = do wenzelm@69499: info <- map_info id (\info -> info {stopped = True}) wenzelm@69499: let ops = case info of Nothing -> []; Just Info{resources} -> map snd (Map.toDescList resources) wenzelm@69499: sequence_ ops wenzelm@69473: wenzelm@69473: wenzelm@69496: {- UUID -} wenzelm@69496: wenzelm@69498: my_uuid :: IO (Maybe UUID.T) wenzelm@69498: my_uuid = fmap uuid <$> my_info wenzelm@69496: wenzelm@69496: stop_uuid :: UUID.T -> IO () wenzelm@69496: stop_uuid uuid = do wenzelm@69496: id <- find_id uuid wenzelm@69496: forM_ id stop wenzelm@69496: wenzelm@69496: wenzelm@69473: {- fork -} wenzelm@69473: wenzelm@69494: type Fork a = (ThreadId, UUID.T, IO (Result a)) wenzelm@69494: wenzelm@69494: fork_finally :: IO a -> (Either SomeException a -> IO b) -> IO (Fork b) wenzelm@69473: fork_finally body finally = do wenzelm@69494: uuid <- UUID.random wenzelm@69473: (id, result) <- wenzelm@69473: Exception.mask (\restore -> wenzelm@69473: Thread.forkIO wenzelm@69473: (Exception.try wenzelm@69473: (do wenzelm@69473: id <- Concurrent.myThreadId wenzelm@69494: atomicModifyIORef' global_state (init_info id uuid) wenzelm@69495: restore body) wenzelm@69495: >>= (\res -> do id <- Concurrent.myThreadId; delete_info id; finally res))) wenzelm@69494: return (id, uuid, result) wenzelm@69494: wenzelm@69494: fork :: IO a -> IO (Fork a) wenzelm@69473: fork body = fork_finally body Thread.result wenzelm@69473: \ wenzelm@69473: wenzelm@69455: generate_file "Isabelle/Server.hs" = \ wenzelm@69455: {- Title: Isabelle/Server.hs wenzelm@69455: Author: Makarius wenzelm@69455: LICENSE: BSD 3-clause (Isabelle) wenzelm@69455: wenzelm@69455: TCP server on localhost. wenzelm@69455: -} wenzelm@69455: wenzelm@69465: module Isabelle.Server ( wenzelm@69465: localhost_name, localhost, publish_text, publish_stdout, wenzelm@69465: server wenzelm@69465: ) wenzelm@69465: where wenzelm@69455: wenzelm@69465: import Data.ByteString (ByteString) wenzelm@69465: import Control.Monad (forever, when) wenzelm@69455: import qualified Control.Exception as Exception wenzelm@69455: import Network.Socket (Socket) wenzelm@69455: import qualified Network.Socket as Socket wenzelm@69472: import qualified System.IO as IO wenzelm@69455: wenzelm@69462: import Isabelle.Library wenzelm@69462: import qualified Isabelle.UUID as UUID wenzelm@69465: import qualified Isabelle.Byte_Message as Byte_Message wenzelm@69473: import qualified Isabelle.Standard_Thread as Standard_Thread wenzelm@69462: wenzelm@69462: wenzelm@69462: {- server address -} wenzelm@69455: wenzelm@69463: localhost_name :: String wenzelm@69463: localhost_name = "127.0.0.1" wenzelm@69463: wenzelm@69455: localhost :: Socket.HostAddress wenzelm@69455: localhost = Socket.tupleToHostAddress (127, 0, 0, 1) wenzelm@69455: wenzelm@69462: publish_text :: String -> String -> UUID.T -> String wenzelm@69462: publish_text name address password = wenzelm@69462: "server " ++ quote name ++ " = " ++ address ++ " (password " ++ quote (show password) ++ ")" wenzelm@69462: wenzelm@69462: publish_stdout :: String -> String -> UUID.T -> IO () wenzelm@69462: publish_stdout name address password = putStrLn (publish_text name address password) wenzelm@69462: wenzelm@69462: wenzelm@69462: {- server -} wenzelm@69462: wenzelm@69462: server :: (String -> UUID.T -> IO ()) -> (Socket -> IO ()) -> IO () wenzelm@69455: server publish handle = wenzelm@69462: Socket.withSocketsDo $ Exception.bracket open (Socket.close . fst) (uncurry loop) wenzelm@69455: where wenzelm@69465: open :: IO (Socket, ByteString) wenzelm@69455: open = do wenzelm@69466: server_socket <- Socket.socket Socket.AF_INET Socket.Stream Socket.defaultProtocol wenzelm@69466: Socket.bind server_socket (Socket.SockAddrInet 0 localhost) wenzelm@69466: Socket.listen server_socket 50 wenzelm@69462: wenzelm@69466: port <- Socket.socketPort server_socket wenzelm@69462: let address = localhost_name ++ ":" ++ show port wenzelm@69462: password <- UUID.random wenzelm@69462: publish address password wenzelm@69455: wenzelm@69466: return (server_socket, UUID.bytes password) wenzelm@69462: wenzelm@69465: loop :: Socket -> ByteString -> IO () wenzelm@69466: loop server_socket password = forever $ do wenzelm@69480: (connection, _) <- Socket.accept server_socket wenzelm@69473: Standard_Thread.fork_finally wenzelm@69465: (do wenzelm@69465: line <- Byte_Message.read_line connection wenzelm@69465: when (line == Just password) $ handle connection) wenzelm@69473: (\finally -> do wenzelm@69472: Socket.close connection wenzelm@69473: case finally of wenzelm@69472: Left exn -> IO.hPutStrLn IO.stderr $ Exception.displayException exn wenzelm@69472: Right () -> return ()) wenzelm@69455: return () wenzelm@69455: \ wenzelm@69455: wenzelm@69662: export_generated_files wenzelm@69628: wenzelm@69222: end