Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clox chapter14 #8

Open
wants to merge 111 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
66c3e20
Branch Commit
gdevanla Sep 19, 2021
29fc9ed
Parse functions
gdevanla Sep 19, 2021
b639351
Prep for function application
gdevanla Sep 20, 2021
b68fdf9
Add Func declaration support
gdevanla Sep 20, 2021
0ea306d
Add basic tests for FuncDecl
gdevanla Sep 20, 2021
973dfc4
Progress invoking custom function
gdevanla Sep 20, 2021
64373ce
Implement function invocation
gdevanla Sep 20, 2021
a2f1092
Use camelCase
gdevanla Sep 20, 2021
c97c124
Support return statement parsing
gdevanla Sep 20, 2021
2937c96
Comment on redundant exe builds
gdevanla Sep 20, 2021
23b6d82
add semi for return statements
gdevanla Sep 20, 2021
c91a766
Cleaup up and debug statements to support returns
gdevanla Sep 20, 2021
edf1025
Implement closures
gdevanla Sep 21, 2021
7f869f5
Making things strict - trying to improve performance
gdevanla Sep 21, 2021
002f050
Strict bombing!
gdevanla Sep 21, 2021
3c15cd2
trying out some optimization switches
gdevanla Sep 21, 2021
35a9a79
Different attempts at optimization
gdevanla Oct 3, 2021
3070b7f
add sample lox file
gdevanla Oct 3, 2021
5db7a3a
Add clox to package
gdevanla Oct 3, 2021
2f30abe
Toy Pratt parser
gdevanla Oct 6, 2021
30c9f73
Add end token
gdevanla Oct 6, 2021
a59589a
Add prefix minus
gdevanla Oct 6, 2021
81d0c0d
Add Exp
gdevanla Oct 6, 2021
d9ce537
Add Paren support
gdevanla Oct 6, 2021
4c944c5
Add a little scanner for demo
gdevanla Oct 6, 2021
678fbaf
Tie up toy parser with Pratt parser
gdevanla Oct 6, 2021
1c19b22
Remove redundant check
gdevanla Oct 6, 2021
f5f22b0
Progress print and generate byte code for simple expressions
gdevanla Oct 6, 2021
11adeff
Code cleanup
gdevanla Oct 6, 2021
980c3e5
Set up skeleton for VM
gdevanla Oct 7, 2021
3b55f13
Add negate operation
gdevanla Oct 7, 2021
1119409
Add all binary operators
gdevanla Oct 7, 2021
0a52c64
Making pratt parser work with LoxTokInfo
gdevanla Oct 8, 2021
20632ab
Add debug mode to VM
gdevanla Oct 8, 2021
56db7cc
Add tests for compiler
gdevanla Oct 8, 2021
1063fef
Add initial tests for vm
gdevanla Oct 8, 2021
7c3afe2
Add test files
gdevanla Oct 8, 2021
ac765cf
add app
gdevanla Oct 8, 2021
10c602e
Wrap the compiler inside a Parsec for extending it.
gdevanla Oct 10, 2021
e205c62
Update tests
gdevanla Oct 10, 2021
b06479e
Use the AST parser to build byte code
gdevanla Oct 11, 2021
a94f5ec
Use the AST parser to build byte code
gdevanla Oct 11, 2021
1a37149
Add custom opcode for boolean and nil
gdevanla Oct 12, 2021
51a15d8
Impelement types-of-values as of Chapter 18
gdevanla Oct 12, 2021
da1b527
Add tests for comparison operators
gdevanla Oct 12, 2021
5c88d81
Add opcode support to store Strings
gdevanla Oct 12, 2021
44c3216
Impelement print statement
gdevanla Oct 12, 2021
689d23a
Assignemnt statements
gdevanla Oct 12, 2021
1cc8c0e
Locals work!
gdevanla Oct 13, 2021
fdebe51
Locals work!
gdevanla Oct 13, 2021
b76c1a6
Handling nil is assignment, refine tests
gdevanla Oct 13, 2021
c8703b3
Remove commented code
gdevanla Oct 13, 2021
1a3aa73
Improve tests
gdevanla Oct 13, 2021
a683c77
Remove TODOs
gdevanla Oct 13, 2021
35861d7
Implement if/else
gdevanla Oct 14, 2021
3fef566
Adjust offst calculation for if-else
gdevanla Oct 16, 2021
95eff29
Fixing proper cleanup for if statements
gdevanla Oct 17, 2021
033f44c
Implement while loop
gdevanla Oct 17, 2021
3b996c4
Add more tests for while
gdevanla Oct 17, 2021
9c2be51
Add func object
gdevanla Oct 17, 2021
e06f646
Merge branch 'functions' into clox-chapter14
gdevanla Oct 17, 2021
d274a4f
Minor adjustments
gdevanla Oct 17, 2021
ae657d1
Move outer script into a CallFrame
gdevanla Oct 17, 2021
4887a66
Progress adding function to globals
gdevanla Oct 18, 2021
8ed30eb
Add stack clean up operations before exiting function
gdevanla Oct 18, 2021
a8619df
Better implementation of Function declaration
gdevanla Oct 18, 2021
fdbb1e8
Support functions, parameters/arguments setup
gdevanla Oct 21, 2021
e3dfdd0
Working function implementation
gdevanla Oct 21, 2021
6be8de1
Update tests
gdevanla Oct 21, 2021
c6479f5
Fixing issues with nested function calls
gdevanla Oct 22, 2021
810b2d7
Add tests
gdevanla Oct 22, 2021
dcd5441
Fixing nested functions
gdevanla Oct 22, 2021
2b433d3
Fixing nested functions
gdevanla Oct 22, 2021
ef39233
Switch to Data.Seq
gdevanla Oct 22, 2021
3957bb7
Switch to Data.Seq continued
gdevanla Oct 23, 2021
2fdd9b5
Use Seq.length
gdevanla Oct 23, 2021
1e3cac4
Move around code
gdevanla Oct 23, 2021
e4ced43
Python version of fib
gdevanla Oct 23, 2021
93b2c32
Add test files
gdevanla Oct 25, 2021
783d7c9
Linting and GHC upgrade
gdevanla Nov 3, 2021
b007513
Clean up and additions
gdevanla Nov 3, 2021
cba829f
Add lisp parser
gdevanla Nov 3, 2021
e113dfd
Linting updates
gdevanla Nov 3, 2021
cd711ea
Implement basic printing of s-exp
gdevanla Nov 4, 2021
5f17072
Add support for IfExpr
gdevanla Nov 4, 2021
1d22152
Add tests for lisp parser
gdevanla Nov 4, 2021
b0176c4
Add tests for printing
gdevanla Nov 4, 2021
1d6af1e
Linting updates
gdevanla Nov 4, 2021
684ff5f
Support Prim operations
gdevanla Nov 7, 2021
365e39f
Setup print for Prim ops
gdevanla Nov 7, 2021
4b07102
Initial version of interpreter with test setup
gdevanla Nov 8, 2021
8091793
Support if expression, fix prim apply
gdevanla Nov 8, 2021
c8ba140
Add cmp and boolean cmp primitives
gdevanla Nov 9, 2021
40419fa
Complet function set up and function application. Complete let expr
gdevanla Nov 10, 2021
ec83f83
Add tests for function application
gdevanla Nov 11, 2021
0f24f29
Parser LetRec
gdevanla Nov 11, 2021
be07dc2
Add fib prog in tests
gdevanla Nov 11, 2021
ae3c46e
Add fib prog in tests
gdevanla Nov 11, 2021
4e9207d
Update test expectation
gdevanla Nov 11, 2021
7dcf9f4
Prepare for implementing interpreter as CPS
gdevanla Nov 12, 2021
4ab7ead
Progress on CPS interpreter
gdevanla Nov 12, 2021
73bde5e
Implement evalRands in CPS style
gdevanla Nov 12, 2021
6f1dede
Setup CPS for comparison operators
gdevanla Nov 12, 2021
4a30de1
Fully implemented CPS version of interpreter
gdevanla Nov 12, 2021
29003f0
Parse Try/Catch/Raise expressions
gdevanla Nov 12, 2021
10ecbbc
Fix test
gdevanla Nov 12, 2021
469e8d9
Add tests for try-catch.
gdevanla Nov 12, 2021
50a31df
Add tests for try-catch.
gdevanla Nov 12, 2021
f6b60fe
Cleanup
gdevanla Nov 12, 2021
4ac6ae1
Making Cont polymorphic
gdevanla Nov 12, 2021
554b0e6
Implement exception handling
gdevanla Nov 12, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Different attempts at optimization
gdevanla committed Oct 3, 2021

