Skip to content

Commit

Permalink
Fix reodering, add TypeError missing required positional argument
Browse files Browse the repository at this point in the history
  • Loading branch information
Pierre Delaunay committed May 22, 2024
1 parent 2482621 commit 6606dc7
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 121 deletions.
2 changes: 1 addition & 1 deletion src/ast/nodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ struct MatchValue: public Pattern {

struct MatchSingleton: public Pattern {
Value value;
ValueDeleter deleter;
ValueDeleter deleter = nullptr;

~MatchSingleton() {
if (deleter) {
Expand Down
92 changes: 18 additions & 74 deletions src/ast/ops/print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -559,24 +559,38 @@ ReturnType Printer::call(Call const* self, int depth, std::ostream& out, int lev

exec(self->func, depth, out, level);
out << "(";
int k = 0;

for (int i = 0; i < self->args.size(); i++) {
if (k > 0) {
out << ", ";
}
exec(self->args[i], depth, out, level);
k += 1;
}

if (i < self->args.size() - 1 || !self->keywords.empty())

for (int i = 0; i < self->varargs.size(); i++) {
if (k > 0) {
out << ", ";
}
exec(self->varargs[i], depth, out, level);
k += 1;
}


for (int i = 0; i < self->keywords.size(); i++) {
if (k > 0) {
out << ", ";
}

auto const& key = self->keywords[i];

out << self->keywords[i].arg;
out << "=";

exec(key.value, depth, out, level);

if (i < self->keywords.size() - 1)
out << ", ";
k += 1;
}

out << ")";
Expand Down Expand Up @@ -1284,76 +1298,6 @@ void Printer::arguments(Arguments const& self, int depth, std::ostream& out, int
i += 1;
prev = kind;
});

#if 0
for (auto& arg: self.args) {
out << arg.arg;

if (arg.annotation.has_value()) {
out << ": ";
exec(arg.annotation.value(), depth, out, level);
}

auto default_offset = self.args.size() - 1 - i;
if (self.defaults.size() > 0 && default_offset < self.defaults.size()) {
if (arg.annotation.has_value()) {
out << " = ";
} else {
out << "=";
}
exec(self.defaults[default_offset], depth, out, -1);
}

if (i + 1 < self.args.size()) {
out << ", ";
}
i += 1;
}

if (self.vararg.has_value()) {
if (self.args.size() > 0) {
out << ", ";
}

out << "*" << self.vararg.value().arg;
}

if ((self.args.size() > 0 || self.vararg.has_value()) && self.kwonlyargs.size() > 0) {
out << ", ";
}

i = 0;
for (auto const& kw: self.kwonlyargs) {
out << kw.arg;

if (kw.annotation.has_value()) {
out << ": ";
exec(kw.annotation.value(), depth, out, level);
}

auto default_offset = self.kwonlyargs.size() - 1 - i;
if (self.kw_defaults.size() > 0 && default_offset < self.kw_defaults.size()) {
if (kw.annotation.has_value()) {
out << " = ";
} else {
out << "=";
}
exec(self.kw_defaults[default_offset], depth, out, -1);
}

if (i + 1 < self.kwonlyargs.size()) {
out << ", ";
}
i += 1;
}

if (self.kwarg.has_value()) {
if (!self.kwonlyargs.empty()) {
out << ", ";
}
out << "**" << self.kwarg.value().arg;
}
#endif
}

int get_precedence(Node const* node) {
Expand Down
108 changes: 89 additions & 19 deletions src/sema/sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -648,19 +648,17 @@ SemanticAnalyser::get_arrow(ExprNode* fun, ExprNode* type, int depth, int& offse
return nullptr;
}

void reorder_arguments(Call* call, FunctionDef* def) {
bool SemanticAnalyser::reorder_arguments(Call* call, FunctionDef* def) {
// return;
// Transform as many argument as possible to positional
//
// We should probably only allow *args && **kwargs for code generation
// We should probably only allow *args && **kwargs at compile time
// as code generator helper
//
//

// fetch the arguments
// this only works if vararg & kwarg are not set
Array<Keyword> args;
Array<ExprNode*> final_args;
Array<ExprNode*> var_args;
Array<Keyword> kw_args;
Array<Keyword> kw_args;

Array<int> used_keywords;

Expand Down Expand Up @@ -731,8 +729,21 @@ void reorder_arguments(Call* call, FunctionDef* def) {
}
});

final_args.resize(args.size());
bool is_ok = true;
final_args.reserve(args.size());
for(Keyword kw: args) {
if (kw.value == nullptr) {
is_ok = false;
SEMA_ERROR(
call,
TypeError,
fmt::format(
"TypeError: {} missing 1 required positional argument: '{}'",
str(call),
str(kw.arg)
)
);
}
final_args.push_back(kw.value);
}

Expand All @@ -742,6 +753,7 @@ void reorder_arguments(Call* call, FunctionDef* def) {
call->args = final_args;
call->varargs = var_args;
call->keywords = kw_args;
return is_ok;
}

TypeExpr* SemanticAnalyser::call(Call* n, int depth) {
Expand All @@ -750,10 +762,16 @@ TypeExpr* SemanticAnalyser::call(Call* n, int depth) {
// this returns the type of the function
auto* type = exec(n->func, depth);

// we are calling a type, this is a constructor
// if (equal(type, Type_t())) {
//
//}
//
bool is_call_valid = false;
if (Name* name = cast<Name>(n->func)) {
BindingEntry const* entry = lookup(name);
if (entry) {
if (FunctionDef* def = cast<FunctionDef>(entry->value)){
is_call_valid = reorder_arguments(n, def);
}
}
}

int offset = 0;
ClassDef* cls = nullptr;
Expand Down Expand Up @@ -814,13 +832,7 @@ TypeExpr* SemanticAnalyser::call(Call* n, int depth) {
}

// FIXME: we do not know the returns so we just use the one we have
if (arrow != nullptr) {
if (got->arg_count() != arrow->arg_count()) {
// we do not really that check
// SEMA_ERROR(TypeError(" missing {} required positional arguments"));
//
}

if (arrow != nullptr && is_call_valid) {
got->returns = arrow->returns;

// (Point, Point) -> Point
Expand Down Expand Up @@ -1174,6 +1186,63 @@ TypeExpr* SemanticAnalyser::slice(Slice* n, int depth) {
// }

void SemanticAnalyser::add_arguments(Arguments& args, Arrow* arrow, ClassDef* def, int depth) {
int i = 0;
TypeExpr* class_t = nullptr;
if (def != nullptr) {
class_t = make_ref(arrow, str(def->name), Type_t());
}

args.visit([&](ArgumentIter<false> const& iter) {
if (in(iter.kind, ArgumentKind::VarArg, ArgumentKind::KwArg)) {
kwdebug(semalog, "Unsupported argument type");
return;
}

TypeExpr* ann_t = nullptr;
TypeExpr* val_t = nullptr;

bool ann_v = false;

if(iter.arg.annotation.has_value()) {
ann_t = exec(iter.arg.annotation.value(), depth);
ann_v = is_type(ann_t, depth, LOC);
}

if (iter.value) {
val_t = exec(iter.value, depth);
}

if (ann_v && val_t) {
typecheck(nullptr, iter.arg.annotation.value(), iter.value, val_t, LOC);
}

TypeExpr* arg_t = ann_v ? iter.arg.annotation.value(): val_t;

// First argument might be self: cls
if (def != nullptr && i == 0 && class_t) {
if (arg_t) {
typecheck(nullptr, arg_t, nullptr, class_t, LOC);
}
arg_t = class_t;
}

// we could populate the default value here
// but we would not want sema to think this is a constant
add_name(iter.arg.arg, nullptr, arg_t);

if (arrow != nullptr) {
arrow->names.push_back(iter.arg.arg);

if (!arrow->add_arg_type(arg_t)) {
SEMA_ERROR(
arrow, TypeError, fmt::format("Cannot have a function type refer to itself"));
}
}

i += 1;
});

#if 0
TypeExpr* class_t = nullptr;
if (def != nullptr) {
class_t = make_ref(arrow, str(def->name), Type_t());
Expand Down Expand Up @@ -1273,6 +1342,7 @@ void SemanticAnalyser::add_arguments(Arguments& args, Arrow* arrow, ClassDef* de
}
}
}
#endif
}

Arrow* SemanticAnalyser::functiondef_arrow(FunctionDef* n, StmtNode* class_t, int depth) {
Expand Down
2 changes: 2 additions & 0 deletions src/sema/sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ struct SemanticAnalyser: public BaseVisitor<SemanticAnalyser, false, SemaVisitor

bool is_type(TypeExpr* node, int depth, lython::CodeLocation const& loc);

bool reorder_arguments(Call* call, FunctionDef* def);

template <typename T, typename... Args>
void sema_error(Node* node, lython::CodeLocation const& loc, Args... args) {
errors.push_back(std::unique_ptr<SemaException>(new T(args...)));
Expand Down
18 changes: 9 additions & 9 deletions tests/cases/parser/Inline.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# >>> case: 0
# >>> code
a = 2; b = c; d = e# <<<

# >>> error
NameError: name 'c' is not defined# <<<
# >>> error
NameError: name 'e' is not defined# <<<
# >>> case: 0
# >>> code
a = 2; b = c; d = e# <<<

# >>> error
NameError: name 'c' is not defined# <<<
# >>> error
NameError: name 'e' is not defined# <<<

Loading

0 comments on commit 6606dc7

Please sign in to comment.