diff --git a/data/test/compile-fail/E0001.bonsai.java b/data/test/compile-fail/E0001.bonsai.java index e3c6ce1..cc1d2c0 100644 --- a/data/test/compile-fail/E0001.bonsai.java +++ b/data/test/compile-fail/E0001.bonsai.java @@ -13,12 +13,12 @@ // limitations under the License. #[error(E0001, 22, 9)] -#[error(E0001, 23, 23)] +#[error(E0001, 23, 30)] package test; public class CannotFindModule { module Unknown2 unknown2; - proc test() = module NotFound notFound; + public proc test() = module NotFound notFound; } diff --git a/data/test/compile-fail/E0002.bonsai.java b/data/test/compile-fail/E0002.bonsai.java index cdaf833..c00fb22 100644 --- a/data/test/compile-fail/E0002.bonsai.java +++ b/data/test/compile-fail/E0002.bonsai.java @@ -21,5 +21,5 @@ public class DuplicateAttribute single_time Dup d; single_time Dup d; - proc test() = nothing + public proc test() = nothing } diff --git a/data/test/compile-fail/E0003_1.bonsai.java b/data/test/compile-fail/E0003_1.bonsai.java index ad168a2..2415d1f 100644 --- a/data/test/compile-fail/E0003_1.bonsai.java +++ b/data/test/compile-fail/E0003_1.bonsai.java @@ -18,7 +18,7 @@ public class DuplicateVar { - proc test() = + public proc test() = single_time Dup d; single_time Dup d; end diff --git a/data/test/compile-fail/E0003_2.bonsai.java b/data/test/compile-fail/E0003_2.bonsai.java index b578611..781dd93 100644 --- a/data/test/compile-fail/E0003_2.bonsai.java +++ b/data/test/compile-fail/E0003_2.bonsai.java @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[error(E0003, 23, 32)] +#[error(E0003, 23, 39)] package test; @@ -20,5 +20,5 @@ public class DuplicateAttributeVar { single_time Dup d; - proc test() = single_time Dup d + public proc test() = single_time Dup d } diff --git a/data/test/compile-fail/E0003_3.bonsai.java b/data/test/compile-fail/E0003_3.bonsai.java index 729768a..32f8c89 100644 --- a/data/test/compile-fail/E0003_3.bonsai.java +++ b/data/test/compile-fail/E0003_3.bonsai.java @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[error(E0003, 24, 33)] -#[error(E0003, 25, 33)] +#[error(E0003, 24, 40)] +#[error(E0003, 25, 40)] package test; @@ -21,6 +21,6 @@ public class TwoDuplicateVar { single_time Dup d; - proc test1() = single_time Dup d - proc test2() = single_time Dup d + public proc test1() = single_time Dup d + public proc test2() = single_time Dup d } diff --git a/data/test/compile-fail/E0004.bonsai.java b/data/test/compile-fail/E0004.bonsai.java index def8606..6d526cd 100644 --- a/data/test/compile-fail/E0004.bonsai.java +++ b/data/test/compile-fail/E0004.bonsai.java @@ -12,17 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[error(E0004, 24, 7)] -#[error(E0004, 27, 7)] +#[error(E0004, 24, 14)] +#[error(E0004, 27, 14)] package test; public class DuplicateProc { - proc unique1() = nothing - proc dup() = nothing - proc dup() = nothing + public proc unique1() = nothing + public proc dup() = nothing + public proc dup() = nothing - proc unique2() = nothing - proc dup() = nothing + public proc unique2() = nothing + public proc dup() = nothing } diff --git a/data/test/compile-fail/E0005.bonsai.java b/data/test/compile-fail/E0005.bonsai.java index 0d99c47..3fbb0cd 100644 --- a/data/test/compile-fail/E0005.bonsai.java +++ b/data/test/compile-fail/E0005.bonsai.java @@ -25,5 +25,5 @@ public class FieldInitializationWithRef public FieldInitializationWithRef(T a) {} - proc test() = nothing + public proc test() = nothing } diff --git a/data/test/compile-fail/E0006_1.bonsai.java b/data/test/compile-fail/E0006_1.bonsai.java index ff200dc..3e70f3b 100644 --- a/data/test/compile-fail/E0006_1.bonsai.java +++ b/data/test/compile-fail/E0006_1.bonsai.java @@ -13,7 +13,7 @@ // limitations under the License. #[error(E0006, 24, 28)] -#[error(E0006, 32, 36)] +#[error(E0006, 32, 43)] package test; import java.lang.System; @@ -24,10 +24,10 @@ public class UndeclaredVariable single_space T t2 = new T(t3); single_space T t3 = new T(); - proc test() = + public proc test() = single_space T t4 = new T(); System.out.println(t4); end - proc test2() = System.out.println(t4) + public proc test2() = System.out.println(t4) } diff --git a/data/test/compile-fail/E0007.bonsai.java b/data/test/compile-fail/E0007.bonsai.java index 7571f29..776977a 100644 --- a/data/test/compile-fail/E0007.bonsai.java +++ b/data/test/compile-fail/E0007.bonsai.java @@ -18,10 +18,10 @@ public class UndeclaredProcess { - proc test() = + public proc test() = run test1(); run test2(); end - proc test1() = nothing + public proc test1() = nothing } diff --git a/data/test/compile-fail/E0008.bonsai.java b/data/test/compile-fail/E0008.bonsai.java index e17f25c..5c1f132 100644 --- a/data/test/compile-fail/E0008.bonsai.java +++ b/data/test/compile-fail/E0008.bonsai.java @@ -23,7 +23,7 @@ public class UnknownField { module Module m = new Module(); - proc test() = + public proc test() = m.a; m.c; J.inside_args(m.d, m.a); diff --git a/data/test/compile-fail/E0009.bonsai.java b/data/test/compile-fail/E0009.bonsai.java index 4c56a69..e4095df 100644 --- a/data/test/compile-fail/E0009.bonsai.java +++ b/data/test/compile-fail/E0009.bonsai.java @@ -21,7 +21,7 @@ public class UnknownProcess { module Module m = new Module(); - proc test() = + public proc test() = run m.test(); run m.wrong(); run m.b.test(); diff --git a/data/test/compile-fail/E0010.bonsai.java b/data/test/compile-fail/E0010.bonsai.java index 1ab9429..054bed9 100644 --- a/data/test/compile-fail/E0010.bonsai.java +++ b/data/test/compile-fail/E0010.bonsai.java @@ -21,7 +21,7 @@ public class ForeignProcessCall { module Module m = new Module(); - proc test() = + public proc test() = run m.test(); run m.a.foreign(); run m.b.a.foreign(); diff --git a/data/test/compile-fail/E0013.bonsai.java b/data/test/compile-fail/E0013.bonsai.java index 3966c17..a82b3ea 100644 --- a/data/test/compile-fail/E0013.bonsai.java +++ b/data/test/compile-fail/E0013.bonsai.java @@ -22,5 +22,5 @@ public class MissingConstructor single_space N b; ref single_space T ok; - proc missing_constructor() = nothing + public proc missing_constructor() = nothing } diff --git a/data/test/compile-fail/E0016.bonsai.java b/data/test/compile-fail/E0016.bonsai.java index 5d3c6ff..b47b302 100644 --- a/data/test/compile-fail/E0016.bonsai.java +++ b/data/test/compile-fail/E0016.bonsai.java @@ -27,7 +27,7 @@ public ForbiddenWriteOnPre(T a) { this.a = a; } - proc test() = + public proc test() = world_line N b; pre a <- 1; pre b <- 2; diff --git a/data/test/compile-fail/E0017.bonsai.java b/data/test/compile-fail/E0017.bonsai.java index 512c08a..c3260db 100644 --- a/data/test/compile-fail/E0017.bonsai.java +++ b/data/test/compile-fail/E0017.bonsai.java @@ -30,7 +30,7 @@ public PreOnlyOnStream(T a) { this.a = a; } - proc test() = + public proc test() = single_time N b; ok <- pre b; ok <- pre m; diff --git a/data/test/compile-fail/E0018.bonsai.java b/data/test/compile-fail/E0018.bonsai.java index 2481e33..8c56b21 100644 --- a/data/test/compile-fail/E0018.bonsai.java +++ b/data/test/compile-fail/E0018.bonsai.java @@ -23,7 +23,7 @@ public class IllegalLocalModuleInitializer { public single_space T a; - proc test() = + public proc test() = module Module ok3 = new Module(); module Module2 ko3 = Module2.create(); module Module2 ko4 = bot; diff --git a/data/test/compile-fail/E0019.bonsai.java b/data/test/compile-fail/E0019.bonsai.java index ae073c9..112bd61 100644 --- a/data/test/compile-fail/E0019.bonsai.java +++ b/data/test/compile-fail/E0019.bonsai.java @@ -21,7 +21,7 @@ public class MissingModuleInitializer { public single_space T a; - proc test() = + public proc test() = module Module ok3 = new Module(); module Module2 ko1; module Module ko2; diff --git a/data/test/compile-fail/E0021.bonsai.java b/data/test/compile-fail/E0021.bonsai.java index 3c405c9..187dae5 100644 --- a/data/test/compile-fail/E0021.bonsai.java +++ b/data/test/compile-fail/E0021.bonsai.java @@ -29,5 +29,5 @@ public class ModuleRefFieldInitializer public module Module2 ko1 = new Module2(a); public module Module2 ko2 = Module2.create(a); - proc test() = nothing + public proc test() = nothing } diff --git a/data/test/compile-fail/E0022.bonsai.java b/data/test/compile-fail/E0022.bonsai.java index db6fb17..0f9243b 100644 --- a/data/test/compile-fail/E0022.bonsai.java +++ b/data/test/compile-fail/E0022.bonsai.java @@ -23,7 +23,7 @@ public class ModuleRefInitializer { public single_space T a; - proc test() = + public proc test() = module Module2 ok1 = new Module2(a); module Module2 ko1 = new Module2(new T()); module Module2 ko2 = new Module2(J.make()); diff --git a/data/test/compile-fail/E0023.bonsai.java b/data/test/compile-fail/E0023.bonsai.java index f905ba2..bd29b32 100644 --- a/data/test/compile-fail/E0023.bonsai.java +++ b/data/test/compile-fail/E0023.bonsai.java @@ -25,7 +25,7 @@ public class ModuleParameterMismatch public single_time T c; public module Module d; - proc test() = + public proc test() = module Module2 ok1 = new Module2(a); module Module2 ko1 = new Module2(b); module Module2 ko2 = new Module2(c); diff --git a/data/test/compile-fail/E0024.bonsai.java b/data/test/compile-fail/E0024.bonsai.java index c5e1cf1..d20904a 100644 --- a/data/test/compile-fail/E0024.bonsai.java +++ b/data/test/compile-fail/E0024.bonsai.java @@ -22,7 +22,7 @@ public class ModuleParameterMismatch public single_space T a; public single_space T b; - proc test() = + public proc test() = module Module2 ko1 = new Module2(a, b); module Module2 ko2 = new Module2(); end diff --git a/data/test/compile-fail/E0025.bonsai.java b/data/test/compile-fail/E0025.bonsai.java index 722e271..6ed6c40 100644 --- a/data/test/compile-fail/E0025.bonsai.java +++ b/data/test/compile-fail/E0025.bonsai.java @@ -22,7 +22,7 @@ public class ForbiddenHostLocalVariable public T ok; public single_space T b; - proc test() = + public proc test() = T ko = new T(); single_space T ok2 = new T(); when ok2 |= ok2 then diff --git a/data/test/compile-fail/E0026.bonsai.java b/data/test/compile-fail/E0026.bonsai.java index 52751bc..0213d40 100644 --- a/data/test/compile-fail/E0026.bonsai.java +++ b/data/test/compile-fail/E0026.bonsai.java @@ -26,7 +26,7 @@ public class IllegalPermissionInContext public single_space LMax a; public single_space LMax b; - proc test() = + public proc test() = write a <- 1; // OK a <- 2; // OK read a <- 3; // KO diff --git a/data/test/compile-fail/E0027.bonsai.java b/data/test/compile-fail/E0027.bonsai.java index 26fc644..f17050c 100644 --- a/data/test/compile-fail/E0027.bonsai.java +++ b/data/test/compile-fail/E0027.bonsai.java @@ -27,7 +27,7 @@ public class IllegalHostFunctionInReadContext public single_space LMax b; public ES t; - proc test() = + public proc test() = t <- a |= b; // OK t <- f(a) |= b; // KO t <- a |= f(b); // KO diff --git a/data/test/compile-fail/E0028.bonsai.java b/data/test/compile-fail/E0028.bonsai.java index 4f454c5..d974fdd 100644 --- a/data/test/compile-fail/E0028.bonsai.java +++ b/data/test/compile-fail/E0028.bonsai.java @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[error(E0028, 34, 20)] +#[error(E0028, 34, 27)] #[error(E0028, 37, 4)] #[error(E0028, 42, 4)] #[error(E0028, 52, 4)] @@ -31,14 +31,14 @@ public class E0028 // InstantaneousLoop public single_space LMax a; public single_space LMax b; - proc test_ko1() = loop nothing end + public proc test_ko1() = loop nothing end - proc test_ko2() = + public proc test_ko2() = loop when a |= b then nothing end end - proc test_ko3() = + public proc test_ko3() = loop when a |= b then nothing @@ -48,21 +48,21 @@ proc test_ko3() = a <- f(a) end - proc test_ko4() = + public proc test_ko4() = loop suspend when a |= b in nothing end end - proc test_ko5() = + public proc test_ko5() = loop abort when a |= b in pause end end - proc test_ko6() = + public proc test_ko6() = loop when a |= b then suspend when a |= b in @@ -73,7 +73,7 @@ proc test_ko6() = end end - proc test_ko7() = + public proc test_ko7() = loop abort when a |= b in loop @@ -83,7 +83,7 @@ proc test_ko7() = pause end - proc test_ko8() = + public proc test_ko8() = loop abort when a |= b in loop @@ -92,17 +92,17 @@ proc test_ko8() = end end - proc test1() = + public proc test1() = abort when a |= b in pause end - proc test_ko9() = + public proc test_ko9() = loop run test1(); end - proc test_ko10() = + public proc test_ko10() = loop par || run test1() diff --git a/data/test/compile-fail/E0029.bonsai.java b/data/test/compile-fail/E0029.bonsai.java index 814c81c..8359734 100644 --- a/data/test/compile-fail/E0029.bonsai.java +++ b/data/test/compile-fail/E0029.bonsai.java @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[error(E0029, 30, 20)] -#[error(E0029, 31, 20)] -#[error(E0029, 32, 20)] -#[error(E0029, 33, 20)] -#[error(E0029, 34, 20)] -#[error(E0029, 35, 20)] -#[error(E0029, 39, 20)] +#[error(E0029, 30, 27)] +#[error(E0029, 31, 27)] +#[error(E0029, 32, 27)] +#[error(E0029, 33, 27)] +#[error(E0029, 34, 27)] +#[error(E0029, 35, 27)] +#[error(E0029, 39, 27)] package test; @@ -27,14 +27,14 @@ public class E0029 // NonInstantaneousSpace public single_space LMax a; public single_space LMax b; - proc test_ko1() = space pause end - proc test_ko2() = space pause up end - proc test_ko3() = space stop end - proc test_ko4() = space loop pause end end - proc test_ko5() = space suspend when a |= b in nothing end end - proc test_ko6() = space when a |= b then nothing else pause end end - proc test1() = nothing - proc test2() = pause - proc test_ok1() = space run test1() end - proc test_ko8() = space run test2() end + public proc test_ko1() = space pause end + public proc test_ko2() = space pause up end + public proc test_ko3() = space stop end + public proc test_ko4() = space loop pause end end + public proc test_ko5() = space suspend when a |= b in nothing end end + public proc test_ko6() = space when a |= b then nothing else pause end end + public proc test1() = nothing + public proc test2() = pause + public proc test_ok1() = space run test1() end + public proc test_ko8() = space run test2() end } diff --git a/data/test/compile-fail/E0030.bonsai.java b/data/test/compile-fail/E0030.bonsai.java index 7adaf51..ca113c4 100644 --- a/data/test/compile-fail/E0030.bonsai.java +++ b/data/test/compile-fail/E0030.bonsai.java @@ -12,28 +12,28 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[error(E0030, 23, 7)] -#[error(E0030, 25, 7)] -#[error(E0030, 29, 7)] +#[error(E0030, 23, 14)] +#[error(E0030, 25, 14)] +#[error(E0030, 29, 14)] package test; public class E0030 { - proc test_ko1() = run test_ko1() + public proc test_ko1() = run test_ko1() - proc test_ko2() = run test_ko2_1() + public proc test_ko2() = run test_ko2_1() - proc test_ko2_1() = run test_ko2() + public proc test_ko2_1() = run test_ko2() - proc test_ko3() = + public proc test_ko3() = when true then module E0030 m = new E0030(); run m.test_ko3(); end // The error is caugth in test_ko1, we do not repeat it. - proc test_ok4() = + public proc test_ok4() = module E0030 m = new E0030(); run m.test_ko1(); end diff --git a/data/test/compile-fail/E0031.bonsai.java b/data/test/compile-fail/E0031.bonsai.java index 29a65a0..49160fc 100644 --- a/data/test/compile-fail/E0031.bonsai.java +++ b/data/test/compile-fail/E0031.bonsai.java @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[error(E0031, 32, 20)] -#[error(E0031, 33, 20)] -#[error(E0031, 40, 20)] +#[error(E0031, 32, 27)] +#[error(E0031, 33, 27)] +#[error(E0031, 40, 27)] #[error(E0031, 43, 4)] -#[error(E0031, 46, 20)] -#[error(E0031, 48, 20)] +#[error(E0031, 46, 27)] +#[error(E0031, 48, 27)] #[error(E0031, 50, 4)] #[error(E0031, 62, 4)] #[error(E0031, 71, 4)] @@ -29,44 +29,44 @@ public class E0031 // SpaceInSpace public single_space LMax a; public single_space LMax b; - proc test_ko1() = space space nothing end end - proc test_ko2() = space + public proc test_ko1() = space space nothing end end + public proc test_ko2() = space par || space nothing end || nothing end end - proc test1() = space nothing end - proc test_ko3() = space run test1() end - proc test_ko4() = + public proc test1() = space nothing end + public proc test_ko3() = space run test1() end + public proc test_ko4() = module E0031 m = new E0031(); space run m.test1() end end - proc test_ko5() = space prune end - proc test2() = prune - proc test_ko6() = space run test2() end - proc test_ko7() = + public proc test_ko5() = space prune end + public proc test2() = prune + public proc test_ko6() = space run test2() end + public proc test_ko7() = space module E0031 m = new E0031(); run m.test2() end - proc test3() = + public proc test3() = par || prune || space nothing end end - proc test_ko8() = + public proc test_ko8() = space run test3() end - proc test4() = + public proc test4() = a <- 1; prune; prune; end - proc test_ko9() = + public proc test_ko9() = space run test4() end } diff --git a/data/test/compile-pass/E0003.bonsai.java b/data/test/compile-pass/E0003.bonsai.java index 4327c6f..03f8075 100644 --- a/data/test/compile-pass/E0003.bonsai.java +++ b/data/test/compile-pass/E0003.bonsai.java @@ -18,6 +18,6 @@ public class DistinctScope { - proc test1() = single_time Dup d - proc test2() = single_time Dup d + public proc test1() = single_time Dup d + public proc test2() = single_time Dup d } diff --git a/data/test/compile-pass/E0005.bonsai.java b/data/test/compile-pass/E0005.bonsai.java index 1ff2886..4fddb8c 100644 --- a/data/test/compile-pass/E0005.bonsai.java +++ b/data/test/compile-pass/E0005.bonsai.java @@ -20,5 +20,5 @@ public class CorrectFieldInitialization single_space L t2 = new L(true); single_space Mixed t3 = new Mixed(0, true, 8, "bonsai"); - proc test() = nothing + public proc test() = nothing } diff --git a/data/test/compile-pass/E0028.bonsai.java b/data/test/compile-pass/E0028.bonsai.java index d95d462..70639b2 100644 --- a/data/test/compile-pass/E0028.bonsai.java +++ b/data/test/compile-pass/E0028.bonsai.java @@ -19,27 +19,28 @@ public class E0028 // NonInstantaneousLoop single_space LMax a; single_space LMax b; - proc test1() = loop pause end - proc test2() = + proc test() = run temporary() // because causality analysis contains unimplemented fields. + public proc test1() = loop pause end + public proc test2() = loop suspend when a |= b in pause end end - proc test3() = loop stop end - proc test4() = loop pause up end - proc test5() = + public proc test3() = loop stop end + public proc test4() = loop pause up end + public proc test5() = loop abort when a |= b in nothing end; pause end - proc test6() = + public proc test6() = loop loop pause end end - proc test7() = + public proc test7() = loop when a |= b then pause else stop end end - proc test8() = + public proc test8() = loop when a |= b then pause @@ -50,7 +51,7 @@ proc test8() = end end - proc test9() = + public proc test9() = loop par || when a |= b then stop end @@ -58,7 +59,7 @@ proc test9() = end end - proc test10() = + public proc test10() = loop par <> when a |= b then pause end @@ -66,12 +67,12 @@ proc test10() = end end - proc test11() = + public proc test11() = loop run test10(); end - proc test12() = + public proc test12() = loop par || when a |= b then run test10() end diff --git a/data/test/compile-pass/W0001_1.bonsai.java b/data/test/compile-pass/W0001_1.bonsai.java new file mode 100644 index 0000000..dc21364 --- /dev/null +++ b/data/test/compile-pass/W0001_1.bonsai.java @@ -0,0 +1,23 @@ +// Copyright 2018 Pierre Talbot (IRCAM) + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package test; + +public class W0001 +{ + public proc test() = pause; par run test2() || run test3() end end + proc test2() = nothing + proc test3() = nothing + public proc test4() = nothing +} diff --git a/data/test/compile-pass/W0001_2.bonsai.java b/data/test/compile-pass/W0001_2.bonsai.java new file mode 100644 index 0000000..a98df1d --- /dev/null +++ b/data/test/compile-pass/W0001_2.bonsai.java @@ -0,0 +1,22 @@ +// Copyright 2018 Pierre Talbot (IRCAM) + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[warning(W0001, 21, 7)] + +package test; + +public class W0001 +{ + proc test() = nothing +} diff --git a/src/ast.rs b/src/ast.rs index 1a3f057..bb96942 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -770,16 +770,23 @@ impl FQN { span: span } } + + pub fn is_empty(&self) -> bool { + self.names.is_empty() + } } impl Display for FQN { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { - let mut i = 0; - while i < self.names.len() - 1 { - fmt.write_fmt(format_args!("{}.", self.names[i]))?; - i += 1; + if !self.is_empty() { + let mut i = 0; + while i < self.names.len() - 1 { + fmt.write_fmt(format_args!("{}.", self.names[i]))?; + i += 1; + } + fmt.write_str(self.names[i].as_str())?; } - fmt.write_str(self.names[i].as_str()) + Ok(()) } } diff --git a/src/context.rs b/src/context.rs index 77a4bb5..3a688f9 100644 --- a/src/context.rs +++ b/src/context.rs @@ -15,6 +15,7 @@ pub use ast::*; pub use visitor::*; pub use partial::*; +use std::fmt::{Display, Error, Formatter}; #[derive(Clone, Debug)] pub struct VarInfo { @@ -106,6 +107,24 @@ impl ModuleInfo { } } +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct ProcessUID { + pub module: Ident, + pub process: Ident +} + +impl ProcessUID { + pub fn new(module: Ident, process: Ident) -> Self { + ProcessUID { module, process } + } +} + +impl Display for ProcessUID { + fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> { + formatter.write_fmt(format_args!("{}.{}", self.module, self.process)) + } +} + pub struct Context { pub ast: JCrate, /// Indexes of `vars` are referred to as "UIDs", and are contained in the `VarPath` structure. @@ -114,7 +133,8 @@ pub struct Context { /// Similarly for the fields of host objects declared in "bonsai". /// Basically, everything we cannot access and that is not part of the "bonsai" world. pub vars: Vec, - pub modules: Vec + pub modules: Vec, + pub entry_points: Vec } impl Context { @@ -123,7 +143,8 @@ impl Context { ast: ast, vars: vec![VarInfo::local(Ident::gen(""), Kind::Host, JType::simple(DUMMY_SP, Ident::gen("")))], - modules: vec![] + modules: vec![], + entry_points: vec![] } } @@ -139,6 +160,11 @@ impl Context { self.ast = ast; } + pub fn set_entry_points(&mut self, entry_points: Vec) { + assert!(self.entry_points.is_empty(), "Context: Entry points have already been set."); + self.entry_points = entry_points; + } + fn alloc_var(&mut self, binding: &mut Binding, var_info: VarInfo) -> usize { let idx = self.vars.len(); self.vars.push(var_info); @@ -184,20 +210,25 @@ impl Context { .expect("module_by_name: Module not declared.") } + pub fn find_proc(&self, uid: ProcessUID) -> Process { + let bug_msg = + &format!("[BUG] Verification that processes and modules exist should be done before calling `find_proc`. ({})", uid); + let module = self.ast.find_mod_by_name(&uid.module).expect(bug_msg); + module.find_process_by_name(&uid.process).expect(bug_msg) + } + // From a process call, we retrieve its module and definition. // It can be used to follow to the call to a process, in contrast to `walk_proc_call` which does not. - pub fn find_proc_from_call(&self, current_mod: Ident, process: Ident, - var: Option) -> (Ident, Process) + pub fn find_proc_from_call(&self, current_mod: Ident, proc_name: Ident, + var: Option) -> (ProcessUID, Process) { - let bug_msg = - &format!("[BUG] Verification that processes and modules exist should be done before calling `find_proc_from_call`. ({}.{})", current_mod, process); - let mod_name = - match var { - None => current_mod.clone(), - Some(var) => self.var_by_uid(var.last_uid()).mod_name() - }; - let module = self.ast.find_mod_by_name(&mod_name).expect(bug_msg); - (mod_name, module.find_process_by_name(&process).expect(bug_msg)) + let mod_name = + match var { + None => current_mod.clone(), + Some(var) => self.var_by_uid(var.last_uid()).mod_name() + }; + let uid = ProcessUID::new(mod_name, proc_name); + (uid.clone(), self.find_proc(uid)) } /// Check in the imports of the current module `mod_name` if `class_name` is explicitly imported. diff --git a/src/errors.rs b/src/errors.rs index 73916e4..6e4de59 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -47,6 +47,7 @@ E0029: r##"`space` statement with a body that is not instantaneous."##, E0030: r##"Recursive process calls are forbidden."##, E0031: r##"Search statement (`space` and `prune`) in the process `p` of a `space p end` statement."##, E0032: r##"Two readwrite accesses on the same variable."##, -E0033: r##"A constraint model generated by the causality analysis is unsatisfiable."##, +E0033: r##"Non causal program: A constraint model generated by the causality analysis is unsatisfiable."##, E0034: r##"Forbidden permission on host paths."##, +W0001: r##"Private process that is never called."## } diff --git a/src/middle/instantaneous.rs b/src/middle/instantaneous.rs index e9772a0..d59040d 100644 --- a/src/middle/instantaneous.rs +++ b/src/middle/instantaneous.rs @@ -169,9 +169,9 @@ impl Visitor for InstantaneousAnalysis } fn visit_proc_call(&mut self, var: Option, process: Ident, _args: Vec) { - let (mod_name, process) = self.context.find_proc_from_call(self.current_module.clone(), process, var); + let (uid, process) = self.context.find_proc_from_call(self.current_module.clone(), process, var); let old = self.current_module.clone(); - self.current_module = mod_name; + self.current_module = uid.module; self.visit_process(process); self.current_module = old; } diff --git a/src/middle/recursive_call.rs b/src/middle/recursive_call.rs index 2e66223..e3343c6 100644 --- a/src/middle/recursive_call.rs +++ b/src/middle/recursive_call.rs @@ -16,8 +16,13 @@ /// Recursion is forbidden in spacetime because an instant must be statically bounded in time. /// On the other hand, we do not allow recursion across instant yet to keep the causality analysis simple. +/// In addition, it sets the entry points UID (of the form `module.proc`) in `context` such that: +/// 1. They are not called from another process. +/// 2. They are not processes from libraries. + use context::*; use session::*; +use std::collections::HashSet; pub fn recursive_call(session: Session, context: Context) -> Env { let recursive_call = RecursiveCall::new(session, context); @@ -29,8 +34,9 @@ pub fn recursive_call(session: Session, context: Context) -> Env { struct RecursiveCall { session: Session, context: Context, - recursion_path: Vec, - process_visited: Vec, + entry_points: HashSet, + recursion_path: Vec, + process_visited: Vec, current_module: Ident } @@ -38,8 +44,9 @@ impl RecursiveCall { pub fn new(session: Session, context: Context) -> Self { let dummy_ident = context.dummy_ident(); RecursiveCall { - session: session, - context: context, + session, + context, + entry_points: HashSet::new(), recursion_path: vec![], process_visited: vec![], current_module: dummy_ident, @@ -49,6 +56,9 @@ impl RecursiveCall { fn analyse(mut self) -> Env { let bcrate_clone = self.context.clone_ast(); self.visit_crate(bcrate_clone); + self.check_entry_points(); + let entry_points: Vec<_> = self.entry_points.into_iter().collect(); + self.context.set_entry_points(entry_points); if self.session.has_errors() { Env::fake(self.session, self.context) } else { @@ -56,6 +66,24 @@ impl RecursiveCall { } } + fn check_entry_points(&self) { + for uid in self.entry_points.iter().cloned() { + let process = self.context.find_proc(uid); + if process.visibility == JVisibility::Private { + self.warn_private_entry_point(process); + } + } + } + + fn warn_private_entry_point(&self, process: Process) { + self.session.struct_span_warn_with_code(process.name.span, + "private process never called.", + "W0001") + .help(&"This process is private but never called.\n\ + Solution: Make the process `public` or delete this process.") + .emit(); + } + fn err_forbid_recursive_call(&mut self, process: Process) { self.session.struct_span_err_with_code(process.name.span, "forbidden recursive process call.", @@ -77,25 +105,47 @@ impl RecursiveCall { path_desc } - fn is_rec(&self, uid: &String) -> bool { + fn is_rec(&self, uid: &ProcessUID) -> bool { self.recursion_path.iter().any(|p| p == uid) } - fn already_visited(&self, uid: &String) -> bool { + fn already_visited(&self, uid: &ProcessUID) -> bool { self.process_visited.iter().any(|p| p == uid) } - fn process_uid(&self, process: &Ident) -> String { - format!("{}.{}", self.current_module, process) + fn process_uid(&self, process_name: &Ident) -> ProcessUID { + ProcessUID::new(self.current_module.clone(), process_name.clone()) + } + + fn current_mod_is_lib(&self) -> bool { + self.context.ast.find_mod_by_name(&self.current_module).unwrap().file.is_lib() + } + + /// Entry points are added only for processes that are not in a library module, and if they have not been explored before. + /// This latest condition is important in case a process is called before its declaration is visited (without this condition, we would consider it an entry point). + fn insert_entry_point(&mut self, process: &Process) { + let uid = self.process_uid(&process.name); + if !self.current_mod_is_lib() && !self.already_visited(&uid) { + self.entry_points.insert(uid); + } + } + + fn remove_entry_point(&mut self, uid: &ProcessUID) { + self.entry_points.remove(uid); } } impl Visitor for RecursiveCall { + /// Every process is a potential entry point. + /// Processes are removed in `visit_proc_call` if they are called. fn visit_module(&mut self, module: JModule) { let old = self.current_module.clone(); self.current_module = module.mod_name(); - walk_processes(self, module.processes); + for process in module.processes { + self.insert_entry_point(&process); + self.visit_process(process); + } self.current_module = old; } @@ -115,9 +165,10 @@ impl Visitor for RecursiveCall } fn visit_proc_call(&mut self, var: Option, process: Ident, _args: Vec) { - let (mod_name, process) = self.context.find_proc_from_call(self.current_module.clone(), process, var); + let (uid, process) = self.context.find_proc_from_call(self.current_module.clone(), process, var); + self.remove_entry_point(&uid); let old = self.current_module.clone(); - self.current_module = mod_name; + self.current_module = uid.module; self.visit_process(process); self.current_module = old; } diff --git a/src/middle/search_tree_wf.rs b/src/middle/search_tree_wf.rs index 31c6736..7a654cb 100644 --- a/src/middle/search_tree_wf.rs +++ b/src/middle/search_tree_wf.rs @@ -99,9 +99,9 @@ impl Visitor for SearchTreeWellFormedness } fn visit_proc_call(&mut self, var: Option, process: Ident, _args: Vec) { - let (mod_name, process) = self.context.find_proc_from_call(self.current_module.clone(), process, var); + let (uid, process) = self.context.find_proc_from_call(self.current_module.clone(), process, var); let old_mod = self.current_module.clone(); - self.current_module = mod_name; + self.current_module = uid.module; let mut old_search = self.search_statements.clone(); self.search_statements = vec![]; self.visit_process(process);