Unverified

This user has not yet uploaded their public signing key.
commit 35a9a79bfd70954eb8d238210a63f55f700e8ca7
98 changes: 70 additions & 28 deletions app/main.hs
Original file line number Diff line number Diff line change
@@ -1,30 +1,72 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE TemplateHaskell #-}
import Import
import Run
import RIO.Process
import Options.Applicative.Simple
import qualified Paths_haskell_lox
{-# LANGUAGE BangPatterns#-}

-- data RunningTotal = RunningTotal
-- { sum :: !Int
-- , count :: !Int
-- }

-- printAverage :: RunningTotal -> IO ()
-- printAverage (RunningTotal !sum !count)
-- | count == 0 = error "Need at least one value!"
-- | otherwise = print (fromIntegral sum / fromIntegral count :: Double)

-- -- | A fold would be nicer... we'll see that later
-- printListAverage :: [Int] -> IO ()
-- printListAverage =
-- go (RunningTotal 0 0)
-- where
-- go rt [] = printAverage rt
-- go (RunningTotal sum count) (x:xs) =
-- let
-- !sum' = sum + x
-- !count' = count + 1
-- rt = RunningTotal sum' count'
-- in go rt xs


-- data Foo = Foo Int
-- data Bar = Bar !Int
-- newtype Baz = Baz Int

-- main :: IO ()
-- main = do
-- putStrLn "inside main"
-- printListAverage [1..1000000]
-- Baz undefined `seq` putStrLn "Still alive!"

#!/usr/bin/env stack
-- stack --resolver lts-12.21 script

-- main :: IO ()
-- main =
-- let nums = [1..10000000 :: Int]
-- in print $ fromIntegral (sum nums) / fromIntegral (length nums)

main :: IO ()
main = do
(options, ()) <- simpleOptions
$(simpleVersion Paths_haskell_lox.version)
"Header for command line arguments"
"Program description, also for command line arguments"
(Options
<$> switch ( long "verbose"
<> short 'v'
<> help "Verbose output?"
)
)
empty
lo <- logOptionsHandle stderr (optionsVerbose options)
pc <- mkDefaultProcessContext
withLogFunc lo $ \lf ->
let app = App
{ appLogFunc = lf
, appProcessContext = pc
, appOptions = options
}
in runRIO app run
main =
let nums1 = [1 .. 10000000 :: Int]
nums2 = [1 .. 10000000 :: Int]
in print $ fromIntegral (sum nums1) / fromIntegral (length nums2)

-- main :: IO ()
-- main = do
-- (options, ()) <- simpleOptions
-- $(simpleVersion Paths_haskell_lox.version)
-- "Header for command line arguments"
-- "Program description, also for command line arguments"
-- (Options
-- <$> switch ( long "verbose"
-- <> short 'v'
-- <> help "Verbose output?"
-- )
-- )
-- empty
-- lo <- logOptionsHandle stderr (optionsVerbose options)
-- pc <- mkDefaultProcessContext
-- withLogFunc lo $ \lf ->
-- let app = App
-- { appLogFunc = lf
-- , appProcessContext = pc
-- , appOptions = options
-- }
-- in runRIO app run
27 changes: 14 additions & 13 deletions package.yaml
Original file line number Diff line number Diff line change
@@ -81,25 +81,26 @@ executables:
- optparse-simple

ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
#- -rtsopts
- -O2
- -funfolding-use-threshold=16
- -fexcess-precision
- -optc-ffast-math
- -fprof-auto
#- -threaded
#- -with-rtsopts=-N

# haskell-lox-exe:
# main: main.hs
# source-dirs: app
# dependencies:
# - haskell-lox
# - optparse-simple
haskell-lox-exe:
main: main.hs
source-dirs: app
dependencies:
- haskell-lox
- optparse-simple

# ghc-options:
# - -threaded
# - -rtsopts
# - -with-rtsopts=-N
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N

tests:
haskell-lox-test-1:
28 changes: 20 additions & 8 deletions src/ExprInterpreter.hs
Original file line number Diff line number Diff line change
@@ -31,19 +31,20 @@ data LoxError = SystemError !T.Text | ControlFlow !LoxValue deriving (Show, Eq)
-- https://www.seas.upenn.edu/~cis552/13fa/lectures/FunEnv.html
data LoxValue
= LoxValueString !T.Text
| LoxValueDouble !Double
| LoxValueDouble {-# UNPACK #-} !Double
| LoxValueNil
| LoxValueBool !Bool
| LoxValueBool {-# UNPACK #-}!Bool
| LoxValueIdentifier !T.Text
| LoxValueSentinel -- This is more for the interpreter to return from statements
| LoxValueReturn !LoxValue
| LoxValueReturn {-# UNPACK #-}!LoxValue
| LoxValueFunction !T.Text [T.Text] [Declaration] !Env -- Hold on to the AST and Closure
deriving (Show, Eq)

isTruthy :: LoxValue -> Bool
isTruthy LoxValueNil = False
isTruthy (LoxValueBool !x) = x
isTruthy _ = True
--{-# INLINE isTruthy #-}

-- type Env = M.Map T.Text LoxValue

@@ -55,6 +56,7 @@ data Env = Env {

initEnv :: Maybe Env -> Env
initEnv !parent = Env {env=M.empty, parent=parent}
--{-# INLINE initEnv #-}

lookupEnv :: T.Text -> Env -> Maybe LoxValue
lookupEnv !k !environ = go (Just environ)
@@ -63,6 +65,7 @@ lookupEnv !k !environ = go (Just environ)
Just v -> Just $! v
Nothing -> go parent
go Nothing = Nothing
--{-# INLINE lookupEnv #-}

updateEnv :: T.Text -> LoxValue -> Env -> Maybe Env
updateEnv !k !v !s = go (Just $! s)
@@ -76,14 +79,15 @@ updateEnv !k !v !s = go (Just $! s)

insertEnv :: T.Text -> LoxValue -> Env -> Env
insertEnv !k !v s@Env {..} = s {env = M.insert k v env}
--{-# INLINE insertEnv #-}

multiInsertEnv :: [(T.Text, LoxValue)] -> Env -> Env
multiInsertEnv !values s@Env {..} = let
new_env = M.fromList values
!new_env' = M.union new_env env
in
s {env=new_env'}

-- {-# INLINE multiInsertEnv #-}

showLoxValue :: LoxValue -> String
showLoxValue (LoxValueString t) = show t
@@ -101,6 +105,7 @@ unpackIdent (LoxValueIdentifier x) = do
Just v' -> lift . return $ v'
Nothing -> ExceptT . return $ Left $ SystemError $ "Unknown var: " <> x
unpackIdent x = lift . return $ x
--{-# INLINE unpackIdent #-}

type InterpreterTIO = ExceptT LoxError (StateT Env IO) LoxValue

@@ -116,6 +121,8 @@ applyOpToDouble !x !y !bop _ = ExceptT . return $ Left $ SystemError value
++ show x
++ " and "
++ show y
--{-# INLINE applyOpToDouble #-}

applyCompOpToDouble :: LoxValue -> LoxValue -> BinOp -> (Double -> Double -> Bool) -> InterpreterTIO
applyCompOpToDouble (LoxValueDouble !x) (LoxValueDouble !y) bop op = lift . return $ LoxValueBool $ op x y
applyCompOpToDouble !x !y !bop _ = ExceptT . return $ Left $ SystemError value
@@ -128,6 +135,7 @@ applyCompOpToDouble !x !y !bop _ = ExceptT . return $ Left $ SystemError value
++ show x
++ " and "
++ show y
--{-# INLINE applyCompOpToDouble #-}

interpret :: Expr -> InterpreterTIO
interpret (Number !x) = lift $ return $ LoxValueDouble x
@@ -205,9 +213,9 @@ interpret (Call !expr !arguments _) = do
LoxValueFunction !func_name !params !block !closure -> do
let !pa = L.zip params args
--liftIO $ putStrLn $ show s'
let s = multiInsertEnv pa (initEnv (Just closure))
let !s = multiInsertEnv pa (initEnv (Just closure))
-- we need to insert this back here to resolve circular dependency
let s' = insertEnv func_name (LoxValueFunction func_name params block closure) s
let !s' = insertEnv func_name (LoxValueFunction func_name params block closure) s
put $! s'
!value <- catchError (interpretProgram block) f
put orig
@@ -217,6 +225,7 @@ interpret (Call !expr !arguments _) = do
f (SystemError e) = ExceptT . return . Left $ SystemError e
f (ControlFlow (LoxValueReturn e)) = return e
f (ControlFlow v) = ExceptT . return . Left $ SystemError $ "Unknown handler:" <> T.pack (show v)
--{-# INLINE interpret #-}

interpretStmt :: Statement -> InterpreterTIO
interpretStmt (StmtExpr expr) = do
@@ -267,6 +276,8 @@ interpretStmt (StmtReturn (Just !expr)) = do
return $ LoxValueReturn result
interpretStmt (StmtReturn Nothing) = return $ LoxValueReturn $ LoxValueDouble 9999.0

-- {-# INLINE interpretStmt #-}

-- interpretDeclaration :: Declaration -> Env -> IO (Env, Maybe T.Text)
interpretDeclaration :: Declaration -> InterpreterTIO
interpretDeclaration (DeclVar (Decl !var (Just !expr))) = do
@@ -285,10 +296,11 @@ interpretDeclaration (DeclStatement !stmt) = interpretStmt stmt

interpretDeclaration (DeclFun (Func !func_name !params !block)) = do
closure <- get
let func = LoxValueFunction func_name params block closure
let closure' = insertEnv func_name func closure -- capture the closure, add back func later on
let !func = LoxValueFunction func_name params block closure
let !closure' = insertEnv func_name func closure -- capture the closure, add back func later on
put closure'
return LoxValueSentinel
--{-# INLINE interpretDeclaration #-}

interpretProgram :: Program -> InterpreterTIO
interpretProgram = go