Skip to content

Commit

Permalink
native: init
Browse files Browse the repository at this point in the history
  • Loading branch information
rockofox committed Aug 16, 2024
1 parent d8c87fc commit 4511f3d
Show file tree
Hide file tree
Showing 10 changed files with 277 additions and 38 deletions.
20 changes: 20 additions & 0 deletions examples/monads.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
trait Monad = do
bind :: Any -> Fn{Any => Any} -> Any
end

struct Maybe = (some: Any, none: Any)

impl Monad for Maybe = do
bind x f = do
f x.some
end
end

let call (x: Fn {Any => Any}) = x "test"

let nop (x: Any) = x

let main => IO = do
let bla = Maybe { some: "hello", none: "" }
bind bla, print
end
2 changes: 1 addition & 1 deletion examples/scratch.in
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@
# add :: Int -> Int -> Int
# add a b = a + b
# let main => IO = println add 3.0, 4.0
2+5
println 14 + 18 / 2 * 18 - 7
13 changes: 13 additions & 0 deletions examples/typematching.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
trait Person
trait Employee

struct Teacher = (name: String, age: Int) is Person, Employee
struct Student = (name: String, age: Int) is Person

let greet (t: Teacher) = "Hello, teacher " + t.name
let greet (s: Student) = "Hello, student " + s.name

let main => IO = do
println greet Teacher { name: "Alice", age: 30 }
println greet Student { name: "Bob", age: 20 }
end
9 changes: 7 additions & 2 deletions indigo.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ library
, RegInst
, Ffi
, Optimizer
, QBE
other-modules: Paths_indigo
build-depends: base,
containers,
Expand All @@ -49,7 +50,10 @@ library
monad-loops,
executable-path,
filepath,
random
random,
qbe,
prettyprinter,
text-short
if flag(ffi)
build-depends:
libffi,
Expand Down Expand Up @@ -98,14 +102,15 @@ test-suite spec
type: exitcode-stdio-1.0
main-is: Spec.hs
hs-source-dirs: tests
build-depends: base, hspec, hspec-contrib, QuickCheck, HUnit, indigo, generic-arbitrary, text, vector, megaparsec, mtl, raw-strings-qq, hspec-megaparsec
build-depends: base, hspec, hspec-contrib, QuickCheck, HUnit, indigo, generic-arbitrary, text, vector, megaparsec, mtl, raw-strings-qq, hspec-megaparsec, qbe, prettyprinter, text-short, process
other-modules:
ParserSpec
BytecodeCompilerSpec
IntegrationSpec
VerifierSpec
RegInstSpec
OptimizerSpec
QBESpec
build-tool-depends: hspec-discover:hspec-discover == 2.*
default-language: Haskell2010
default-extensions: OverloadedStrings, ImportQualifiedPost, QuasiQuotes, DisambiguateRecordFields, DuplicateRecordFields, OverloadedRecordDot
Expand Down
43 changes: 22 additions & 21 deletions lib/BytecodeCompiler.hs
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,13 @@ findSourceFile fileName = do
preludeFile :: IO String
preludeFile = findSourceFile "std/prelude.in" >>= readFile

doBinOp :: Parser.Expr -> Parser.Expr -> Instruction -> StateT (CompilerState a) IO [Instruction]
doBinOp :: Parser.Expr -> Parser.Expr -> [Instruction] -> StateT (CompilerState a) IO [Instruction]
doBinOp x y op = do
id' <- allocId
functions' <- gets functions
let f = findAnyFunction (Data.Text.unpack $ Data.Text.toLower $ Data.Text.pack $ show op) functions'
let aName = "__op_a_" ++ show id'
let bName = "__op_b_" ++ show id'
-- let aName = "__op_a_" ++ show id'
-- let bName = "__op_b_" ++ show id'
x' <- compileExpr x
y' <- compileExpr y

