diff options
Diffstat (limited to 'fig-bless/src/Fig')
| -rw-r--r-- | fig-bless/src/Fig/Bless/Runtime.hs | 4 | ||||
| -rw-r--r-- | fig-bless/src/Fig/Bless/Syntax.hs | 34 | ||||
| -rw-r--r-- | fig-bless/src/Fig/Bless/TypeChecker.hs | 23 | ||||
| -rw-r--r-- | fig-bless/src/Fig/Bless/Types.hs | 17 |
4 files changed, 45 insertions, 33 deletions
diff --git a/fig-bless/src/Fig/Bless/Runtime.hs b/fig-bless/src/Fig/Bless/Runtime.hs index c1170f3..4de75e0 100644 --- a/fig-bless/src/Fig/Bless/Runtime.hs +++ b/fig-bless/src/Fig/Bless/Runtime.hs @@ -153,15 +153,15 @@ runWord _ w vm | Just (b, _) <- Map.lookup w $ vm.builtins ?term = b vm runWord f w vm | Just p <- lookup w vm.bindings.defs = runProgram f p vm runWord _ w _ = throwM $ RuntimeErrorWordNotFound ?term w -literalValue :: Syn.Literal -> ValueF t +literalValue :: Syn.LiteralF t -> ValueF t literalValue (Syn.LiteralInteger i) = ValueInteger i literalValue (Syn.LiteralDouble i) = ValueDouble i literalValue (Syn.LiteralString i) = ValueString i literalValue (Syn.LiteralArray xs) = ValueArray $ literalValue <$> xs +literalValue (Syn.LiteralQuote p) = ValueProgram p run :: Running m t => Syn.Extractor m t -> t -> VM m t -> m (VM m t) run f v vm = let ?term = Just v in f v >>= \case Syn.TermLiteral l -> push (literalValue l) <$> checkFuel vm - Syn.TermQuote p -> push (ValueProgram p) <$> checkFuel vm Syn.TermWord w -> runWord f w =<< checkFuel vm diff --git a/fig-bless/src/Fig/Bless/Syntax.hs b/fig-bless/src/Fig/Bless/Syntax.hs index f4dea0a..9cd8aec 100644 --- a/fig-bless/src/Fig/Bless/Syntax.hs +++ b/fig-bless/src/Fig/Bless/Syntax.hs @@ -2,7 +2,7 @@ module Fig.Bless.Syntax ( Word(..) - , Literal(..) + , LiteralF(..) , ProgramF(..) , Program , TermF(..) @@ -10,7 +10,7 @@ module Fig.Bless.Syntax , DictionaryF(..) , Dictionary , Extractor - , word, literal, termF, term, programF, program, dictionaryF, dictionary, P.eof + , word, literalF, termF, term, programF, program, dictionaryF, dictionary, P.eof , Spanning(..), unSpanning, spanning , ParseError(..) , parse @@ -36,18 +36,20 @@ instance IsString Word where instance Pretty Word where pretty (Word t) = t -data Literal +data LiteralF t = LiteralInteger Integer | LiteralDouble Double | LiteralString Text - | LiteralArray [Literal] - deriving (Show, Eq, Ord, Generic) -instance Aeson.ToJSON Literal -instance Pretty Literal where + | LiteralArray [LiteralF t] + | LiteralQuote (ProgramF t) + deriving (Show, Eq, Ord, Generic, Functor) +instance Aeson.ToJSON t => Aeson.ToJSON (LiteralF t) +instance Pretty t => Pretty (LiteralF t) where pretty (LiteralInteger i) = tshow i pretty (LiteralDouble d) = tshow d pretty (LiteralString s) = tshow s pretty (LiteralArray xs) = "{" <> unwords (pretty <$> xs) <> "}" + pretty (LiteralQuote p) = pretty p newtype ProgramF t = Program [t] deriving (Show, Eq, Ord, Generic, Functor) @@ -58,14 +60,12 @@ type Program = ProgramF (Fix TermF) data TermF t = TermWord Word - | TermLiteral Literal - | TermQuote (ProgramF t) + | TermLiteral (LiteralF t) deriving (Show, Eq, Ord, Generic, Functor) instance Aeson.ToJSON t => Aeson.ToJSON (TermF t) instance Pretty t => Pretty (TermF t) where pretty (TermWord w) = pretty w pretty (TermLiteral l) = pretty l - pretty (TermQuote p) = pretty p type Term = TermF (Fix TermF) newtype DictionaryF t = Dictionary @@ -90,12 +90,12 @@ ws = P.C.L.space (P.C.L.skipBlockComment "/*" "*/") wordChar :: Char -> Bool -wordChar c = not $ elem @[] c ['[', ']', '=', ';'] || isSpace c +wordChar c = not $ elem @[] c ['[', ']', '{', '}', '=', ';'] || isSpace c word :: Parser Word word = Word . pack <$> P.some (P.satisfy wordChar) -literal :: Parser Literal -literal = +literalF :: Parser t -> Parser (LiteralF t) +literalF pt = P.try ( (LiteralDouble <$> P.C.L.signed (pure ()) P.C.L.float) P.<?> "floating-point literal" ) P.<|> @@ -111,8 +111,11 @@ literal = ( (LiteralString . pack <$> (P.C.char '"' *> P.manyTill P.C.L.charLiteral (P.C.char '"'))) P.<?> "string literal" ) P.<|> - ( (LiteralArray <$> (P.C.char '{' *> P.many (ws *> literal <* ws) <* P.C.char '}')) + ( (LiteralArray <$> (P.C.char '{' *> P.many (ws *> literalF pt <* ws) <* P.C.char '}')) P.<?> "array literal" + ) P.<|> + ( (LiteralQuote <$> (P.C.char '[' *> programF pt <* P.C.char ']')) + P.<?> "quotation" ) programF :: Parser t -> Parser (ProgramF t) @@ -123,9 +126,8 @@ program = programF $ Fix <$> term termF :: Parser t -> Parser (TermF t) termF pt = - ( P.try (TermLiteral <$> literal) + ( P.try (TermLiteral <$> literalF pt) P.<|> (TermWord <$> word) - P.<|> (TermQuote <$> (P.C.char '[' *> programF pt <* P.C.char ']')) ) P.<?> "term" term :: Parser Term diff --git a/fig-bless/src/Fig/Bless/TypeChecker.hs b/fig-bless/src/Fig/Bless/TypeChecker.hs index 272d98c..2b2cb6d 100644 --- a/fig-bless/src/Fig/Bless/TypeChecker.hs +++ b/fig-bless/src/Fig/Bless/TypeChecker.hs @@ -86,7 +86,9 @@ unifyTypes subst = case completeSubstitution subst of | otherwise -> throwM $ TypeErrorMismatch ?term t0 t1 -- otherwise, mismatch combineProgTypes :: forall m t. Typing m t => BProgType -> BProgType -> m BProgType -combineProgTypes f s = do +combineProgTypes f s' = do + let fvars = typeVariables $ BTypeProgram f + let s = BProgType { inp = ensureUniqueVars fvars <$> s'.inp, out = ensureUniqueVars fvars <$> s'.out } subst <- unifyTypes $ zip f.out s.inp let finp = applySubstitution subst <$> f.inp let fout = applySubstitution subst <$> f.out @@ -106,15 +108,16 @@ combineProgTypes f s = do , out = sout <> leftover } -typeOfLiteral :: Typing m t => Literal -> m BType -typeOfLiteral LiteralInteger{} = pure BTypeInteger -typeOfLiteral LiteralDouble{} = pure BTypeDouble -typeOfLiteral LiteralString{} = pure BTypeString -typeOfLiteral (LiteralArray xs) = mapM typeOfLiteral xs >>= \case +typeOfLiteral :: Typing m t => Env m t -> LiteralF t -> m BType +typeOfLiteral _ LiteralInteger{} = pure BTypeInteger +typeOfLiteral _ LiteralDouble{} = pure BTypeDouble +typeOfLiteral _ LiteralString{} = pure BTypeString +typeOfLiteral e (LiteralArray xs) = mapM (typeOfLiteral e) xs >>= \case [] -> pure $ BTypeArray (BTypeVariable "a") ts@(t:_) | length (Set.fromList ts) == 1 -> pure $ BTypeArray t | otherwise -> throwM $ TypeErrorMixedArray ?term +typeOfLiteral e (LiteralQuote p) = BTypeProgram <$> typeOfProgram e p typeOfProgram :: Typing m t => Env m t -> ProgramF t -> m BProgType typeOfProgram e (Program p) = case p of @@ -131,17 +134,11 @@ typeOf e wt = do Nothing -> throwM $ TypeErrorWordNotFound ?term w Just p -> pure p TermLiteral l -> do - out <- typeOfLiteral l + out <- typeOfLiteral e l pure BProgType { inp = [] , out = [out] } - TermQuote p -> do - ty <- typeOfProgram e p - pure BProgType - { inp = [] - , out = [BTypeProgram ty] - } initializeEnv :: Extractor m t -> Builtins m t -> Env m t initializeEnv ext bs = Env diff --git a/fig-bless/src/Fig/Bless/Types.hs b/fig-bless/src/Fig/Bless/Types.hs index c2e5d41..f7263e7 100644 --- a/fig-bless/src/Fig/Bless/Types.hs +++ b/fig-bless/src/Fig/Bless/Types.hs @@ -2,6 +2,8 @@ module Fig.Bless.Types where import Fig.Prelude +import Prelude (error) + import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map import Data.Set (Set) @@ -23,8 +25,8 @@ instance Pretty BType where pretty BTypeInteger = "integer" pretty BTypeDouble = "double" pretty BTypeString = "string" - pretty (BTypeProgram p) = "(" <> pretty p <> ")" - pretty (BTypeArray p) = "Array<" <> pretty p <> ">" + pretty (BTypeProgram p) = "[" <> pretty p <> "]" + pretty (BTypeArray p) = "{" <> pretty p <> "}" data BProgType = BProgType { inp :: [BType] @@ -44,6 +46,17 @@ renameVars f (BTypeProgram p) = BTypeProgram BProgType } renameVars _ x = x +ensureUniqueVars :: Set Text -> BType -> BType +ensureUniqueVars bad = renameVars \v -> if Set.member v bad + then do + let + names :: [Text] + names = fmap (pack . (:[])) ['a'..'z'] <> fmap (<>"'") names + case headMay $ filter (not . flip Set.member bad) names of + Nothing -> error "unreachable" -- this can't happen because names is an infinite list + Just x -> x + else v + substitute :: Text -> BType -> BType -> BType substitute n v (BTypeVariable n') | n == n' = v substitute n v (BTypeArray t) = BTypeArray $ substitute n v t |
