Fix #250 (raise ... from)

typecheck-v2
Ibrahim Numanagić 2024-11-26 10:47:57 -08:00
parent 543068d903
commit 48c848cf52
13 changed files with 93 additions and 21 deletions

View File

@ -391,13 +391,14 @@ std::string TryStmt::toString(int indent) const {
: "");
}
ThrowStmt::ThrowStmt(Expr *expr, bool transformed)
: AcceptorExtend(), expr(expr), transformed(transformed) {}
ThrowStmt::ThrowStmt(Expr *expr, Expr *from, bool transformed)
: AcceptorExtend(), expr(expr), from(from), transformed(transformed) {}
ThrowStmt::ThrowStmt(const ThrowStmt &stmt, bool clean)
: AcceptorExtend(stmt, clean), expr(ast::clone(stmt.expr, clean)),
transformed(stmt.transformed) {}
from(ast::clone(stmt.from, clean)), transformed(stmt.transformed) {}
std::string ThrowStmt::toString(int indent) const {
return format("(throw{})", expr ? " " + expr->toString(indent) : "");
return format("(throw{}{})", expr ? " " + expr->toString(indent) : "",
from ? format(" :from {}", from->toString(indent)) : "");
}
GlobalStmt::GlobalStmt(std::string var, bool nonLocal)

View File

