automated commit TP3
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
# Visitor to *interpret* MiniC files
|
||||
from typing import Dict, List, cast
|
||||
from MiniCVisitor import MiniCVisitor
|
||||
from MiniCParser import MiniCParser
|
||||
from Lib.Errors import MiniCRuntimeError, MiniCInternalError
|
||||
|
||||
MINIC_VALUE = int | str | bool | float | List['MINIC_VALUE']
|
||||
|
||||
|
||||
class MiniCInterpretVisitor(MiniCVisitor):
|
||||
|
||||
_memory: Dict[str, MINIC_VALUE]
|
||||
|
||||
def __init__(self):
|
||||
self._memory = dict() # store all variable ids and values.
|
||||
self.has_main = False
|
||||
|
||||
# visitors for variable declarations
|
||||
|
||||
def visitVarDecl(self, ctx) -> None:
|
||||
# Initialise all variables in self._memory
|
||||
type_str = ctx.typee().getText()
|
||||
raise NotImplementedError()
|
||||
|
||||
def visitIdList(self, ctx) -> List[str]:
|
||||
raise NotImplementedError()
|
||||
|
||||
def visitIdListBase(self, ctx) -> List[str]:
|
||||
return [ctx.ID().getText()]
|
||||
|
||||
# visitors for atoms --> value
|
||||
|
||||
def visitParExpr(self, ctx) -> MINIC_VALUE:
|
||||
return self.visit(ctx.expr())
|
||||
|
||||
def visitIntAtom(self, ctx) -> int:
|
||||
return int(ctx.getText())
|
||||
|
||||
def visitFloatAtom(self, ctx) -> float:
|
||||
return float(ctx.getText())
|
||||
|
||||
def visitBooleanAtom(self, ctx) -> bool:
|
||||
return ctx.getText() == "true"
|
||||
|
||||
def visitIdAtom(self, ctx) -> MINIC_VALUE:
|
||||
raise NotImplementedError()
|
||||
|
||||
def visitStringAtom(self, ctx) -> str:
|
||||
return ctx.getText()[1:-1] # Remove the ""
|
||||
|
||||
# visit expressions
|
||||
|
||||
def visitAtomExpr(self, ctx) -> MINIC_VALUE:
|
||||
return self.visit(ctx.atom())
|
||||
|
||||
def visitOrExpr(self, ctx) -> bool:
|
||||
lval = self.visit(ctx.expr(0))
|
||||
rval = self.visit(ctx.expr(1))
|
||||
return lval | rval
|
||||
|
||||
def visitAndExpr(self, ctx) -> bool:
|
||||
lval = self.visit(ctx.expr(0))
|
||||
rval = self.visit(ctx.expr(1))
|
||||
return lval & rval
|
||||
|
||||
def visitEqualityExpr(self, ctx) -> bool:
|
||||
assert ctx.myop is not None
|
||||
lval = self.visit(ctx.expr(0))
|
||||
rval = self.visit(ctx.expr(1))
|
||||
# be careful for float equality
|
||||
if ctx.myop.type == MiniCParser.EQ:
|
||||
return lval == rval
|
||||
else:
|
||||
return lval != rval
|
||||
|
||||
def visitRelationalExpr(self, ctx) -> bool:
|
||||
assert ctx.myop is not None
|
||||
lval = self.visit(ctx.expr(0))
|
||||
rval = self.visit(ctx.expr(1))
|
||||
if ctx.myop.type == MiniCParser.LT:
|
||||
return lval < rval
|
||||
elif ctx.myop.type == MiniCParser.LTEQ:
|
||||
return lval <= rval
|
||||
elif ctx.myop.type == MiniCParser.GT:
|
||||
return lval > rval
|
||||
elif ctx.myop.type == MiniCParser.GTEQ:
|
||||
return lval >= rval
|
||||
else:
|
||||
raise MiniCInternalError(
|
||||
"Unknown comparison operator '%s'" % ctx.myop
|
||||
)
|
||||
|
||||
def visitAdditiveExpr(self, ctx) -> MINIC_VALUE:
|
||||
assert ctx.myop is not None
|
||||
lval = self.visit(ctx.expr(0))
|
||||
rval = self.visit(ctx.expr(1))
|
||||
if ctx.myop.type == MiniCParser.PLUS:
|
||||
if any(isinstance(x, str) for x in (lval, rval)):
|
||||
return '{}{}'.format(lval, rval)
|
||||
else:
|
||||
return lval + rval
|
||||
elif ctx.myop.type == MiniCParser.MINUS:
|
||||
return lval - rval
|
||||
else:
|
||||
raise MiniCInternalError(
|
||||
"Unknown additive operator '%s'" % ctx.myop)
|
||||
|
||||
def visitMultiplicativeExpr(self, ctx) -> MINIC_VALUE:
|
||||
assert ctx.myop is not None
|
||||
lval = self.visit(ctx.expr(0))
|
||||
rval = self.visit(ctx.expr(1))
|
||||
if ctx.myop.type == MiniCParser.MULT:
|
||||
return lval * rval
|
||||
elif ctx.myop.type == MiniCParser.DIV:
|
||||
if rval == 0:
|
||||
raise MiniCRuntimeError("Division by 0")
|
||||
if isinstance(lval, int):
|
||||
return lval // rval
|
||||
else:
|
||||
return lval / rval
|
||||
elif ctx.myop.type == MiniCParser.MOD:
|
||||
# TODO : interpret modulo
|
||||
raise NotImplementedError()
|
||||
else:
|
||||
raise MiniCInternalError(
|
||||
"Unknown multiplicative operator '%s'" % ctx.myop)
|
||||
|
||||
def visitNotExpr(self, ctx) -> bool:
|
||||
return not self.visit(ctx.expr())
|
||||
|
||||
def visitUnaryMinusExpr(self, ctx) -> MINIC_VALUE:
|
||||
return -self.visit(ctx.expr())
|
||||
|
||||
# visit statements
|
||||
|
||||
def visitPrintlnintStat(self, ctx) -> None:
|
||||
val = self.visit(ctx.expr())
|
||||
print(val)
|
||||
|
||||
def visitPrintlnfloatStat(self, ctx) -> None:
|
||||
val = self.visit(ctx.expr())
|
||||
if isinstance(val, float):
|
||||
val = "%.2f" % val
|
||||
print(val)
|
||||
|
||||
def visitPrintlnboolStat(self, ctx) -> None:
|
||||
val = self.visit(ctx.expr())
|
||||
print('1' if val else '0')
|
||||
|
||||
def visitPrintlnstringStat(self, ctx) -> None:
|
||||
val = self.visit(ctx.expr())
|
||||
print(val)
|
||||
|
||||
def visitAssignStat(self, ctx) -> None:
|
||||
raise NotImplementedError()
|
||||
|
||||
def visitIfStat(self, ctx) -> None:
|
||||
raise NotImplementedError()
|
||||
|
||||
def visitWhileStat(self, ctx) -> None:
|
||||
raise NotImplementedError()
|
||||
|
||||
# TOPLEVEL
|
||||
def visitProgRule(self, ctx) -> None:
|
||||
self.visitChildren(ctx)
|
||||
if not self.has_main:
|
||||
# A program without a main function is compilable (hence
|
||||
# it's not a typing error per se), but not executable,
|
||||
# hence we consider it a runtime error.
|
||||
raise MiniCRuntimeError("No main function in file")
|
||||
|
||||
# Visit a function: ignore if non main!
|
||||
def visitFuncDef(self, ctx) -> None:
|
||||
funname = ctx.ID().getText()
|
||||
if funname == "main":
|
||||
self.has_main = True
|
||||
self.visit(ctx.vardecl_l())
|
||||
self.visit(ctx.block())
|
||||
@@ -0,0 +1,147 @@
|
||||
# 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
|
||||
|
||||
|
||||
class BaseType(Enum):
|
||||
Float, Integer, Boolean, String = range(4)
|
||||
|
||||
|
||||
# Basic Type Checking for MiniC programs.
|
||||
class MiniCTypingVisitor(MiniCVisitor):
|
||||
|
||||
def __init__(self):
|
||||
self._memorytypes = dict() # id -> types
|
||||
# For now, we don't have real functions ...
|
||||
self._current_function = "main"
|
||||
|
||||
def _raise(self, ctx, for_what, *types):
|
||||
raise MiniCTypeError(
|
||||
'In function {}: Line {} col {}: invalid type for {}: {}'.format(
|
||||
self._current_function,
|
||||
ctx.start.line, ctx.start.column, for_what,
|
||||
' and '.join(t.name.lower() for t in types)))
|
||||
|
||||
def _assertSameType(self, ctx, for_what, *types):
|
||||
if not all(types[0] == t for t in types):
|
||||
raise MiniCTypeError(
|
||||
'In function {}: Line {} col {}: type mismatch for {}: {}'.format(
|
||||
self._current_function,
|
||||
ctx.start.line, ctx.start.column, for_what,
|
||||
' and '.join(t.name.lower() for t in types)))
|
||||
|
||||
def _raiseNonType(self, ctx, message):
|
||||
raise MiniCTypeError(
|
||||
'In function {}: Line {} col {}: {}'.format(
|
||||
self._current_function,
|
||||
ctx.start.line, ctx.start.column, message))
|
||||
|
||||
# type declaration
|
||||
|
||||
def visitVarDecl(self, ctx) -> None:
|
||||
raise NotImplementedError()
|
||||
|
||||
def visitBasicType(self, ctx):
|
||||
assert ctx.mytype is not None
|
||||
if ctx.mytype.type == MiniCParser.INTTYPE:
|
||||
return BaseType.Integer
|
||||
elif ctx.mytype.type == MiniCParser.FLOATTYPE:
|
||||
return BaseType.Float
|
||||
else: # TODO: same for other types
|
||||
raise NotImplementedError()
|
||||
|
||||
def visitIdList(self, ctx) -> List[str]:
|
||||
raise NotImplementedError()
|
||||
|
||||
def visitIdListBase(self, ctx) -> List[str]:
|
||||
raise NotImplementedError()
|
||||
|
||||
# typing visitors for expressions, statements !
|
||||
|
||||
# visitors for atoms --> type
|
||||
def visitParExpr(self, ctx):
|
||||
return self.visit(ctx.expr())
|
||||
|
||||
def visitIntAtom(self, ctx):
|
||||
return BaseType.Integer
|
||||
|
||||
def visitFloatAtom(self, ctx):
|
||||
return BaseType.Float
|
||||
|
||||
def visitBooleanAtom(self, ctx):
|
||||
raise NotImplementedError()
|
||||
|
||||
def visitIdAtom(self, ctx):
|
||||
try:
|
||||
return self._memorytypes[ctx.getText()]
|
||||
except KeyError:
|
||||
self._raiseNonType(ctx,
|
||||
"Undefined variable {}".format(ctx.getText()))
|
||||
|
||||
def visitStringAtom(self, ctx):
|
||||
return BaseType.String
|
||||
|
||||
# now visit expr
|
||||
|
||||
def visitAtomExpr(self, ctx):
|
||||
return self.visit(ctx.atom())
|
||||
|
||||
def visitOrExpr(self, ctx):
|
||||
raise NotImplementedError()
|
||||
|
||||
def visitAndExpr(self, ctx):
|
||||
raise NotImplementedError()
|
||||
|
||||
def visitEqualityExpr(self, ctx):
|
||||
raise NotImplementedError()
|
||||
|
||||
def visitRelationalExpr(self, ctx):
|
||||
raise NotImplementedError()
|
||||
|
||||
def visitAdditiveExpr(self, ctx):
|
||||
assert ctx.myop is not None
|
||||
raise NotImplementedError()
|
||||
|
||||
def visitMultiplicativeExpr(self, ctx):
|
||||
raise NotImplementedError()
|
||||
|
||||
def visitNotExpr(self, ctx):
|
||||
raise NotImplementedError()
|
||||
|
||||
def visitUnaryMinusExpr(self, ctx):
|
||||
raise NotImplementedError()
|
||||
|
||||
# visit statements
|
||||
|
||||
def visitPrintlnintStat(self, ctx):
|
||||
etype = self.visit(ctx.expr())
|
||||
if etype != BaseType.Integer:
|
||||
self._raise(ctx, 'println_int statement', etype)
|
||||
|
||||
def visitPrintlnfloatStat(self, ctx):
|
||||
etype = self.visit(ctx.expr())
|
||||
if etype != BaseType.Float:
|
||||
self._raise(ctx, 'println_float statement', etype)
|
||||
|
||||
def visitPrintlnboolStat(self, ctx):
|
||||
etype = self.visit(ctx.expr())
|
||||
if etype != BaseType.Boolean:
|
||||
self._raise(ctx, 'println_int statement', etype)
|
||||
|
||||
def visitPrintlnstringStat(self, ctx):
|
||||
etype = self.visit(ctx.expr())
|
||||
if etype != BaseType.String:
|
||||
self._raise(ctx, 'println_string statement', etype)
|
||||
|
||||
def visitAssignStat(self, ctx):
|
||||
raise NotImplementedError()
|
||||
|
||||
def visitWhileStat(self, ctx):
|
||||
raise NotImplementedError()
|
||||
|
||||
def visitIfStat(self, ctx):
|
||||
raise NotImplementedError()
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main(){
|
||||
int n;
|
||||
n=17;
|
||||
m=n+3;
|
||||
println_int(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXPECTED
|
||||
// EXITCODE 2
|
||||
// In function main: Line 6 col 2: Undefined variable m
|
||||
@@ -0,0 +1,10 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main(){
|
||||
int x;
|
||||
x="blablabla";
|
||||
return 0;
|
||||
}
|
||||
// EXITCODE 2
|
||||
// EXPECTED
|
||||
// In function main: Line 5 col 2: type mismatch for x: integer and string
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main(){
|
||||
int n;
|
||||
string s;
|
||||
n=17;
|
||||
s="seventeen";
|
||||
s = n*s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXITCODE 2
|
||||
// EXPECTED
|
||||
// In function main: Line 8 col 6: invalid type for multiplicative operands: integer and string
|
||||
@@ -0,0 +1,11 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main(){
|
||||
string x;
|
||||
x=1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXITCODE 2
|
||||
// EXPECTED
|
||||
// In function main: Line 5 col 2: type mismatch for x: string and integer
|
||||
@@ -0,0 +1,10 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main(){
|
||||
int x;
|
||||
x=34+f;
|
||||
return 0;
|
||||
}
|
||||
// EXITCODE 2
|
||||
// EXPECTED
|
||||
// In function main: Line 5 col 7: Undefined variable f
|
||||
@@ -0,0 +1,11 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main(){
|
||||
println_int("foo");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXITCODE 2
|
||||
// EXPECTED
|
||||
// In function main: Line 4 col 2: invalid type for println_int statement: string
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main(){
|
||||
println_int(true+true);
|
||||
return 0;
|
||||
}
|
||||
// EXITCODE 2
|
||||
// EXPECTED
|
||||
// In function main: Line 4 col 14: invalid type for additive operands: boolean and boolean
|
||||
@@ -0,0 +1,12 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main(){
|
||||
int x,y;
|
||||
int z,x;
|
||||
x=42;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXITCODE 2
|
||||
// EXPECTED
|
||||
// In function main: Line 5 col 2: Variable x already declared
|
||||
@@ -0,0 +1,11 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int toto(){
|
||||
println_int(42);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXITCODE 1
|
||||
// EXPECTED
|
||||
// No main function in file
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
int n,u;
|
||||
n=17;
|
||||
u=n;
|
||||
println_int(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXPECTED
|
||||
// 17
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
if (2 < 3)
|
||||
{
|
||||
println_int(1);
|
||||
}
|
||||
if (2 > 3)
|
||||
{
|
||||
println_int(2);
|
||||
}
|
||||
if (2 <= 2)
|
||||
{
|
||||
println_int(3);
|
||||
}
|
||||
if (2 >= 2)
|
||||
{
|
||||
println_int(4);
|
||||
}
|
||||
|
||||
if (2 == 3)
|
||||
{
|
||||
println_int(10);
|
||||
}
|
||||
if (2 != 3)
|
||||
{
|
||||
println_int(20);
|
||||
}
|
||||
if (2 == 2)
|
||||
{
|
||||
println_int(30);
|
||||
}
|
||||
if (2 != 2)
|
||||
{
|
||||
println_int(40);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXPECTED
|
||||
// 1
|
||||
// 3
|
||||
// 4
|
||||
// 20
|
||||
// 30
|
||||
@@ -0,0 +1,11 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main() {
|
||||
if ((1.0 + 2.0) * 3.0 == 9.0) {
|
||||
println_string("OK");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXPECTED
|
||||
// OK
|
||||
@@ -0,0 +1,15 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main(){
|
||||
println_int(3/2+45*(2/1));
|
||||
println_int(23+19);
|
||||
println_bool( (false || 3 != 77 ) && (42<=1515) );
|
||||
println_string("coucou");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXPECTED
|
||||
// 91
|
||||
// 42
|
||||
// 1
|
||||
// coucou
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main(){
|
||||
println_int(42);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXPECTED
|
||||
// 42
|
||||
@@ -0,0 +1,11 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main(){
|
||||
int x;
|
||||
x="blabla";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXPECTED
|
||||
// In function main: Line 5 col 2: type mismatch for x: integer and string
|
||||
// EXITCODE 2
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main(){
|
||||
string x,y,z;
|
||||
x = "ENS";
|
||||
y = "De Lyon";
|
||||
z = x + " " + y;
|
||||
println_string(z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXPECTED
|
||||
// ENS De Lyon
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main(){
|
||||
string n,m;
|
||||
n = "foo";
|
||||
m = "bar";
|
||||
println_string(n);
|
||||
println_string(m);
|
||||
println_string(n + m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXPECTED
|
||||
// foo
|
||||
// bar
|
||||
// foobar
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main() {
|
||||
string s;
|
||||
println_string(s);
|
||||
s = s + "Coucou";
|
||||
println_string(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXPECTED
|
||||
//
|
||||
// Coucou
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main() {
|
||||
bool x;
|
||||
if (x) {
|
||||
println_int(1);
|
||||
}
|
||||
x = !x;
|
||||
if (x) {
|
||||
println_int(2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXPECTED
|
||||
// 2
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main() {
|
||||
float x;
|
||||
println_float(x);
|
||||
x = x + 1.0;
|
||||
println_float(x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXPECTED
|
||||
// 0.00
|
||||
// 1.00
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main() {
|
||||
int x;
|
||||
println_int(x);
|
||||
x = x + 1;
|
||||
println_int(x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXPECTED
|
||||
// 0
|
||||
// 1
|
||||
@@ -0,0 +1 @@
|
||||
Add your own tests in this directory.
|
||||
Reference in New Issue
Block a user