Skip to content

Commit 36c50d6

Browse files
authored
Merge pull request #144 from hhefesto/brands
User Defined Types
2 parents 73860f7 + 0ab7b39 commit 36c50d6

15 files changed

Lines changed: 871 additions & 248 deletions

.github/workflows/telomare-ci.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ jobs:
88
runs-on: ubuntu-latest
99
steps:
1010
- uses: actions/checkout@v4
11+
with:
12+
fetch-depth: 0
1113
- uses: cachix/install-nix-action@v25
1214
with:
15+
install_url: https://releases.nixos.org/nix/nix-2.31.5/install
1316
nix_path: nixpkgs=channel:nixos-unstable
1417
extra_nix_config: |
1518
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
@@ -46,8 +49,11 @@ jobs:
4649
steps:
4750
- name: Checkout telomare repository
4851
uses: actions/checkout@v4
52+
with:
53+
fetch-depth: 0
4954
- uses: cachix/install-nix-action@v25
5055
with:
56+
install_url: https://releases.nixos.org/nix/nix-2.31.5/install
5157
extra_nix_config: |
5258
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
5359
- uses: DeterminateSystems/magic-nix-cache-action@v2
@@ -72,8 +78,11 @@ jobs:
7278
steps:
7379
- name: Checkout telomare repository
7480
uses: actions/checkout@v4
81+
with:
82+
fetch-depth: 0
7583
- uses: cachix/install-nix-action@v25
7684
with:
85+
install_url: https://releases.nixos.org/nix/nix-2.31.5/install
7786
extra_nix_config: |
7887
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
7988
- uses: DeterminateSystems/magic-nix-cache-action@v2
@@ -103,14 +112,17 @@ jobs:
103112
repository: Stand-In-Language/stand-in-language
104113
token: ${{ secrets.API_TOKEN_GITHUB }}
105114
path: ./telomare
115+
fetch-depth: 0
106116
- name: Checkout telomare site repository
107117
uses: actions/checkout@v4
108118
with:
109119
repository: Stand-In-Language/stand-in-language.github.io
110120
token: ${{ secrets.API_TOKEN_GITHUB }}
111121
path: ./stand-in-language.github.io
122+
fetch-depth: 0
112123
- uses: cachix/install-nix-action@v25
113124
with:
125+
install_url: https://releases.nixos.org/nix/nix-2.31.5/install
114126
extra_nix_config: |
115127
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
116128
- uses: DeterminateSystems/magic-nix-cache-action@v2

Prelude.tel

Lines changed: 42 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -142,57 +142,45 @@ gcd = \a b ->
142142

143143
lcm = \a b -> dDiv (dTimes a b) (gcd a b)
144144

