Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Topic/genc v2: ready for general review #290

Merged
merged 77 commits into from
Feb 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
37b7e5a
Make GenCSuite more robust
mantognini Oct 3, 2016
420b145
Add many regression tests
mantognini Nov 8, 2016
86a0538
Clean slate for GenC
mantognini Nov 8, 2016
bf7d3b1
Add TimedLeonPhase trait
mantognini Nov 1, 2016
d35c0d3
Implement RemoveVCPhase
mantognini Oct 19, 2016
0e280b1
Add GenC v2
mantognini Nov 8, 2016
c31230a
Add more regression tests for scope, inheritance and generics
mantognini Nov 10, 2016
6e56930
Make sure to use a new reporter for each test in GenCSuite
mantognini Nov 10, 2016
0e9528c
Improve ClassLifter for fields and arrays
mantognini Nov 12, 2016
09cb198
Reorder GenC internal pipeline
mantognini Nov 12, 2016
6cd74d0
Cleanly reject unsupported operators
mantognini Nov 12, 2016
3c00391
Add missing update of IR
mantognini Nov 12, 2016
f40514e
Make an invalid test more relevant
mantognini Nov 12, 2016
3907f38
Blind attempt to improve GenCSuite for Larabot
mantognini Nov 13, 2016
0321eb5
Explicitly reject ArrayUpdated constructs
mantognini Nov 13, 2016
7c5fe34
Improve error messages for unsupported casts
mantognini Nov 14, 2016
ad0266c
Add chaining regression test
mantognini Nov 14, 2016
862775f
Update IntegralColor to no longer use VLA
mantognini Nov 15, 2016
121d765
Ensure GenC tests actually test something
mantognini Nov 15, 2016
91b4dff
Improve normalisation with mutable types
mantognini Nov 16, 2016
4d4ad3f
Minor improvements, make IRPrinter more verbose for debugging purpose
mantognini Nov 16, 2016
be87190
Make GenC tests return a value in [0, 255] to avoid false positive
mantognini Nov 16, 2016
240326b
Add regression test for operator Equals
mantognini Nov 16, 2016
ffaa95c
Add more vicious normalisation tests
mantognini Nov 16, 2016
bd81242
Make normaliser great again!
mantognini Nov 16, 2016
fe3bb1f
Improve support for nesting & generic functions
mantognini Nov 17, 2016
d151c31
Remove useless optimisation of id translation
mantognini Nov 17, 2016
0472cd5
Update regression test about invalid pattern matching
mantognini Nov 17, 2016
1dd6229
Minor improvements of FIS/FOS
mantognini Nov 18, 2016
8e015bf
Cosmetic update
mantognini Nov 20, 2016
8460f96
Implement tryReadInt & tweak some other I/O APIs
mantognini Nov 20, 2016
a5f5a76
Add support for Byte in GenC
mantognini Dec 1, 2016
2516a3c
Fix shift conversion to C
mantognini Dec 1, 2016
e463dbb
Add functions to StdIn/StdOut to read/write bytes
mantognini Dec 2, 2016
c198ce0
Make GenCSuite robust against encoding issues
mantognini Dec 2, 2016
8929200
Add functions to File(Input|Output)Stream to read/write bytes
mantognini Dec 2, 2016
c592017
Add support for more forms of Pattern Matching in GenC
mantognini Dec 6, 2016
f71f3f1
Fix type probing on enumerations
mantognini Dec 6, 2016
261bcb9
Fix mismatch in global id counter with FieldAssignment
mantognini Dec 6, 2016
49ae298
When building an array using call by name, always freshen ids
mantognini Dec 6, 2016
a539b6a
Fix Referentiator and Normalisator relationship
mantognini Dec 12, 2016
584ae3b
Fix more aliasing issues
mantognini Dec 12, 2016
782c9b9
Fix incorrect assumption in Expr.getType
mantognini Dec 12, 2016
bbf6d6e
Significantly optimise processing initialisation of arrays of zeros i…
mantognini Dec 12, 2016
b00e85f
Fix some typo
mantognini Dec 12, 2016
b2a45f5
Make C compilers not emit warnings with ^, |, and & by using parentheses
mantognini Dec 12, 2016
4c99fcc
Properly reject functions returning arrays
mantognini Dec 13, 2016
739a1c7
Update GenC tests
mantognini Dec 13, 2016
02b89d8
Add regression tests that should fail about aliasing
mantognini Dec 13, 2016
9194733
Add some aliasing regression tests that should get rejected
mantognini Dec 13, 2016
9b4a33d
Emit warnings on recursive functions
mantognini Dec 13, 2016
1b8e55f
Enable more C optimisation by making every function static
mantognini Dec 13, 2016
ca6a2de
Make library functions static as well
mantognini Dec 13, 2016
76b546a
Add a first implementation of LZW for GenC
mantognini Oct 17, 2016
2855b6b
LZW v2.dirty
mantognini Dec 9, 2016
3282308
Remove debug output in LZW
mantognini Dec 9, 2016
bedc207
Make LZW continue with full dictionary
mantognini Dec 9, 2016
fc1236d
Remove old code from LZW
mantognini Dec 9, 2016
38f1c76
Avoid overflow in LZW
mantognini Dec 12, 2016
b687527
Update LZW parameters
mantognini Dec 12, 2016
34ff8ee
Rename function
mantognini Dec 12, 2016
b98422b
Use a different representation for Dictionary in LZW
mantognini Dec 12, 2016
ec5db50
Keep both versions of LZW around
mantognini Dec 12, 2016
c8ecf7c
Move some tests around
mantognini Dec 14, 2016
8ca576f
Fix LZW object names for testing purposes
mantognini Dec 14, 2016
ec37922
Moving LZW implementations to a new testcases section
mantognini Dec 14, 2016
1748148
Fix generation of union
mantognini Jan 13, 2017
46be524
Update LZW parameters
mantognini Jan 13, 2017
70138c5
Use block comment in C code
mantognini Jan 18, 2017
f77238b
Add support for Tuple6 to Tuple8
mantognini Jan 27, 2017
a583e1b
Remove RemoveVCPhase, for performance and issue reasons
mantognini Jan 27, 2017
05c2136
Minor improvement of scrutinee handling in pattern matching
mantognini Jan 27, 2017
a35be9a
Report special assertion as Overflows
mantognini Jan 31, 2017
3b53420
Add regression test for GenC
mantognini Jan 27, 2017
5e84253
Add support for more scrutinee kind
mantognini Jan 27, 2017
bae8c9a
Fix typos
mantognini Jan 30, 2017
e27a4f7
Add case study ImageProcessing for GenC
mantognini Jan 27, 2017
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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ Leon.iml
#scripts
out-classes

