Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 4 additions & 2 deletions src/Solcore/Frontend/Syntax/ElabTree.hs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,8 @@ extraTopDeclsForContract c@(S.Contract cname ts decls) = do
decls' = decls ++ extraTopDeclsForContractField cname field offset
offset = foldr pair unit tys

translateFieldType :: Ty -> Ty
translateFieldType t = TyCon "storage" [t]

extraTopDeclsForContractField :: ContractName -> Field Name -> Ty -> [TopDecl Name]
extraTopDeclsForContractField cname field@(Field fname fty _minit) offset = [selDecl, TInstDef sfInstance] where
Expand All @@ -281,7 +283,7 @@ extraTopDeclsForContractField cname field@(Field fname fty _minit) offset = [sel
, instVars = []
, instContext = []
, instName = "StructField"
, paramsTy = [fty, offset]
, paramsTy = [translateFieldType fty, offset]
, mainTy = TyCon "StructField" [ctxTy, selType]
, instFunctions = []
}
Expand Down Expand Up @@ -645,7 +647,7 @@ instance Elab S.Exp where
-- condition for valid constructor use
if isCon && isNothing me' then
pure (Con n es')
else if isClass then do
else if isClass then do
pure (Call Nothing (mkClassName me' n) es')
-- condition for function call
else pure (Call me' n es')
Expand Down
2 changes: 1 addition & 1 deletion src/Solcore/Frontend/TypeInference/TcSimplify.hs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ toHnf depth p@(InCls c _ _)
info [">>>> No default instance found for:", pretty p]
pure [p]
Just (_, s) -> do
info [">>>> Default instance for:", pretty p, "found! (Solved)"]
info [">>>> Default instance for:", pretty p, " found! (Solved), \n>>> Subst: ", pretty s]
-- default instances should not have any additional contraints.
_ <- extSubst s
pure []
Expand Down
11 changes: 11 additions & 0 deletions std/dispatch.solc
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ instance uint256:ABIString {
}
}

instance address:ABIString {
function append(head : word, tail : word, prx : Proxy(address)) -> word {
let size : word = 7;
assembly {
mstore(head, add(mload(head), size))
mstore(tail, 0x6164647265737300000000000000000000000000000000000000000000000000)
}
return Add.add(tail, size);
}
}

instance ():ABIString {
function append(head : word, tail : word, prx : Proxy(())) -> word {
return(tail);
Expand Down
178 changes: 135 additions & 43 deletions std/std.solc
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,12 @@ forall self . class self:ABIAttribs {
function isStatic(ty:Proxy(self)) -> bool;
}

forall t.
default instance t:ABIAttribs {
function headSize(ty : Proxy(t)) -> word { return 32; }
function isStatic(ty : Proxy(t)) -> bool { return true; }
}

instance ():ABIAttribs {
function headSize(ty : Proxy(())) -> word { return 0; }
function isStatic(ty : Proxy(())) -> bool { return true; }
Expand All @@ -745,6 +751,10 @@ instance uint256:ABIAttribs {
function headSize(ty : Proxy(uint256)) -> word { return 32; }
function isStatic(ty : Proxy(uint256)) -> bool { return true; }
}
instance address:ABIAttribs {
function headSize(ty : Proxy(address)) -> word { return 32; }
function isStatic(ty : Proxy(address)) -> bool { return true; }
}
forall t . instance DynArray(t):ABIAttribs {
function headSize(ty : Proxy(DynArray(t))) -> word { return 32; }
function isStatic(ty : Proxy(DynArray(t))) -> bool { return false; }
Expand Down Expand Up @@ -837,6 +847,16 @@ instance uint256:ABIEncode {
}
}

instance bool:ABIEncode {

function encodeInto(x:bool, basePtr:word, offset:word, tail:word) -> word {

let repx : word = frombool(x);
assembly { mstore(add(basePtr, offset), repx) }
return tail;
}
}

function round_up_to_mul_of_32(value:word) -> word {
let result : word;
assembly { result := and(add(value, 31), not(31)) }
Expand Down Expand Up @@ -951,6 +971,13 @@ forall reader . reader:WordReader => instance ABIDecoder(uint256, reader):ABIDec
}
}

// ABI Decoding for address
forall reader . reader:WordReader => instance ABIDecoder(address, reader):ABIDecode(address) {
function decode(ptr:ABIDecoder(address, reader), currentHeadOffset:word) -> address {
return Typedef.abs(WordReader.read(WordReader.advance(ptr, currentHeadOffset))) : address;
}
}

forall reader . reader:WordReader => instance ABIDecoder((), reader):ABIDecode(()) {
function decode(ptr:ABIDecoder((), reader), currentHeadOffset:word) -> () {
return ();
Expand Down Expand Up @@ -1080,9 +1107,9 @@ forall baseType baseType_decoded reader . ABIDecoder(baseType, CalldataWordReade
*/


pragma no-patterson-condition RVA;
pragma no-coverage-condition MemberAccessProxy, LVA, RVA, StructField;

pragma no-patterson-condition RVA, Assign;
pragma no-coverage-condition MemberAccessProxy, LVA, RVA, StructField, Assign;
pragma no-bounded-variable-condition LVA, RVA;
// -- storage

function sload_(x:word) -> word {
Expand All @@ -1098,11 +1125,20 @@ function sstore_(a:word, v:word) {
}



forall self.
class self:StorageSize {
function size(x:Proxy(self)) -> word;
}


forall self.
default instance self:StorageSize {
function size(x:Proxy(self)) -> word {
return 1;
}
}

instance ():StorageSize {
function size(x:Proxy(())) -> word {
return 0;
Expand Down Expand Up @@ -1133,7 +1169,19 @@ instance address:StorageSize {
}
}

forall a b . a:StorageSize, b:StorageSize => instance (a,b):StorageSize {
instance string:StorageSize {
function size(x:Proxy(string)) -> word {
return 1;
}
}

instance memory(string):StorageSize {
function size(x:Proxy(memory(string))) -> word {
return 1;
}
}

forall a b. a:StorageSize, b:StorageSize => instance (a,b):StorageSize {
function size(x:Proxy((a,b))) -> word {
let a_sz:word = StorageSize.size(Proxy:Proxy(a));
let b_sz:word = StorageSize.size(Proxy:Proxy(b));
Expand Down Expand Up @@ -1201,15 +1249,15 @@ instance uint256:StorageType {

// -- structure fields (including contract fields)

forall self fieldType offsetType.
forall self fieldType offsetType.
class self:StructField(fieldType, offsetType) {}
data StructField(structType, fieldSelector) = StructField(structType);


data MemberAccessProxy(a, field, offset) = MemberAccessProxy(a, field);
data MemberAccessProxy(a, field, fieldtype, offset) = MemberAccessProxy(a, field);

forall a field offset .
function memberAccessBase(x:MemberAccessProxy(a, field, offset)) -> a {
forall a field fieldType storageType offset .
function memberAccessBase(x:MemberAccessProxy(a, field, fieldType, offset)) -> a {
match x {
| MemberAccessProxy(y,z) => return y;
}
Expand All @@ -1220,33 +1268,35 @@ function memberAccessBase(x:MemberAccessProxy(a, field, offset)) -> a {
// Contract field access
// ------------------------------------------------------------------

forall cxt fieldSelector fieldType offsetType
. StructField(ContractStorage(cxt), fieldSelector):StructField(fieldType, offsetType)
, offsetType:StorageSize
=> instance MemberAccessProxy(ContractStorage(cxt), fieldSelector, offsetType):LVA(storage(fieldType)) {
function acc(x:MemberAccessProxy(ContractStorage(cxt), fieldSelector, offsetType)) -> storage(fieldType) {
let offset:word = StorageSize.size(Proxy:Proxy(offsetType));
return storage(offset);
}
forall cxt fieldSelector loadType offsetType storageType
. StructField(ContractStorage(cxt), fieldSelector) : StructField (storage(storageType), offsetType)
, offsetType : StorageSize
, storage(storageType): CanStore(loadType)
=> instance MemberAccessProxy(ContractStorage(cxt), fieldSelector, loadType, offsetType) : LVA (storage(storageType)) {
function acc (x : MemberAccessProxy(ContractStorage(cxt), fieldSelector, loadType, offsetType)) -> storage(storageType) {
let offset : word = StorageSize.size(Proxy : Proxy(offsetType)) ;
return storage(offset):storage(storageType);
}
}

forall cxt fieldSelector fieldType offsetType
. StructField(ContractStorage(cxt), fieldSelector):StructField(fieldType, offsetType)
, fieldType:StorageType
forall cxt fieldSelector loadType offsetType storageType
. StructField(ContractStorage(cxt), fieldSelector):StructField(storage(storageType), offsetType)
, storage(storageType):CanStore(loadType)
, offsetType:StorageSize
=> instance MemberAccessProxy(ContractStorage(cxt), fieldSelector, offsetType):RVA(fieldType) {
function acc(x:MemberAccessProxy(ContractStorage(cxt), fieldSelector, offsetType)) -> fieldType {
=> instance MemberAccessProxy(ContractStorage(cxt), fieldSelector, loadType, offsetType):RVA(loadType) {
function acc(x:MemberAccessProxy(ContractStorage(cxt), fieldSelector, loadType, offsetType)) -> loadType {
let offset:word = StorageSize.size(Proxy:Proxy(offsetType));
return StorageType.sload(offset):fieldType;
return CanStore.sload(storage(offset):storage(storageType)):loadType;
}
}


forall structType fieldSelector fieldType offsetType
// TODO: structures other than contract context
/*
forall structType fieldSelector fieldType storageType offsetType
. StructField(structType, fieldSelector):StructField(fieldType, offsetType)
, offsetType:StorageSize
=> instance MemberAccessProxy(storage(structType), fieldSelector, offsetType):LVA(storage(fieldType)) {
function acc(x:MemberAccessProxy(storage(structType), fieldSelector, offsetType)) -> storage(fieldType) {
=> instance MemberAccessProxy(storage(structType), fieldSelector, fieldType, offsetType):LVA(storage(fieldType)) {
function acc(x:MemberAccessProxy(storage(structType), fieldSelector, fieldType, offsetType)) -> storage(fieldType) {
let ptr:word = Typedef.rep(memberAccessBase(x));
let size:word = StorageSize.size(Proxy:Proxy(offsetType));
assembly {
Expand All @@ -1256,22 +1306,21 @@ forall structType fieldSelector fieldType offsetType
}
}


forall structType fieldSelector fieldType offsetType
forall structType fieldSelector fieldType storageType offsetType
. StructField(structType, fieldSelector):StructField(fieldType, offsetType)
, offsetType:StorageSize
, fieldType:StorageType
=> instance MemberAccessProxy(storage(structType), fieldSelector, offsetType):RVA(fieldType) {
function acc(x:MemberAccessProxy(storage(structType), fieldSelector, offsetType)) -> fieldType {
=> instance MemberAccessProxy(storage(structType), fieldSelector, fieldType, offsetType):RVA(fieldType) {
function acc(x:MemberAccessProxy(storage(structType), fieldSelector, fieldType, offsetType)) -> fieldType {
let ptr:word = Typedef.rep(memberAccessBase(x));
let size:word = StorageSize.size(Proxy:Proxy(offsetType));
assembly {
ptr := add(ptr, size)
}
return StorageType.sload(ptr);
return CanStore.sload(ptr);
}
}

*/



Expand Down Expand Up @@ -1315,38 +1364,81 @@ function rval(x:a) -> b {
}


// TODO: consider merging CanStore and Assign
forall lhs rhs.
class lhs:Assign(rhs) {
function assign(l:lhs, r:rhs) -> ();
}

// a can be stored in storage(b); e.g. memory(string) : Storable(string)
pragma no-coverage-condition Storable, Assign;

// a can store b; e.g. storage(string) : memory(string)
forall a b.
class a:Storable(b) {
function store(r:storage(b), v:a);
function sload(r:storage(b)) -> a;
class a:CanStore(b) {
function store(r:a, v:b);
function sload(r:a) -> b;
}


forall a b. a:Storable(b) =>
instance storage(b):Assign(a) {
function assign(l:storage(b), r:a) -> () {
Storable.store(l, r);
forall a b. a:CanStore(b) =>
instance a:Assign(b) {
function assign(l:a, r:b) -> () {
CanStore.store(l, r);
}
}

/*
forall a. a:StorageType =>
default instance a:Storable(a) {
default instance a:CanStore(a) {
function store(l:storage(a), r:a) -> () {
StorageType.store(Typedef.rep(l), r);
}
function sload(l:storage(a)) -> a {
return StorageType.sload(Typedef.rep(l));
}
}
*/

instance storage(word):CanStore(word) {
function store(l:storage(word), r:word) -> () {
StorageType.store(Typedef.rep(l), r);
}
function sload(l:storage(word)) -> word {
return StorageType.sload(Typedef.rep(l));
}
}

instance storage(uint256):CanStore(uint256) {
function store(l:storage(uint256), r:uint256) -> () {
StorageType.store(Typedef.rep(l), r);
}
function sload(l:storage(uint256)) -> uint256 {
return StorageType.sload(Typedef.rep(l));
}
}

instance storage(address):CanStore(address) {
function store(l:storage(address), r:address) -> () {
StorageType.store(Typedef.rep(l), r);
}
function sload(l:storage(address)) -> address {
return StorageType.sload(Typedef.rep(l));
}
}

forall k v.
instance storage(mapping(k,v)):CanStore(storage(mapping(k,v))) {
function store(l:storage(mapping(k,v)), r:storage(mapping(k,v))) -> () {
// StorageType.store(Typedef.rep(l), r);
unimplemented();
}
function sload(l:storage(mapping(k,v))) -> storage(mapping(k,v)) {
// return StorageType.sload(Typedef.rep(l));
return unimplemented();
}
}


instance memory(string):Storable(string) {
instance storage(string):CanStore(memory(string)) {
function store(dst:storage(string), src:memory(string)) -> () {
let srcPtr : word = Typedef.rep(src);
let slot = Typedef.rep(dst);
Expand Down
1 change: 1 addition & 0 deletions test/Cases.hs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ dispatches =
"Files for dispatch cases"
[ runDispatchTest "basic.solc"
, runDispatchTest "stringid.solc"
, runDispatchTest "miniERC20.solc"
]
where
runDispatchTest file = runTestForFileWith (emptyOption mempty) file "./test/examples/dispatch"
Expand Down
Loading