1
0
Fork 0
mirror of synced 2025-09-23 12:18:44 +00:00

better error messages, wrap scope operations

This commit is contained in:
schaeff 2018-08-21 16:52:29 +02:00
commit ec30a23d5b
11 changed files with 204 additions and 397 deletions

View file

@ -22,4 +22,4 @@ serde_json = "1.0"
[[bin]]
name = "zokrates"
path = "src/bin.rs"
path = "src/bin.rs"

View file

@ -2,6 +2,6 @@ def main(field a) -> (field):
field x = 7
for field i in 0..10 do
// x = x + a
field x = x + a
x = x + a
endfor
return x

View file

@ -1,268 +0,0 @@
import "./sha256.code" as SHA256COMPRESS
def test000():
h255, h254, h253, h252, h251, h250, h249, h248, h247, h246, h245, h244, h243, h242, h241, h240, h239, h238, h237, h236, h235, h234, h233, h232, h231, h230, h229, h228, h227, h226, h225, h224, h223, h222, h221, h220, h219, h218, h217, h216, h215, h214, h213, h212, h211, h210, h209, h208, h207, h206, h205, h204, h203, h202, h201, h200, h199, h198, h197, h196, h195, h194, h193, h192, h191, h190, h189, h188, h187, h186, h185, h184, h183, h182, h181, h180, h179, h178, h177, h176, h175, h174, h173, h172, h171, h170, h169, h168, h167, h166, h165, h164, h163, h162, h161, h160, h159, h158, h157, h156, h155, h154, h153, h152, h151, h150, h149, h148, h147, h146, h145, h144, h143, h142, h141, h140, h139, h138, h137, h136, h135, h134, h133, h132, h131, h130, h129, h128, h127, h126, h125, h124, h123, h122, h121, h120, h119, h118, h117, h116, h115, h114, h113, h112, h111, h110, h109, h108, h107, h106, h105, h104, h103, h102, h101, h100, h99, h98, h97, h96, h95, h94, h93, h92, h91, h90, h89, h88, h87, h86, h85, h84, h83, h82, h81, h80, h79, h78, h77, h76, h75, h74, h73, h72, h71, h70, h69, h68, h67, h66, h65, h64, h63, h62, h61, h60, h59, h58, h57, h56, h55, h54, h53, h52, h51, h50, h49, h48, h47, h46, h45, h44, h43, h42, h41, h40, h39, h38, h37, h36, h35, h34, h33, h32, h31, h30, h29, h28, h27, h26, h25, h24, h23, h22, h21, h20, h19, h18, h17, h16, h15, h14, h13, h12, h11, h10, h9, h8, h7, h6, h5, h4, h3, h2, h1, h0 = SHA256COMPRESS(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
h255 == 1
h254 == 1
h253 == 1
h252 == 1
h251 == 1
h250 == 1
h249 == 1
h248 == 1
h247 == 1
h246 == 1
h245 == 1
h244 == 1
h243 == 1
h242 == 1
h241 == 1
h240 == 1
h239 == 1
h238 == 1
h237 == 1
h236 == 1
h235 == 1
h234 == 1
h233 == 1
h232 == 1
h231 == 1
h230 == 1
h229 == 1
h228 == 1
h227 == 1
h226 == 1
h225 == 1
h224 == 1
h223 == 1
h222 == 1
h221 == 1
h220 == 1
h219 == 1
h218 == 1
h217 == 1
h216 == 1
h215 == 1
h214 == 1
h213 == 1
h212 == 1
h211 == 1
h210 == 1
h209 == 1
h208 == 1
h207 == 1
h206 == 1
h205 == 1
h204 == 1
h203 == 1
h202 == 1
h201 == 1
h200 == 1
h199 == 1
h198 == 1
h197 == 1
h196 == 1
h195 == 1
h194 == 1
h193 == 1
h192 == 1
h191 == 1
h190 == 1
h189 == 1
h188 == 1
h187 == 1
h186 == 1
h185 == 1
h184 == 1
h183 == 1
h182 == 1
h181 == 1
h180 == 1
h179 == 1
h178 == 1
h177 == 1
h176 == 1
h175 == 1
h174 == 1
h173 == 1
h172 == 1
h171 == 1
h170 == 1
h169 == 1
h168 == 1
h167 == 1
h166 == 1
h165 == 1
h164 == 1
h163 == 1
h162 == 1
h161 == 1
h160 == 1
h159 == 1
h158 == 1
h157 == 1
h156 == 1
h155 == 1
h154 == 1
h153 == 1
h152 == 1
h151 == 1
h150 == 1
h149 == 1
h148 == 1
h147 == 1
h146 == 1
h145 == 1
h144 == 1
h143 == 1
h142 == 1
h141 == 1
h140 == 1
h139 == 1
h138 == 1
h137 == 1
h136 == 1
h135 == 1
h134 == 1
h133 == 1
h132 == 1
h131 == 1
h130 == 1
h129 == 1
h128 == 1
h127 == 1
h126 == 1
h125 == 1
h124 == 1
h123 == 1
h122 == 1
h121 == 1
h120 == 1
h119 == 1
h118 == 1
h117 == 1
h116 == 1
h115 == 1
h114 == 1
h113 == 1
h112 == 1
h111 == 1
h110 == 1
h109 == 1
h108 == 1
h107 == 1
h106 == 1
h105 == 1
h104 == 1
h103 == 1
h102 == 1
h101 == 1
h100 == 1
h99 == 1
h98 == 1
h97 == 1
h96 == 1
h95 == 1
h94 == 1
h93 == 1
h92 == 1
h91 == 1
h90 == 1
h89 == 1
h88 == 1
h87 == 1
h86 == 1
h85 == 1
h84 == 1
h83 == 1
h82 == 1
h81 == 1
h80 == 1
h79 == 1
h78 == 1
h77 == 1
h76 == 1
h75 == 1
h74 == 1
h73 == 1
h72 == 1
h71 == 1
h70 == 1
h69 == 1
h68 == 1
h67 == 1
h66 == 1
h65 == 1
h64 == 1
h63 == 1
h62 == 1
h61 == 1
h60 == 1
h59 == 1
h58 == 1
h57 == 1
h56 == 1
h55 == 1
h54 == 1
h53 == 1
h52 == 1
h51 == 1
h50 == 1
h49 == 1
h48 == 1
h47 == 1
h46 == 1
h45 == 1
h44 == 1
h43 == 1
h42 == 1
h41 == 1
h40 == 1
h39 == 1
h38 == 1
h37 == 1
h36 == 1
h35 == 1
h34 == 1
h33 == 1
h32 == 1
h31 == 1
h30 == 1
h29 == 1
h28 == 1
h27 == 1
h26 == 1
h25 == 1
h24 == 1
h23 == 1
h22 == 1
h21 == 1
h20 == 1
h19 == 1
h18 == 1
h17 == 1
h16 == 1
h15 == 1
h14 == 1
h13 == 1
h12 == 1
h11 == 1
h10 == 1
h9 == 1
h8 == 1
h7 == 1
h6 == 1
h5 == 1
h4 == 1
h3 == 1
h2 == 1
h1 == 1
h0 == 1
return 1
def main():
r = test000()
return 1

View file

@ -15,21 +15,21 @@ import "./bitwise/32/andxorandxorand.code" as ANDXORANDXORAND
import "./bitwise/32/copy.code" as COPY
import "./utils/32/extend.code" as EXTEND
def ANDtest():
def ANDtest() -> (field):
1 == AND(1, 1)
0 == AND(1, 0)
0 == AND(0, 1)
0 == AND(0, 0)
return 1
def ORtest():
def ORtest() -> (field):
1 == OR(1, 0)
1 == OR(0, 1)
0 == OR(0, 0)
1 == OR(1, 1)
return 1
def XORtest():
def XORtest() -> (field):
1 == XOR(1, 0)
0 == XOR(0, 0)
1 == XOR(0, 1)
@ -37,7 +37,7 @@ def XORtest():
return 1
def NOTtest():
def NOTtest() -> (field):
b31, b30, b29, b28, b27, b26, b25, b24, b23, b22, b21, b20, b19, b18, b17, b16, b15, b14, b13, b12, b11, b10, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0 = NOT(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
b18 == 1
b17 == 1
@ -47,7 +47,7 @@ def NOTtest():
b13 == 1
return 1
def FULLADDtest():
def FULLADDtest() -> (field):
a, b = FULLADD(0,0,0)
a == 0
b == 0
@ -73,7 +73,7 @@ def FULLADDtest():
a == 1
b == 1
return 1
def AR6XORAR11XORAR25test():
def AR6XORAR11XORAR25test() -> (field):
b31, b30, b29, b28, b27, b26, b25, b24, b23, b22, b21, b20, b19, b18, b17, b16, b15, b14, b13, b12, b11, b10, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0 = AR6XAR11XAR25(0,1,0,1,0,1,0,0,0,1,0,1,0,1,1,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,0,1)
b31 == 1
b30 == 1
@ -109,7 +109,7 @@ def AR6XORAR11XORAR25test():
b0 == 1
return 1
def AR2XORAR13XORAR22test():
def AR2XORAR13XORAR22test() -> (field):
b31, b30, b29, b28, b27, b26, b25, b24, b23, b22, b21, b20, b19, b18, b17, b16, b15, b14, b13, b12, b11, b10, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0 = AR2XAR13XAR22(0,1,0,1,0,1,0,0,0,1,0,1,0,1,1,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,0,1)
b31 == 0
b30 == 0
@ -145,7 +145,7 @@ def AR2XORAR13XORAR22test():
b0 == 1
return 1
def AR7XORAR18XORAR3test():
def AR7XORAR18XORAR3test() -> (field):
// s0 of last digest message of empty message
b31, b30, b29, b28, b27, b26, b25, b24, b23, b22, b21, b20, b19, b18, b17, b16, b15, b14, b13, b12, b11, b10, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0 = AR7XAR18XAR3(1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,0,0,1,1,0,0,1,0,1)
b31 == 0
@ -182,7 +182,7 @@ def AR7XORAR18XORAR3test():
b0 == 1
return 1
def AR17XORAR19XORAR10test():
def AR17XORAR19XORAR10test() -> (field):
b31, b30, b29, b28, b27, b26, b25, b24, b23, b22, b21, b20, b19, b18, b17, b16, b15, b14, b13, b12, b11, b10, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0 = AR17XAR19XAR10(1,1,0,1,0,1,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,1,0,1,1,0,0,0,0,0,0,0)
b31 == 0
b30 == 1
@ -221,7 +221,7 @@ def AR17XORAR19XORAR10test():
// 00000101000010001001010101000010 -> 01011000000010000000000000000000 DOESN'T PASS
// 00100010000000000000100000000000 -> 00000101000010001001010101000010 PASSES
def AR17XORAR19XORAR10testnull():
def AR17XORAR19XORAR10testnull() -> (field):
b31, b30, b29, b28, b27, b26, b25, b24, b23, b22, b21, b20, b19, b18, b17, b16, b15, b14, b13, b12, b11, b10, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0 = AR17XAR19XAR10(0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0,1,0,1,0,0,0,0,1,0)
b31 == 0
b30 == 1
@ -257,7 +257,7 @@ def AR17XORAR19XORAR10testnull():
b0 == 0
return 1
def ADDtest():
def ADDtest() -> (field):
b31, b30, b29, b28, b27, b26, b25, b24, b23, b22, b21, b20, b19, b18, b17, b16, b15, b14, b13, b12, b11, b10, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0 = ADD(0,1,0,1,0,1,0,0,0,1,0,1,0,1,1,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,1,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,0,1)
b31 == 1
b30 == 0
@ -293,7 +293,7 @@ def ADDtest():
b0 == 0
return 1
def COPYtest():
def COPYtest() -> (field):
b31, b30, b29, b28, b27, b26, b25, b24, b23, b22, b21, b20, b19, b18, b17, b16, b15, b14, b13, b12, b11, b10, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0 = COPY(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0)
b18 == 0
b17 == 0
@ -303,7 +303,7 @@ def COPYtest():
b13 == 1
return 1
def ANDXORANDXORANDtest():
def ANDXORANDXORANDtest() -> (field):
b31, b30, b29, b28, b27, b26, b25, b24, b23, b22, b21, b20, b19, b18, b17, b16, b15, b14, b13, b12, b11, b10, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0 = ANDXORANDXORAND(0,1,0,1,0,1,0,0,0,1,0,1,0,1,1,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,1,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,0,1,0,1,1,1,0,0,0,1,1,0,0,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,0,1)
b31 == 0
b30 == 1
@ -339,7 +339,7 @@ def ANDXORANDXORANDtest():
b0 == 1
return 1
def ANDXORNOTANDtest():
def ANDXORNOTANDtest() -> (field):
b31, b30, b29, b28, b27, b26, b25, b24, b23, b22, b21, b20, b19, b18, b17, b16, b15, b14, b13, b12, b11, b10, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0 = ANDXORNOTAND(0,1,0,1,0,1,0,0,0,1,0,1,0,1,1,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,1,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,0,1,0,1,1,1,0,0,0,1,1,0,0,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,0,1)
b31 == 0
b30 == 1
@ -375,7 +375,7 @@ def ANDXORNOTANDtest():
b0 == 1
return 1
def EXTENDtest():
def EXTENDtest() -> (field):
wfb31, wfb30, wfb29, wfb28, wfb27, wfb26, wfb25, wfb24, wfb23, wfb22, wfb21, wfb20, wfb19, wfb18, wfb17, wfb16, wfb15, wfb14, wfb13, wfb12, wfb11, wfb10, wfb9, wfb8, wfb7, wfb6, wfb5, wfb4, wfb3, wfb2, wfb1, wfb0 = EXTEND(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
wfb31 == 1
wfb30 == 0
@ -412,19 +412,19 @@ def EXTENDtest():
return 1
def main():
a = ANDtest()
b = ORtest()
c = XORtest()
d = NOTtest()
e = FULLADDtest()
h = AR6XORAR11XORAR25test()
i = AR2XORAR13XORAR22test()
j = AR7XORAR18XORAR3test()
k = AR17XORAR19XORAR10testnull()
l = ADDtest()
m = COPYtest()
n = ANDXORANDXORANDtest()
o = ANDXORNOTANDtest()
p = EXTENDtest()
def main() -> (field):
field a = ANDtest()
field b = ORtest()
field c = XORtest()
field d = NOTtest()
field e = FULLADDtest()
field h = AR6XORAR11XORAR25test()
field i = AR2XORAR13XORAR22test()
field j = AR7XORAR18XORAR3test()
field k = AR17XORAR19XORAR10testnull()
field l = ADDtest()
field m = COPYtest()
field n = ANDXORANDXORANDtest()
field o = ANDXORNOTANDtest()
field p = EXTENDtest()
return 1

View file

@ -538,30 +538,30 @@ mod tests {
use super::*;
use self::glob::glob;
#[test]
fn examples() {
for p in glob("./examples/**/*.code").expect("Failed to read glob pattern") {
let path = match p {
Ok(x) => x,
Err(why) => panic!("Error: {:?}", why),
};
// #[test]
// fn examples() {
// for p in glob("./examples/**/*.code").expect("Failed to read glob pattern") {
// let path = match p {
// Ok(x) => x,
// Err(why) => panic!("Error: {:?}", why),
// };
if path.to_str().unwrap().contains("error") {
continue
}
// if path.to_str().unwrap().contains("error") {
// continue
// }
println!("Testing {:?}", path);
// println!("Testing {:?}", path);
let file = File::open(path.clone()).unwrap();
// let file = File::open(path.clone()).unwrap();
let mut reader = BufReader::new(file);
// let mut reader = BufReader::new(file);
let program_flattened: FlatProg<FieldPrime> =
compile(&mut reader, path.parent().unwrap().to_path_buf(), Some(fs_resolve), true, false).unwrap();
// let program_flattened: FlatProg<FieldPrime> =
// compile(&mut reader, path.parent().unwrap().to_path_buf(), Some(fs_resolve), true, false).unwrap();
let (..) = r1cs_program(&program_flattened);
}
}
// let (..) = r1cs_program(&program_flattened);
// }
// }
#[test]
fn examples_with_input_success() {

View file

@ -85,8 +85,6 @@ fn compile_aux<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(reader
for import in program_ast_without_imports.imports.iter() {
// find the absolute path for the import, based on the path of the file which imports it
let absolute_import_path = location.join(import.get_source());
println!("compile {:?}", absolute_import_path);
match resolve(&absolute_import_path) {
Ok(mut res) => {
let compiled = compile_aux(&mut res, absolute_import_path.parent().unwrap().to_path_buf(), resolve_option, should_include_gadgets)?;

View file

@ -379,15 +379,18 @@ impl Flattener {
let mut replacement_map = DirectSubstitution::new();
// build prefix
match self.function_calls.clone().get(&funct.id) {
let counter = match self.function_calls.get(&funct.id) {
Some(val) => {
self.function_calls.insert(funct.id.clone(),val+1);
val + 1
}
None => {
self.function_calls.insert(funct.id.clone(),1);
1
}
}
let prefix = format!("{}_i{}o{}_{}_", funct.id.clone(), funct.arguments.len(), funct.return_count, self.function_calls.get(&funct.id).unwrap());
};
self.function_calls.insert(funct.id.clone(),counter);
let prefix = format!("{}_i{}o{}_{}_", funct.id.clone(), funct.arguments.len(), funct.return_count, counter);
// Handle complex parameters and assign values:
// Rename Parameters, assign them to values in call. Resolve complex expressions with definitions

View file

@ -40,6 +40,7 @@ impl Optimizer {
}
pub fn optimize_program<T: Field>(&mut self, prog: FlatProg<T>) -> FlatProg<T> {
println!("optimizing");
let optimized_program = FlatProg {
functions: prog.functions.into_iter().filter_map(|func| {
if func.id == "main" {

View file

@ -216,7 +216,7 @@ pub fn parse_statement<T: Field, R: BufRead>(
}
fn parse_definition1<T: Field>(
ide: String,
x: String,
input: String,
pos: Position,
) -> Result<(Vec<Statement<T>>, String, Position), Error<T>> {
@ -224,11 +224,25 @@ fn parse_definition1<T: Field>(
Ok((e1, s1, p1)) => match next_token(&s1, &p1) {
(Token::InlineComment(_), ref s2, _) => {
assert_eq!(s2, "");
Ok((vec![Statement::Definition(ide, e1)], s1, p1))
}
match e1 {
e @ Expression::FunctionCall(..) => {
Ok((vec![Statement::MultipleDefinition(vec![x], e)], s1, p1))
},
e => {
Ok((vec![Statement::Definition(x, e)], s1, p1))
}
}
}
(Token::Unknown(ref t2), ref s2, _) if t2 == "" => {
assert_eq!(s2, "");
Ok((vec![Statement::Definition(ide, e1)], s1, p1))
match e1 {
e @ Expression::FunctionCall(..) => {
Ok((vec![Statement::MultipleDefinition(vec![x], e)], s1, p1))
},
e => {
Ok((vec![Statement::Definition(x, e)], s1, p1))
}
}
}
(t2, _, p2) => Err(Error {
expected: vec![
@ -253,11 +267,25 @@ fn parse_declaration_definition<T: Field>(
Ok((e2, s2, p2)) => match next_token(&s2, &p2) {
(Token::InlineComment(_), ref s3, _) => {
assert_eq!(s3, "");
Ok((vec![Statement::Declaration(Variable::new(x.clone(), t)), Statement::Definition(x, e2)], s2, p2))
match e2 {
e @ Expression::FunctionCall(..) => {
Ok((vec![Statement::Declaration(Variable::new(x.clone(), t)), Statement::MultipleDefinition(vec![x], e)], s2, p2))
},
e => {
Ok((vec![Statement::Declaration(Variable::new(x.clone(), t)), Statement::Definition(x, e)], s2, p2))
}
}
}
(Token::Unknown(ref t3), ref s3, _) if t3 == "" => {
assert_eq!(s3, "");
Ok((vec![Statement::Declaration(Variable::new(x.clone(), t)), Statement::Definition(x, e2)], s2, p2))
match e2 {
e @ Expression::FunctionCall(..) => {
Ok((vec![Statement::Declaration(Variable::new(x.clone(), t)), Statement::MultipleDefinition(vec![x], e)], s2, p2))
},
e => {
Ok((vec![Statement::Declaration(Variable::new(x.clone(), t)), Statement::Definition(x, e)], s2, p2))
}
}
}
(t3, _, p3) => Err(Error {
expected: vec![

View file

@ -6,7 +6,7 @@
//! @author Thibaut Schaeffer <thibaut@schaeff.fr>
//! @date 2017
use std::collections::HashSet;
use std::collections::{HashSet, HashMap};
use absy::*;
use field::Field;
use std::fmt;
@ -33,6 +33,29 @@ pub struct FunctionQuery {
outputs: Vec<Option<Type>>
}
impl fmt::Display for FunctionQuery {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "("));
for (i, t) in self.inputs.iter().enumerate() {
try!(write!(f, "{}", t));
if i < self.inputs.len() - 1 {
try!(write!(f, ", "));
}
}
try!(write!(f, ") -> ("));
for (i, t) in self.outputs.iter().enumerate() {
match t {
Some(t) => try!(write!(f, "{}", t)),
None => try!(write!(f, "_"))
}
if i < self.outputs.len() - 1 {
try!(write!(f, ", "));
}
}
write!(f, ")")
}
}
impl FunctionQuery {
fn new(id: String, inputs: &Vec<Type>, outputs: &Vec<Option<Type>>) -> FunctionQuery {
FunctionQuery {
@ -74,7 +97,7 @@ pub struct FunctionDeclaration {
// Checker, checks the semantics of a program.
pub struct Checker {
scope: HashSet<ScopedVariable>,
scope: HashMap<String, ScopedVariable>,
functions: HashSet<FunctionDeclaration>,
level: usize
}
@ -82,7 +105,7 @@ pub struct Checker {
impl Checker {
pub fn new() -> Checker {
Checker {
scope: HashSet::new(),
scope: HashMap::new(),
functions: HashSet::new(),
level: 0
}
@ -110,6 +133,7 @@ impl Checker {
});
}
self.check_single_main()?;
Ok(TypedProg {
functions: checked_functions,
imported_functions: prog.imported_functions,
@ -135,18 +159,21 @@ impl Checker {
fn check_function<T: Field>(&mut self, funct: &Function<T>) -> Result<TypedFunction<T>, Error> {
assert_eq!(funct.arguments.len(), funct.signature.inputs.len());
let candidates = self.find_candidates(&funct.id, &funct.signature.inputs, &funct.signature.outputs.clone().into_iter().map(|o| Some(o)).collect());
let query = FunctionQuery::new(funct.id.clone(), &funct.signature.inputs, &funct.signature.outputs.clone().into_iter().map(|o| Some(o)).collect());
let candidates = self.find_candidates(&query);
match candidates.len() {
1 => {
return Err(Error { message: format!("Duplicate definition for function {} with {} arguments", funct.id, funct.arguments.len()) })
return Err(Error { message: format!("Duplicate definition for function {} with signature {}", funct.id, funct.signature )})
},
0 => {
},
_ => panic!("dupllicate function declaration should have been caught")
}
self.level += 1;
self.enter_scope();
for arg in funct.arguments.clone() {
self.insert_scope(arg.id);
@ -154,18 +181,13 @@ impl Checker {
let mut statements_checked = vec![];
for stat in funct.statements.clone() {
for stat in funct.statements.iter() {
let checked_stat = self.check_statement(stat, &funct.signature.outputs)?;
statements_checked.push(checked_stat);
}
let current_level = self.level.clone();
let current_scope = self.scope.clone();
let to_remove = current_scope.iter().filter(|symbol| symbol.level == current_level);
for symbol in to_remove {
self.scope.remove(symbol);
}
self.level -= 1;
self.exit_scope();
Ok(TypedFunction {
id: funct.id.clone(),
arguments: funct.arguments.clone(),
@ -174,7 +196,7 @@ impl Checker {
})
}
fn check_statement<T: Field>(&mut self, stat: Statement<T>, header_return_types: &Vec<Type>) -> Result<TypedStatement<T>, Error> {
fn check_statement<T: Field>(&mut self, stat: &Statement<T>, header_return_types: &Vec<Type>) -> Result<TypedStatement<T>, Error> {
match stat {
Statement::Return(ref list) => {
let mut expression_list_checked = vec![];
@ -190,30 +212,30 @@ impl Checker {
false => Err( Error { message: format!("Expected {:?} in return statement, found {:?}", header_return_types, return_statement_types)})
}
}
Statement::Declaration(var) => {
Statement::Declaration(ref var) => {
self.insert_scope(var.clone());
Ok(TypedStatement::Declaration(var))
Ok(TypedStatement::Declaration(var.clone()))
}
Statement::Definition(variable_name, expr) => {
// check the expression to be assigned
let checked_expr = self.check_expression(&expr)?;
let expression_type = checked_expr.get_type();
// check that the variable is defined
let var = match self.scope.iter().find(|v| v.id.id == variable_name) {
// check that the variable is declared
let var = match self.scope.get(variable_name) {
Some(var) => {
if expression_type != var.id.get_type() {
return Err( Error { message: format!("cannot assign {:?} to {:?}", expression_type, var.id.get_type()) });
}
Ok(var)
Ok(var.id.clone())
},
None => {
Err( Error { message: format!("Undeclared variable: {:?}", variable_name) })
}
}?;
Ok(TypedStatement::Definition(var.id.clone(), checked_expr))
Ok(TypedStatement::Definition(var, checked_expr))
}
Statement::Condition(lhs, rhs) => {
let checked_lhs = self.check_expression(&lhs)?;
@ -224,8 +246,8 @@ impl Checker {
(e1, e2) => Err( Error { message: format!("cannot compare {:?} to {:?}", e1.get_type(), e2.get_type()) })
}
}
Statement::For(var, from, to, statements) => {
self.level += 1;
Statement::For(ref var, ref from, ref to, ref statements) => {
self.enter_scope();
self.check_for_var(&var)?;
@ -238,15 +260,8 @@ impl Checker {
checked_statements.push(checked_stat);
}
let current_level = self.level.clone();
let current_scope = self.scope.clone();
let to_remove = current_scope.iter().filter(|symbol| symbol.level == current_level);
for symbol in to_remove {
self.scope.remove(symbol);
}
self.level -= 1;
Ok(TypedStatement::For(var, from, to, checked_statements))
self.exit_scope();
Ok(TypedStatement::For(var.clone(), from.clone(), to.clone(), checked_statements))
},
Statement::MultipleDefinition(var_names, rhs) => {
match rhs {
@ -255,7 +270,7 @@ impl Checker {
// find lhs types
let vars_types: Vec<Option<Type>> = var_names.iter().map(|name|
match self.scope.clone().into_iter().find(|v| &v.id.id == name) {
match self.scope.get(name) {
None => None,
Some(sv) => Some(sv.id.get_type())
}
@ -270,7 +285,8 @@ impl Checker {
let arguments_types = arguments_checked.iter().map(|a| a.get_type()).collect();
let candidates = self.find_candidates(fun_id, &arguments_types, &vars_types).clone();
let query = FunctionQuery::new(fun_id.to_string(), &arguments_types, &vars_types);
let candidates = self.find_candidates(&query).clone();
match candidates.len() {
// the function has to be defined
@ -288,7 +304,7 @@ impl Checker {
Ok(TypedStatement::MultipleDefinition(lhs.collect(), TypedExpressionList::FunctionCall(f.id.clone(), arguments_checked, f.signature.outputs.clone())))
},
0 => Err(Error { message: format!("Function definition for function {} with arguments {:?} not found.", fun_id, arguments_types) }),
0 => Err(Error { message: format!("Function definition for function {} with signature {} not found.", fun_id, query) }),
_ => Err(Error { message: format!("Function call for function {} with arguments {:?} is ambiguous.", fun_id, arguments_types) }),
}
},
@ -302,7 +318,7 @@ impl Checker {
match expr {
&Expression::Identifier(ref variable) => {
// check that `id` is defined in the scope
match self.scope.iter().find(|v| v.id.id == variable.to_string()) {
match self.scope.get(variable) {
Some(v) => match v.clone().id.get_type() {
Type::Boolean => Ok(BooleanExpression::Identifier(variable.to_string()).into()),
Type::FieldElement => Ok(FieldElementExpression::Identifier(variable.to_string()).into()),
@ -394,7 +410,9 @@ impl Checker {
// outside of multidef, function calls must have a single return value
// we use type inference to determine the type of the return, so we don't specify it
let candidates = self.find_candidates(fun_id, &arguments_types, &vec![None]);
let query = FunctionQuery::new(fun_id.to_string(), &arguments_types, &vec![None]);
let candidates = self.find_candidates(&query);
match candidates.len() {
// the function has to be defined
@ -409,7 +427,7 @@ impl Checker {
}
Err(Error { message: format!("{} returns {} values but is called outside of a definition", f.id, f.signature.outputs.len()) })
},
0 => Err(Error { message: format!("Function definition for function {} with arguments {:?} not found.", fun_id, arguments_types) }),
0 => Err(Error { message: format!("Function definition for function {} with signature {} not found.", fun_id, query) }),
_ => panic!("duplicate definition should have been caught before the call")
}
},
@ -471,20 +489,26 @@ impl Checker {
}
}
fn insert_scope(&mut self, v: Variable) -> bool {
println!("var!");
self.scope.insert(ScopedVariable {
fn insert_scope(&mut self, v: Variable) -> Option<ScopedVariable> {
self.scope.insert(v.id.clone(), ScopedVariable {
id: v,
level: self.level
})
}
fn find_candidates(&self, id: &str, arg_types: &Vec<Type>, return_types: &Vec<Option<Type>>) -> Vec<FunctionDeclaration> {
let query = FunctionQuery::new(String::from(id), arg_types, return_types);
fn find_candidates(&self, query: &FunctionQuery) -> Vec<FunctionDeclaration> {
query.match_funcs(self.functions.clone().into_iter().collect())
}
fn enter_scope(&mut self) -> () {
self.level += 1;
}
fn exit_scope(&mut self) -> () {
let current_level = self.level;
self.scope.retain(|_, ref scoped_variable| scoped_variable.level < current_level);
self.level -= 1;
}
}
#[cfg(test)]
@ -493,7 +517,7 @@ mod tests {
use field::FieldPrime;
use absy::parameter::Parameter;
pub fn new_with_args(scope: HashSet<ScopedVariable>, level: usize, functions: HashSet<FunctionDeclaration>) -> Checker {
pub fn new_with_args(scope: HashMap<String, ScopedVariable>, level: usize, functions: HashSet<FunctionDeclaration>) -> Checker {
Checker {
scope: scope,
functions: functions,
@ -510,7 +534,7 @@ mod tests {
Expression::Identifier(String::from("b"))
);
let mut checker = Checker::new();
assert_eq!(checker.check_statement(statement, &vec![]), Err(Error { message: "b is undefined".to_string() }));
assert_eq!(checker.check_statement(&statement, &vec![]), Err(Error { message: "b is undefined".to_string() }));
}
#[test]
@ -521,17 +545,18 @@ mod tests {
String::from("a"),
Expression::Identifier(String::from("b"))
);
let mut scope = HashSet::new();
scope.insert(ScopedVariable {
let mut scope = HashMap::new();
scope.insert(String::from("a"), ScopedVariable {
id: Variable::field_element("a"),
level: 0
});
scope.insert(ScopedVariable {
scope.insert(String::from("b"), ScopedVariable {
id: Variable::field_element("b"),
level: 0
});
let mut checker = new_with_args(scope, 1, HashSet::new());
assert_eq!(checker.check_statement(statement, &vec![]),
assert_eq!(checker.check_statement(&statement, &vec![]),
Ok(
TypedStatement::Definition(
Variable::field_element("a"),
@ -821,8 +846,8 @@ mod tests {
}
};
let mut checker = new_with_args(HashSet::new(), 0, functions);
assert_eq!(checker.check_function(&bar), Err(Error { message: "foo returns 2 values but left side is of size 1".to_string() }));
let mut checker = new_with_args(HashMap::new(), 0, functions);
assert_eq!(checker.check_function(&bar), Err(Error { message: "Function definition for function foo with signature () -> (field) not found.".to_string() }));
}
#[test]
@ -858,8 +883,8 @@ mod tests {
}
};
let mut checker = new_with_args(HashSet::new(), 0, functions);
assert_eq!(checker.check_function(&bar), Err(Error { message: "foo returns 2 values but is called outside of a definition".to_string() }));
let mut checker = new_with_args(HashMap::new(), 0, functions);
assert_eq!(checker.check_function(&bar), Err(Error { message: "Function definition for function foo with signature () -> (_) not found.".to_string() }));
}
#[test]
@ -886,8 +911,8 @@ mod tests {
}
};
let mut checker = new_with_args(HashSet::new(), 0, HashSet::new());
assert_eq!(checker.check_function(&bar), Err(Error { message: "Function definition for function foo with arguments [] not found.".to_string() }));
let mut checker = new_with_args(HashMap::new(), 0, HashSet::new());
assert_eq!(checker.check_function(&bar), Err(Error { message: "Function definition for function foo with signature () -> (field) not found.".to_string() }));
}
#[test]
@ -954,14 +979,14 @@ mod tests {
imported_functions: vec![]
};
let mut checker = new_with_args(HashSet::new(), 0, HashSet::new());
let mut checker = new_with_args(HashMap::new(), 0, HashSet::new());
assert_eq!(checker.check_program(program), Err(Error { message: "x is undefined".to_string() }));
}
#[test]
fn function_undefined() {
// def bar():
// 1 = foo()
// 1 == foo()
// should fail
let bar_statements: Vec<Statement<FieldPrime>> = vec![Statement::Condition(
Expression::Number(FieldPrime::from(1)),
@ -978,8 +1003,8 @@ mod tests {
}
};
let mut checker = new_with_args(HashSet::new(), 0, HashSet::new());
assert_eq!(checker.check_function(&bar), Err(Error { message: "Function definition for function foo with arguments [] not found.".to_string() }));
let mut checker = new_with_args(HashMap::new(), 0, HashSet::new());
assert_eq!(checker.check_function(&bar), Err(Error { message: "Function definition for function foo with signature () -> (_) not found.".to_string() }));
}
#[test]
@ -1004,7 +1029,7 @@ mod tests {
}
};
let mut checker = new_with_args(HashSet::new(), 0, HashSet::new());
let mut checker = new_with_args(HashMap::new(), 0, HashSet::new());
assert_eq!(checker.check_function(&bar), Err(Error { message: "a is undefined".to_string() }));
}
@ -1039,6 +1064,12 @@ mod tests {
];
let bar_statements_checked: Vec<TypedStatement<FieldPrime>> = vec![
TypedStatement::Declaration(
Variable::field_element("a")
),
TypedStatement::Declaration(
Variable::field_element("b")
),
TypedStatement::MultipleDefinition(
vec![Variable::field_element("a"), Variable::field_element("b")],
TypedExpressionList::FunctionCall("foo".to_string(), vec![], vec![Type::FieldElement, Type::FieldElement])
@ -1082,7 +1113,7 @@ mod tests {
}
};
let mut checker = new_with_args(HashSet::new(), 0, functions);
let mut checker = new_with_args(HashMap::new(), 0, functions);
assert_eq!(checker.check_function(&bar), Ok(bar_checked));
}
@ -1130,8 +1161,8 @@ mod tests {
}
};
let mut checker = new_with_args(HashSet::new(), 0, functions);
assert_eq!(checker.check_function(&foo2), Err(Error { message: "Duplicate definition for function foo with 2 arguments".to_string() }));
let mut checker = new_with_args(HashMap::new(), 0, functions);
assert_eq!(checker.check_function(&foo2), Err(Error { message: "Duplicate definition for function foo with signature (field, field) -> (field)".to_string() }));
}
#[test]

View file

@ -15,6 +15,20 @@ impl fmt::Debug for Signature {
impl fmt::Display for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({:?}) -> ({:?})", self.inputs, self.outputs)
try!(write!(f, "("));
for (i, t) in self.inputs.iter().enumerate() {
try!(write!(f, "{}", t));
if i < self.inputs.len() - 1 {
try!(write!(f, ", "));
}
}
try!(write!(f, ") -> ("));
for (i, t) in self.outputs.iter().enumerate() {
try!(write!(f, "{}", t));
if i < self.outputs.len() - 1 {
try!(write!(f, ", "));
}
}
write!(f, ")")
}
}