Skip to content

Commit

Permalink
Allow multiple declarations in let expressions.
Browse files Browse the repository at this point in the history
  • Loading branch information
noteed committed Jul 3, 2024
1 parent 4839134 commit 69530f4
Show file tree
Hide file tree
Showing 9 changed files with 54 additions and 29 deletions.
3 changes: 3 additions & 0 deletions examples/let.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
<p>
1 5 9 13 15
</p>
<p>
1 5
</p>
5 changes: 5 additions & 0 deletions examples/let.slab
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@ let e =
8 +
7
p #(a) #(b) #(c) #(d) #(e)

let f = 1
g
= 2 + 3
p #(f) #(g)
6 changes: 3 additions & 3 deletions src/Slab/Evaluate.hs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ eval env stack bl = case bl of
pure $ BlockImport path (Just body) args
node@(BlockRun _ _) -> pure node
node@(BlockReadJson _ _ _) -> pure node
node@(BlockAssignVar _ _) -> pure node
node@(BlockAssignVars _) -> pure node
BlockIf cond as bs -> do
cond' <- evalExpr env cond
case cond' of
Expand Down Expand Up @@ -400,7 +400,7 @@ extractVariable env = \case
(BlockRun _ _) -> []
(BlockReadJson name _ (Just val)) -> [(name, jsonToExpr val)]
(BlockReadJson _ _ Nothing) -> []
(BlockAssignVar name val) -> [(name, val)]
(BlockAssignVars pairs) -> pairs
(BlockIf _ _ _) -> []
(BlockList _) -> []
(BlockCode _) -> []
Expand Down Expand Up @@ -435,7 +435,7 @@ simplify' = \case
BlockImport _ mbody _ -> maybe [] simplify mbody
BlockRun _ mbody -> maybe [] simplify mbody
BlockReadJson _ _ _ -> []
BlockAssignVar _ _ -> []
BlockAssignVars _ -> []
BlockIf _ [] bs -> simplify bs
BlockIf _ as _ -> simplify as
BlockList nodes -> simplify nodes
Expand Down
2 changes: 1 addition & 1 deletion src/Slab/Execute.hs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ exec ctx = \case
Syntax.BlockRun cmd $
Just [Syntax.BlockText Syntax.RunOutput [Syntax.Lit $ T.pack out]]
node@(Syntax.BlockReadJson _ _ _) -> pure node
node@(Syntax.BlockAssignVar _ _) -> pure node
node@(Syntax.BlockAssignVars _) -> pure node
Syntax.BlockIf cond as bs -> do
as' <- execute ctx as
bs' <- execute ctx bs
Expand Down
50 changes: 34 additions & 16 deletions src/Slab/Parse.hs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Except (ExceptT, except, runExceptT, withExceptT)
import Data.Char (isSpace)
import Data.Functor (($>))
import Data.List (intercalate)
import Data.List (intercalate, isSuffixOf)
import Data.Maybe (isJust)
import Data.Text (Text)
import Data.Text qualified as T
Expand Down Expand Up @@ -433,7 +433,16 @@ parserInclude = do
pure $ L.IndentNone $ BlockInclude mname path Nothing

parserPath :: Parser FilePath
parserPath = lexeme (some (noneOf ("'\"\n" :: String))) <?> "path"
parserPath = do
path <- lexeme (some (noneOf ("'\"\n" :: String))) <?> "path"
-- TODO Simply require a slash.
guard
( ".slab" `isSuffixOf` path
|| ".json" `isSuffixOf` path
|| ".html" `isSuffixOf` path
|| ".txt" `isSuffixOf` path
)
pure path

--------------------------------------------------------------------------------
parserFragmentDef :: Parser (L.IndentOpt Parser Block Block)
Expand Down Expand Up @@ -604,23 +613,32 @@ parserRun = do