@ -439,16 +439,19 @@ private:
/// Throw statement (raise expr).
/// @li: raise a
struct ThrowStmt : public AcceptorExtend<ThrowStmt, Stmt> {
explicit ThrowStmt(Expr *expr = nullptr, bool transformed = false);
explicit ThrowStmt(Expr *expr = nullptr, Expr *from = nullptr,
bool transformed = false);
ThrowStmt(const ThrowStmt &, bool);
Expr *getExpr() const { return expr; }
Expr *getFrom() const { return from; }
bool isTransformed() const { return transformed; }
ACCEPT(ThrowStmt, ASTVisitor, expr, transformed);
ACCEPT(ThrowStmt, ASTVisitor, expr, from, transformed);
private:
Expr *expr;
Expr *from;
// True if a statement was transformed during type-checking stage
// (to avoid setting up ExcHeader multiple times).
bool transformed;

View File

@ -138,10 +138,11 @@ del_stmt <- 'del' SPACE tlist(',', expression) {
return_stmt <- 'return' (SPACE expressions)? {
return asts(Return, LOC, !VS.empty() ? ac_expr(V0) : nullptr);
}
# TODO: raise expression 'from' expression
raise_stmt <- 'raise' (SPACE expression)? {
return asts(Throw, LOC, !VS.empty() ? ac_expr(V0) : nullptr);
}
raise_stmt <-
/ 'raise' SPACE expression (SPACE 'from' SPACE expression)? {
return asts(Throw, LOC, ac_expr(V0), VS.size() > 1 ? ac_expr(V1) : nullptr);
}
/ 'raise' { return asts(Throw, LOC, nullptr); }
print_stmt <-
/ 'print' SPACE star_expression (_ ',' _ star_expression)* (_ <','>)? {
return asts(Print, LOC, VS.transform<Expr*>(), !VS.tokens.empty());
@ -448,7 +449,7 @@ custom_small_stmt__PREDICATE {
expressions <- tlist(',', expression) { return wrap_tuple(CTX, VS, LOC); }
expression <-
/ lambdef { return ac_expr(V0); }
/ disjunction SPACE 'if' SPACE disjunction SPACE 'else' SPACE expression {
/ disjunction SPACE? 'if' SPACE? disjunction SPACE? 'else' SPACE? expression {
return aste(If, LOC, ac_expr(V1), ac_expr(V0), ac_expr(V2));
}
/ pipe { return ac_expr(V0); }
@ -471,7 +472,7 @@ pipe <-
}
/ disjunction { return ac_expr(V0); }
disjunction <-
/ conjunction (SPACE 'or' SPACE conjunction)+ {
/ conjunction (SPACE? 'or' SPACE? conjunction)+ {
auto b = aste(Binary, LOC, ac_expr(V0), "||", ac_expr(V1));
for (int i = 2; i < VS.size(); i++)
b = aste(Binary, LOC, b, "||", ac_expr(VS[i]));
@ -479,7 +480,7 @@ disjunction <-
}
/ conjunction { return ac_expr(V0); }
conjunction <-
/ inversion (SPACE 'and' SPACE inversion)+ {
/ inversion (SPACE? 'and' SPACE? inversion)+ {
auto b = aste(Binary, LOC, ac_expr(V0), "&&", ac_expr(V1));
for (int i = 2; i < VS.size(); i++)
b = aste(Binary, LOC, b, "&&", ac_expr(VS[i]));
@ -636,7 +637,7 @@ for_if_clauses <- for_if_clause (SPACE for_if_clause)* {
return v;
}
for_if_clause <- 'for' SPACE star_targets SPACE 'in' SPACE disjunction
(SPACE 'if' SPACE disjunction)* {
(SPACE? 'if' SPACE? disjunction)* {
std::vector<Stmt*> v{asts(For, LOC, ac_expr(V0), ac_expr(V1), nullptr)};
auto tail = VS.transform<Expr*>(2);
for (auto &t: tail)

View File

@ -347,7 +347,10 @@ void FormatVisitor::visit(GlobalStmt *stmt) {
}
void FormatVisitor::visit(ThrowStmt *stmt) {
result = fmt::format("{} {}", keyword("raise"), transform(stmt->getExpr()));
result = fmt::format("{} {}{}", keyword("raise"), transform(stmt->getExpr()),
stmt->getFrom() ? fmt::format(" {} {}", keyword("from"),
transform(stmt->getFrom()))
: "");
}
void FormatVisitor::visit(FunctionStmt *fstmt) {

View File

@ -158,7 +158,12 @@ void TypecheckVisitor::visit(ThrowStmt *stmt) {
stmt->expr = transform(N<CallExpr>(
N<IdExpr>("__internal__.set_header:0"), stmt->getExpr(),
N<StringExpr>(ctx->getBase()->name), N<StringExpr>(stmt->getSrcInfo().file),
N<IntExpr>(stmt->getSrcInfo().line), N<IntExpr>(stmt->getSrcInfo().col)));
N<IntExpr>(stmt->getSrcInfo().line), N<IntExpr>(stmt->getSrcInfo().col),
stmt->getFrom()
? (Expr *)N<CallExpr>(N<DotExpr>(N<IdExpr>("__internal__"), "class_super"),
stmt->getFrom(),
N<IdExpr>("std.internal.types.error.BaseException.0"))
: N<CallExpr>(N<IdExpr>("NoneType"))));
}
if (stmt->getExpr()->isDone())
stmt->setDone();

View File

@ -296,7 +296,10 @@ public:
transform(stmt->suite);
}
void visit(GlobalStmt *stmt) override {}
void visit(ThrowStmt *stmt) override { transform(stmt->expr); }
void visit(ThrowStmt *stmt) override {
transform(stmt->expr);
transform(stmt->from);
}
void visit(FunctionStmt *stmt) override {
transform(stmt->ret);
for (auto &a : stmt->items) {
@ -486,7 +489,10 @@ public:
stmt->suite = SuiteStmt::wrap(transform(stmt->suite));
}
void visit(GlobalStmt *stmt) override {}
void visit(ThrowStmt *stmt) override { stmt->expr = transform(stmt->expr); }
void visit(ThrowStmt *stmt) override {
stmt->expr = transform(stmt->expr);
stmt->from = transform(stmt->from);
}
void visit(FunctionStmt *stmt) override {
stmt->ret = transform(stmt->ret);
for (auto &a : stmt->items) {

View File

@ -157,6 +157,7 @@ struct SeqExcHeader_t {
seq_int_t line;
seq_int_t col;
void *python_type;
void *cause;
};
void seq_exc_init(int flags) {

View File

@ -486,7 +486,7 @@ class __internal__:
raise NameError(f"name '{s}' is not defined")
@__hidden__
def set_header(e, func, file, line, col):
def set_header(e, func, file, line, col, cause):
if not isinstance(e, BaseException):
compile_error("exceptions must derive from BaseException")
@ -494,6 +494,8 @@ class __internal__:
e.file = file
e.line = line
e.col = col
if cause is not None:
e.cause = cause
return e
def kwargs_get(kw, key: Static[str], default):

View File

@ -11,6 +11,7 @@ class BaseException:
line: int
col: int
python_type: cobj
cause: Optional[BaseException]
def __init__(self, typename: str, message: str = ""):
self.typename = typename
@ -20,6 +21,7 @@ class BaseException:
self.line = 0
self.col = 0
self.python_type = BaseException._pytype
self.cause = __internal__.opt_ref_new(T=BaseException)
def __str__(self):
return self.message
@ -27,6 +29,10 @@ class BaseException:
def __repr__(self):
return f'{self.typename}({self.message.__repr__()})'
@property
def __cause__(self):
return self.cause
class Exception(Static[BaseException]):
_pytype: ClassVar[cobj] = cobj()
def __init__(self, typename: str, msg: str = ""):

View File

@ -93,4 +93,4 @@ optional = Optional
def unwrap(opt: Optional[T], T: type) -> T:
if opt.__has__():
return opt.__val__()
raise ValueError("optional is None")
raise ValueError(f"optional unpack failed: expected {T.__class__.__name__}, got None")

View File

@ -44,3 +44,31 @@ except MyError as e:
raise 'hello'
#! exceptions must derive from BaseException
#%% raise_from,barebones
def foo(bar):
try:
bar()
except ValueError as e:
raise RuntimeError("oops") from e
raise RuntimeError("oops")
def bar1():
raise ValueError("bar1")
try:
foo(bar1)
except RuntimeError as e:
print(e.message, e.__cause__) #: oops bar1
def bar2():
raise ValueError("bar2")
try:
foo(bar2)
except RuntimeError as e:
print(e.message, e.__cause__) #: oops bar2
def bar3():
pass
try:
foo(bar3)
except RuntimeError as e:
print(e.message, e.__cause__) #: oops None

View File

@ -230,7 +230,7 @@ Optional(5) |> foo2 #: 5
try:
Optional[int]() |> foo2
except ValueError as e:
print e.message #: optional is None
print e.message #: optional unpack failed: expected int, got None
#%% pipe_prepend_error,barebones
def foo2(a: int):

View File

@ -11,3 +11,19 @@ def foo(return_, pass_, yield_, break_, continue_, print_, assert_):
print foo([1], [1], [1], [1], [1], [1], [1])
#: ([1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [1, 7])
#%% spaces,barebones
def space_test():
x = 0.77
y = 0.86
z = x/(1if((1if(y==0)else(y))==0)else((1if(y==0)else(y))))
print(z) #: 0.895349
h = "hello"
b = ((True)or(False))or((("sR2Kt7"))==(h))
print(b) #: True
h2: Optional[str] = "hi"
h3 = "r"
b2 = (((h2)==None)and(h3)==("r"))
print(b2) #: False
space_test()