Expand All @@ -177,7 +177,8 @@ doBinOp x y op = do
(Parser.Placeholder, Parser.Placeholder) -> return [PushPf (funame $ fromJust f) 0]
(Parser.Placeholder, _) -> return $ y' ++ [PushPf (funame $ fromJust f) 1]
(_, Parser.Placeholder) -> return $ x' ++ [PushPf (funame $ fromJust f) 1]
_ -> return (x' ++ LStore aName : y' ++ [LStore bName, LLoad aName, LLoad bName] ++ cast ++ [op])
-- _ -> return (x' ++ LStore aName : y' ++ [LStore bName, LLoad aName, LLoad bName] ++ cast ++ [op])
_ -> return (x' ++ MovReg id' : y' ++ MovReg (id' + 1) : [PushReg id', PushReg (id' + 1)] ++ cast ++ op)

typeOf :: Parser.Expr -> StateT (CompilerState a) IO Parser.Type
typeOf (Parser.FuncCall funcName _ _) = do
Expand Down Expand Up @@ -228,24 +229,24 @@ typeToData (Parser.StructT "Char") = VM.DChar ' '
typeToData (Parser.StructT "CPtr") = VM.DCPtr 0
typeToData Parser.StructT{} = VM.DMap Data.Map.empty
typeToData Parser.Any = VM.DNone
typeToData x = error $ "Cannot convert type " ++ show x ++ " to data"
typeToData _ = VM.DNone

