Work on usable codegen
- escape js names - executable output - better FC in parsing - experiment with IO
This commit is contained in:
2
TODO.md
2
TODO.md
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
I may be done with `U` - I keep typing `Type`.
|
I may be done with `U` - I keep typing `Type`.
|
||||||
|
|
||||||
|
- [ ] Sanitize JS idents, e.g. `_+_`
|
||||||
- [ ] Generate some programs that do stuff
|
- [ ] Generate some programs that do stuff
|
||||||
- [x] import
|
- [x] import
|
||||||
- [ ] consider making meta application implicit in term, so its more readable when printed
|
- [ ] consider making meta application implicit in term, so its more readable when printed
|
||||||
@@ -48,6 +49,7 @@ I may be done with `U` - I keep typing `Type`.
|
|||||||
- [ ] magic tuple? (codegen as array)
|
- [ ] magic tuple? (codegen as array)
|
||||||
- [ ] magic newtype? (drop in codegen)
|
- [ ] magic newtype? (drop in codegen)
|
||||||
- [ ] records / copatterns
|
- [ ] records / copatterns
|
||||||
|
- [ ] vscode: syntax highlighting for String
|
||||||
|
|
||||||
- [ ] Read Ulf Norell thesis
|
- [ ] Read Ulf Norell thesis
|
||||||
|
|
||||||
|
|||||||
30
newt/IO.newt
Normal file
30
newt/IO.newt
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
module IO
|
||||||
|
|
||||||
|
import Prelude
|
||||||
|
|
||||||
|
data Foo : U where
|
||||||
|
MkFoo : Nat -> Nat -> Foo
|
||||||
|
|
||||||
|
data World : U where
|
||||||
|
|
||||||
|
data IORes : U -> U where
|
||||||
|
MkIORes : {a : U} -> a -> World -> IORes a
|
||||||
|
|
||||||
|
IO : U -> U
|
||||||
|
IO a = World -> IORes a
|
||||||
|
|
||||||
|
iobind : {a b : U} -> IO a -> (a -> IO b) -> IO b
|
||||||
|
iobind ma mab w = case ma w of
|
||||||
|
(MkIORes a w) => mab a w
|
||||||
|
|
||||||
|
_>>=_ : {a b : U} -> IO a -> (a -> IO b) -> IO b
|
||||||
|
_>>=_ = iobind
|
||||||
|
|
||||||
|
infixr 2 _>>=_
|
||||||
|
infixr 2 _>>_
|
||||||
|
|
||||||
|
-- FIXME - bad parse error for lambda without the parens
|
||||||
|
|
||||||
|
_>>_ : {a b : U} -> IO a -> IO b -> IO b
|
||||||
|
_>>_ ma mb = ma >>= (\ _ => mb)
|
||||||
|
|
||||||
17
newt/JSLib.newt
Normal file
17
newt/JSLib.newt
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
module JSLib
|
||||||
|
|
||||||
|
ptype Int
|
||||||
|
ptype String
|
||||||
|
|
||||||
|
infixl 4 _+_
|
||||||
|
infixl 5 _*_
|
||||||
|
|
||||||
|
pfunc _+_ : Int -> Int -> Int := "(x,y) => x + y"
|
||||||
|
pfunc _*_ : Int -> Int -> Int := "(x,y) => x * y"
|
||||||
|
|
||||||
|
ptype JVoid
|
||||||
|
|
||||||
|
-- REVIEW - maybe we only have body, use names from the pi-type and generate
|
||||||
|
-- the arrow (or inline?) ourselves
|
||||||
|
pfunc log : String -> JVoid := "x => console.log(x)"
|
||||||
|
pfunc debug : {a : U} -> String -> a -> JVoid := "(_,x,a) => console.log(x,a)"
|
||||||
22
newt/Prelude.newt
Normal file
22
newt/Prelude.newt
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
module Prelude
|
||||||
|
|
||||||
|
data Nat : U where
|
||||||
|
Z : Nat
|
||||||
|
S : Nat -> Nat
|
||||||
|
|
||||||
|
data Maybe : U -> U where
|
||||||
|
Just : {a : U} -> a -> Maybe a
|
||||||
|
Nothing : {a : U} -> Maybe a
|
||||||
|
|
||||||
|
data Either : U -> U -> U where
|
||||||
|
Left : {a b : U} -> a -> Either a b
|
||||||
|
Right : {a b : U} -> b -> Either a b
|
||||||
|
|
||||||
|
-- TODO this is special cased in some languages, maybe for easier
|
||||||
|
-- inference? Figure out why.
|
||||||
|
|
||||||
|
infixr 0 _$_
|
||||||
|
|
||||||
|
_$_ : {a b : U} -> (a -> b) -> a -> b
|
||||||
|
f $ a = f a
|
||||||
|
|
||||||
@@ -11,6 +11,8 @@ import Lib.Types
|
|||||||
import Lib.Prettier
|
import Lib.Prettier
|
||||||
import Lib.CompileExp
|
import Lib.CompileExp
|
||||||
import Data.String
|
import Data.String
|
||||||
|
import Data.Maybe
|
||||||
|
import Data.Nat
|
||||||
|
|
||||||
data Kind = Plain | Return | Assign String
|
data Kind = Plain | Return | Assign String
|
||||||
|
|
||||||
@@ -136,9 +138,30 @@ termToJS env (CCase t alts) f =
|
|||||||
maybeCaseStmt nm alts = (JCase (Dot (Var nm) "tag") (map (termToJSAlt nm) alts))
|
maybeCaseStmt nm alts = (JCase (Dot (Var nm) "tag") (map (termToJSAlt nm) alts))
|
||||||
|
|
||||||
|
|
||||||
-- FIXME escape
|
-- REVIEW the escaping in show might not match JS
|
||||||
jsString : String -> Doc
|
jsString : String -> Doc
|
||||||
jsString str = text "\"\{str}\""
|
jsString str = text (show str)
|
||||||
|
|
||||||
|
||| escape identifiers for js
|
||||||
|
jsIdent : String -> Doc
|
||||||
|
jsIdent id = text $ pack $ fix (unpack id)
|
||||||
|
where
|
||||||
|
chars : List Char
|
||||||
|
chars = unpack "0123456789ABCDEF"
|
||||||
|
|
||||||
|
toHex : Nat -> List Char
|
||||||
|
toHex 0 = []
|
||||||
|
toHex v = snoc (toHex (div v 16)) (fromMaybe ' ' (getAt (mod v 16) chars))
|
||||||
|
|
||||||
|
fix : List Char -> List Char
|
||||||
|
fix [] = []
|
||||||
|
fix (x :: xs) =
|
||||||
|
if isAlphaNum x || x == '_' then
|
||||||
|
x :: fix xs
|
||||||
|
else if x == '$' then
|
||||||
|
'$' :: '$' :: fix xs
|
||||||
|
else
|
||||||
|
'$' :: (toHex (cast x)) ++ fix xs
|
||||||
|
|
||||||
stmtToDoc : JSStmt e -> Doc
|
stmtToDoc : JSStmt e -> Doc
|
||||||
|
|
||||||
@@ -153,17 +176,17 @@ expToDoc (LitObject xs) = text "{" <+> folddoc (\ a, e => a ++ ", " <+/> e) (map
|
|||||||
where
|
where
|
||||||
entry : (String, JSExp) -> Doc
|
entry : (String, JSExp) -> Doc
|
||||||
-- TODO quote if needed
|
-- TODO quote if needed
|
||||||
entry (nm, exp) = text nm ++ ":" <+> expToDoc exp
|
entry (nm, exp) = jsIdent nm ++ ":" <+> expToDoc exp
|
||||||
|
|
||||||
expToDoc (LitString str) = jsString str
|
expToDoc (LitString str) = jsString str
|
||||||
expToDoc (LitInt i) = text $ show i
|
expToDoc (LitInt i) = text $ show i
|
||||||
expToDoc (Apply x xs) = expToDoc x ++ "(" ++ commaSep (map expToDoc xs) ++ ")"
|
expToDoc (Apply x xs) = expToDoc x ++ "(" ++ commaSep (map expToDoc xs) ++ ")"
|
||||||
expToDoc (Var nm) = text nm
|
expToDoc (Var nm) = jsIdent nm
|
||||||
expToDoc (JLam nms (JReturn exp)) = text "(" <+> text (joinBy ", " nms) <+> ") =>" <+> "(" ++ expToDoc exp ++ ")"
|
expToDoc (JLam nms (JReturn exp)) = text "(" <+> commaSep (map jsIdent nms) <+> ") =>" <+> "(" ++ expToDoc exp ++ ")"
|
||||||
expToDoc (JLam nms body) = text "(" <+> text (joinBy ", " nms) <+> ") =>" <+> bracket "{" (stmtToDoc body) "}"
|
expToDoc (JLam nms body) = text "(" <+> commaSep (map jsIdent nms) <+> ") =>" <+> bracket "{" (stmtToDoc body) "}"
|
||||||
expToDoc JUndefined = text "undefined"
|
expToDoc JUndefined = text "undefined"
|
||||||
expToDoc (Index obj ix) = expToDoc obj ++ "[" ++ expToDoc ix ++ "]"
|
expToDoc (Index obj ix) = expToDoc obj ++ "[" ++ expToDoc ix ++ "]"
|
||||||
expToDoc (Dot obj nm) = expToDoc obj ++ "." ++ text nm
|
expToDoc (Dot obj nm) = expToDoc obj ++ "." ++ jsIdent nm
|
||||||
|
|
||||||
caseBody : JSStmt e -> Doc
|
caseBody : JSStmt e -> Doc
|
||||||
caseBody stmt@(JReturn x) = nest 2 (line ++ stmtToDoc stmt)
|
caseBody stmt@(JReturn x) = nest 2 (line ++ stmtToDoc stmt)
|
||||||
@@ -176,11 +199,11 @@ altToDoc (JDefAlt stmt) = text "default" ++ ":" ++ caseBody stmt
|
|||||||
stmtToDoc (JSnoc x y) = stmtToDoc x </> stmtToDoc y
|
stmtToDoc (JSnoc x y) = stmtToDoc x </> stmtToDoc y
|
||||||
stmtToDoc (JPlain x) = expToDoc x ++ ";"
|
stmtToDoc (JPlain x) = expToDoc x ++ ";"
|
||||||
-- I might not need these split yet.
|
-- I might not need these split yet.
|
||||||
stmtToDoc (JLet nm body) = "let" <+> text nm ++ ";" </> stmtToDoc body
|
stmtToDoc (JLet nm body) = "let" <+> jsIdent nm ++ ";" </> stmtToDoc body
|
||||||
stmtToDoc (JAssign nm expr) = text nm <+> "=" <+> expToDoc expr ++ ";"
|
stmtToDoc (JAssign nm expr) = jsIdent nm <+> "=" <+> expToDoc expr ++ ";"
|
||||||
stmtToDoc (JConst nm x) = text "const" <+> text nm <+> "=" <+/> expToDoc x ++ ";"
|
stmtToDoc (JConst nm x) = text "const" <+> jsIdent nm <+> "=" <+/> expToDoc x ++ ";"
|
||||||
stmtToDoc (JReturn x) = text "return" <+> expToDoc x ++ ";"
|
stmtToDoc (JReturn x) = text "return" <+> expToDoc x ++ ";"
|
||||||
stmtToDoc (JError str) = text "throw new Error(" ++ text str ++ ");"
|
stmtToDoc (JError str) = text "throw new Error(" ++ jsString str ++ ");"
|
||||||
stmtToDoc (JCase sc alts) =
|
stmtToDoc (JCase sc alts) =
|
||||||
text "switch (" ++ expToDoc sc ++ ")" <+> bracket "{" (stack $ map altToDoc alts) "}"
|
text "switch (" ++ expToDoc sc ++ ")" <+> bracket "{" (stack $ map altToDoc alts) "}"
|
||||||
|
|
||||||
@@ -204,12 +227,12 @@ entryToDoc (MkEntry name ty (Fn tm)) = do
|
|||||||
ct <- compileFun tm
|
ct <- compileFun tm
|
||||||
-- now show for ct...
|
-- now show for ct...
|
||||||
let body = stmtToDoc $ termToJS [] ct JPlain
|
let body = stmtToDoc $ termToJS [] ct JPlain
|
||||||
pure (text "const" <+> text name <+> text "=" <+/> body)
|
pure (text "const" <+> jsIdent name <+> text "=" <+/> body)
|
||||||
entryToDoc (MkEntry name type Axiom) = pure ""
|
entryToDoc (MkEntry name type Axiom) = pure ""
|
||||||
entryToDoc (MkEntry name type (TCon strs)) = pure $ dcon name (piArity type)
|
entryToDoc (MkEntry name type (TCon strs)) = pure $ dcon name (piArity type)
|
||||||
entryToDoc (MkEntry name type (DCon arity str)) = pure $ dcon name arity
|
entryToDoc (MkEntry name type (DCon arity str)) = pure $ dcon name arity
|
||||||
entryToDoc (MkEntry name type PrimTCon) = pure $ dcon name (piArity type)
|
entryToDoc (MkEntry name type PrimTCon) = pure $ dcon name (piArity type)
|
||||||
entryToDoc (MkEntry name _ (PrimFn src)) = pure $ text "const" <+> text name <+> "=" <+> text src
|
entryToDoc (MkEntry name _ (PrimFn src)) = pure $ text "const" <+> jsIdent name <+> "=" <+> text src
|
||||||
|
|
||||||
export
|
export
|
||||||
compile : M Doc
|
compile : M Doc
|
||||||
|
|||||||
@@ -68,8 +68,10 @@ atom = RU <$> getPos <* keyword "U"
|
|||||||
<|> parens typeExpr
|
<|> parens typeExpr
|
||||||
|
|
||||||
-- Argument to a Spine
|
-- Argument to a Spine
|
||||||
pArg : Parser (Icit,Raw)
|
pArg : Parser (Icit,FC,Raw)
|
||||||
pArg = (Explicit,) <$> atom <|> (Implicit,) <$> braces typeExpr
|
pArg = do
|
||||||
|
fc <- getPos
|
||||||
|
(Explicit,fc,) <$> atom <|> (Implicit,fc,) <$> braces typeExpr
|
||||||
|
|
||||||
|
|
||||||
-- starter pack, but we'll move some to prelude
|
-- starter pack, but we'll move some to prelude
|
||||||
@@ -84,10 +86,10 @@ pArg = (Explicit,) <$> atom <|> (Implicit,) <$> braces typeExpr
|
|||||||
|
|
||||||
parseApp : Parser Raw
|
parseApp : Parser Raw
|
||||||
parseApp = do
|
parseApp = do
|
||||||
|
fc <- getPos
|
||||||
hd <- atom
|
hd <- atom
|
||||||
rest <- many pArg
|
rest <- many pArg
|
||||||
fc <- getPos
|
pure $ foldl (\a, (icit,fc,b) => RApp fc a b icit) hd rest
|
||||||
pure $ foldl (\a, (c,b) => RApp fc a b c) hd rest
|
|
||||||
|
|
||||||
parseOp : Parser Raw
|
parseOp : Parser Raw
|
||||||
parseOp = parseApp >>= go 0
|
parseOp = parseApp >>= go 0
|
||||||
|
|||||||
@@ -46,8 +46,10 @@ dumpSource = do
|
|||||||
writeSource : String -> M ()
|
writeSource : String -> M ()
|
||||||
writeSource fn = do
|
writeSource fn = do
|
||||||
doc <- compile
|
doc <- compile
|
||||||
Right _ <- writeFile fn $ render 90 doc
|
let src = "#!/usr/bin/env node\n" ++ render 90 doc ++ "\nmain();"
|
||||||
|
Right _ <- writeFile fn src
|
||||||
| Left err => fail (show err)
|
| Left err => fail (show err)
|
||||||
|
Right _ <- chmodRaw fn 493 | Left err => fail (show err)
|
||||||
pure ()
|
pure ()
|
||||||
|
|
||||||
parseFile : String -> M (String,Module)
|
parseFile : String -> M (String,Module)
|
||||||
|
|||||||
Reference in New Issue
Block a user