#genc test suite
*.o
echo.txt
test.txt

#z3
.z3-trace

Expand Down
184 changes: 137 additions & 47 deletions library/leon/io/FileInputStream.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
package leon.io

import leon.annotation._
import leon.lang.Option

// See NOTEs in StdIn.
//
// NOTE Don't attempt to create a FileInputStream directly. Use FileInputStream.open instead.
//
// NOTE Don't forget to close the stream.

import leon.lang._

/**
* See NOTEs for GenC in StdIn.
*
* NOTE Don't attempt to create a FileInputStream directly. Use FileInputStream.open instead.
*
* NOTE Don't forget to close the stream.
*/
@library
object FileInputStream {

Expand All @@ -20,35 +21,33 @@ object FileInputStream {
@extern
@cCode.function(code =
"""
|FILE* __FUNCTION__(char* filename, void* unused) {
|static FILE* __FUNCTION__(char* filename, void* unused) {
| FILE* this = fopen(filename, "r");
| // this == NULL on failure
| /* this == NULL on failure */
| return this;
|}
"""
)
def open(filename: String)(implicit state: State): FileInputStream = {
state.seed += 1

// FIXME Importing leon.lang.Option doesn't mean it is imported, why?
new FileInputStream(
try {
// Check whether the stream can be opened or not
val out = new java.io.FileReader(filename)
out.close()
leon.lang.Some[String](filename)
Some[String](filename)
} catch {
case _: Throwable => leon.lang.None[String]
},
0 // nothing consumed yet
case _: Throwable => None[String]
}
)
}

}