compileExpr :: Parser.Expr -> StateT (CompilerState a) IO [Instruction]
compileExpr (Parser.Add x y) = compileExpr (Parser.FuncCall "+" [x, y] zeroPosition) >>= doBinOp x y . last
compileExpr (Parser.Sub x y) = compileExpr (Parser.FuncCall "-" [x, y] zeroPosition) >>= doBinOp x y . last
compileExpr (Parser.Mul x y) = compileExpr (Parser.FuncCall "*" [x, y] zeroPosition) >>= doBinOp x y . last
compileExpr (Parser.Div x y) = compileExpr (Parser.FuncCall "/" [x, y] zeroPosition) >>= doBinOp x y . last
compileExpr (Parser.Modulo x y) = compileExpr (Parser.FuncCall "%" [x, y] zeroPosition) >>= doBinOp x y . last
compileExpr (Parser.Power x y) = compileExpr (Parser.FuncCall "^" [x, y] zeroPosition) >>= doBinOp x y . last
compileExpr (Parser.Gt x y) = compileExpr (Parser.FuncCall ">" [x, y] zeroPosition) >>= doBinOp x y . last
compileExpr (Parser.Lt x y) = compileExpr (Parser.FuncCall "<" [x, y] zeroPosition) >>= doBinOp x y . last
compileExpr (Parser.Ge x y) = compileExpr (Parser.FuncCall ">=" [x, y] zeroPosition) >>= doBinOp x y . last
compileExpr (Parser.Le x y) = compileExpr (Parser.FuncCall "<=" [x, y] zeroPosition) >>= doBinOp x y . last
compileExpr (Parser.Add x y) = compileExpr (Parser.FuncCall "+" [x, y] zeroPosition) >>= doBinOp x y
compileExpr (Parser.Sub x y) = compileExpr (Parser.FuncCall "-" [x, y] zeroPosition) >>= doBinOp x y
compileExpr (Parser.Mul x y) = compileExpr (Parser.FuncCall "*" [x, y] zeroPosition) >>= doBinOp x y
compileExpr (Parser.Div x y) = compileExpr (Parser.FuncCall "/" [x, y] zeroPosition) >>= doBinOp x y
compileExpr (Parser.Modulo x y) = compileExpr (Parser.FuncCall "%" [x, y] zeroPosition) >>= doBinOp x y
compileExpr (Parser.Power x y) = compileExpr (Parser.FuncCall "^" [x, y] zeroPosition) >>= doBinOp x y
compileExpr (Parser.Gt x y) = compileExpr (Parser.FuncCall ">" [x, y] zeroPosition) >>= doBinOp x y
compileExpr (Parser.Lt x y) = compileExpr (Parser.FuncCall "<" [x, y] zeroPosition) >>= doBinOp x y
compileExpr (Parser.Ge x y) = compileExpr (Parser.FuncCall ">=" [x, y] zeroPosition) >>= doBinOp x y
compileExpr (Parser.Le x y) = compileExpr (Parser.FuncCall "<=" [x, y] zeroPosition) >>= doBinOp x y
compileExpr (Parser.Not x) = compileExpr x >>= \x' -> return (x' ++ [Not])
compileExpr (Parser.Eq x y) = compileExpr (Parser.FuncCall "==" [x, y] zeroPosition) >>= doBinOp x y . last
compileExpr (Parser.Neq x y) = compileExpr (Parser.FuncCall "!=" [x, y] zeroPosition) >>= doBinOp x y . last
compileExpr (Parser.And x y) = compileExpr (Parser.FuncCall "&&" [x, y] zeroPosition) >>= doBinOp x y . last
compileExpr (Parser.Or x y) = compileExpr (Parser.FuncCall "||" [x, y] zeroPosition) >>= doBinOp x y . last
compileExpr (Parser.Eq x y) = compileExpr (Parser.FuncCall "==" [x, y] zeroPosition) >>= doBinOp x y
compileExpr (Parser.Neq x y) = compileExpr (Parser.FuncCall "!=" [x, y] zeroPosition) >>= doBinOp x y
compileExpr (Parser.And x y) = compileExpr (Parser.FuncCall "&&" [x, y] zeroPosition) >>= doBinOp x y
compileExpr (Parser.Or x y) = compileExpr (Parser.FuncCall "||" [x, y] zeroPosition) >>= doBinOp x y
compileExpr (Parser.IntLit x) = return [Push $ DInt $ fromIntegral x]
compileExpr (Parser.UnaryMinus (Parser.FloatLit x)) = return [Push $ DFloat (-x)]
compileExpr (Parser.UnaryMinus (Parser.IntLit x)) = return [Push $ DInt $ -fromInteger x]
Expand Down Expand Up @@ -306,7 +307,7 @@ compileExpr (Parser.FuncCall funcName args _) = do
case funcDec of
(Just fd) -> do
if length args == length (Parser.types fd) - 1
then concatMapM compileExpr args >>= \args' -> return (args' ++ [callWay])
then concatMapM compileExpr args >>= \args' -> return (args' ++ [PragmaMethodTypes (map typeToData argTypes)] ++ [callWay])
else
concatMapM compileExpr args >>= \args' ->
return $
Expand Down Expand Up @@ -338,7 +339,7 @@ compileExpr (Parser.FuncDef origName args body) = do
funcDecs'' <- gets funcDecs
args' <- concatMapM (`compileParameter` name) (reverse (filter (/= Parser.Placeholder) args))
let funcDec = fromJust $ find (\(Parser.FuncDec name' _ _) -> name' == name) funcDecs''
let function = Label funame : args' ++ body' ++ ([Ret | name /= "main"])
let function = Label funame : PragmaMethodTypes (map typeToData (init funcDec.types)) : args' ++ body' ++ ([Ret | name /= "main"]) -- TODO: Put in actual types
-- modify (\s -> s{functions = Function name funame function funcDec.types : tail (functions s)})
modify (\s -> s{functions = Function name funame function funcDec.types curCon : functions s})
modify (\s -> s{currentContext = previousContext})
Expand Down
93 changes: 93 additions & 0 deletions lib/QBE.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeApplications #-}

module QBE where

import Data.Either (partitionEithers)
import Data.List.NonEmpty
import Data.Text
import Data.Text.IO qualified as Text
import Data.Text.Lazy qualified as Text
import Data.Text.Short as ShortText
import Debug.Trace
import Language.QBE
import Prettyprinter
import Prettyprinter.Render.Text
import RegInst
import Text.Printf
import VM qualified

-- tempIdent :: [Char] -> Val
-- tempIdent str = ValTemporary (Ident @'Temporary $ ShortText.pack str)
--
-- compileRegInst :: RegInst -> Either [Inst] [Block]
-- compileRegInst (RegInst (VM.Add) [a,b]) = Left [BinaryOp (Assignment "v0" Word) Add (tempIdent ("r"++show a)) (tempIdent ("r"++show b))]
-- compileRegInst (RegInst (VM.Mov a b) _) = Left [BinaryOp (Assignment "v0" Word) Alloc4 ""]
-- compileRegInst x = error $ "Not implemented: " ++ show x
--
-- render :: Pretty a => a -> Text
-- render = renderStrict . layoutPretty defaultLayoutOptions . pretty
--
-- block :: Block
-- block = Block "start" [] [] (Ret Nothing)
--
--
-- test :: IO ()
-- test = Text.putStrLn $ render $ Program [] [] [FuncDef [] Nothing "main" Nothing [] NoVariadic (fromList [block])]
--
--
-- toQbe :: [VM.Instruction] -> Text
-- toQbe is = do
-- let (insts, blocks) = (partitionEithers (Prelude.map compileRegInst (toRegInst is)))
-- let (insts', blocks') = (Prelude.concat insts, Prelude.concat blocks)
-- render $ Program [] [] [FuncDef [] Nothing "main" Nothing [] NoVariadic (fromList blocks')]
--
--
--
convertLabelName :: String -> String
convertLabelName ('+' : xs) = "plus" ++ convertLabelName xs
convertLabelName ('#' : xs) = "_no_" ++ convertLabelName xs
convertLabelName (x : xs) = x : convertLabelName xs
convertLabelName [] = []

mkArgs :: (Show a) => [a] -> String
mkArgs [] = ""
mkArgs (x : xs) = "(" ++ show x ++ ")" ++ mkArgs xs

compileRegInst :: [RegInst] -> String
compileRegInst [] = ""
-- compileRegInst ((RegInst (VM.Label label) _):((RegInst (VM.PragmaMethodTypes types) _)):xs) = (if label == "main" then "export " else "") ++ "function w $" ++ convertLabelName label ++ "(w %a, w %b) {\n@start\n" ++ compileRegInst xs
-- compileRegInst ((RegInst (VM.Jmp label) _):xs)= "jmp @" ++ convertLabelName label ++ "\n"++ compileRegInst xs
-- compileRegInst ((RegInst (VM.Call label) _):xs)= "jmp @" ++ convertLabelName label ++ "\n"++ compileRegInst xs
-- compileRegInst ((RegInst VM.Ret _):xs)= "ret 0\n}\n"++ compileRegInst xs
-- compileRegInst ((RegInst VM.Exit _):xs)= "ret 0\n}\n"++ compileRegInst xs
-- compileRegInst ((RegInst (VM.Mov slot (VM.DInt value)) _):xs)= printf "%%v%d =d add d_0, d_%d\n" slot value ++ compileRegInst xs
-- compileRegInst ((RegInst VM.Add [a,b]):xs)= printf "%%v3 =l add %%v%d, %%v%d\n" a b++ compileRegInst xs
-- compileRegInst ((RegInst VM.Sub [a,b]):xs)= printf "%%v3 =l sub %%v%d, %%v%d\n" a b++ compileRegInst xs
-- compileRegInst x = error $ "Not implemented: " ++ show x

-- Compile to Javascript
compileRegInst ((RegInst (VM.Label label) _) : ((RegInst (VM.PragmaMethodTypes types) _)) : xs) = (if label == "main" then "" else "") ++ "function " ++ convertLabelName label ++ "() {\n" ++ compileRegInst xs
compileRegInst ((RegInst (VM.Jmp label) _) : xs) = printf "return %s()\n" (convertLabelName label) ++ compileRegInst xs
compileRegInst (((RegInst (VM.PragmaMethodTypes types) _)) : (RegInst (VM.Call label) args) : xs) = printf "%s%s\n" (convertLabelName label) (mkArgs $ Prelude.take (Prelude.length types) args) ++ compileRegInst xs
compileRegInst ((RegInst VM.Ret _) : xs) = "return \n}\n" ++ compileRegInst xs
compileRegInst ((RegInst VM.Exit _) : xs) = "return\n}\n" ++ compileRegInst xs
compileRegInst ((RegInst (VM.Mov slot (VM.DInt value)) _) : xs) = printf "v%d = %v\n" slot value ++ compileRegInst xs
compileRegInst ((RegInst VM.Add [a, b]) : xs) = printf "st = v%d + v%d\n" a b ++ compileRegInst xs
compileRegInst ((RegInst VM.Sub [a, b]) : xs) = printf "st = v%d - v%d\n" a b ++ compileRegInst xs
compileRegInst ((RegInst (VM.Builtin VM.Print) [a]) : xs) = printf "console.log(v%d)\n" a ++ compileRegInst xs
compileRegInst (x : xs) = compileRegInst xs

-- compileRegInst (RegInst (VM.Mov slot (VM.DInt value)) _) = printf "%%v%d =l alloc4 4\nstorew %d, %%v%d" slot value slot
-- compileRegInst (RegInst (VM.LStore name) _) = printf "%%v%s =l alloc4 4\nstorew %%v0, %%v%s" name name
-- compileRegInst (RegInst (VM.LLoad name) _) = printf "%%v0 =l loadw %%v%s" name
toQbe :: [VM.Instruction] -> [Char]
toQbe is =
-- "export function w $main() {\n@start\n" ++
-- Prelude.foldl (\acc x -> acc <> compileRegInst x <> "\n") "" (toRegInst is)
-- Prelude.foldl (\acc x -> acc <> compileRegInst x <> "\n") "" (toRegInst is)

-- Prelude.foldl (\acc x -> acc <> compileRegInst x <> "\n") "" (toRegInst is)
compileRegInst (toRegInst is) ++ "\nmain()"

-- ++ "\nret\n}\n"
35 changes: 33 additions & 2 deletions lib/RegInst.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
module RegInst where

import Control.Monad.State
import Data.List (find)
import Debug.Trace
import VM

data RegInst = RegInst Instruction [Int]
Expand All @@ -13,6 +15,7 @@ data RegCell = RegCell

data RegInstState = RegInstState
{ virtualStack :: [Int]
, localMapping :: [(Int, String)]
}
deriving (Eq, Show)

Expand All @@ -25,7 +28,13 @@ unstack (x : xs) n = do
unstack [] _ = return []

toRegInst :: [Instruction] -> [RegInst]
toRegInst is = evalState (toRegInst' is) (RegInstState [])
toRegInst is = evalState (toRegInst' is) (RegInstState [] [])

createLocalMapping :: String -> State RegInstState ()
createLocalMapping name = do
s <- get
let i = length (localMapping s) + length (virtualStack s)
put $ s{localMapping = (i, name) : localMapping s}

toRegInst' :: [Instruction] -> State RegInstState [RegInst]
toRegInst' [] = return []
Expand Down Expand Up @@ -54,10 +63,32 @@ toRegInst' (Swp : is) = do
toRegInst' (l@(Label _) : is) = do
rs <- toRegInst' is
return $ RegInst l [] : rs
-- Push a value out of a register onto the stack
toRegInst' (PushReg r : is) = do
modify $ \s -> s{virtualStack = r : virtualStack s}
toRegInst' is
-- Push a value out of a register onto the stack
toRegInst' (MovReg r : is) = do
modify $ \s -> s{virtualStack = drop 1 (r : virtualStack s)}
toRegInst' is
toRegInst' (LStore name : is) = do
createLocalMapping name
toRegInst' is
toRegInst' (LLoad name : is) = do
regForName <- gets (find (\(_, n) -> n == name) . localMapping)
case regForName of
Just (i, _) -> do
modify $ \s -> s{virtualStack = i : virtualStack s}
toRegInst' is
Nothing -> error $ "Variable " ++ name ++ " not found"
toRegInst' x@(Call _ : _) = unstack x 0
-- toRegInst' (l@Add : is) = do
-- virtualStack' <- gets virtualStack
-- modify $ \s -> s { virtualStack = drop 2 (virtualStack s) } -- TODO: !!!
-- rs <- toRegInst' is
-- return $ RegInst l virtualStack' : rs
toRegInst' x@(Add : _) = unstack x 2
toRegInst' _ = error "Not implemented"
toRegInst' x@(Builtin Print : _) = unstack x 1
toRegInst' (x : xs) = do
rs <- toRegInst' xs
return $ RegInst x [] : rs
Loading

0 comments on commit 4511f3d

Please sign in to comment.