145-
Rational =
146-
let wrapper = \h -> (
147-
\n d -> if dEqual d 0
148-
then abort "Denominator cannot be zero"
149-
else
150-
let g = gcd n d
151-
num = dDiv n g
152-
den = dDiv d g
153-
in (h, (num, den))
154-
, \i -> if dEqual (left i) h
155-
then right i
156-
else abort "Not a Rational"
157-
)
158-
in wrapper (# wrapper)
159-
160-
toRational = right Rational
161-
162-
fromRational = left Rational
163-
164-
rPlus = \a b ->
165-
let n1 = left (right a)
166-
d1 = right (right a)
167-
n2 = left (right b)
168-
d2 = right (right b)
169-
num = dPlus (dTimes n1 d2) (dTimes n2 d1)
170-
den = dTimes d1 d2
171-
in fromRational num den
172-
173-
rTimes = \a b ->
174-
let n1 = left (right a)
175-
d1 = right (right a)
176-
n2 = left (right b)
177-
d2 = right (right b)
178-
num = dTimes n1 n2
179-
den = dTimes d1 d2
180-
in fromRational num den
181-
182-
rMinus = \a b ->
183-
let n1 = left (right a)
184-
d1 = right (right a)
185-
n2 = left (right b)
186-
d2 = right (right b)
187-
num = dMinus (dTimes n1 d2) (dTimes n2 d1)
188-
den = dTimes d1 d2
189-
in fromRational num den
190-
191-
rDiv = \a b ->
192-
let n1 = left (right a)
193-
d1 = right (right a)
194-
n2 = left (right b)
195-
d2 = right (right b)
196-
num = dTimes n1 d2
197-
den = dTimes d1 n2
198-
in fromRational num den
145+
[Rational, fromRational, toRational, rPlus, rTimes, rMinus, rDiv] = \h ->
146+
[ \n d -> if dEqual d 0
147+
then abort "Denominator cannot be zero"
148+
else
149+
let g = gcd n d
150+
num = dDiv n g
151+
den = dDiv d g
152+
in (h, (num, den))
153+
, \i -> Rational i
154+
, \a b ->
155+
let n1 = left (right a)
156+
d1 = right (right a)
157+
n2 = left (right b)
158+
d2 = right (right b)
159+
num = dPlus (dTimes n1 d2) (dTimes n2 d1)
160+
den = dTimes d1 d2
161+
in fromRational num den
162+
, \a b ->
163+
let n1 = left (right a)
164+
d1 = right (right a)
165+
n2 = left (right b)
166+
d2 = right (right b)
167+
num = dTimes n1 n2
168+
den = dTimes d1 d2
169+
in fromRational num den
170+
, \a b ->
171+
let n1 = left (right a)
172+
d1 = right (right a)
173+
n2 = left (right b)
174+
d2 = right (right b)
175+
num = dMinus (dTimes n1 d2) (dTimes n2 d1)
176+
den = dTimes d1 d2
177+
in fromRational num den
178+
, \a b ->
179+
let n1 = left (right a)
180+
d1 = right (right a)
181+
n2 = left (right b)
182+
d2 = right (right b)
183+
num = dTimes n1 d2
184+
den = dTimes d1 n2
185+
in fromRational num den
186+
]

app/Evaluare.hs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
{-# LANGUAGE RecursiveDo #-}
2+
13
module Main where
24

35
import Control.Comonad.Cofree (Cofree ((:<)))
@@ -164,16 +166,29 @@ nodify = removeExtraNumbers . fmap go . allNodes 0 where
164166
loadModules :: [String] -> IO [(String, [Either AnnotatedUPT (String, AnnotatedUPT)])]
165167
loadModules filenames = do
166168
filesStrings :: [String] <- mapM Strict.readFile filenames
167-
case sequence $ parseModule <$> filesStrings of
169+
case mapM parseModule filesStrings of
168170
Right p -> pure $ zip filesStrings p
169171
Left pe -> error pe
170172

173+
mainWidgetInit
174+
:: (forall t m.
175+
( MonadVtyApp t m
176+
, HasImageWriter t m
177+
, MonadNodeId m
178+
, HasDisplayRegion t m
179+
, HasFocusReader t m
180+
, HasTheme t m
181+
, HasInput t m
182+
) => Layout t (Focus t m) (Event t ()))
183+
-> IO ()
184+
mainWidgetInit w = mainWidget (initManager_ w)
185+
171186
main :: IO ()
172187
main = do
173188
modules :: [(String, [Either AnnotatedUPT (String, AnnotatedUPT)])] <- getArgs >>= loadModules
174189
let go :: Text -> IO ()
175190
go textErr =
176-
mainWidget $ initManager_ $ do
191+
mainWidgetInit $ do
177192
let cfg = def
178193
{ _textInputConfig_initialValue = TZ.fromText . T.pack . unlines $
179194
[ "-- Example:"
@@ -185,14 +200,14 @@ main = do
185200
escOrCtrlcQuit :: (Monad m, HasInput t m, Reflex t) => m (Event t ())
186201
escOrCtrlcQuit = do
187202
inp <- input
188-
pure $ fforMaybe inp $ \case
203+
pure . fforMaybe inp $ \case
189204
V.EvKey (V.KChar 'c') [V.MCtrl] -> Just ()
190205
V.EvKey V.KEsc [] -> Just ()
191206
_ -> Nothing
192207
getout <- escOrCtrlcQuit
193208
tile flex . box (pure roundedBoxStyle) . row $ do
194209
rec
195-
eEitherIExpr :: Event t (Either String IExpr) <- grout flex $ col $ do
210+
eEitherIExpr :: Event t (Either String IExpr) <- grout flex . col $ do
196211
telomareTextInput :: TextInput t <- grout flex textBox
197212
pure . updated $ TE.eval2IExpr modules . T.unpack <$> _textInput_value telomareTextInput
198213
grout (fixed 2) . col . text $ ""

app/Main.hs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
module Main where
44

5+
import Data.Maybe (mapMaybe)
56
import qualified Options.Applicative as O
6-
import System.Directory (listDirectory)
7-
import System.FilePath (takeBaseName, takeExtension)
8-
import qualified System.IO.Strict as Strict
7+
import System.FilePath (takeBaseName)
98
import Telomare.Eval (runMain)
109

1110
newtype TelomareOpts
@@ -16,21 +15,34 @@ telomareOpts :: O.Parser TelomareOpts
1615
telomareOpts = TelomareOpts
1716
<$> O.argument O.str (O.metavar "TELOMARE-FILE")
1817

19-
getAllModules :: IO [(String, String)]
20-
getAllModules = do
21-
allEntries <- listDirectory "."
22-
let telFiles = filter (\f -> takeExtension f == ".tel") allEntries
23-
readTelFile :: FilePath -> IO (String, String)
24-
readTelFile file = do
25-
content <- readFile file
26-
return (takeBaseName file, content)
27-
mapM readTelFile telFiles
18+
-- | Recursively load only the modules reachable from the entry file.
19+
getModulesFor :: String -> IO [(String, String)]
20+
getModulesFor entryModule = go [entryModule] []
21+
where
22+
go [] loaded = return loaded
23+
go (m:queue) loaded
24+
| m `elem` fmap fst loaded = go queue loaded
25+
| otherwise = do
26+
let filePath = m <> ".tel"
27+
content <- readFile filePath
28+
let imports = extractImports content
29+
go (queue <> imports) ((m, content) : loaded)
30+
31+
extractImports :: String -> [String]
32+
extractImports = mapMaybe parseImportLine . lines
33+
34+
parseImportLine :: String -> Maybe String
35+
parseImportLine line = case words line of
36+
("import":"qualified":name:_) -> Just name
37+
("import":name:_) -> Just name
38+
_ -> Nothing
2839

2940
main :: IO ()
3041
main = do
3142
let opts = O.info (telomareOpts O.<**> O.helper)
3243
( O.fullDesc
3344
<> O.progDesc "A simple but robust virtual machine" )
3445
topts <- O.execParser opts
35-
allModules :: [(String, String)] <- getAllModules
36-
runMain allModules . takeBaseName . telomareFile $ topts
46+
let entryModule = takeBaseName (telomareFile topts)
47+
allModules <- getModulesFor entryModule
48+
runMain allModules entryModule

examples.tel

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,38 @@
1+
import Prelude
2+
13
-- File for small illustrative telomare programs and for testing
24

35
-- Hello World example.
4-
aux = "Hello"
5-
-- main = \input -> (aux, 0)
6-
main = \input -> ("Hello", 0)
6+
-- aux = "Hello"
7+
-- -- main = \input -> (aux, 0)
8+
-- main = \input -> ("Hello", 0)
79

8-
-- -- refinement fail
10+
-- refinement fail
911
-- main : (\x -> if x then "fail" else 0) = 1
12+
-- main : (\x -> assert 1 "fail") = 1
13+
-- main : (\x -> assert (not (left x)) "fail") = 1
14+
15+
-- main : (\x -> assert (not x) "fail") = 1
1016

1117
-- Ad hoc user defined types example:
1218

13-
-- MyInt = let wrapper = \h -> ( \i -> if not i
14-
-- then abort "MyInt cannot be 0"
15-
-- else i
16-
-- , \i -> if dEqual (left i) h
17-
-- then 0
18-
-- else abort "Not a MyInt"
19-
-- )
20-
-- in wrapper (# wrapper)
21-
22-
-- aux = \x -> if dEqual x 8 then "Success" else "Failure"
23-
-- main = \i -> (aux ((left MyInt) 8), 0)
24-
25-
-- aux2 = [1,2,3]
26-
27-
-- something
28-
-- main =
29-
-- let toCase = (("a string", 99),(8,"pattern-match"))
30-
-- caseTest =
31-
-- case toCase of
32-
-- (0,(8,2)) -> "Failure 1"
33-
-- ("a string",(8,x)) -> concat [x, " failure 2"]
34-
-- (("a string", 99),(8,x)) -> concat [x, " success with ints, strings and variables"]
35-
-- in \input -> (caseTest, 0)
19+
-- Plain list assignments bind multiple names from a list-shaped value:
20+
-- [leftName, rightName] = ["left", "right"]
21+
-- [keep, drop] = \x -> [\_ -> x, \z -> z]
22+
23+
[MyInt, mkMyInt, unMyInt] = \h ->
24+
[ \i -> if not i
25+
then abort "MyInt cannot be 0"
26+
else (h, i)
27+
, \(i : MyInt) -> i
28+
]
29+
30+
aux = \x -> if dEqual x 8 then "Success" else "Failure"
31+
main = \i -> (aux (unMyInt (mkMyInt 8)), 0)
32+
33+
-- User-defined type example used by the test suite:
34+
-- [Nat, toNat, nPlus, nMinus] = \h ->
35+
-- [ \x -> (h, x)
36+
-- , \(aa : Nat) (bb : Nat) -> (h, d2c aa succ bb)
37+
-- , \(aa : Nat) (bb : Nat) -> ...
38+
-- ]

0 commit comments

Comments
 (0)