Compare commits

..

No commits in common. "293c52d9677fa6bd2fff098d2ace1fe1a73950f9" and "df9ebe0a3b4304e773d4f8c3a438a3229875c15b" have entirely different histories.

26 changed files with 1 additions and 1061 deletions

View File

@ -103,45 +103,13 @@ _Academic first semester 2024-2025_
- :hammer: Lab 5b (2/2): Monday 18/11/2024, 13h30-15h30. Room E001 (Samuel Humeau & Emma Nardino)
- :book: Course: Thursday 21/11/2024, 10h15-12h15. Amphi J (Yannick Zakowski)
* Functions: code generation [slides in english](course/cap_cours08_func_codegen.pdf).
# Week 10:
- :notebook: TD: Monday 25/11/2024, 13h30-15h30. Room E001 (Samuel Humeau & Emma Nardino)
- :book: Course: Thursday 28/11/2024, 10h15-12h15. Amphi B (Yannick Zakowski)
* Functions: semantics [slides in english](course/cap_cour309_func_semantics.pdf).
# Week 11:
- :hammer: Choice Lab (1/3): Monday 02/12/2024, 8h00-13h30. Room E001 (Samuel Humeau & Emma Nardino)
* Optimisations under SSA form [TP5c](TP05/tp5c.pdf), code in [MiniC/TPoptim/](MiniC/TPoptim/).
* Parsing and typechecking functions [TP06a](TP06/tp6a.pdf), code in [MiniC/](MiniC/).
* Code generation for functions [TP06b](TP06/tp6b.pdf), code in [MiniC/](MiniC/).
- :book: Course: Thursday 05/12/2024, 10h15-12h15. Amphi B (Yannick Zakowski)
* On parallelism [slides in english](course/cap_cours10_parallelism.pdf).
# Week 12:
- :hammer: Choice Lab (2/3): Thursday 09/12/2024, 13h30-15h30. Room E001 (Samuel Humeau & Emma Nardino)
* Optimisations under SSA form [TP5c](TP05/tp5c.pdf), code in [MiniC/TPoptim/](MiniC/TPoptim/).
* Parsing and typechecking functions [TP06a](TP06/tp6a.pdf), code in [MiniC/](MiniC/).
* Code generation for functions [TP06b](TP06/tp6b.pdf), code in [MiniC/](MiniC/).
* Going Parallel with futures [TPfutures](TPfutures/tpfutures.pdf), code in [TPfutures/MiniC-futures/](TPfutures/MiniC-futures/).
- :book: Course: Thursday 12/12/2024, 10h15-12h15. Amphi B (Yannick Zakowski)
* Verified Compilation [introduction slides](course/cap_cours11_verified.pdf).
* Course on black board
* Additional resources: [Xavier Leroy's class at Collège de France](https://www.college-de-france.fr/en/agenda/lecture/mechanized-semantics-when-the-machine-reasons-about-its-languages)
# Week 13:
- :hammer: Choice Lab (3/3): Monday 16/12/2024, 13h30-15h30. Room E001 (Samuel Humeau & Emma Nardino)
* Other possibilities next week.

Binary file not shown.

Binary file not shown.

View File

@ -1,15 +0,0 @@
/MiniCLexer.py
/MiniCParser.py
/MiniCVisitor.py
/MiniCListener.py
*.dot
*.dot.pdf
*.riscv
*-naive.s
*-gcc.s
*-all_in_mem.s
*-smart.s
*.cfut
*.o
/MiniC.interp
/MiniCLexer.interp

View File

@ -1,14 +0,0 @@
class MiniCRuntimeError(Exception):
pass
class MiniCInternalError(Exception):
pass
class MiniCUnsupportedError(Exception):
pass
class MiniCTypeError(Exception):
pass

View File

@ -1,56 +0,0 @@
PACKAGE = MiniC
# Example: stop at the first failed test:
# make PYTEST_OPTS=-x tests
PYTEST_OPTS =
# Run the whole test infrastructure for a subset of test files e.g.
# make TEST_FILES='TP03/**/bad*.c' tests
ifdef TEST_FILES
export TEST_FILES
endif
PYTEST_BASE_OPTS=-vv -rs --failed-first --cov="$(PWD)" --cov-report=term --cov-report=html
ifndef ANTLR4
abort:
$(error variable ANTLR4 is not set)
endif
all: antlr
.PHONY: antlr
antlr MiniCLexer.py MiniCParser.py: $(PACKAGE).g4
$(ANTLR4) $< -Dlanguage=Python3 -visitor
main-deps: MiniCLexer.py MiniCParser.py MiniCTypingVisitor.py MiniCPPListener.py
%.o: %.c $(HEADERS)
gcc -g -c -Wall -Wextra $< -o $@
$(TESTFILE:%.c=%.o): $(TESTFILE:%.c=%.cfut) $(HEADERS)
gcc -g -c -Iinclude -Wall -Wextra -x c $(TESTFILE:%.c=%.cfut) -o $(TESTFILE:%.c=%.o)
$(TESTFILE:%.c=%.out): $(TESTFILE:%.c=%.o) lib/futurelib.o
gcc -g $(TESTFILE:%.c=%.o) lib/futurelib.o -o $(TESTFILE:%.c=%.out) -lpthread
$(TESTFILE:%.c=%.cfut): main-deps
python3 MiniCC.py $(TESTFILE)
run: $(TESTFILE:%.c=%.out)
$(TESTFILE:%.c=%.out)
test: test_futures.py main-deps
python3 -m pytest $(PYTEST_BASE_OPTS) $(PYTEST_OPTS) ./test_futures.py
tar: clean
dir=$$(basename "$$PWD") && cd .. && \
tar cvfz "$$dir.tgz" --exclude="*.riscv" --exclude=".git" --exclude=".pytest_cache" \
--exclude="htmlcov" "$$dir"
@echo "Created ../$$(basename "$$PWD").tgz"
clean-tests:
cd tests && \
find . \( -iname "*.cfut" -or -iname "*.out" \) -print0 | xargs -0 rm -rf \;
clean: clean-tests
find . \( -iname "*~" -or -iname ".cache*" -or -iname "*.diff" -or -iname "log*.txt" -or -iname "__pycache__" -or -iname "*.tokens" -or -iname "*.interp" -or -iname "*.o" \) -print0 | xargs -0 rm -rf \;
rm -rf *~ $(PACKAGE)Parser.py $(PACKAGE)Lexer.py $(PACKAGE)Visitor.py $(PACKAGE)Listener.py .coverage .benchmarks

View File

@ -1,164 +0,0 @@
grammar MiniC;
prog: include* function* EOF #progRule;
//include statements reduced to string
include: INCLUDE STRING #includestat ;
function
: typee ID OPAR param_l? CPAR OBRACE vardecl_l block RETURN expr SCOL CBRACE #funcDef
| typee ID OPAR param_l? CPAR SCOL #funcDecl
;
vardecl_l: vardecl* #varDeclList;
vardecl: typee id_l SCOL #varDecl;
param: typee ID #paramDecl;
param_l
: param #paramListBase
| param COM param_l #paramList
;
id_l
: ID #idListBase
| ID COM id_l #idList
;
block: stat* #statList;
stat
: assignment SCOL
| if_stat
| while_stat
| print_stat
;
assignment: ID ASSIGN expr #assignStat;
if_stat: IF OPAR expr CPAR then_block=stat_block (ELSE else_block=stat_block)? #ifStat;
stat_block
: OBRACE block CBRACE
| stat
;
while_stat: WHILE OPAR expr CPAR body=stat_block #whileStat;
print_stat
: PRINTINT OPAR expr CPAR SCOL #printlnintStat
| PRINTFLOAT OPAR expr CPAR SCOL #printlnfloatStat
| PRINTBOOL OPAR expr CPAR SCOL #printlnboolStat
| PRINTSTRING OPAR expr CPAR SCOL #printstringStat
;
expr_l
: expr #exprListBase
| expr COM expr_l #exprList
;
expr
: MINUS expr #unaryMinusExpr
| NOT expr #notExpr
| expr myop=(MULT|DIV|MOD) expr #multiplicativeExpr
| expr myop=(PLUS|MINUS) expr #additiveExpr
| expr myop=(GT|LT|GTEQ|LTEQ) expr #relationalExpr
| expr myop=(EQ|NEQ) expr #equalityExpr
| expr AND expr #andExpr
| expr OR expr #orExpr
| ID OPAR expr_l? CPAR #funcCall
| GET OPAR expr CPAR #getCall
| ASYNC OPAR ID COM expr_l? CPAR #asyncFuncCall
| atom #atomExpr
;
atom
: OPAR expr CPAR #parExpr
| INT #intAtom
| FLOAT #floatAtom
| (TRUE | FALSE) #booleanAtom
| ID #idAtom
| STRING #stringAtom
;
typee
: mytype=(INTTYPE|FLOATTYPE|BOOLTYPE|STRINGTYPE|FUTINTTYPE) #basicType
;
ASYNC : 'Async';
GET : 'Get';
OR : '||';
AND : '&&';
EQ : '==';
NEQ : '!=';
GT : '>';
LT : '<';
GTEQ : '>=';
LTEQ : '<=';
PLUS : '+';
MINUS : '-';
MULT : '*';
DIV : '/';
MOD : '%';
NOT : '!';
COL: ':';
SCOL : ';';
COM : ',';
ASSIGN : '=';
OPAR : '(';
CPAR : ')';
OBRACE : '{';
CBRACE : '}';
TRUE : 'true';
FALSE : 'false';
IF : 'if';
ELSE : 'else';
WHILE : 'while';
RETURN : 'return';
PRINTINT : 'println_int';
PRINTBOOL : 'println_bool';
PRINTSTRING : 'println_string';
PRINTFLOAT : 'println_float';
FUTINTTYPE: 'futint';
INTTYPE: 'int';
FLOATTYPE: 'float';
STRINGTYPE: 'string';
BOOLTYPE : 'bool';
INCLUDE : '#include';
ID
: [a-zA-Z_] [a-zA-Z_0-9]*
;
INT
: [0-9]+
;
FLOAT
: [0-9]+ '.' [0-9]*
| '.' [0-9]+
;
STRING
: '"' (~["\r\n] | '""')* '"'
;
COMMENT
// # is a comment in Mini-C, and used for #include in real C so that we ignore #include statements
// BUT now we want to keep includes => # removed
: '//' ~[\r\n]* -> skip
;
SPACE
// here is a little for code rewriting.
: [ \t\r\n] -> channel(HIDDEN)
;

View File

@ -1,112 +0,0 @@
#! /usr/bin/env python3
"""
MiniC-futures Lab. Language Extension for MiniC with future primitives
Usage:
python3 Main.py <filename>
python3 Main.py --help
"""
import traceback
from MiniCLexer import MiniCLexer
from MiniCParser import MiniCParser
from MiniCTypingVisitor import MiniCTypingVisitor, MiniCTypeError
from MiniCPPListener import MiniCPPListener
from Errors import MiniCUnsupportedError, MiniCInternalError
import argparse
from antlr4 import FileStream, CommonTokenStream, ParseTreeWalker
from antlr4.error.ErrorListener import ErrorListener
import os
import sys
class CountErrorListener(ErrorListener):
"""Count number of errors.
Parser provides getNumberOfSyntaxErrors(), but the Lexer
apparently doesn't provide an easy way to know if an error occured
after the fact. Do the counting ourserves with a listener.
"""
def __init__(self):
super(CountErrorListener, self).__init__()
self.count = 0
def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
self.count += 1
def main(inputname,
typecheck=True, typecheck_only=False, stdout=False, output_name=None, debug=False):
(basename, rest) = os.path.splitext(inputname)
if not typecheck_only:
if stdout:
output_name = None
elif output_name is None:
output_name = basename + ".cfut"
input_s = FileStream(inputname, encoding='utf-8')
lexer = MiniCLexer(input_s)
counter = CountErrorListener()
lexer._listeners.append(counter)
stream = CommonTokenStream(lexer)
parser = MiniCParser(stream)
parser._listeners.append(counter)
tree = parser.prog()
if counter.count > 0:
exit(3) # Syntax or lexicography errors occurred, don't try to go further.
if typecheck:
typing_visitor = MiniCTypingVisitor()
try:
typing_visitor.visit(tree)
except MiniCTypeError as e:
print(e.args[0])
exit(2)
if typecheck_only:
if debug:
print("Not running code generation because of --disable-codegen.")
return
pw = ParseTreeWalker()
extractor = MiniCPPListener(stream)
pw.walk(extractor, tree)
with open(output_name, 'w') if output_name else sys.stdout as output:
extractor.printrw(output)
# command line management
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Generate code for .c file')
parser.add_argument('filename', type=str,
help='Source file.')
parser.add_argument('--stdout', action='store_true',
help='Generate code to stdout')
parser.add_argument('--debug', action='store_true',
default=False,
help='Emit verbose debug output')
parser.add_argument('--disable-typecheck', action='store_true',
default=False,
help="Don't run the typechecker before generating code")
parser.add_argument('--disable-codegen', action='store_true',
default=False,
help="Run only the typechecker, don't try generating code.")
parser.add_argument('--output', type=str,
help='Generate code to outfile')
args = parser.parse_args()
try:
main(args.filename,
not args.disable_typecheck, args.disable_codegen,
args.stdout, args.output, args.debug,
)
except MiniCUnsupportedError as e:
print(e)
exit(5)
except (MiniCInternalError):
traceback.print_exc()
exit(4)

View File

@ -1,27 +0,0 @@
from MiniCListener import MiniCListener
from antlr4.TokenStreamRewriter import TokenStreamRewriter
class MiniCPPListener(MiniCListener):
def __init__(self, t):
self.rewriter = TokenStreamRewriter(tokens=t)
def printrw(self, output):
output.write(self.rewriter.getText('default', 0, 1000))
def enterProgRule(self, ctx):
"""Adds an include futurelib.h at the beginning of program."""
indexprog = ctx.start.tokenIndex
self.rewriter.insertBeforeIndex(indexprog, '#include \"futurelib.h\"\n')
def exitFuncDef(self, ctx):
"""Adds a call to freeAllFutures at the end of the body of the main function."""
(indexret, endret) = ctx.RETURN().getSourceInterval()
if ctx.ID().getText() == "main":
self.rewriter.insertBeforeIndex(indexret, 'freeAllFutures();\n')
def enterAsyncFuncCall(self, ctx):
"""Adds a & for getting a function pointer to the asynchronous called function."""
indexfunid = ctx.start.tokenIndex # token of async
self.rewriter.insertBeforeIndex(indexfunid + 2, '&')

View File

@ -1,17 +0,0 @@
# Visitor to *typecheck* MiniC files
from typing import List
from MiniCVisitor import MiniCVisitor
from MiniCParser import MiniCParser
from Lib.Errors import MiniCInternalError, MiniCTypeError
from enum import Enum
# NEW: ADD FutInteger
class BaseType(Enum):
Float, Integer, Boolean, String, FutInteger = range(5)
class MiniCTypingVisitor(MiniCVisitor):
# TODO Add your own typer here
pass

View File

@ -1,25 +0,0 @@
# MiniC Compiler
LAB8 (Futures) CAP 2022-23
# Authors
YOUR NAME HERE
# Contents
TODO:
- Explain any design choices you may have made.
- Did you implement a bonus?
# Howto
`make run TESTFILE=tests/provided/test_fut0.c`: launch the compiler, then GCC and run a single file.
# Test design
TODO: explain your tests.
# Known bugs
TODO: bugs you could not fix (if any) and limitations.

View File

@ -1,12 +0,0 @@
#include "stdio.h"
typedef char * string;
typedef int bool;
static const int true = 1;
static const int false = 0;
void print_int(int i) {printf("%i",i);}
void println_int(int i) {printf("%i\n",i);}
void print_string(string);
void println_string(string);

View File

@ -1,34 +0,0 @@
#include <pthread.h>
typedef struct // a struct for storing a future to int
{
int Id;
int Value;
int resolved;
pthread_t tid;
} FutureInt;
typedef FutureInt* futint; // a typedef to deal with the future type of MiniCFut
FutureInt *fresh_future_malloc(); // allocates (malloc) a fresh future and initializes its field
void print_futureInt(FutureInt *fut); // for debug purposes: print a fut int status
void free_future(FutureInt *fut); // frees the pointer allocated by fresh_future
void resolve_future(FutureInt *fut, int val); // function called when an async call is finished
int Get(FutureInt *fut);
// called by the main program:
// checks that the future is resolved and
// returns the value stored in the future
FutureInt *Async(int (*fun)(int), int p);
// asynchronous function call:
// takes a function pointer as parameter and the fun call parameter as second parameter
// returns an unresolved future
// creates a thread to perform the asynchronous function call
void freeAllFutures();
// called at the end of the main block: waits for the resolution of all futures
// and frees all future pointers created by fresh_future

View File

@ -1,77 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include "../include/futurelib.h"
FutureInt *All[70];
// A table of future pointers to store all the futures created
// In a realistic scenario this would be a dynamic structure
int NbAll = 0;
// Number of futures created
typedef struct
// A structure for the argument of thread creation: function pointer and parameter
{
FutureInt *fut;
int (*fun)(int);
int param;
} arg_struct;
FutureInt *fresh_future_malloc()
{
// TODO Exercise 4.2
// Use malloc(sizeof(FutureInt)) and reference created futures
}
void print_futureInt(FutureInt *f)
{
// TODO
// For debug purposes only
}
void free_future(FutureInt *fut)
{
free(fut);
}
void resolve_future(FutureInt *fut, int val)
{
// TODO Exercise 5.1
// Fill fut accordingly
}
int Get(FutureInt *fut)
{
// TODO Exercise 5.2
// Wait until future is resolved (do a sleep(1) between two checks)
// Do not forget to do a pthread_join(fut->tid, NULL);
return 0;
}
void *runTask(void *param)
{
// TODO Exercise 4.1
// function that is launched by the created thread: should call the function and
// deal with the future, using the function resolve_future
// param can be cast to (arg_struct *)
// this function should free the pointer param
return NULL;
}
FutureInt *Async(int (*fun)(int), int p)
{
// TODO Exercise 4.3
// Main system call should be: int err = pthread_create(&fut->tid, NULL, &runTask, (args));
// Allocate a future and space for arguments: args = malloc(sizeof(arg_struct));
// Do not forget to populate args
return NULL;
}
void freeAllFutures()
{
// TODO Exercises 4.4 & 5.3
// 1 - Wait for all futures (Get) to avoid dangling threads (Exercise 5.3)
// 2 - Call free_future for all futures (Exercise 4.4)
}

View File

@ -1,193 +0,0 @@
import collections
import re
import os
import subprocess
import sys
import pytest
testinfo = collections.namedtuple(
'testinfo',
['exitcode', 'execcode', 'output', 'linkargs', 'skip_test_expected'])
default_testinfo = testinfo(
exitcode=0, execcode=0, output='', linkargs=[], skip_test_expected=False)
def cat(filename):
with open(filename, "rb") as f:
for line in f:
sys.stdout.buffer.write(line)
def env_bool_variable(name, globals):
if name not in globals:
globals[name] = False
if name in os.environ:
globals[name] = True
def env_str_variable(name, globals):
if name in os.environ:
globals[name] = os.environ[name]
class TestExpectPragmas(object):
"""Base class for tests that read the expected result as annotations
in test files.
get_expect(file) will parse the file, looking EXPECT and EXITCODE
pragmas.
run_command(command) is a wrapper around subprocess.check_output()
that extracts the output and exit code.
"""
def get_expect(self, filename):
"""Parse "filename" looking for EXPECT and EXITCODE annotations.
Look for a line "EXPECTED" (possibly with whitespaces and
comments). Text after this "EXPECTED" line is the expected
output.
The file may also contain a line like "EXITCODE <n>" where <n>
is an integer, and is the expected exitcode of the command.
The result is cached to avoid re-parsing the file multiple
times.
"""
if filename not in self.__expect:
self.__expect[filename] = self._extract_expect(filename)
return self.__expect[filename]
def remove(self, file):
"""Like os.remove(), but ignore errors, e.g. don't complain if the
file doesn't exist.
"""
try:
os.remove(file)
except OSError:
pass
def run_command(self, cmd, scope="compile"):
"""Run the command cmd (given as [command, arg1, arg2, ...]), and
return testinfo(exitcode=..., output=...) containing the
exit code of the command it its standard output + standard error.
If scope="compile" (resp. "runtime"), then the exitcode (resp.
execcode) is set with the exit status of the command, and the
execcode (resp. exitcode) is set to 0.
"""
try:
output = subprocess.check_output(cmd, timeout=60,
stderr=subprocess.STDOUT)
status = 0
except subprocess.CalledProcessError as e:
output = e.output
status = e.returncode
if scope == "runtime":
return default_testinfo._replace(execcode=status,
output=output.decode())
else:
return default_testinfo._replace(exitcode=status,
output=output.decode())
def skip_if_partial_match(self, actual, expect, ignore_error_message):
if not ignore_error_message:
return False
# TODO: Deal with undefined behavior here?
if expect.exitcode != actual.exitcode:
# Not the same exit code => something's wrong anyway
return False
if actual.exitcode == 3:
# There's a syntax error in both expected and actual,
# but the actual error may slightly differ if we don't
# have the exact same .g4.
return True
# Let the test pass with 'return True' if appropriate.
# Otherwise, continue to the full assertion for a
# complete diagnostic.
if actual.exitcode != 0 and expect.exitcode == actual.exitcode:
if expect.output == '':
# No output expected, but we know there must be an
# error. If there was a particular error message
# expected, we'd have written it in the output,
# hence just ignore the actual message.
return True
# Ignore difference in error message except in the
# line number (ignore the column too, it may
# slightly vary, eg. in "foo" / 4, the error may
# be considered on "foo" or on /):
if re.match(r'^In function [^ :]*: Line [0-9]* col [0-9]*:',
actual.output):
out_loc = re.sub(r' col [0-9]*:.*$', '', actual.output)
exp_loc = re.sub(r' col [0-9]*:.*$', '', expect.output)
if out_loc == exp_loc:
return True
if any(x.output and
(x.output.endswith('has no value yet!' + os.linesep)
or x.output.endswith(' by 0' + os.linesep))
for x in (actual, expect)):
# Ignore the error message when our compiler
# raises this error (either in actual or expect,
# depending on what we're testing).
return True
return False
__expect = {}
def _extract_expect(self, file):
exitcode = 0
execcode = 0
linkargs = []
inside_expected = False
skip_test_expected = False
expected_lines = []
expected_present = False
with open(file, encoding="utf-8") as f:
for line in f.readlines():
# Ignore non-comments
if not re.match(r'\s*//', line):
continue
# Cleanup comment start and whitespaces
line = re.sub(r'\s*//\s*', '', line)
line = re.sub(r'\s*$', '', line)
if line == 'END EXPECTED':
inside_expected = False
elif line.startswith('EXITCODE'):
words = line.split(' ')
assert len(words) == 2
exitcode = int(words[1])
elif line.startswith('EXECCODE'):
words = line.split(' ')
assert len(words) == 2
execcode = int(words[1])
elif line.startswith('LINKARGS'):
words = line.split(' ')
assert len(words) >= 2
linkargs += [w.replace("$dir", os.path.dirname(file))
for w in words[1:]]
elif line == 'EXPECTED':
inside_expected = True
expected_present = True
elif line == 'SKIP TEST EXPECTED':
skip_test_expected = True
elif inside_expected:
expected_lines.append(line)
if not expected_present:
pytest.fail("Missing EXPECTED directive in test file")
if expected_lines == []:
output = ''
else:
output = os.linesep.join(expected_lines) + os.linesep
return testinfo(exitcode=exitcode, execcode=execcode,
output=output, linkargs=linkargs,
skip_test_expected=skip_test_expected)

View File

@ -1,105 +0,0 @@
#! /usr/bin/env python3
import os
import sys
import pytest
import glob
import subprocess
import re
from test_expect_pragma import (
TestExpectPragmas, cat, testinfo,
env_bool_variable, env_str_variable
)
"""
Usage:
python3 test_futur.py
(or make test)
"""
"""
CAP, 2020
Unit test infrastructure for testing futures:
1) compare the actual output to the expected one (in comments)
2) compare the actual output to the one obtained by simulation
"""
DISABLE_TYPECHECK = False
TYPECHECK_ONLY = False
HERE = os.path.dirname(os.path.realpath(__file__))
if HERE == os.path.realpath('.'):
HERE = '.'
TEST_DIR = HERE
IMPLEM_DIR = HERE
MINIC_FUT = os.path.join(IMPLEM_DIR, 'MiniCC.py')
ALL_FILES = glob.glob(os.path.join(TEST_DIR, 'tests/**/[a-zA-Z]*.c'),
recursive=True)
GCC = 'gcc'
if 'TEST_FILES' in os.environ:
ALL_FILES = glob.glob(os.environ['TEST_FILES'], recursive=True)
class TestFuture(TestExpectPragmas):
# Not in test_expect_pragma to get assertion rewritting
def assert_equal(self, actual, expected):
if TYPECHECK_ONLY and expected.exitcode == 0:
# Compiler does not fail => no output expected
assert actual.output == "", \
("Compiler unexpectedly generated some"
"output with --disable-codegen")
assert actual.exitcode == 0, \
"Compiler unexpectedly failed with --disable-codegen"
return
if DISABLE_TYPECHECK and expected.exitcode != 0:
# Test should fail at typecheck, and we don't do
# typechecking => nothing to check.
pytest.skip("Test that doesn't typecheck with --disable-typecheck")
if expected.output is not None and actual.output is not None:
assert actual.output == expected.output, \
"Output of the program is incorrect."
assert actual.exitcode == expected.exitcode, \
"Exit code of the compiler is incorrect"
assert actual.execcode == expected.execcode, \
"Exit code of the execution is incorrect"
def c2c(self, file):
return self.run_command(['python3', MINIC_FUT, file])
def compile_with_gcc(self, file, output_name):
print("Compiling with GCC...")
result = self.run_command(
[GCC, '-Iinclude', '-Ilib', '-x', 'c', file, "lib/futurelib.c",
'--output=' + output_name, '-lpthread'])
print(result.output)
print("Compiling with GCC... DONE")
return result
def compile_and_run(self, file):
basename, _ = os.path.splitext(file)
rw_name = basename + '.cfut'
exec_name = basename + '.out'
print("File: " + rw_name)
resgcc = self.compile_with_gcc(rw_name, exec_name)
if resgcc.exitcode != 0:
return resgcc._replace(exitcode=1, output=None)
res2 = self.run_command(exec_name, scope="runtime")
return res2
@pytest.mark.parametrize('filename', ALL_FILES)
def test_future(self, filename):
expect = self.get_expect(filename)
c2csuccess = self.c2c(filename)
if c2csuccess.exitcode == 0:
actual = self.compile_and_run(filename)
else:
actual = c2csuccess
self.assert_equal(actual, expect)
if __name__ == '__main__':
pytest.main(sys.argv)

View File

@ -1,38 +0,0 @@
#include "compat.h"
// Call future
int slow(int x)
{
int i;
i=0;
while (i<1000) { i=i+1 ; x=2*i+x;}
return x;
}
int summ(int x)
{
int ret,i;
if (x == 1)
ret=1;
else
{
ret = x + summ(x - 1);
i=0;
while (i<100) { i=i+1 ; x=slow(2);}
}
return ret;
}
int main()
{
int val;
val=Async(summ,1);
println_int(val);
return 0;
}
// EXITCODE 2
// EXPECTED
// In function main: Line 29 col 4: type mismatch for val: integer and futinteger

View File

@ -1,20 +0,0 @@
#include "compat.h"
// Call future
int functi(int x){
int y;
y=x;
y = 42;
println_int(0);
return y;
}
int main(){
futint fval;
fval = Async(functi,123);
return 0;
}
// EXPECTED
// 0

View File

@ -1,22 +0,0 @@
#include "compat.h"
// Call future
int functi(int x){
int y;
y=x;
y = 42;
return y;
}
int main(){
futint fval;
int val;
fval = Async(functi,123);
val = Get(fval);
println_int(val);
return 0;
}
// EXPECTED
// 42

View File

@ -1,41 +0,0 @@
#include "compat.h"
// Call future
int summ(int x)
{
int ret;
if (x == 1)
ret=1;
else
{
ret=x + summ(x - 1);
}
return ret;
}
int useFuture(futint f)
{
int x;
x=Get(f);
return x+1;
}
int main()
{
int val,x;
futint f,g;
f=Async(summ,15);
g=Async(summ,16);
val=Get(f)+Get(g)+useFuture(g);
println_int(val);
return 0;
}
// EXPECTED
// 393

View File

@ -1,56 +0,0 @@
#include "compat.h"
// Call future
int slow(int x)
{
int i,t;
i=0;
t=0;
while (i<x*1000) { i=i+1 ; t=t+2*i+x;}
return t;
}
int summ(int x)
{
int ret;
int i;
if (x == 1)
ret=1;
else
{
ret = x + summ(x - 1);
i=0;
while (i<100) { i=i+1 ; x=slow(20);}
}
return ret;
}
int summandprint(int x)
{
int ret;
ret=summ(x);
println_int(ret);
return ret;
}
int main()
{
int val;
futint f,g;
f=Async(summandprint,500);
g=Async(summandprint,2);
val=Get(f)+Get(g);
return 0;
}
// EXPECTED
// 3
// 125250

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.