@library
@cCode.typedef(alias = "FILE*", include = "stdio.h")
case class FileInputStream(var filename: Option[String], var consumed: BigInt) {
case class FileInputStream private (var filename: Option[String], var consumed: BigInt = 0) {

/**
* Close the stream; return `true` on success.
Expand All @@ -57,18 +56,18 @@ case class FileInputStream(var filename: Option[String], var consumed: BigInt) {
*/
@cCode.function(code =
"""
|bool __FUNCTION__(FILE* this, void* unused) {
|static bool __FUNCTION__(FILE* this, void* unused) {
| if (this != NULL)
| return fclose(this) == 0;
| else
| return true;
|}
"""
)
def close(implicit state: State): Boolean = {
def close()(implicit state: State): Boolean = {
state.seed += 1

filename = leon.lang.None[String]
filename = None[String]
true // This implementation never fails
}

Expand All @@ -79,7 +78,7 @@ case class FileInputStream(var filename: Option[String], var consumed: BigInt) {
*/
@cCode.function(code =
"""
|bool __FUNCTION__(FILE* this) {
|static bool __FUNCTION__(FILE* this) {
| return this != NULL;
|}
"""
Expand All @@ -89,26 +88,116 @@ case class FileInputStream(var filename: Option[String], var consumed: BigInt) {
filename.isDefined
}

/**
* Read the next byte of data from the stream.
*
* NOTE on failure (i.e. EOF), 0 is returned
*/
@library
@cCode.function(code = """
|int32_t __FUNCTION__(FILE* this, void* unused) {
| int32_t x;
| fscanf(this, "%"SCNd32, &x);
| return x;
|}
"""
)
def readInt(implicit state: State): Int = {
def readByte()(implicit state: State): Byte = {
require(isOpen)
state.seed += 1
nativeReadInt(state.seed)
tryReadByte() getOrElse 0
}

/**
* Attempt to read the next byte of data.
*/
@library
def tryReadByte()(implicit state: State): Option[Byte] = {
require(isOpen)

var valid = true

// Similar to tryReadInt, but here we have to use %c to read a byte
// (which assumes CHAR_BITS == 8) because SCNi8 will read char '0' to '9'
// and not the "raw" data.
@cCode.function(code = """
|static int8_t __FUNCTION__(FILE** this, void** unused, bool* valid) {
| int8_t x;
| *valid = fscanf(*this, "%c", &x) == 1;
| return x;
|}
""",
includes = "inttypes.h"
)
def impl(): Byte = {
state.seed += 1
val (check, value) = nativeReadByte(state.seed)
valid = check
value
}

val res = impl()
if (valid) Some(res) else None()
}

/**
* Read the next signed decimal integer
*
* NOTE on failure, 0 is returned
*/
@library
def readInt()(implicit state: State): Int = {
require(isOpen)
tryReadInt() getOrElse 0
}

/**
* Attempt to read the next signed decimal integer
*/
@library
def tryReadInt()(implicit state: State): Option[Int] = {
require(isOpen)

var valid = true

// Because this is a nested function, contexts variables are passes by reference.
@cCode.function(code = """
|static int32_t __FUNCTION__(FILE** this, void** unused, bool* valid) {
| int32_t x;
| *valid = fscanf(*this, "%"SCNd32, &x) == 1;
| return x;
|}
""",
includes = "inttypes.h"
)
def impl(): Int = {
state.seed += 1
val (check, value) = nativeReadInt(state.seed)
valid = check
value
}

val res = impl()
if (valid) Some(res) else None()
}

// Implementation detail
@library
@extern
@cCode.drop
private def nativeReadInt(seed: BigInt): Int = {
private def nativeReadByte(seed: BigInt): (Boolean, Byte) = {
val in = new java.io.FileInputStream(filename.get)

// Skip what was already consumed by previous reads
assert(in.skip(consumed.toLong) == consumed.toLong) // Yes, skip might not skip the requested number of bytes...

val b = Array[Byte](0)
val read = in.read(b)

in.close()

if (read != 1) (false, 0)
else {
consumed += read
(true, b(0))
}
}

@library
@extern
@cCode.drop
private def nativeReadInt(seed: BigInt): (Boolean, Int) = {
/* WARNING This code is singificantly a duplicate of leon.io.StdIn.nativeReadInt
* because there's no clean way to refactor this in Leon's library.
*
Expand Down Expand Up @@ -149,19 +238,21 @@ case class FileInputStream(var filename: Option[String], var consumed: BigInt) {
// Skip what was already consumed by previous reads
assert(in.skip(consumed.toLong) == consumed.toLong) // Yes, skip might not skip the requested number of bytes...

// Handle error in parsing and close the stream, return the given error code
def fail(e: Int): Int = {
// Handle error in parsing and close the stream
def fail(): (Boolean, Int) = {
in.close()
e // TODO throw an exception and change `e` for a decent error message
(false, 0)
}

// Handle success (nothing to do actually) and close the stream
def success(x: Int): Int = {
def success(x: Int): (Boolean, Int) = {
in.close()
x
(true, x)
}

// Match C99 isspace function: either space (0x20), form feed (0x0c), line feed (0x0a), carriage return (0x0d), horizontal tab (0x09) or vertical tab (0x0b)
// Match C99 isspace function:
// either space (0x20), form feed (0x0c), line feed (0x0a), carriage return (0x0d),
// horizontal tab (0x09) or vertical tab (0x0b)
def isSpace(c: Int): Boolean = Set(0x20, 0x0c, 0x0a, 0x0d, 0x09, 0x0b) contains c

// Digit base 10
Expand All @@ -188,26 +279,25 @@ case class FileInputStream(var filename: Option[String], var consumed: BigInt) {
// Read as many digit as possible, and after each digit we mark
// the stream to simulate a "peek" at the next, possibly non-digit,
// character on the stream.
def readDecInt(acc: Int, mark: Boolean): Int = {
def readDecInt(acc: Int, mark: Boolean): (Boolean, Int) = {
if (mark) markStream()

val c = read()

if (isDigit(c)) readDecInt(safeAdd(acc, c), true)
else if (mark) success(acc) // at least one digit was processed
else fail(-2) // no digit was processed
else fail() // no digit was processed
}

val first = skipSpaces()
first match {
case EOF => fail(-1)
case '-' => - readDecInt(0, false)
case '+' => readDecInt(0, false)
case c if isDigit(c) => readDecInt(c - '0', true)
case _ => fail(-3)
case EOF => fail()
case '-' => val (c, x) = readDecInt(0, false); (c, -x)
case '+' => readDecInt(0, false)
case c if isDigit(c) => readDecInt(c - '0', true)
case _ => fail()
}
} ensuring((x: Int) => true)

}

}

Loading