Skip to content

Commit 9455ffb

Browse files
authored
Merge pull request #210 from argotorg/mbenke/sail-objects
Sail objects
2 parents c8fbefe + 7efc71d commit 9455ffb

File tree

10 files changed

+145
-80
lines changed

10 files changed

+145
-80
lines changed

src/Language/Core.hs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
{-# OPTIONS_GHC -Wincomplete-patterns #-}
33
{-# LANGUAGE InstanceSigs #-}
44
module Language.Core
5-
( Expr(..), Stmt(..), Arg(..), Alt(..), pattern ConAlt, Pat(..), Con(..), Contract(..), Core(..), Body
5+
( Expr(..), Stmt(..), Arg(..), Alt(..), pattern ConAlt, Pat(..), Con(..), Contract(..), Object(..), Body
66
, module Language.Core.Types
77
, pattern SAV
88
, Name
@@ -13,6 +13,8 @@ import Language.Core.Types
1313
import Language.Yul
1414

1515

16+
data Object = Object { objName :: Name, objCode :: Body, objInners :: [Object] }
17+
type Body = [Stmt]
1618
type Name = String
1719

1820
data Expr
@@ -47,7 +49,6 @@ data Stmt
4749
| SRevert String
4850
-- deriving Show
4951

50-
type Body = [Stmt]
5152
data Arg = TArg Name Type
5253
instance Show Arg where show = render . ppr
5354
instance Show Stmt where show :: Stmt -> String
@@ -67,6 +68,19 @@ newtype Core = Core [Stmt]
6768
instance Show Core where show = render . ppr
6869
instance Show Contract where show = render . ppr
6970

71+
72+
instance Pretty Object where
73+
ppr (Object name code inners) = vcat
74+
[ text "object" <+> ppr name <+> lbrace
75+
, nest 2 $ vcat
76+
[ text "code" <+> lbrace
77+
, nest 2 $ ppr code
78+
, rbrace
79+
]
80+
, nvlist inners
81+
, rbrace
82+
]
83+
7084
instance Pretty Contract where
7185
ppr (Contract n stmts) = text "contract" <+> text n <+> lbrace $$ nest 4 (vcat (map ppr stmts)) $$ rbrace
7286

@@ -139,6 +153,8 @@ instance Pretty Arg where
139153
instance Pretty Core where
140154
ppr (Core stmts) = vcat (map ppr stmts)
141155

156+
pprBody :: Body -> Doc
157+
pprBody stmts = braces $ nest 2 (vcat (map ppr stmts))
142158

143159
instance Pretty [Stmt] where
144160
ppr stmts = vcat (map ppr stmts)

src/Language/Core/Parser.hs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module Language.Core.Parser where
22
import Language.Core
3-
( Core(..), Contract(..), Body,
3+
( Object(..),
4+
Body,
45
Alt(..),
56
Pat(..),
67
Arg(..),
@@ -14,11 +15,9 @@ import Text.Megaparsec.Char.Lexer qualified as L
1415
import Control.Monad.Combinators.Expr
1516
import Language.Yul.Parser(yulBlock)
1617

17-
parseCore :: String -> Core
18-
parseCore = runMyParser "core" coreProgram
1918

20-
parseContract :: String -> String -> Contract
21-
parseContract filename = runMyParser filename coreContract
19+
parseObject :: String -> String -> Object
20+
parseObject filename = runMyParser filename coreObject
2221

2322
-- Note: this module repeats some definitions from YulParser.Name
2423
-- This is intentional as we may want to make different syntax choices
@@ -158,9 +157,9 @@ corePat = choice
158157
, PWildcard <$ pKeyword "_"
159158
]
160159

161-
coreProgram :: Parser Core
162-
coreProgram = sc *> (Core <$> many coreStmt) <* eof
160+
coreObject :: Parser Object
161+
coreObject = sc *> (Object <$> (pKeyword "object" *> identifier <* symbol "{")
162+
<*> coreCode <*> many coreObject) <* symbol "}"
163163

164-
coreContract :: Parser Contract
165-
coreContract = sc *> (Contract <$> (pKeyword "contract" *> identifier )
166-
<*> braces (many coreStmt)) <* eof
164+
coreCode :: Parser Body
165+
coreCode = sc *> (Object <$> pKeyword "code" *> coreBody)

src/Language/Yul.hs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,22 @@ data YLiteral
7070
| YulFalse
7171
deriving (Eq, Ord, Data, Typeable)
7272

73-
yulInt :: Integral i => i -> YulExp
74-
yulInt = YLit . YulNumber . fromIntegral
73+
yulIntegral :: Integral i => i -> YulExp
74+
yulIntegral = YLit . YulNumber . fromIntegral
75+
76+
yulInt :: Integer -> YulExp
77+
yulInt = YLit . YulNumber
7578

7679
yulBool :: Bool -> YulExp
7780
yulBool True = YLit YulTrue
7881
yulBool False = YLit YulFalse
7982

83+
yulString :: String -> YulExp
84+
yulString = YLit . YulString
8085

8186
-- auxilliary functions
8287

83-
hlist, vlist, nvlist :: Pretty a => [a] -> Doc
88+
hlist, vlist, nvlist, pprBlock :: Pretty a => [a] -> Doc
8489
hlist = hsep . map ppr
8590
vlist = vcat . map ppr
8691
nvlist = nest 2 . vlist

src/Solcore/Desugarer/EmitCore.hs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import Solcore.Primitives.Primitives
2121
import Solcore.Desugarer.Specialise(typeOfTcExp)
2222
import System.Exit
2323

24-
emitCore :: Bool -> TcEnv -> CompUnit Id -> IO [Core.Contract]
24+
emitCore :: Bool -> TcEnv -> CompUnit Id -> IO [Core.Object]
2525
emitCore debugp env cu = fmap concat $ runEM debugp env $ mapM emitTopDecl (contracts cu)
2626

2727
type EM a = StateT EcState IO a
@@ -103,7 +103,7 @@ type Translation a = EM (a, [Core.Stmt])
103103

104104
type CoreName = String
105105

106-
emitTopDecl :: TopDecl Id -> EM [Core.Contract]
106+
emitTopDecl :: TopDecl Id -> EM [Core.Object]
107107
emitTopDecl (TContr c) = fmap pure (emitContract c)
108108
emitTopDecl (TDataDef dt) = addData dt >> pure []
109109
emitTopDecl _ = pure []
@@ -116,14 +116,12 @@ buildTConInfo :: DataTy -> TConInfo
116116
buildTConInfo (DataTy n tvs dcs) = (tvs, map conInfo dcs) where
117117
conInfo (Constr n ts) = (n, ts)
118118
-}
119-
emitContract :: Contract Id -> EM Core.Contract
119+
emitContract :: Contract Id -> EM Core.Object
120120
emitContract c = do
121121
let cname = show (name c)
122122
writes ["Emitting core for contract ", cname]
123123
coreBody <- concatMapM emitCDecl (decls c)
124-
let result = Core.Contract cname coreBody
125-
-- writeln (show result)
126-
pure result
124+
pure(Core.Object cname coreBody [])
127125

128126
emitCDecl :: ContractDecl Id -> EM [Core.Stmt]
129127
emitCDecl cd@(CFunDecl f) = do

src/Solcore/Pipeline/SolcorePipeline.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pipeline = do
4747
writeFile filename (show c)
4848

4949
-- Version that returns Either for testing
50-
compile :: Option -> IO (Either String [Core.Contract])
50+
compile :: Option -> IO (Either String [Core.Object])
5151
compile opts = runExceptT $ do
5252
let verbose = optVerbose opts
5353
noDesugarCalls = optNoDesugarCalls opts

testsol.sh

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,22 @@ function esolc() {
55
cabal exec sol-core -- -f $file $*
66
}
77

8-
function testsol() {
8+
9+
function runsol() {
910
file=$1
1011
echo $file
1112
shift
1213
rm -f -v output1.core Output.sol
1314
/usr/bin/time -f "Compilation time: %E" cabal run sol-core -- -f $file $* && \
14-
cabal exec yule -- output1.core -w -O > /dev/null && \
15+
cabal exec yule -- output1.core -w -O --nodeploy > /dev/null && \
1516
forge script --via-ir Output.sol | egrep '(Gas|RESULT)'
1617
}
1718

18-
function testspec() {
19-
file=$1
20-
echo $file
21-
shift
22-
rm -f -v output1.core
23-
cabal exec sol-core -- -f $file --debug-spec --dump-spec $*
24-
# cabal run yule -- output1.core -O && \
25-
# forge script Output.sol
26-
}
27-
2819

29-
function testcore() {
20+
function runcore() {
3021
echo $1
3122
rm -f -v Output.sol
32-
cabal exec yule -- $1 -w -O && forge script --via-ir Output.sol | egrep '(Gas|RESULT)'
23+
cabal exec yule -- $1 -w --nodeploy -O && forge script --via-ir Output.sol | egrep '(Gas|RESULT)'
3324
}
3425

3526
function hevmcore() {
@@ -38,9 +29,9 @@ function hevmcore() {
3829
echo $yulfile
3930
local hexfile=$base.hex
4031
rm -f -v $yulfile $hexfile
41-
cabal exec yule -- $1 -o $yulfile
42-
solc --strict-assembly --bin --optimize $yulfile | tail -1 > $hexfile
43-
hevm exec --code $(cat $hexfile) | awk -f parse_hevm_output.awk
32+
cabal exec yule -- $1 --nodeploy -o $yulfile
33+
solc --strict-assembly --bin --optimize --optimize-yul $yulfile | tail -1 > $hexfile
34+
hevm exec --code-file $hexfile | awk -f parse_hevm_output.awk
4435
}
4536

4637
function hevmsol() {
@@ -53,8 +44,46 @@ function hevmsol() {
5344
echo Hex: $hexfile
5445
shift
5546
cabal exec sol-core -- -f $file $* && \
56-
cabal exec yule -- $core -O -o $yulfile && \
47+
cabal exec yule -- $core --nodeploy -O -o $yulfile && \
5748
solc --strict-assembly --bin --optimize $yulfile | tail -1 > $hexfile && \
58-
hevm exec --code $(cat $hexfile) | awk -f parse_hevm_output.awk
49+
hevm exec --code-file $hexfile | awk -f parse_hevm_output.awk
50+
51+
}
52+
53+
function deploysol() {
54+
file=$1
55+
shift
56+
echo "Solc: $file"
57+
local base=$(basename $1 .solc)
58+
local core=output1.core
59+
echo "Sail: $core"
60+
local yulfile=$base.yul
61+
echo "Yul: $yulfile"
62+
rm -f -v $yulfile
63+
cabal exec sol-core -- -f $file $* && \
64+
cabal exec yule -- $core -o $yulfile
65+
hex=$(solc --strict-assembly --bin --optimize --optimize-yul $yulfile | tail -1)
66+
rawtx=$(cast mktx --private-key=$PRIVATE_KEY --create $hex)
67+
addr=$(cast publish $rawtx | jq .contractAddress)
68+
echo $addr
69+
}
70+
71+
function deploycore() {
72+
local base=$(basename $1 .core)
73+
local yulfile=$base.yul
74+
echo $yulfile
75+
local hexfile=$base.hex
76+
rm -f -v $yulfile $hexfile
77+
cabal exec yule -- $1 -o $yulfile
78+
hex=$(solc --strict-assembly --bin --optimize --optimize-yul $yulfile | tail -1)
79+
rawtx=$(cast mktx --private-key=$PRIVATE_KEY --create $hex)
80+
addr=$(cast publish $rawtx | jq .contractAddress)
81+
echo $addr
82+
}
5983

84+
function sail() {
85+
local base=$(basename $1 .core)
86+
local yulfile=$base.yul
87+
rm -f -v $yulfile
88+
cabal exec yule -- $1 -o $yulfile
6089
}

yule/Builtins.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
{-# LANGUAGE OverloadedStrings #-}
2-
module Builtins(yulBuiltins) where
2+
module Builtins(yulBuiltins, revertStmt) where
33
import Data.String
44
import Language.Yul
55

6-
yulBuiltins :: Yul
7-
yulBuiltins = Yul []
6+
yulBuiltins :: [YulStmt]
7+
yulBuiltins = []
88

99
revertStmt :: String -> [YulStmt]
1010
revertStmt s = [ YExp $ YCall "mstore" [yulInt 0, YLit (YulString s)]
11-
, YExp $ YCall "revert" [yulInt 0, yulInt (length s)]
11+
, YExp $ YCall "revert" [yulInt 0, yulIntegral (length s)]
1212
]
1313

1414
{-

yule/Main.hs

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{-# LANGUAGE OverloadedStrings #-}
22
module Main where
3-
import Language.Core(Contract(..))
4-
import Language.Core.Parser(parseContract)
3+
import Language.Core(Object(..))
4+
import Language.Core.Parser(parseObject)
55
import Solcore.Frontend.Syntax.Name -- FIXME: move Name to Common
66
import Common.Pretty -- (Doc, Pretty(..), nest, render)
77
import Builtins(yulBuiltins)
@@ -21,54 +21,62 @@ main = do
2121
-- print options
2222
let filename = Options.input options
2323
src <- readFile filename
24-
let coreContract = parseContract filename src
25-
let core = ccStmts coreContract
26-
when (Options.verbose options) $ do
27-
putStrLn "/* Core:"
28-
putStrLn (render (nest 2 (ppr coreContract)))
29-
putStrLn "*/"
24+
let (Object name code inners) = parseObject filename src
3025
let oCompress = Options.compress options
31-
let source = if oCompress then compress core else core
3226
when oCompress $ do
3327
putStrLn "Compressing sums"
28+
let source = if oCompress then compress code else code
3429
generatedYul <- runTM options (translateStmts source)
35-
let name = fromString (ccName coreContract)
36-
30+
let withDeployment = not (Options.runOnce options)
3731
let doc = if Options.wrap options
38-
then wrapInSol name generatedYul
39-
else wrapInObject name generatedYul
32+
then wrapInSol (Name name) generatedYul
33+
else wrapInObject (Name name) withDeployment generatedYul
4034
putStrLn ("writing output to " ++ Options.output options)
4135
writeFile (Options.output options) (render doc)
4236

4337
-- wrap in a Yul object with the given name
44-
wrapInObject :: Name -> Yul -> Doc
45-
wrapInObject name yul = ppr object where
46-
object = YulObject (show name) (YulCode stmts) []
47-
stmts = yulStmts yul ++ retcode
38+
wrapInObject :: Name -> Bool -> [YulStmt] -> Doc
39+
wrapInObject name deploy yul
40+
| deploy = ppr nested
41+
| otherwise = ppr runtime
42+
where
43+
nested = YulObject "Deployable" deploycode [InnerObject runtime]
44+
runtime = YulObject (show name) (YulCode stmts) []
45+
cname = yulString (show name)
46+
stmts = yul ++ retcode
4847
retcode =
49-
[ call "mstore" [yulInt (0::Integer), YIdent "_mainresult"]
50-
, call "return" [yulInt (0::Integer), yulInt (32::Integer)]
48+
[ calls "mstore" [yulInt 0, YIdent "_mainresult"]
49+
, calls "return" [yulInt 0, yulInt 32]
50+
]
51+
deploycode = YulCode
52+
[ calls "mstore" [yulInt 64, YCall "memoryguard" [yulInt 128]]
53+
, ylva "memPtr" (YCall "mload" [yulInt 64])
54+
-- call constructor here
55+
, calls "datacopy" [yulInt 0, dataoffset, datasize]
56+
, calls "return" [yulInt 0, datasize]
5157
]
52-
call f args = YExp (YCall f args)
58+
calls f args = YExp (YCall f args)
59+
ylva x e = YLet [Name x] (Just e)
60+
datasize = YCall "datasize"[cname]
61+
dataoffset = YCall "dataoffset"[cname]
5362

5463
{- | wrap a Yul chunk in a Solidity function with the given name
5564
assumes result is in a variable named "_result"
5665
-}
57-
wrapInSol :: Name -> Yul -> Doc
66+
wrapInSol :: Name -> [YulStmt] -> Doc
5867
wrapInSol name yul = wrapInContract name "wrapper()" wrapper
5968
where
6069
wrapper = wrapInSolFunction "wrapper" (yulBuiltins <> yul)
6170

62-
wrapInSolFunction :: Name -> Yul -> Doc
71+
wrapInSolFunction :: Name -> [YulStmt] -> Doc
6372
wrapInSolFunction name yul =
6473
text "function" <+> ppr name <+> prettyargs <+> text " public returns (uint256 _wrapresult)" <+> lbrace
6574
$$ nest 2 assembly
6675
$$ rbrace
6776
where
68-
yul' = yul <> Yul [YAssign1 "_wrapresult" (YIdent "_mainresult")]
69-
assembly = text "assembly" <+> lbrace
70-
$$ nest 2 (ppr yul')
71-
$$ rbrace
77+
yul' = yul <> [YAssign1 "_wrapresult" (YIdent "_mainresult")]
78+
assembly = text "assembly" <+> braces (nest 2 prettybody)
79+
prettybody = vcat (map ppr yul')
7280
prettyargs = parens empty
7381

7482
wrapInContract :: Name -> Name -> Doc -> Doc

yule/Options.hs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ data Options = Options
1010
, debug :: Bool
1111
, compress :: Bool
1212
, wrap :: Bool
13+
, runOnce :: Bool
1314
} deriving Show
1415

1516
optionsParser :: Parser Options
@@ -53,6 +54,10 @@ optionsParser = Options
5354
<> short 'w'
5455
<> help "Wrap Yul in a Solidity contract"
5556
)
57+
<*> switch
58+
( long "nodeploy"
59+
<> help "Output code to be run once, without the deployment code"
60+
)
5661

5762
parseOptions :: IO Options
5863
parseOptions = execParser opts

0 commit comments

Comments
 (0)