hic-0.0.0.1: test/Language/Cimple/Hic/Inference/IterationSpec.hs
{-# LANGUAGE OverloadedStrings #-}
module Language.Cimple.Hic.Inference.IterationSpec
( spec
) where
import Language.Cimple.Hic.Inference (inferProgram)
import Language.Cimple.Hic.InferenceSpec (checkInference, mustParse)
import Test.Hspec (Spec, describe, it,
shouldBe)
spec :: Spec
spec = describe "Iteration inference" $ do
describe "ForEach" $ do
checkInference
[ "void f() {"
, " for (int i = 0; i < 10; ++i) {"
, " printf(\"%d\\n\", arr[i]);"
, " }"
, "}"
]
[ "void f() {"
, " for_each i in arr {"
, " printf(\"%d\\n\", i);"
, " }"
, "}"
]
checkInference
[ "void f() {"
, " for (int i = 0; i < 10; ++i) {"
, " printf(\"%d: %d\\n\", i, arr[i]);"
, " }"
, "}"
]
[ "void f() {"
, " for_each (index, i) in enumerate(arr) {"
, " printf(\"%d: %d\\n\", index, i);"
, " }"
, "}"
]
checkInference
[ "uint64_t calculate_comp_value(const uint8_t *pk1, const uint8_t *pk2) {"
, " uint64_t cmp1 = 0;"
, " uint64_t cmp2 = 0;"
, " for (size_t i = 0; i < 8; ++i) {"
, " cmp1 = (cmp1 << 8) + (uint64_t)pk1[i];"
, " cmp2 = (cmp2 << 8) + (uint64_t)pk2[i];"
, " }"
, " return cmp1 - cmp2;"
, "}"
]
[ "uint64_t calculate_comp_value(uint8_t const* pk1, uint8_t const* pk2) {"
, " uint64_t cmp1 = 0;"
, ""
, " uint64_t cmp2 = 0;"
, ""
, " for_each index in (pk1, pk2) {"
, " cmp1 = (cmp1 << 8) + (uint64_t)pk1[index];"
, ""
, " cmp2 = (cmp2 << 8) + (uint64_t)pk2[index];"
, " }"
, ""
, " return cmp1 - cmp2;"
, "}"
]
checkInference
[ "void f() {"
, " for (uint32_t i = 0; i < c->crypto_connections_length; ++i) {"
, " process(c->crypto_connections[i]);"
, " }"
, "}"
]
[ "void f() {"
, " for_each i in c->crypto_connections {"
, " process(i);"
, " }"
, "}"
]
checkInference
[ "void f() {"
, " for (int i = 0; i < 10; ++i) {"
, " arr[i] = i;"
, " }"
, "}"
]
[ "void f() {"
, " for_each (index, i) in enumerate(arr) {"
, " i = index;"
, " }"
, "}"
]
it "warns when induction variable is modified" $ do
prog <- mustParse
[ "void f() {"
, " for (int i = 0; i < 10; ++i) {"
, " arr[i] = 0;"
, " i = 5;"
, " }"
, "}"
]
let (_, diags) = inferProgram prog
diags `shouldBe` ["test.c:2: Induction variable 'i' is modified within the loop body. Refactor to enable for_each lifting."]
checkInference
[ "void f() {"
, " for (int i = 0; i < 10; ++i) {"
, " arr[i] = 0;"
, " arr2[i] = 1;"
, " }"
, "}"
]
[ "void f() {"
, " for_each index in (arr, arr2) {"
, " arr[index] = 0;"
, ""
, " arr2[index] = 1;"
, " }"
, "}"
]
it "warns when container expression is not stable" $ do
prog <- mustParse
[ "void f(int matrix[10][10], int j) {"
, " for (int i = 0; i < 10; ++i) {"
, " matrix[j][i] = 0;"
, " }"
, "}"
]
let (_, diags) = inferProgram prog
diags `shouldBe` ["test.c:2: Container expression is not stable. Refactor to enable for_each lifting."]
checkInference
[ "void f(int matrix[10][10], int j) {"
, " int *row = matrix[j];"
, " for (int i = 0; i < 10; ++i) {"
, " row[i] = 0;"
, " }"
, "}"
]
[ "void f(int matrix[10][10], int j) {"
, " int* row = matrix[j];"
, ""
, " for_each i in row {"
, " i = 0;"
, " }"
, "}"
]
describe "Find" $ do
checkInference
[ "int find(int *arr, int size, int key) {"
, " for (int i = 0; i < size; ++i) {"
, " if (arr[i] == key) return i;"
, " }"
, " return -1;"
, "}"
]
[ "int find(int* arr, int size, int key) {"
, " find i in arr where i == key {"
, " return index;"
, " } else {"
, " return -1;"
, " }"
, "}"
]
checkInference
[ "int find_wrapped(int *arr, int size, int key) {"
, " for (int i = 0; i < size; ++i) {"
, " if (arr[i] == key) {"
, " return i;"
, " }"
, " }"
, " return -1;"
, "}"
]
[ "int find_wrapped(int* arr, int size, int key) {"
, " find i in arr where i == key {"
, " return index;"
, " } else {"
, " return -1;"
, " }"
, "}"
]