mirror of
https://github.com/anoma/juvix.git
synced 2024-09-11 08:15:41 +03:00
Support extract-module-statements
attribute in juvix code blocks (#2734)
This PR adds support for the `extract-module-statements` attribute for Juvix code blocks: So if you write something like the following block in a Juvix markdown file: ```` ```juvix extract-module-statements module Foo; type T := t; end; ``` ```` The statement `type T := t;` from the body of the module is rendered in the output. The `module Foo;` , and `end;` lines are not rendered in the output. A block with the `extract-module-statements` must contain a single local module statement and nothing else. An error is reported if this is not the case. The `extract-module-statements` attribute also takes an optional argument. It sets the number of statements from the module body to drop from the output. In the following example, the output will contain the single line `a : T := t;`. ```` ```juvix extract-module-statements 1 module Foo; type T := t; a : T := t; end; ``` ```` --------- Co-authored-by: Jan Mas Rovira <janmasrovira@gmail.com>
This commit is contained in:
parent
75b5228258
commit
52a3eed162
@ -0,0 +1,66 @@
|
|||||||
|
module Juvix.Compiler.Backend.Markdown.Data.MkJuvixBlockOptions where
|
||||||
|
|
||||||
|
import Juvix.Parser.Error.Base
|
||||||
|
import Juvix.Prelude.Base
|
||||||
|
import Juvix.Prelude.Parsing hiding (runParser)
|
||||||
|
import Juvix.Prelude.Path
|
||||||
|
import Text.Megaparsec qualified as P
|
||||||
|
import Text.Megaparsec.Char.Lexer qualified as L
|
||||||
|
|
||||||
|
data MkJuvixBlockOptions
|
||||||
|
= MkJuvixBlockOptionsHide
|
||||||
|
| MkJuvixBlockOptionsShow
|
||||||
|
| MkJuvixBlockOptionsExtractModule JuvixBlockOptionsExtractModule
|
||||||
|
deriving stock (Eq, Show)
|
||||||
|
|
||||||
|
newtype JuvixBlockOptionsExtractModule = JuvixBlockOptionsExtractModule
|
||||||
|
{ _juvixBlockOptionsExtractModuleDrop :: Int
|
||||||
|
}
|
||||||
|
deriving stock (Eq, Show)
|
||||||
|
|
||||||
|
makeLenses ''JuvixBlockOptionsExtractModule
|
||||||
|
|
||||||
|
optionExtractModuleStatements :: (IsString s) => s
|
||||||
|
optionExtractModuleStatements = "extract-module-statements"
|
||||||
|
|
||||||
|
optionHide :: (IsString s) => s
|
||||||
|
optionHide = "hide"
|
||||||
|
|
||||||
|
parseJuvixBlockOptions :: Path Abs File -> Text -> Either MegaparsecError MkJuvixBlockOptions
|
||||||
|
parseJuvixBlockOptions p = mapLeft MegaparsecError . P.runParser parseOptions (toFilePath p)
|
||||||
|
|
||||||
|
type Parser = P.Parsec Void Text
|
||||||
|
|
||||||
|
spaceConsumer :: Parser ()
|
||||||
|
spaceConsumer = L.space space1 empty empty
|
||||||
|
|
||||||
|
lexeme :: Parser a -> Parser a
|
||||||
|
lexeme = L.lexeme spaceConsumer
|
||||||
|
|
||||||
|
symbol :: Text -> Parser ()
|
||||||
|
symbol = void . L.symbol spaceConsumer
|
||||||
|
|
||||||
|
decimal :: Parser Int
|
||||||
|
decimal = lexeme L.decimal
|
||||||
|
|
||||||
|
parseOptions :: Parser MkJuvixBlockOptions
|
||||||
|
parseOptions = do
|
||||||
|
spaceConsumer
|
||||||
|
opts <-
|
||||||
|
parseHide
|
||||||
|
<|> parseExtractModule
|
||||||
|
<|> parseShow
|
||||||
|
eof
|
||||||
|
return opts
|
||||||
|
|
||||||
|
parseShow :: Parser MkJuvixBlockOptions
|
||||||
|
parseShow = return MkJuvixBlockOptionsShow
|
||||||
|
|
||||||
|
parseHide :: Parser MkJuvixBlockOptions
|
||||||
|
parseHide = symbol optionHide $> MkJuvixBlockOptionsHide
|
||||||
|
|
||||||
|
parseExtractModule :: Parser MkJuvixBlockOptions
|
||||||
|
parseExtractModule = do
|
||||||
|
symbol optionExtractModuleStatements
|
||||||
|
dropNum <- fromMaybe 0 <$> optional decimal
|
||||||
|
return (MkJuvixBlockOptionsExtractModule (JuvixBlockOptionsExtractModule dropNum))
|
@ -1,20 +1,20 @@
|
|||||||
module Juvix.Compiler.Backend.Markdown.Data.Types where
|
module Juvix.Compiler.Backend.Markdown.Data.Types
|
||||||
|
( module Juvix.Compiler.Backend.Markdown.Data.Types,
|
||||||
|
module Juvix.Compiler.Backend.Markdown.Data.MkJuvixBlockOptions,
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
import Commonmark qualified as MK
|
import Commonmark qualified as MK
|
||||||
import Data.Text qualified as T
|
import Data.Text qualified as T
|
||||||
|
import Juvix.Compiler.Backend.Markdown.Data.MkJuvixBlockOptions
|
||||||
import Juvix.Data.Loc
|
import Juvix.Data.Loc
|
||||||
import Juvix.Prelude hiding (Raw)
|
import Juvix.Prelude hiding (Raw)
|
||||||
import Juvix.Prelude.Pretty
|
import Juvix.Prelude.Pretty
|
||||||
import Text.Show qualified as Show
|
import Text.Show qualified as Show
|
||||||
|
|
||||||
newtype MkJuvixBlockOptions = MkJuvixBlockOptions
|
|
||||||
{ _mkJuvixBlockOptionsHide :: Bool
|
|
||||||
}
|
|
||||||
deriving stock (Eq, Ord)
|
|
||||||
|
|
||||||
data JuvixCodeBlock = JuvixCodeBlock
|
data JuvixCodeBlock = JuvixCodeBlock
|
||||||
{ _juvixCodeBlock :: Text,
|
{ _juvixCodeBlock :: Text,
|
||||||
_juvixCodeBlockOptions :: MkJuvixBlockOptions,
|
_juvixCodeBlockOptions :: Text,
|
||||||
_juvixCodeBlockInterval :: Maybe Interval
|
_juvixCodeBlockInterval :: Maybe Interval
|
||||||
}
|
}
|
||||||
deriving stock (Eq, Ord)
|
deriving stock (Eq, Ord)
|
||||||
@ -26,33 +26,16 @@ data TextBlock = TextBlock
|
|||||||
deriving stock (Eq, Ord)
|
deriving stock (Eq, Ord)
|
||||||
|
|
||||||
makeLenses ''JuvixCodeBlock
|
makeLenses ''JuvixCodeBlock
|
||||||
makeLenses ''MkJuvixBlockOptions
|
|
||||||
makeLenses ''TextBlock
|
makeLenses ''TextBlock
|
||||||
|
|
||||||
defaultMkJuvixBlockOptions :: MkJuvixBlockOptions
|
|
||||||
defaultMkJuvixBlockOptions =
|
|
||||||
MkJuvixBlockOptions
|
|
||||||
{ _mkJuvixBlockOptionsHide = False
|
|
||||||
}
|
|
||||||
|
|
||||||
instance Show TextBlock where
|
instance Show TextBlock where
|
||||||
show t = T.unpack (t ^. textBlock)
|
show t = T.unpack (t ^. textBlock)
|
||||||
|
|
||||||
textJuvixBlockOptions :: MkJuvixBlockOptions -> Text
|
|
||||||
textJuvixBlockOptions opt =
|
|
||||||
T.intercalate " " $
|
|
||||||
catMaybes
|
|
||||||
[ if opt ^. mkJuvixBlockOptionsHide then Just "hide" else Nothing
|
|
||||||
]
|
|
||||||
|
|
||||||
instance Show MkJuvixBlockOptions where
|
|
||||||
show opt = T.unpack (textJuvixBlockOptions opt)
|
|
||||||
|
|
||||||
textJuvixCodeBlock :: JuvixCodeBlock -> Text
|
textJuvixCodeBlock :: JuvixCodeBlock -> Text
|
||||||
textJuvixCodeBlock cb =
|
textJuvixCodeBlock cb =
|
||||||
mconcat
|
mconcat
|
||||||
[ "```juvix",
|
[ "```juvix",
|
||||||
textJuvixBlockOptions (cb ^. juvixCodeBlockOptions),
|
cb ^. juvixCodeBlockOptions,
|
||||||
nl,
|
nl,
|
||||||
cb ^. juvixCodeBlock,
|
cb ^. juvixCodeBlock,
|
||||||
"```"
|
"```"
|
||||||
@ -83,19 +66,6 @@ instance Monoid TextBlock where
|
|||||||
}
|
}
|
||||||
mappend = (<>)
|
mappend = (<>)
|
||||||
|
|
||||||
instance Semigroup MkJuvixBlockOptions where
|
|
||||||
a <> b =
|
|
||||||
MkJuvixBlockOptions
|
|
||||||
{ _mkJuvixBlockOptionsHide = a ^. mkJuvixBlockOptionsHide || b ^. mkJuvixBlockOptionsHide
|
|
||||||
}
|
|
||||||
|
|
||||||
instance Monoid MkJuvixBlockOptions where
|
|
||||||
mempty =
|
|
||||||
MkJuvixBlockOptions
|
|
||||||
{ _mkJuvixBlockOptionsHide = False
|
|
||||||
}
|
|
||||||
mappend = (<>)
|
|
||||||
|
|
||||||
instance Semigroup Mk where
|
instance Semigroup Mk where
|
||||||
a <> MkNull = a
|
a <> MkNull = a
|
||||||
MkNull <> a = a
|
MkNull <> a = a
|
||||||
@ -190,25 +160,20 @@ instance MK.IsInline TextBlock where
|
|||||||
toTextBlock t
|
toTextBlock t
|
||||||
| otherwise = mempty
|
| otherwise = mempty
|
||||||
|
|
||||||
getJuvixBlockOptions :: Text -> MkJuvixBlockOptions
|
|
||||||
getJuvixBlockOptions = \case
|
|
||||||
"hide" -> mempty {_mkJuvixBlockOptionsHide = True}
|
|
||||||
_ -> mempty
|
|
||||||
|
|
||||||
nl' :: Mk
|
nl' :: Mk
|
||||||
nl' = toMK nl
|
nl' = toMK nl
|
||||||
|
|
||||||
processCodeBlock :: Text -> Text -> Maybe Interval -> Mk
|
processCodeBlock :: Text -> Text -> Maybe Interval -> Mk
|
||||||
processCodeBlock info t loc =
|
processCodeBlock info t loc =
|
||||||
case T.splitOn " " (T.strip info) of
|
case T.stripPrefix "juvix" (T.strip info) of
|
||||||
("juvix" : opts) ->
|
Just opts ->
|
||||||
MkJuvixCodeBlock
|
MkJuvixCodeBlock
|
||||||
JuvixCodeBlock
|
JuvixCodeBlock
|
||||||
{ _juvixCodeBlock = t,
|
{ _juvixCodeBlock = t,
|
||||||
_juvixCodeBlockOptions = foldMap getJuvixBlockOptions opts,
|
_juvixCodeBlockOptions = opts,
|
||||||
_juvixCodeBlockInterval = loc
|
_juvixCodeBlockInterval = loc
|
||||||
}
|
}
|
||||||
_ ->
|
Nothing ->
|
||||||
let b = "```" <> info <> t <> "```"
|
let b = "```" <> info <> t <> "```"
|
||||||
in MkTextBlock TextBlock {_textBlock = b, _textBlockInterval = loc}
|
in MkTextBlock TextBlock {_textBlock = b, _textBlockInterval = loc}
|
||||||
|
|
||||||
|
@ -1,18 +1,24 @@
|
|||||||
module Juvix.Compiler.Backend.Markdown.Error where
|
module Juvix.Compiler.Backend.Markdown.Error where
|
||||||
|
|
||||||
|
import Juvix.Compiler.Backend.Markdown.Data.Types
|
||||||
import Juvix.Compiler.Concrete.Language
|
import Juvix.Compiler.Concrete.Language
|
||||||
import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.Scoping.Error.Pretty
|
import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.Scoping.Error.Pretty
|
||||||
|
import Juvix.Parser.Error.Base
|
||||||
import Juvix.Prelude
|
import Juvix.Prelude
|
||||||
|
|
||||||
data MarkdownBackendError
|
data MarkdownBackendError
|
||||||
= ErrInternalNoMarkdownInfo NoMarkdownInfoError
|
= ErrInternalNoMarkdownInfo NoMarkdownInfoError
|
||||||
| ErrNoJuvixCodeBlocks NoJuvixCodeBlocksError
|
| ErrNoJuvixCodeBlocks NoJuvixCodeBlocksError
|
||||||
|
| ErrInvalidExtractModuleBlock InvalidExtractModuleBlockError
|
||||||
|
| ErrInvalidCodeBlockAttribtues InvalidCodeBlockAttributesError
|
||||||
deriving stock (Show)
|
deriving stock (Show)
|
||||||
|
|
||||||
instance ToGenericError MarkdownBackendError where
|
instance ToGenericError MarkdownBackendError where
|
||||||
genericError = \case
|
genericError = \case
|
||||||
ErrInternalNoMarkdownInfo e -> genericError e
|
ErrInternalNoMarkdownInfo e -> genericError e
|
||||||
ErrNoJuvixCodeBlocks e -> genericError e
|
ErrNoJuvixCodeBlocks e -> genericError e
|
||||||
|
ErrInvalidExtractModuleBlock e -> genericError e
|
||||||
|
ErrInvalidCodeBlockAttribtues e -> genericError e
|
||||||
|
|
||||||
newtype NoMarkdownInfoError = NoMarkdownInfoError
|
newtype NoMarkdownInfoError = NoMarkdownInfoError
|
||||||
{ _noMarkdownInfoFilepath :: Path Abs File
|
{ _noMarkdownInfoFilepath :: Path Abs File
|
||||||
@ -49,3 +55,35 @@ instance ToGenericError NoJuvixCodeBlocksError where
|
|||||||
where
|
where
|
||||||
i :: Interval
|
i :: Interval
|
||||||
i = singletonInterval . mkInitialLoc $ _noJuvixCodeBlocksErrorFilepath
|
i = singletonInterval . mkInitialLoc $ _noJuvixCodeBlocksErrorFilepath
|
||||||
|
|
||||||
|
data InvalidExtractModuleBlockError = InvalidExtractModuleBlockError
|
||||||
|
{ _invalidExtractModuleBlockErrorInterval :: Maybe Interval,
|
||||||
|
_invalidExtractModuleBlockErrorPath :: Path Abs File
|
||||||
|
}
|
||||||
|
deriving stock (Show)
|
||||||
|
|
||||||
|
instance ToGenericError InvalidExtractModuleBlockError where
|
||||||
|
genericError InvalidExtractModuleBlockError {..} = do
|
||||||
|
let msg :: Doc Ann
|
||||||
|
msg = "Juvix code blocks with attribute" <+> optionExtractModuleStatements <+> "must contain a single local module"
|
||||||
|
return
|
||||||
|
GenericError
|
||||||
|
{ _genericErrorLoc = i,
|
||||||
|
_genericErrorMessage = prettyError msg,
|
||||||
|
_genericErrorIntervals = [i]
|
||||||
|
}
|
||||||
|
where
|
||||||
|
i :: Interval
|
||||||
|
i =
|
||||||
|
fromMaybe
|
||||||
|
(singletonInterval (mkInitialLoc (_invalidExtractModuleBlockErrorPath)))
|
||||||
|
_invalidExtractModuleBlockErrorInterval
|
||||||
|
|
||||||
|
newtype InvalidCodeBlockAttributesError = InvalidCodeBlockAttributesError
|
||||||
|
{ _invalidCodeBlockAttributesErrorMegaparsecError :: MegaparsecError
|
||||||
|
}
|
||||||
|
deriving stock (Show)
|
||||||
|
|
||||||
|
instance ToGenericError InvalidCodeBlockAttributesError where
|
||||||
|
genericError InvalidCodeBlockAttributesError {..} =
|
||||||
|
genericError _invalidCodeBlockAttributesErrorMegaparsecError
|
||||||
|
@ -86,7 +86,7 @@ fromJuvixMarkdown opts = do
|
|||||||
_processingStateStmtsSeparation = sepr,
|
_processingStateStmtsSeparation = sepr,
|
||||||
_processingStateStmts = indModuleFilter $ m ^. Concrete.moduleBody
|
_processingStateStmts = indModuleFilter $ m ^. Concrete.moduleBody
|
||||||
}
|
}
|
||||||
(_, r) <- runState st . runReader htmlOptions . runReader opts $ go
|
(_, r) <- runState st . runReader htmlOptions . runReader opts $ go fname
|
||||||
return $ MK.toPlainText r
|
return $ MK.toPlainText r
|
||||||
Nothing ->
|
Nothing ->
|
||||||
throw
|
throw
|
||||||
@ -104,34 +104,49 @@ go ::
|
|||||||
( Members
|
( Members
|
||||||
'[ Reader HtmlRender.HtmlOptions,
|
'[ Reader HtmlRender.HtmlOptions,
|
||||||
Reader ProcessJuvixBlocksArgs,
|
Reader ProcessJuvixBlocksArgs,
|
||||||
State ProcessingState
|
State ProcessingState,
|
||||||
|
Error MarkdownBackendError
|
||||||
]
|
]
|
||||||
r
|
r
|
||||||
) =>
|
) =>
|
||||||
|
Path Abs File ->
|
||||||
Sem r Mk
|
Sem r Mk
|
||||||
go = do
|
go fname = do
|
||||||
stmts <- gets @ProcessingState (^. processingStateStmts)
|
stmts <- gets @ProcessingState (^. processingStateStmts)
|
||||||
sepr <- gets @ProcessingState (^. processingStateStmtsSeparation)
|
sepr <- gets @ProcessingState (^. processingStateStmtsSeparation)
|
||||||
mk <- gets @ProcessingState (^. processingStateMk)
|
mk <- gets @ProcessingState (^. processingStateMk)
|
||||||
case (sepr, stmts) of
|
case sepr of
|
||||||
([], _) -> return mk
|
[] -> return mk
|
||||||
((n : ns), _) -> do
|
(n : ns) -> do
|
||||||
case mk of
|
case mk of
|
||||||
MkNull -> return mk
|
MkNull -> return mk
|
||||||
MkTextBlock _ -> return mk
|
MkTextBlock _ -> return mk
|
||||||
MkConcat l r -> do
|
MkConcat l r -> do
|
||||||
modify (set processingStateMk l)
|
modify (set processingStateMk l)
|
||||||
lS <- go
|
lS <- go fname
|
||||||
modify (set processingStateMk r)
|
modify (set processingStateMk r)
|
||||||
MkConcat lS <$> go
|
MkConcat lS <$> go fname
|
||||||
MkJuvixCodeBlock j -> do
|
MkJuvixCodeBlock j -> do
|
||||||
|
opts <- case parseJuvixBlockOptions fname (j ^. juvixCodeBlockOptions) of
|
||||||
|
Left e ->
|
||||||
|
throw
|
||||||
|
( ErrInvalidCodeBlockAttribtues
|
||||||
|
(InvalidCodeBlockAttributesError e)
|
||||||
|
)
|
||||||
|
Right o -> return o
|
||||||
|
|
||||||
m <-
|
m <-
|
||||||
asks @ProcessJuvixBlocksArgs
|
asks @ProcessJuvixBlocksArgs
|
||||||
(^. processJuvixBlocksArgsModule)
|
(^. processJuvixBlocksArgsModule)
|
||||||
|
|
||||||
isFirstBlock <- gets @ProcessingState (^. processingStateFirstBlock)
|
isFirstBlock <- gets @ProcessingState (^. processingStateFirstBlock)
|
||||||
|
|
||||||
let stmts' = take n stmts
|
stmts' <-
|
||||||
|
let blockStmts = take n stmts
|
||||||
|
in case opts of
|
||||||
|
MkJuvixBlockOptionsExtractModule o ->
|
||||||
|
checkExtractModule j (o ^. juvixBlockOptionsExtractModuleDrop) blockStmts
|
||||||
|
_ -> return blockStmts
|
||||||
|
|
||||||
htmlStatements :: [Html] <-
|
htmlStatements :: [Html] <-
|
||||||
mapM (\s -> goRender s <> pure htmlSemicolon) stmts'
|
mapM (\s -> goRender s <> pure htmlSemicolon) stmts'
|
||||||
@ -153,15 +168,14 @@ go = do
|
|||||||
Text.intercalate "\n\n" $
|
Text.intercalate "\n\n" $
|
||||||
map (toStrict . Html.renderHtml) htmlStatements
|
map (toStrict . Html.renderHtml) htmlStatements
|
||||||
|
|
||||||
let _processingStateMk =
|
let _processingStateMk = case opts of
|
||||||
if j ^. juvixCodeBlockOptions . mkJuvixBlockOptionsHide
|
MkJuvixBlockOptionsHide -> MkNull
|
||||||
then MkNull
|
_ ->
|
||||||
else
|
MkTextBlock
|
||||||
MkTextBlock
|
TextBlock
|
||||||
TextBlock
|
{ _textBlock = Text.replace "\n" "<br/>" resHtml,
|
||||||
{ _textBlock = Text.replace "\n" "<br/>" resHtml,
|
_textBlockInterval = j ^. juvixCodeBlockInterval
|
||||||
_textBlockInterval = j ^. juvixCodeBlockInterval
|
}
|
||||||
}
|
|
||||||
let newState =
|
let newState =
|
||||||
ProcessingState
|
ProcessingState
|
||||||
{ _processingStateFirstBlock = False,
|
{ _processingStateFirstBlock = False,
|
||||||
@ -171,6 +185,20 @@ go = do
|
|||||||
}
|
}
|
||||||
modify @ProcessingState $ const newState
|
modify @ProcessingState $ const newState
|
||||||
return _processingStateMk
|
return _processingStateMk
|
||||||
|
where
|
||||||
|
checkExtractModule :: JuvixCodeBlock -> Int -> [Concrete.Statement 'Concrete.Scoped] -> Sem r [Concrete.Statement 'Concrete.Scoped]
|
||||||
|
checkExtractModule j dropNum xs = case xs of
|
||||||
|
[Concrete.StatementModule m] -> do
|
||||||
|
return (drop dropNum (indModuleFilter (m ^. Concrete.moduleBody)))
|
||||||
|
_ ->
|
||||||
|
throw
|
||||||
|
( ErrInvalidExtractModuleBlock
|
||||||
|
( InvalidExtractModuleBlockError
|
||||||
|
{ _invalidExtractModuleBlockErrorPath = fname,
|
||||||
|
_invalidExtractModuleBlockErrorInterval = j ^. juvixCodeBlockInterval
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
goRender ::
|
goRender ::
|
||||||
(Concrete.PrettyPrint c, Members '[Reader HtmlRender.HtmlOptions, Reader ProcessJuvixBlocksArgs] r) =>
|
(Concrete.PrettyPrint c, Members '[Reader HtmlRender.HtmlOptions, Reader ProcessJuvixBlocksArgs] r) =>
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
module Juvix.Parser.Error where
|
module Juvix.Parser.Error
|
||||||
|
( module Juvix.Parser.Error,
|
||||||
|
module Juvix.Parser.Error.Base,
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
import Commonmark qualified as MK
|
import Commonmark qualified as MK
|
||||||
import Juvix.Compiler.Backend.Markdown.Error
|
import Juvix.Compiler.Backend.Markdown.Error
|
||||||
@ -7,9 +11,9 @@ import Juvix.Compiler.Concrete.Pretty.Options (fromGenericOptions)
|
|||||||
import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.Scoping.Error.Pretty
|
import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.Scoping.Error.Pretty
|
||||||
import Juvix.Compiler.Pipeline.Loader.PathResolver.Error
|
import Juvix.Compiler.Pipeline.Loader.PathResolver.Error
|
||||||
import Juvix.Extra.Paths
|
import Juvix.Extra.Paths
|
||||||
|
import Juvix.Parser.Error.Base
|
||||||
import Juvix.Prelude
|
import Juvix.Prelude
|
||||||
import Text.Megaparsec qualified as M
|
import Text.Megaparsec qualified as M
|
||||||
import Text.Megaparsec.Error (errorOffset)
|
|
||||||
import Text.Parsec.Error qualified as P
|
import Text.Parsec.Error qualified as P
|
||||||
import Text.Parsec.Pos qualified as P
|
import Text.Parsec.Pos qualified as P
|
||||||
|
|
||||||
@ -33,43 +37,6 @@ instance ToGenericError ParserError where
|
|||||||
ErrDanglingJudoc e -> genericError e
|
ErrDanglingJudoc e -> genericError e
|
||||||
ErrMarkdownBackend e -> genericError e
|
ErrMarkdownBackend e -> genericError e
|
||||||
|
|
||||||
instance Pretty MegaparsecError where
|
|
||||||
pretty (MegaparsecError b) = pretty (M.errorBundlePretty b)
|
|
||||||
|
|
||||||
instance HasLoc MegaparsecError where
|
|
||||||
getLoc (MegaparsecError b) = singletonInterval (mkLoc offset sourcePos)
|
|
||||||
where
|
|
||||||
state :: M.PosState Text
|
|
||||||
state = M.bundlePosState b
|
|
||||||
offset = errorOffset (head (M.bundleErrors b))
|
|
||||||
|
|
||||||
sourcePos :: M.SourcePos
|
|
||||||
sourcePos =
|
|
||||||
(snd . head . fst)
|
|
||||||
(M.attachSourcePos errorOffset (M.bundleErrors b) state)
|
|
||||||
|
|
||||||
newtype MegaparsecError = MegaparsecError
|
|
||||||
{ _megaParsecError :: M.ParseErrorBundle Text Void
|
|
||||||
}
|
|
||||||
deriving stock (Show)
|
|
||||||
|
|
||||||
instance ToGenericError MegaparsecError where
|
|
||||||
genericError e =
|
|
||||||
return
|
|
||||||
GenericError
|
|
||||||
{ _genericErrorLoc = i,
|
|
||||||
_genericErrorMessage = mkAnsiText $ pretty @_ @AnsiStyle e,
|
|
||||||
_genericErrorIntervals = [i]
|
|
||||||
}
|
|
||||||
where
|
|
||||||
i = getLoc e
|
|
||||||
|
|
||||||
-- | Use only for debugging
|
|
||||||
fromMegaParsecError :: Either MegaparsecError a -> a
|
|
||||||
fromMegaParsecError = \case
|
|
||||||
Left e -> error (prettyText e)
|
|
||||||
Right a -> a
|
|
||||||
|
|
||||||
newtype CommonmarkError = CommonmarkError
|
newtype CommonmarkError = CommonmarkError
|
||||||
{ _commonMarkError :: MK.ParseError
|
{ _commonMarkError :: MK.ParseError
|
||||||
}
|
}
|
||||||
|
43
src/Juvix/Parser/Error/Base.hs
Normal file
43
src/Juvix/Parser/Error/Base.hs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
module Juvix.Parser.Error.Base where
|
||||||
|
|
||||||
|
import Juvix.Prelude
|
||||||
|
import Juvix.Prelude.Pretty
|
||||||
|
import Text.Megaparsec qualified as M
|
||||||
|
import Text.Megaparsec.Error (errorOffset)
|
||||||
|
|
||||||
|
instance Pretty MegaparsecError where
|
||||||
|
pretty (MegaparsecError b) = pretty (M.errorBundlePretty b)
|
||||||
|
|
||||||
|
instance HasLoc MegaparsecError where
|
||||||
|
getLoc (MegaparsecError b) = singletonInterval (mkLoc offset sourcePos)
|
||||||
|
where
|
||||||
|
state :: M.PosState Text
|
||||||
|
state = M.bundlePosState b
|
||||||
|
offset = errorOffset (head (M.bundleErrors b))
|
||||||
|
|
||||||
|
sourcePos :: M.SourcePos
|
||||||
|
sourcePos =
|
||||||
|
(snd . head . fst)
|
||||||
|
(M.attachSourcePos errorOffset (M.bundleErrors b) state)
|
||||||
|
|
||||||
|
newtype MegaparsecError = MegaparsecError
|
||||||
|
{ _megaParsecError :: M.ParseErrorBundle Text Void
|
||||||
|
}
|
||||||
|
deriving stock (Show)
|
||||||
|
|
||||||
|
instance ToGenericError MegaparsecError where
|
||||||
|
genericError e =
|
||||||
|
return
|
||||||
|
GenericError
|
||||||
|
{ _genericErrorLoc = i,
|
||||||
|
_genericErrorMessage = mkAnsiText $ pretty @_ @AnsiStyle e,
|
||||||
|
_genericErrorIntervals = [i]
|
||||||
|
}
|
||||||
|
where
|
||||||
|
i = getLoc e
|
||||||
|
|
||||||
|
-- | Use only for debugging
|
||||||
|
fromMegaParsecError :: Either MegaparsecError a -> a
|
||||||
|
fromMegaParsecError = \case
|
||||||
|
Left e -> error (prettyText e)
|
||||||
|
Right a -> a
|
@ -2,6 +2,9 @@ module BackendMarkdown.Negative where
|
|||||||
|
|
||||||
import Base
|
import Base
|
||||||
import Juvix.Compiler.Backend.Markdown.Error
|
import Juvix.Compiler.Backend.Markdown.Error
|
||||||
|
import Juvix.Compiler.Backend.Markdown.Translation.FromTyped.Source
|
||||||
|
import Juvix.Compiler.Concrete qualified as Concrete
|
||||||
|
import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.Scoping qualified as Scoper
|
||||||
import Juvix.Parser.Error
|
import Juvix.Parser.Error
|
||||||
|
|
||||||
type FailMsg = String
|
type FailMsg = String
|
||||||
@ -10,7 +13,7 @@ data NegTest = NegTest
|
|||||||
{ _name :: String,
|
{ _name :: String,
|
||||||
_relDir :: Path Rel Dir,
|
_relDir :: Path Rel Dir,
|
||||||
_file :: Path Rel File,
|
_file :: Path Rel File,
|
||||||
_checkErr :: ParserError -> Maybe FailMsg
|
_checkErr :: JuvixError -> Maybe FailMsg
|
||||||
}
|
}
|
||||||
|
|
||||||
testDescr :: NegTest -> TestDescr
|
testDescr :: NegTest -> TestDescr
|
||||||
@ -22,12 +25,33 @@ testDescr NegTest {..} =
|
|||||||
_testRoot = tRoot,
|
_testRoot = tRoot,
|
||||||
_testAssertion = Single $ do
|
_testAssertion = Single $ do
|
||||||
entryPoint <- testDefaultEntryPointIO tRoot file'
|
entryPoint <- testDefaultEntryPointIO tRoot file'
|
||||||
result <- testTaggedLockedToIO (runIOEither entryPoint upToParsing)
|
result <- testTaggedLockedToIO (runIOEither entryPoint upToScoping)
|
||||||
case mapLeft fromJuvixError result of
|
case result of
|
||||||
Left (Just err) -> whenJust (_checkErr err) assertFailure
|
Left err -> whenJust (_checkErr err) assertFailure
|
||||||
Right _ -> assertFailure "Unexpected success."
|
Right (_, pipelineRes) -> checkResult pipelineRes
|
||||||
Left Nothing -> assertFailure "Unexpected error."
|
|
||||||
}
|
}
|
||||||
|
where
|
||||||
|
checkResult :: PipelineResult Scoper.ScoperResult -> IO ()
|
||||||
|
checkResult PipelineResult {..} = do
|
||||||
|
let m = _pipelineResult ^. Scoper.resultModule
|
||||||
|
opts =
|
||||||
|
ProcessJuvixBlocksArgs
|
||||||
|
{ _processJuvixBlocksArgsConcreteOpts = Concrete.defaultOptions,
|
||||||
|
_processJuvixBlocksArgsUrlPrefix = "",
|
||||||
|
_processJuvixBlocksArgsIdPrefix = "",
|
||||||
|
_processJuvixBlocksArgsNoPath = True,
|
||||||
|
_processJuvixBlocksArgsExt = ".html",
|
||||||
|
_processJuvixBlocksArgsStripPrefix = "",
|
||||||
|
_processJuvixBlocksArgsComments = Comments mempty,
|
||||||
|
_processJuvixBlocksArgsFolderStructure = False,
|
||||||
|
_processJuvixBlocksArgsModule = m,
|
||||||
|
_processJuvixBlocksArgsOutputDir =
|
||||||
|
root <//> $(mkRelDir "markdown")
|
||||||
|
}
|
||||||
|
res = fromJuvixMarkdown' opts
|
||||||
|
case res of
|
||||||
|
Left err -> whenJust (_checkErr (JuvixError err)) assertFailure
|
||||||
|
Right _ -> assertFailure "Unexpected success"
|
||||||
|
|
||||||
allTests :: TestTree
|
allTests :: TestTree
|
||||||
allTests =
|
allTests =
|
||||||
@ -38,8 +62,8 @@ allTests =
|
|||||||
root :: Path Abs Dir
|
root :: Path Abs Dir
|
||||||
root = relToProject $(mkRelDir "tests/negative")
|
root = relToProject $(mkRelDir "tests/negative")
|
||||||
|
|
||||||
wrongError :: Maybe FailMsg
|
wrongError :: JuvixError -> Maybe FailMsg
|
||||||
wrongError = Just "Incorrect error"
|
wrongError e = Just ("unexpected error: " <> unpack (renderTextDefault e))
|
||||||
|
|
||||||
tests :: [NegTest]
|
tests :: [NegTest]
|
||||||
tests =
|
tests =
|
||||||
@ -47,14 +71,35 @@ tests =
|
|||||||
"Empty file"
|
"Empty file"
|
||||||
$(mkRelDir "Markdown")
|
$(mkRelDir "Markdown")
|
||||||
$(mkRelFile "Empty.juvix.md")
|
$(mkRelFile "Empty.juvix.md")
|
||||||
$ \case
|
$ \e -> case fromJuvixError e of
|
||||||
ErrMarkdownBackend (ErrNoJuvixCodeBlocks _) -> Nothing
|
Just (ErrMarkdownBackend (ErrNoJuvixCodeBlocks _)) -> Nothing
|
||||||
_ -> wrongError,
|
_ -> wrongError e,
|
||||||
NegTest
|
NegTest
|
||||||
"No Juvix code blocks"
|
"No Juvix code blocks"
|
||||||
$(mkRelDir "Markdown")
|
$(mkRelDir "Markdown")
|
||||||
$(mkRelFile "NoJuvixCodeBlocks.juvix.md")
|
$(mkRelFile "NoJuvixCodeBlocks.juvix.md")
|
||||||
$ \case
|
$ \e -> case fromJuvixError e of
|
||||||
ErrMarkdownBackend (ErrNoJuvixCodeBlocks _) -> Nothing
|
Just (ErrMarkdownBackend (ErrNoJuvixCodeBlocks _)) -> Nothing
|
||||||
_ -> wrongError
|
_ -> wrongError e,
|
||||||
|
NegTest
|
||||||
|
"extract-module-statements with no local module"
|
||||||
|
$(mkRelDir "Markdown")
|
||||||
|
$(mkRelFile "InvalidExtractModuleBlockNoModule.juvix.md")
|
||||||
|
$ \e -> case fromJuvixError e of
|
||||||
|
Just (ErrInvalidExtractModuleBlock _) -> Nothing
|
||||||
|
_ -> wrongError e,
|
||||||
|
NegTest
|
||||||
|
"extract-module-statements with no local module"
|
||||||
|
$(mkRelDir "Markdown")
|
||||||
|
$(mkRelFile "InvalidExtractModuleBlockNotJustModule.juvix.md")
|
||||||
|
$ \e -> case fromJuvixError e of
|
||||||
|
Just (ErrInvalidExtractModuleBlock _) -> Nothing
|
||||||
|
_ -> wrongError e,
|
||||||
|
NegTest
|
||||||
|
"code block with both hide and extract-module-statements"
|
||||||
|
$(mkRelDir "Markdown")
|
||||||
|
$(mkRelFile "InvalidCodeBlockExtraAttribute.juvix.md")
|
||||||
|
$ \e -> case fromJuvixError e of
|
||||||
|
Just (ErrInvalidCodeBlockAttribtues _) -> Nothing
|
||||||
|
_ -> wrongError e
|
||||||
]
|
]
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
# Title
|
||||||
|
|
||||||
|
```juvix
|
||||||
|
module InvalidExtractModuleBlockExtraAttribute;
|
||||||
|
```
|
||||||
|
|
||||||
|
```juvix hide extract-module-statements
|
||||||
|
type T := t;
|
||||||
|
```
|
@ -0,0 +1,9 @@
|
|||||||
|
# Title
|
||||||
|
|
||||||
|
```juvix
|
||||||
|
module InvalidExtractModuleBlockUnknownAttribute;
|
||||||
|
```
|
||||||
|
|
||||||
|
```juvix invalid-attribute
|
||||||
|
type T := t;
|
||||||
|
```
|
@ -0,0 +1,9 @@
|
|||||||
|
# Title
|
||||||
|
|
||||||
|
```juvix
|
||||||
|
module InvalidExtractModuleBlockNoModule;
|
||||||
|
```
|
||||||
|
|
||||||
|
```juvix extract-module-statements
|
||||||
|
type T := t;
|
||||||
|
```
|
@ -0,0 +1,12 @@
|
|||||||
|
# Title
|
||||||
|
|
||||||
|
```juvix
|
||||||
|
module InvalidExtractModuleBlockNotJustModule;
|
||||||
|
```
|
||||||
|
|
||||||
|
```juvix extract-module-statements
|
||||||
|
module Inner;
|
||||||
|
type T1 := t1;
|
||||||
|
end;
|
||||||
|
type T2 := t2;
|
||||||
|
```
|
@ -22,6 +22,23 @@ fib : Nat → Nat → Nat → Nat
|
|||||||
fibonacci (n : Nat) : Nat := fib n 0 1;
|
fibonacci (n : Nat) : Nat := fib n 0 1;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The `extract-module-statements` attribute can be used to display only the statements contained in a module in the output.
|
||||||
|
|
||||||
|
```juvix extract-module-statements
|
||||||
|
module Foo1;
|
||||||
|
type T := t;
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
You can pass a number to the `extract-module-statements` attribute to drop that number of statements from the start of the module.
|
||||||
|
|
||||||
|
```juvix extract-module-statements 1
|
||||||
|
module Foo2;
|
||||||
|
type T := t;
|
||||||
|
a : T := t;
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
Commands like `typecheck` and `compile` can be used with Juvix Markdown files.
|
Commands like `typecheck` and `compile` can be used with Juvix Markdown files.
|
||||||
|
|
||||||
```juvix
|
```juvix
|
||||||
@ -89,4 +106,4 @@ We also use other markup for documentation such as:
|
|||||||
| n zero := n
|
| n zero := n
|
||||||
| n (suc m) := suc (add n m);
|
| n (suc m) := suc (add n m);
|
||||||
end;
|
end;
|
||||||
```
|
```
|
||||||
|
@ -9,11 +9,19 @@ Certain blocks can be hidden from the output by adding the `hide` attribute, as
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<pre class="highlight"><code class="juvix"><pre class="src-content"><span id="YTest:1"><span class="annot"><a href="X#YTest:1"><span class="annot"><a href="X#YTest:1"><span class="ju-function">fib</span></a></span></a></span></span> <span class="ju-keyword">:</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span> <span class="ju-keyword">→</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span> <span class="ju-keyword">→</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span> <span class="ju-keyword">→</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span><br/> <span class="ju-keyword">|</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:2"><span class="ju-constructor">zero</span></a></span> <span id="YTest:4"><span class="annot"><a href="X#YTest:4"><span class="annot"><a href="X#YTest:4"><span class="ju-var">x1</span></a></span></a></span></span> <span class="ju-keyword">_</span> <span class="ju-keyword">:=</span> <span class="annot"><a href="X#YTest:4"><span class="ju-var">x1</span></a></span><br/> <span class="ju-keyword">|</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:3"><span class="ju-constructor"><span class="ju-delimiter">(</span>suc</span></a></span> <span id="YTest:5"><span class="annot"><a href="X#YTest:5"><span class="annot"><a href="X#YTest:5"><span class="ju-var">n</span></a></span></a></span></span><span class="ju-delimiter">)</span> <span id="YTest:6"><span class="annot"><a href="X#YTest:6"><span class="annot"><a href="X#YTest:6"><span class="ju-var">x1</span></a></span></a></span></span> <span id="YTest:7"><span class="annot"><a href="X#YTest:7"><span class="annot"><a href="X#YTest:7"><span class="ju-var">x2</span></a></span></a></span></span> <span class="ju-keyword">:=</span> <span class="annot"><a href="X#YTest:1"><span class="ju-function">fib</span></a></span> <span class="annot"><a href="X#YTest:5"><span class="ju-var">n</span></a></span> <span class="annot"><a href="X#YTest:7"><span class="ju-var">x2</span></a></span> <span class="annot"><a href="X#YTest:6"><span class="ju-var"><span class="ju-delimiter">(</span>x1</span></a></span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Trait.Natural:3"><span class="ju-function">+</span></a></span> <span class="annot"><a href="X#YTest:7"><span class="ju-var">x2</span></a></span><span class="ju-delimiter">)</span><span class="ju-delimiter">;</span><br/><br/><span id="YTest:2"><span class="annot"><a href="X#YTest:2"><span class="annot"><a href="X#YTest:2"><span class="ju-function">fibonacci</span></a></span></a></span></span> <span class="ju-delimiter">(</span><span class="annot"><a href="X#YTest:8"><span class="ju-var">n</span></a></span> <span class="ju-keyword">:</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span><span class="ju-delimiter">)</span> <span class="ju-keyword">:</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span> <span class="ju-keyword">:=</span> <span class="annot"><a href="X#YTest:1"><span class="ju-function">fib</span></a></span> <span class="annot"><a href="X#YTest:8"><span class="ju-var">n</span></a></span> <span class="ju-number">0</span> <span class="ju-number">1</span><span class="ju-delimiter">;</span></pre></code></pre>
|
<pre class="highlight"><code class="juvix"><pre class="src-content"><span id="YTest:1"><span class="annot"><a href="X#YTest:1"><span class="annot"><a href="X#YTest:1"><span class="ju-function">fib</span></a></span></a></span></span> <span class="ju-keyword">:</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span> <span class="ju-keyword">→</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span> <span class="ju-keyword">→</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span> <span class="ju-keyword">→</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span><br/> <span class="ju-keyword">|</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:2"><span class="ju-constructor">zero</span></a></span> <span id="YTest:3"><span class="annot"><a href="X#YTest:3"><span class="annot"><a href="X#YTest:3"><span class="ju-var">x1</span></a></span></a></span></span> <span class="ju-keyword">_</span> <span class="ju-keyword">:=</span> <span class="annot"><a href="X#YTest:3"><span class="ju-var">x1</span></a></span><br/> <span class="ju-keyword">|</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:3"><span class="ju-constructor"><span class="ju-delimiter">(</span>suc</span></a></span> <span id="YTest:4"><span class="annot"><a href="X#YTest:4"><span class="annot"><a href="X#YTest:4"><span class="ju-var">n</span></a></span></a></span></span><span class="ju-delimiter">)</span> <span id="YTest:5"><span class="annot"><a href="X#YTest:5"><span class="annot"><a href="X#YTest:5"><span class="ju-var">x1</span></a></span></a></span></span> <span id="YTest:6"><span class="annot"><a href="X#YTest:6"><span class="annot"><a href="X#YTest:6"><span class="ju-var">x2</span></a></span></a></span></span> <span class="ju-keyword">:=</span> <span class="annot"><a href="X#YTest:1"><span class="ju-function">fib</span></a></span> <span class="annot"><a href="X#YTest:4"><span class="ju-var">n</span></a></span> <span class="annot"><a href="X#YTest:6"><span class="ju-var">x2</span></a></span> <span class="annot"><a href="X#YTest:5"><span class="ju-var"><span class="ju-delimiter">(</span>x1</span></a></span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Trait.Natural:3"><span class="ju-function">+</span></a></span> <span class="annot"><a href="X#YTest:6"><span class="ju-var">x2</span></a></span><span class="ju-delimiter">)</span><span class="ju-delimiter">;</span><br/><br/><span id="YTest:2"><span class="annot"><a href="X#YTest:2"><span class="annot"><a href="X#YTest:2"><span class="ju-function">fibonacci</span></a></span></a></span></span> <span class="ju-delimiter">(</span><span class="annot"><a href="X#YTest:7"><span class="ju-var">n</span></a></span> <span class="ju-keyword">:</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span><span class="ju-delimiter">)</span> <span class="ju-keyword">:</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span> <span class="ju-keyword">:=</span> <span class="annot"><a href="X#YTest:1"><span class="ju-function">fib</span></a></span> <span class="annot"><a href="X#YTest:7"><span class="ju-var">n</span></a></span> <span class="ju-number">0</span> <span class="ju-number">1</span><span class="ju-delimiter">;</span></pre></code></pre>
|
||||||
|
|
||||||
|
The `extract-module-statements` attribute can be used to display only the statements contained in a module in the output.
|
||||||
|
|
||||||
|
<pre class="highlight"><code class="juvix"><pre class="src-content"><span class="ju-keyword">type</span> <span id="YTest:8"><span class="annot"><a href="X#YTest:8"><span class="annot"><a href="X#YTest:8"><span class="ju-inductive">T</span></a></span></a></span></span> <span class="ju-keyword">:=</span> <span id="YTest:9"><span class="annot"><a href="X#YTest:9"><span class="annot"><a href="X#YTest:9"><span class="ju-constructor">t</span></a></span></a></span></span><span class="ju-delimiter">;</span></pre></code></pre>
|
||||||
|
|
||||||
|
You can pass a number to the `extract-module-statements` attribute to drop that number of statements from the start of the module.
|
||||||
|
|
||||||
|
<pre class="highlight"><code class="juvix"><pre class="src-content"><span id="YTest:15"><span class="annot"><a href="X#YTest:15"><span class="annot"><a href="X#YTest:15"><span class="ju-function">a</span></a></span></a></span></span> <span class="ju-keyword">:</span> <span class="annot"><a href="X#YTest:12"><span class="ju-inductive">T</span></a></span> <span class="ju-keyword">:=</span> <span class="annot"><a href="X#YTest:13"><span class="ju-constructor">t</span></a></span><span class="ju-delimiter">;</span></pre></code></pre>
|
||||||
|
|
||||||
Commands like `typecheck` and `compile` can be used with Juvix Markdown files.
|
Commands like `typecheck` and `compile` can be used with Juvix Markdown files.
|
||||||
|
|
||||||
<pre class="highlight"><code class="juvix"><pre class="src-content"><span id="YTest:3"><span class="annot"><a href="X#YTest:3"><span class="annot"><a href="X#YTest:3"><span class="ju-function">main</span></a></span></a></span></span> <span class="ju-keyword">:</span> <span class="annot"><a href="X#YStdlib.System.IO.Base:1"><span class="ju-axiom">IO</span></a></span> <span class="ju-keyword">:=</span> <span class="annot"><a href="X#YStdlib.System.IO.String:2"><span class="ju-axiom">readLn</span></a></span> <span class="annot"><a href="X#YStdlib.System.IO.Nat:2"><span class="ju-function"><span class="ju-delimiter">(</span>printNatLn</span></a></span> <span class="annot"><a href="X#YStdlib.Function:1"><span class="ju-function">∘</span></a></span> <span class="annot"><a href="X#YTest:2"><span class="ju-function">fibonacci</span></a></span> <span class="annot"><a href="X#YStdlib.Function:1"><span class="ju-function">∘</span></a></span> <span class="annot"><a href="X#YStdlib.Data.Nat:2"><span class="ju-axiom">stringToNat</span></a></span><span class="ju-delimiter">)</span><span class="ju-delimiter">;</span></pre></code></pre>
|
<pre class="highlight"><code class="juvix"><pre class="src-content"><span id="YTest:17"><span class="annot"><a href="X#YTest:17"><span class="annot"><a href="X#YTest:17"><span class="ju-function">main</span></a></span></a></span></span> <span class="ju-keyword">:</span> <span class="annot"><a href="X#YStdlib.System.IO.Base:1"><span class="ju-axiom">IO</span></a></span> <span class="ju-keyword">:=</span> <span class="annot"><a href="X#YStdlib.System.IO.String:2"><span class="ju-axiom">readLn</span></a></span> <span class="annot"><a href="X#YStdlib.System.IO.Nat:2"><span class="ju-function"><span class="ju-delimiter">(</span>printNatLn</span></a></span> <span class="annot"><a href="X#YStdlib.Function:1"><span class="ju-function">∘</span></a></span> <span class="annot"><a href="X#YTest:2"><span class="ju-function">fibonacci</span></a></span> <span class="annot"><a href="X#YStdlib.Function:1"><span class="ju-function">∘</span></a></span> <span class="annot"><a href="X#YStdlib.Data.Nat:2"><span class="ju-axiom">stringToNat</span></a></span><span class="ju-delimiter">)</span><span class="ju-delimiter">;</span></pre></code></pre>
|
||||||
|
|
||||||
Other code blocks are not touched, e.g:
|
Other code blocks are not touched, e.g:
|
||||||
|
|
||||||
@ -57,8 +65,8 @@ We also use other markup for documentation such as:
|
|||||||
Initial function arguments that match variables or wildcards in all clauses can
|
Initial function arguments that match variables or wildcards in all clauses can
|
||||||
be moved to the left of the colon in the function definition. For example,
|
be moved to the left of the colon in the function definition. For example,
|
||||||
|
|
||||||
<pre class="highlight"><code class="juvix"><pre class="src-content"><span class="ju-keyword">module</span> <span id="YTest:12"><span class="annot"><a href="X#YTest:12"><span class="annot"><a href="X#YTest:12"><span class="ju-var">move-to-left</span></a></span></a></span></span><span class="ju-delimiter">;</span><br/> <span class="ju-keyword">import</span> <span id="YStdlib.Data.Nat:0"><span class="annot"><a href="X#YStdlib.Data.Nat:0"><span class="annot"><a href="X#YStdlib.Data.Nat:0"><span class="ju-var">Stdlib<span class="ju-delimiter">.</span>Data<span class="ju-delimiter">.</span>Nat</span></a></span></a></span></span> <span class="ju-keyword">open</span><span class="ju-delimiter">;</span><br/> <span id="YTest:9"><span class="annot"><a href="X#YTest:9"><span class="annot"><a href="X#YTest:9"><span class="ju-function"><br/> add</span></a></span></a></span></span> <span class="ju-delimiter">(</span><span class="annot"><a href="X#YTest:10"><span class="ju-var">n</span></a></span> <span class="ju-keyword">:</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span><span class="ju-delimiter">)</span> <span class="ju-keyword">:</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span> <span class="ju-keyword">-></span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span><br/> <span class="ju-keyword">|</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:2"><span class="ju-constructor">zero</span></a></span> <span class="ju-keyword">:=</span> <span class="annot"><a href="X#YTest:10"><span class="ju-var">n</span></a></span><br/> <span class="ju-keyword">|</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:3"><span class="ju-constructor"><span class="ju-delimiter">(</span>suc</span></a></span> <span id="YTest:11"><span class="annot"><a href="X#YTest:11"><span class="annot"><a href="X#YTest:11"><span class="ju-var">m</span></a></span></a></span></span><span class="ju-delimiter">)</span> <span class="ju-keyword">:=</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:3"><span class="ju-constructor">suc</span></a></span> <span class="annot"><a href="X#YTest:9"><span class="ju-function"><span class="ju-delimiter">(</span>add</span></a></span> <span class="annot"><a href="X#YTest:10"><span class="ju-var">n</span></a></span> <span class="annot"><a href="X#YTest:11"><span class="ju-var">m</span></a></span><span class="ju-delimiter">)</span><span class="ju-delimiter">;</span><br/><span class="ju-keyword">end</span><span class="ju-delimiter">;</span></pre></code></pre>
|
<pre class="highlight"><code class="juvix"><pre class="src-content"><span class="ju-keyword">module</span> <span id="YTest:21"><span class="annot"><a href="X#YTest:21"><span class="annot"><a href="X#YTest:21"><span class="ju-var">move-to-left</span></a></span></a></span></span><span class="ju-delimiter">;</span><br/> <span class="ju-keyword">import</span> <span id="YStdlib.Data.Nat:0"><span class="annot"><a href="X#YStdlib.Data.Nat:0"><span class="annot"><a href="X#YStdlib.Data.Nat:0"><span class="ju-var">Stdlib<span class="ju-delimiter">.</span>Data<span class="ju-delimiter">.</span>Nat</span></a></span></a></span></span> <span class="ju-keyword">open</span><span class="ju-delimiter">;</span><br/> <span id="YTest:18"><span class="annot"><a href="X#YTest:18"><span class="annot"><a href="X#YTest:18"><span class="ju-function"><br/> add</span></a></span></a></span></span> <span class="ju-delimiter">(</span><span class="annot"><a href="X#YTest:19"><span class="ju-var">n</span></a></span> <span class="ju-keyword">:</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span><span class="ju-delimiter">)</span> <span class="ju-keyword">:</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span> <span class="ju-keyword">-></span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span><br/> <span class="ju-keyword">|</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:2"><span class="ju-constructor">zero</span></a></span> <span class="ju-keyword">:=</span> <span class="annot"><a href="X#YTest:19"><span class="ju-var">n</span></a></span><br/> <span class="ju-keyword">|</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:3"><span class="ju-constructor"><span class="ju-delimiter">(</span>suc</span></a></span> <span id="YTest:20"><span class="annot"><a href="X#YTest:20"><span class="annot"><a href="X#YTest:20"><span class="ju-var">m</span></a></span></a></span></span><span class="ju-delimiter">)</span> <span class="ju-keyword">:=</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:3"><span class="ju-constructor">suc</span></a></span> <span class="annot"><a href="X#YTest:18"><span class="ju-function"><span class="ju-delimiter">(</span>add</span></a></span> <span class="annot"><a href="X#YTest:19"><span class="ju-var">n</span></a></span> <span class="annot"><a href="X#YTest:20"><span class="ju-var">m</span></a></span><span class="ju-delimiter">)</span><span class="ju-delimiter">;</span><br/><span class="ju-keyword">end</span><span class="ju-delimiter">;</span></pre></code></pre>
|
||||||
|
|
||||||
is equivalent to
|
is equivalent to
|
||||||
|
|
||||||
<pre class="highlight"><code class="juvix"><pre class="src-content"><span class="ju-keyword">module</span> <span id="YTest:17"><span class="annot"><a href="X#YTest:17"><span class="annot"><a href="X#YTest:17"><span class="ju-var">example-add</span></a></span></a></span></span><span class="ju-delimiter">;</span><br/> <span class="ju-keyword">import</span> <span id="YStdlib.Data.Nat:0"><span class="annot"><a href="X#YStdlib.Data.Nat:0"><span class="annot"><a href="X#YStdlib.Data.Nat:0"><span class="ju-var">Stdlib<span class="ju-delimiter">.</span>Data<span class="ju-delimiter">.</span>Nat</span></a></span></a></span></span> <span class="ju-keyword">open</span><span class="ju-delimiter">;</span><br/> <span id="YTest:13"><span class="annot"><a href="X#YTest:13"><span class="annot"><a href="X#YTest:13"><span class="ju-function"><br/> add</span></a></span></a></span></span> <span class="ju-keyword">:</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span> <span class="ju-keyword">-></span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span> <span class="ju-keyword">-></span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span><br/> <span class="ju-keyword">|</span> <span id="YTest:14"><span class="annot"><a href="X#YTest:14"><span class="annot"><a href="X#YTest:14"><span class="ju-var">n</span></a></span></a></span></span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:2"><span class="ju-constructor">zero</span></a></span> <span class="ju-keyword">:=</span> <span class="annot"><a href="X#YTest:14"><span class="ju-var">n</span></a></span><br/> <span class="ju-keyword">|</span> <span id="YTest:15"><span class="annot"><a href="X#YTest:15"><span class="annot"><a href="X#YTest:15"><span class="ju-var">n</span></a></span></a></span></span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:3"><span class="ju-constructor"><span class="ju-delimiter">(</span>suc</span></a></span> <span id="YTest:16"><span class="annot"><a href="X#YTest:16"><span class="annot"><a href="X#YTest:16"><span class="ju-var">m</span></a></span></a></span></span><span class="ju-delimiter">)</span> <span class="ju-keyword">:=</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:3"><span class="ju-constructor">suc</span></a></span> <span class="annot"><a href="X#YTest:13"><span class="ju-function"><span class="ju-delimiter">(</span>add</span></a></span> <span class="annot"><a href="X#YTest:15"><span class="ju-var">n</span></a></span> <span class="annot"><a href="X#YTest:16"><span class="ju-var">m</span></a></span><span class="ju-delimiter">)</span><span class="ju-delimiter">;</span><br/><span class="ju-keyword">end</span><span class="ju-delimiter">;</span></pre></code></pre>
|
<pre class="highlight"><code class="juvix"><pre class="src-content"><span class="ju-keyword">module</span> <span id="YTest:26"><span class="annot"><a href="X#YTest:26"><span class="annot"><a href="X#YTest:26"><span class="ju-var">example-add</span></a></span></a></span></span><span class="ju-delimiter">;</span><br/> <span class="ju-keyword">import</span> <span id="YStdlib.Data.Nat:0"><span class="annot"><a href="X#YStdlib.Data.Nat:0"><span class="annot"><a href="X#YStdlib.Data.Nat:0"><span class="ju-var">Stdlib<span class="ju-delimiter">.</span>Data<span class="ju-delimiter">.</span>Nat</span></a></span></a></span></span> <span class="ju-keyword">open</span><span class="ju-delimiter">;</span><br/> <span id="YTest:22"><span class="annot"><a href="X#YTest:22"><span class="annot"><a href="X#YTest:22"><span class="ju-function"><br/> add</span></a></span></a></span></span> <span class="ju-keyword">:</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span> <span class="ju-keyword">-></span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span> <span class="ju-keyword">-></span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:1"><span class="ju-inductive">Nat</span></a></span><br/> <span class="ju-keyword">|</span> <span id="YTest:23"><span class="annot"><a href="X#YTest:23"><span class="annot"><a href="X#YTest:23"><span class="ju-var">n</span></a></span></a></span></span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:2"><span class="ju-constructor">zero</span></a></span> <span class="ju-keyword">:=</span> <span class="annot"><a href="X#YTest:23"><span class="ju-var">n</span></a></span><br/> <span class="ju-keyword">|</span> <span id="YTest:24"><span class="annot"><a href="X#YTest:24"><span class="annot"><a href="X#YTest:24"><span class="ju-var">n</span></a></span></a></span></span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:3"><span class="ju-constructor"><span class="ju-delimiter">(</span>suc</span></a></span> <span id="YTest:25"><span class="annot"><a href="X#YTest:25"><span class="annot"><a href="X#YTest:25"><span class="ju-var">m</span></a></span></a></span></span><span class="ju-delimiter">)</span> <span class="ju-keyword">:=</span> <span class="annot"><a href="X#YJuvix.Builtin.V1.Nat.Base:3"><span class="ju-constructor">suc</span></a></span> <span class="annot"><a href="X#YTest:22"><span class="ju-function"><span class="ju-delimiter">(</span>add</span></a></span> <span class="annot"><a href="X#YTest:24"><span class="ju-var">n</span></a></span> <span class="annot"><a href="X#YTest:25"><span class="ju-var">m</span></a></span><span class="ju-delimiter">)</span><span class="ju-delimiter">;</span><br/><span class="ju-keyword">end</span><span class="ju-delimiter">;</span></pre></code></pre>
|
||||||
|
Loading…
Reference in New Issue
Block a user