--------------------------------------------------------------------------------
parserLet :: Parser (L.IndentOpt Parser Block Block)
parserLet = do
_ <- lexeme (string "let")
initialIndent <- getSourcePos
name <- lexeme' initialIndent parserName
_ <- lexeme' initialIndent (string "=")
parserLet =
choice
[ parserAssignVar initialIndent name
, parserReadJson name
[ try parserReadJson
, parserAssignVar
]

parserAssignVar :: SourcePos -> Text -> Parser (L.IndentOpt Parser Block Block)
parserAssignVar initialIndent name = do
val <- parserExprInd initialIndent
pure $ L.IndentNone $ BlockAssignVar name val

parserReadJson :: Text -> Parser (L.IndentOpt Parser Block Block)
parserReadJson name = do
parserAssignVar :: Parser (L.IndentOpt Parser Block Block)
parserAssignVar = do
_ <- lexeme (string "let")
blockIndent <- getSourcePos
pairs <- some $ do
initialIndent <- getSourcePos
guard
(sourceColumn blockIndent == sourceColumn initialIndent
)
name <- lexeme' initialIndent parserName
_ <- lexeme' initialIndent (string "=")
val <- parserExprInd initialIndent
pure (name, val)
pure $ L.IndentNone $ BlockAssignVars pairs

parserReadJson :: Parser (L.IndentOpt Parser Block Block)
parserReadJson = do
_ <- lexeme (string "let")
name <- lexeme parserName
_ <- lexeme (string "=")
path <- parserPath
pure $ L.IndentNone $ BlockReadJson name path Nothing

Expand Down
2 changes: 1 addition & 1 deletion src/Slab/PreProcess.hs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ preproc ctx@Context {..} = \case
pure $ BlockReadJson name path $ Just val
Left err ->
throwE $ Error.PreProcessError $ "Can't decode JSON: " <> T.pack err
node@(BlockAssignVar _ _) -> pure node
node@(BlockAssignVars _) -> pure node
BlockIf cond as bs -> do
-- File inclusion is done right away, without checking the condition.
as' <- preprocess ctx as
Expand Down
4 changes: 2 additions & 2 deletions src/Slab/Render.hs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ renderBlock (Syntax.BlockRun _ (Just nodes)) = mapM_ renderBlock nodes
renderBlock (Syntax.BlockRun cmd _) = H.textComment $ "run " <> cmd
renderBlock (Syntax.BlockImport path Nothing _) = H.stringComment $ "extends " <> path
renderBlock (Syntax.BlockReadJson _ _ _) = mempty
renderBlock (Syntax.BlockAssignVar _ _) = mempty
renderBlock (Syntax.BlockAssignVars _) = mempty
renderBlock (Syntax.BlockIf _ as bs) = do
-- The evaluation code transforms a BlockIf into a BlockList, so this should
-- not be called.
Expand Down Expand Up @@ -149,7 +149,7 @@ extractText = f
f (Syntax.BlockImport _ _ _) = error "extractTexts called on a BlockImport"
f (Syntax.BlockRun _ _) = error "extractTexts called on a BlockRun"
f (Syntax.BlockReadJson _ _ _) = error "extractTexts called on a BlockReadJson"
f (Syntax.BlockAssignVar _ _) = error "extractTexts called on a BlockAssignVar"
f (Syntax.BlockAssignVars _) = error "extractTexts called on a BlockAssignVars"
f (Syntax.BlockIf _ _ _) = error "extractTexts called on a BlockIf"
f (Syntax.BlockList _) = error "extractTexts called on a BlockList"
f (Syntax.BlockCode _) = error "extractTexts called on a BlockCode"
Expand Down
2 changes: 1 addition & 1 deletion src/Slab/Report.hs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ extractHeadings = concatMap f
f (Syntax.BlockImport _ children args) = maybe [] extractHeadings children <> extractHeadings args
f (Syntax.BlockRun _ _) = []
f (Syntax.BlockReadJson _ _ _) = []
f (Syntax.BlockAssignVar _ _) = []
f (Syntax.BlockAssignVars _) = []
f (Syntax.BlockIf _ as bs) = extractHeadings as <> extractHeadings bs
f (Syntax.BlockList children) = extractHeadings children
f (Syntax.BlockCode _) = []
9 changes: 4 additions & 5 deletions src/Slab/Syntax.hs
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,9 @@ data Block
-- content of the referenced file.
BlockImport FilePath (Maybe [Block]) [Block]
| BlockRun Text (Maybe [Block])
| -- | Allow to assign the content of a JSON file to a variable. The syntax
-- is specific to how Struct has a @require@ function in scope.
| -- | Allow to assign the content of a JSON file to a variable.
BlockReadJson Text FilePath (Maybe Aeson.Value)
| BlockAssignVar Text Expr
| BlockAssignVars [(Text, Expr)]
| BlockIf Expr [Block] [Block]
| BlockList [Block]
| BlockCode Expr
Expand Down Expand Up @@ -299,7 +298,7 @@ extractClasses = nub . sort . concatMap f
f (BlockImport _ children blocks) = maybe [] extractClasses children <> extractClasses blocks
f (BlockRun _ _) = []
f (BlockReadJson _ _ _) = []
f (BlockAssignVar _ _) = []
f (BlockAssignVars _) = []
f (BlockIf _ as bs) = extractClasses as <> extractClasses bs
f (BlockList children) = extractClasses children
f (BlockCode _) = []
Expand Down Expand Up @@ -335,7 +334,7 @@ extractFragments = concatMap f
f (BlockImport _ children args) = maybe [] extractFragments children <> extractFragments args
f (BlockRun _ _) = []
f (BlockReadJson _ _ _) = []
f (BlockAssignVar _ _) = []
f (BlockAssignVars _) = []
f (BlockIf _ as bs) = extractFragments as <> extractFragments bs
f (BlockList children) = extractFragments children
f (BlockCode _) = []
Expand Down

0 comments on commit 69530f4

Please sign in to comment.