mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Migrate Declaration to variant (#644)
Note this makes some structural choices that I'm not sure how popular they'll be... Most notably, I could remove `DeclarationKind` because I'm using `std::visit` and `Declaration::Visitor` in reality. I could go to `switch(tag())` instead, but I'm wondering if this approach will be well received for the separation of ownership. Alternatively, I could move `Declaration` around so that it actually implements the things like `TopLevel` -- I did feel weird with the old structure of typecheck.cpp implementing members of declaration.h, though.
This commit is contained in:
@@ -8,33 +8,101 @@
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
void FunctionDeclaration::Print() const { definition.Print(); }
|
||||
|
||||
void StructDeclaration::Print() const {
|
||||
std::cout << "struct " << *definition.name << " {" << std::endl;
|
||||
for (auto& member : *definition.members) {
|
||||
member->Print();
|
||||
}
|
||||
std::cout << "}" << std::endl;
|
||||
auto Declaration::MakeFunctionDeclaration(FunctionDefinition definition)
|
||||
-> const Declaration {
|
||||
Declaration d;
|
||||
d.value = FunctionDeclaration({.definition = definition});
|
||||
return d;
|
||||
}
|
||||
|
||||
void ChoiceDeclaration::Print() const {
|
||||
std::cout << "choice " << name << " {" << std::endl;
|
||||
for (const auto& [name, signature] : alternatives) {
|
||||
std::cout << "alt " << name << " ";
|
||||
PrintExp(signature);
|
||||
std::cout << ";" << std::endl;
|
||||
}
|
||||
std::cout << "}" << std::endl;
|
||||
auto Declaration::MakeStructDeclaration(int line_num, std::string name,
|
||||
std::list<Member*> members)
|
||||
-> const Declaration {
|
||||
Declaration d;
|
||||
d.value = StructDeclaration(
|
||||
{.definition = StructDefinition({.line_num = line_num,
|
||||
.name = std::move(name),
|
||||
.members = std::move(members)})});
|
||||
return d;
|
||||
}
|
||||
|
||||
// Print a global variable declaration to standard out.
|
||||
void VariableDeclaration::Print() const {
|
||||
std::cout << "var ";
|
||||
PrintExp(type);
|
||||
std::cout << " : " << name << " = ";
|
||||
PrintExp(initializer);
|
||||
std::cout << std::endl;
|
||||
auto Declaration::MakeChoiceDeclaration(
|
||||
int line_num, std::string name,
|
||||
std::list<std::pair<std::string, const Expression*>> alternatives)
|
||||
-> const Declaration {
|
||||
Declaration d;
|
||||
d.value = ChoiceDeclaration({.line_num = line_num,
|
||||
.name = std::move(name),
|
||||
.alternatives = std::move(alternatives)});
|
||||
return d;
|
||||
}
|
||||
|
||||
auto Declaration::MakeVariableDeclaration(int source_location, std::string name,
|
||||
const Expression* type,
|
||||
const Expression* initializer)
|
||||
-> const Declaration {
|
||||
Declaration d;
|
||||
d.value = VariableDeclaration({.source_location = source_location,
|
||||
.name = std::move(name),
|
||||
.type = type,
|
||||
.initializer = initializer});
|
||||
return d;
|
||||
}
|
||||
|
||||
auto Declaration::GetFunctionDeclaration() const -> const FunctionDeclaration& {
|
||||
return std::get<FunctionDeclaration>(value);
|
||||
}
|
||||
|
||||
auto Declaration::GetStructDeclaration() const -> const StructDeclaration& {
|
||||
return std::get<StructDeclaration>(value);
|
||||
}
|
||||
|
||||
auto Declaration::GetChoiceDeclaration() const -> const ChoiceDeclaration& {
|
||||
return std::get<ChoiceDeclaration>(value);
|
||||
}
|
||||
|
||||
auto Declaration::GetVariableDeclaration() const -> const VariableDeclaration& {
|
||||
return std::get<VariableDeclaration>(value);
|
||||
}
|
||||
|
||||
void Declaration::Print() const {
|
||||
switch (tag()) {
|
||||
case DeclarationKind::FunctionDeclaration:
|
||||
GetFunctionDeclaration().definition.Print();
|
||||
break;
|
||||
|
||||
case DeclarationKind::StructDeclaration: {
|
||||
const StructDefinition& struct_def = GetStructDeclaration().definition;
|
||||
std::cout << "struct " << struct_def.name << " {" << std::endl;
|
||||
for (Member* m : struct_def.members) {
|
||||
m->Print();
|
||||
}
|
||||
std::cout << "}" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
case DeclarationKind::ChoiceDeclaration: {
|
||||
const auto& choice = GetChoiceDeclaration();
|
||||
std::cout << "choice " << choice.name << " {" << std::endl;
|
||||
for (const auto& [name, signature] : choice.alternatives) {
|
||||
std::cout << "alt " << name << " ";
|
||||
PrintExp(signature);
|
||||
std::cout << ";" << std::endl;
|
||||
}
|
||||
std::cout << "}" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
case DeclarationKind::VariableDeclaration: {
|
||||
const auto& var = GetVariableDeclaration();
|
||||
std::cout << "var ";
|
||||
PrintExp(var.type);
|
||||
std::cout << " : " << var.name << " = ";
|
||||
PrintExp(var.initializer);
|
||||
std::cout << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
@@ -14,10 +14,6 @@
|
||||
#include "executable_semantics/interpreter/address.h"
|
||||
#include "executable_semantics/interpreter/dictionary.h"
|
||||
|
||||
namespace yy {
|
||||
class parser;
|
||||
}
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
struct Value;
|
||||
@@ -32,148 +28,72 @@ struct TypeCheckContext {
|
||||
Env values;
|
||||
};
|
||||
|
||||
// An existential AST declaration satisfying the Declaration concept.
|
||||
class Declaration {
|
||||
public: // ValueSemantic concept API.
|
||||
Declaration(const Declaration& other) = default;
|
||||
Declaration& operator=(const Declaration& other) = default;
|
||||
|
||||
// Constructs an instance equivalent to `d`, where `Model` satisfies the
|
||||
// Declaration concept.
|
||||
template <class Model>
|
||||
Declaration(Model d) : box(std::make_shared<Boxed<Model>>(d)) {}
|
||||
|
||||
public: // Declaration concept API, in addition to ValueSemantic.
|
||||
void Print() const { box->Print(); }
|
||||
auto Name() const -> std::string { return box->Name(); }
|
||||
|
||||
// Signals a type error if the declaration is not well typed,
|
||||
// otherwise returns this declaration with annotated types.
|
||||
//
|
||||
// - Parameter env: types of run-time names.
|
||||
// - Paraemter ct_env: values of compile-time names.
|
||||
auto TypeChecked(TypeEnv env, Env ct_env) const -> Declaration {
|
||||
return box->TypeChecked(env, ct_env);
|
||||
}
|
||||
// Add an entry in the runtime global symbol table for this declaration.
|
||||
void InitGlobals(Env& globals) const { return box->InitGlobals(globals); }
|
||||
// Add an entry in the compile time global symbol tables for this declaration.
|
||||
auto TopLevel(TypeCheckContext& e) const -> void { return box->TopLevel(e); }
|
||||
|
||||
private:
|
||||
// A base class that erases the type of a `Boxed<Content>`, where `Content`
|
||||
// satisfies the Declaration concept.
|
||||
struct Box {
|
||||
protected:
|
||||
Box() {}
|
||||
|
||||
public:
|
||||
Box(const Box& other) = delete;
|
||||
Box& operator=(const Box& other) = delete;
|
||||
|
||||
virtual ~Box() {}
|
||||
virtual auto Print() const -> void = 0;
|
||||
virtual auto Name() const -> std::string = 0;
|
||||
virtual auto TypeChecked(TypeEnv env, Env ct_env) const -> Declaration = 0;
|
||||
virtual auto InitGlobals(Env& globals) const -> void = 0;
|
||||
virtual auto TopLevel(TypeCheckContext&) const -> void = 0;
|
||||
};
|
||||
|
||||
// The derived class that holds an instance of `Content` satisfying the
|
||||
// Declaration concept.
|
||||
template <class Content>
|
||||
struct Boxed final : Box {
|
||||
const Content content;
|
||||
explicit Boxed(Content content) : Box(), content(content) {}
|
||||
|
||||
auto Print() const -> void override { return content.Print(); }
|
||||
auto Name() const -> std::string override { return content.Name(); }
|
||||
auto TypeChecked(TypeEnv env, Env ct_env) const -> Declaration override {
|
||||
return content.TypeChecked(env, ct_env);
|
||||
}
|
||||
auto InitGlobals(Env& globals) const -> void override {
|
||||
content.InitGlobals(globals);
|
||||
}
|
||||
auto TopLevel(TypeCheckContext& e) const -> void override {
|
||||
content.TopLevel(e);
|
||||
}
|
||||
};
|
||||
|
||||
// Constructs an instance in a "partially formed" state, which can only be
|
||||
// assigned to or destroyed.
|
||||
Declaration() = default;
|
||||
|
||||
// Give Bison access to the default constructor.
|
||||
friend class yy::parser;
|
||||
|
||||
// Note: the pointee is const as long as we have no mutating methods. When
|
||||
std::shared_ptr<const Box> box;
|
||||
enum class DeclarationKind {
|
||||
FunctionDeclaration,
|
||||
StructDeclaration,
|
||||
ChoiceDeclaration,
|
||||
VariableDeclaration,
|
||||
};
|
||||
|
||||
struct FunctionDeclaration {
|
||||
static constexpr DeclarationKind Kind = DeclarationKind::FunctionDeclaration;
|
||||
FunctionDefinition definition;
|
||||
explicit FunctionDeclaration(FunctionDefinition definition)
|
||||
: definition(std::move(definition)) {}
|
||||
|
||||
auto Print() const -> void;
|
||||
auto Name() const -> std::string;
|
||||
auto TypeChecked(TypeEnv env, Env ct_env) const -> Declaration;
|
||||
auto InitGlobals(Env& globals) const -> void;
|
||||
auto TopLevel(TypeCheckContext&) const -> void;
|
||||
};
|
||||
|
||||
struct StructDeclaration {
|
||||
static constexpr DeclarationKind Kind = DeclarationKind::StructDeclaration;
|
||||
StructDefinition definition;
|
||||
StructDeclaration(int line_num, std::string name, std::list<Member*>* members)
|
||||
: definition{line_num, new std::string(name), members} {}
|
||||
|
||||
void Print() const;
|
||||
auto Name() const -> std::string;
|
||||
auto TypeChecked(TypeEnv env, Env ct_env) const -> Declaration;
|
||||
void InitGlobals(Env& globals) const;
|
||||
auto TopLevel(TypeCheckContext&) const -> void;
|
||||
};
|
||||
|
||||
struct ChoiceDeclaration {
|
||||
static constexpr DeclarationKind Kind = DeclarationKind::ChoiceDeclaration;
|
||||
int line_num;
|
||||
std::string name;
|
||||
std::list<std::pair<std::string, const Expression*>> alternatives;
|
||||
|
||||
ChoiceDeclaration(
|
||||
int line_num, std::string name,
|
||||
std::list<std::pair<std::string, const Expression*>> alternatives)
|
||||
: line_num(line_num), name(name), alternatives(std::move(alternatives)) {}
|
||||
|
||||
void Print() const;
|
||||
auto Name() const -> std::string;
|
||||
auto TypeChecked(TypeEnv env, Env ct_env) const -> Declaration;
|
||||
void InitGlobals(Env& globals) const;
|
||||
auto TopLevel(TypeCheckContext&) const -> void;
|
||||
};
|
||||
|
||||
// Global variable definition implements the Declaration concept.
|
||||
class VariableDeclaration {
|
||||
public:
|
||||
VariableDeclaration(int source_location, std::string name,
|
||||
const Expression* type, const Expression* initializer)
|
||||
: source_location(source_location),
|
||||
name(name),
|
||||
type(type),
|
||||
initializer(initializer) {}
|
||||
|
||||
void Print() const;
|
||||
auto Name() const -> std::string;
|
||||
auto TypeChecked(TypeEnv env, Env ct_env) const -> Declaration;
|
||||
void InitGlobals(Env& globals) const;
|
||||
auto TopLevel(TypeCheckContext&) const -> void;
|
||||
|
||||
private:
|
||||
struct VariableDeclaration {
|
||||
static constexpr DeclarationKind Kind = DeclarationKind::VariableDeclaration;
|
||||
int source_location;
|
||||
std::string name;
|
||||
const Expression* type;
|
||||
const Expression* initializer;
|
||||
};
|
||||
|
||||
class Declaration {
|
||||
public:
|
||||
static auto MakeFunctionDeclaration(FunctionDefinition definition)
|
||||
-> const Declaration;
|
||||
static auto MakeStructDeclaration(int line_num, std::string name,
|
||||
std::list<Member*> members)
|
||||
-> const Declaration;
|
||||
static auto MakeChoiceDeclaration(
|
||||
int line_num, std::string name,
|
||||
std::list<std::pair<std::string, const Expression*>> alternatives)
|
||||
-> const Declaration;
|
||||
static auto MakeVariableDeclaration(int source_location, std::string name,
|
||||
const Expression* type,
|
||||
const Expression* initializer)
|
||||
-> const Declaration;
|
||||
|
||||
auto GetFunctionDeclaration() const -> const FunctionDeclaration&;
|
||||
auto GetStructDeclaration() const -> const StructDeclaration&;
|
||||
auto GetChoiceDeclaration() const -> const ChoiceDeclaration&;
|
||||
auto GetVariableDeclaration() const -> const VariableDeclaration&;
|
||||
|
||||
void Print() const;
|
||||
|
||||
inline auto tag() const -> DeclarationKind {
|
||||
return std::visit([](const auto& t) { return t.Kind; }, value);
|
||||
}
|
||||
|
||||
private:
|
||||
std::variant<FunctionDeclaration, StructDeclaration, ChoiceDeclaration,
|
||||
VariableDeclaration>
|
||||
value;
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
#endif // EXECUTABLE_SEMANTICS_AST_DECLARATION_H_
|
||||
|
||||
@@ -14,8 +14,8 @@ namespace Carbon {
|
||||
|
||||
struct StructDefinition {
|
||||
int line_num;
|
||||
std::string* name;
|
||||
std::list<Member*>* members;
|
||||
std::string name;
|
||||
std::list<Member*> members;
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
@@ -278,57 +278,70 @@ auto EvalPrim(Operator op, const std::vector<const Value*>& args, int line_num)
|
||||
}
|
||||
|
||||
// Globally-defined entities, such as functions, structs, choices.
|
||||
Env globals;
|
||||
static Env globals;
|
||||
|
||||
void InitGlobals(std::list<Declaration>* fs) {
|
||||
for (auto const& d : *fs) {
|
||||
d.InitGlobals(globals);
|
||||
}
|
||||
}
|
||||
void InitEnv(const Declaration& d, Env* env) {
|
||||
switch (d.tag()) {
|
||||
case DeclarationKind::FunctionDeclaration: {
|
||||
const FunctionDefinition& func_def =
|
||||
d.GetFunctionDeclaration().definition;
|
||||
auto pt = InterpExp(*env, func_def.param_pattern);
|
||||
auto f = Value::MakeFunctionValue(func_def.name, pt, func_def.body);
|
||||
Address a = state->heap.AllocateValue(f);
|
||||
env->Set(func_def.name, a);
|
||||
break;
|
||||
}
|
||||
|
||||
auto ChoiceDeclaration::InitGlobals(Env& globals) const -> void {
|
||||
VarValues alts;
|
||||
for (const auto& [name, signature] : alternatives) {
|
||||
auto t = InterpExp(Env(), signature);
|
||||
alts.push_back(make_pair(name, t));
|
||||
}
|
||||
auto ct = Value::MakeChoiceType(name, std::move(alts));
|
||||
auto a = state->heap.AllocateValue(ct);
|
||||
globals.Set(name, a);
|
||||
}
|
||||
|
||||
auto StructDeclaration::InitGlobals(Env& globals) const -> void {
|
||||
VarValues fields;
|
||||
VarValues methods;
|
||||
for (Member* m : *definition.members) {
|
||||
switch (m->tag()) {
|
||||
case MemberKind::FieldMember: {
|
||||
const auto& field = m->GetFieldMember();
|
||||
auto t = InterpExp(Env(), field.type);
|
||||
fields.push_back({field.name, t});
|
||||
break;
|
||||
case DeclarationKind::StructDeclaration: {
|
||||
const StructDefinition& struct_def = d.GetStructDeclaration().definition;
|
||||
VarValues fields;
|
||||
VarValues methods;
|
||||
for (const Member* m : struct_def.members) {
|
||||
switch (m->tag()) {
|
||||
case MemberKind::FieldMember: {
|
||||
const auto& field = m->GetFieldMember();
|
||||
auto t = InterpExp(Env(), field.type);
|
||||
fields.push_back(make_pair(field.name, t));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto st = Value::MakeStructType(struct_def.name, std::move(fields),
|
||||
std::move(methods));
|
||||
auto a = state->heap.AllocateValue(st);
|
||||
env->Set(struct_def.name, a);
|
||||
break;
|
||||
}
|
||||
|
||||
case DeclarationKind::ChoiceDeclaration: {
|
||||
const auto& choice = d.GetChoiceDeclaration();
|
||||
VarValues alts;
|
||||
for (const auto& [name, signature] : choice.alternatives) {
|
||||
auto t = InterpExp(Env(), signature);
|
||||
alts.push_back(make_pair(name, t));
|
||||
}
|
||||
auto ct = Value::MakeChoiceType(choice.name, std::move(alts));
|
||||
auto a = state->heap.AllocateValue(ct);
|
||||
env->Set(choice.name, a);
|
||||
break;
|
||||
}
|
||||
|
||||
case DeclarationKind::VariableDeclaration: {
|
||||
const auto& var = d.GetVariableDeclaration();
|
||||
// Adds an entry in `globals` mapping the variable's name to the
|
||||
// result of evaluating the initializer.
|
||||
auto v = InterpExp(*env, var.initializer);
|
||||
Address a = state->heap.AllocateValue(v);
|
||||
env->Set(var.name, a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto st = Value::MakeStructType(*definition.name, std::move(fields),
|
||||
std::move(methods));
|
||||
auto a = state->heap.AllocateValue(st);
|
||||
globals.Set(*definition.name, a);
|
||||
}
|
||||
|
||||
auto FunctionDeclaration::InitGlobals(Env& globals) const -> void {
|
||||
auto pt = InterpExp(globals, definition.param_pattern);
|
||||
auto f = Value::MakeFunctionValue(definition.name, pt, definition.body);
|
||||
Address a = state->heap.AllocateValue(f);
|
||||
globals.Set(definition.name, a);
|
||||
}
|
||||
|
||||
// Adds an entry in `globals` mapping the variable's name to the
|
||||
// result of evaluating the initializer.
|
||||
auto VariableDeclaration::InitGlobals(Env& globals) const -> void {
|
||||
auto v = InterpExp(globals, initializer);
|
||||
Address a = state->heap.AllocateValue(v);
|
||||
globals.Set(name, a);
|
||||
static void InitGlobals(std::list<Declaration>* fs) {
|
||||
for (auto const& d : *fs) {
|
||||
InitEnv(d, &globals);
|
||||
}
|
||||
}
|
||||
|
||||
// { S, H} -> { { C, E, F} :: S, H}
|
||||
|
||||
@@ -97,7 +97,8 @@ struct State {
|
||||
|
||||
extern State* state;
|
||||
|
||||
auto PrintFrame(Frame* frame, std::ostream& out) -> void;
|
||||
void InitEnv(const Declaration& d, Env* env);
|
||||
void PrintFrame(Frame* frame, std::ostream& out);
|
||||
void PrintStack(Stack<Frame*> ls, std::ostream& out);
|
||||
void PrintEnv(Env values);
|
||||
auto CopyVal(const Value* val, int line_num) -> const Value*;
|
||||
|
||||
@@ -681,65 +681,120 @@ auto TypeOfStructDef(const StructDefinition* sd, TypeEnv /*types*/, Env ct_top)
|
||||
-> const Value* {
|
||||
VarValues fields;
|
||||
VarValues methods;
|
||||
for (Member* m : *sd->members) {
|
||||
for (const Member* m : sd->members) {
|
||||
switch (m->tag()) {
|
||||
case MemberKind::FieldMember:
|
||||
const auto& field = m->GetFieldMember();
|
||||
auto t = InterpExp(ct_top, field.type);
|
||||
fields.push_back(std::make_pair(field.name, t));
|
||||
auto t = InterpExp(ct_top, m->GetFieldMember().type);
|
||||
fields.push_back(std::make_pair(m->GetFieldMember().name, t));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Value::MakeStructType(*sd->name, std::move(fields),
|
||||
std::move(methods));
|
||||
return Value::MakeStructType(sd->name, std::move(fields), std::move(methods));
|
||||
}
|
||||
|
||||
auto FunctionDeclaration::Name() const -> std::string {
|
||||
return definition.name;
|
||||
static auto GetName(const Declaration& d) -> const std::string& {
|
||||
switch (d.tag()) {
|
||||
case DeclarationKind::FunctionDeclaration:
|
||||
return d.GetFunctionDeclaration().definition.name;
|
||||
case DeclarationKind::StructDeclaration:
|
||||
return d.GetStructDeclaration().definition.name;
|
||||
case DeclarationKind::ChoiceDeclaration:
|
||||
return d.GetChoiceDeclaration().name;
|
||||
case DeclarationKind::VariableDeclaration:
|
||||
return d.GetVariableDeclaration().name;
|
||||
}
|
||||
}
|
||||
|
||||
auto StructDeclaration::Name() const -> std::string { return *definition.name; }
|
||||
auto MakeTypeChecked(const Declaration& d, const TypeEnv& types,
|
||||
const Env& values) -> Declaration {
|
||||
switch (d.tag()) {
|
||||
case DeclarationKind::FunctionDeclaration:
|
||||
return Declaration::MakeFunctionDeclaration(*TypeCheckFunDef(
|
||||
&d.GetFunctionDeclaration().definition, types, values));
|
||||
|
||||
auto ChoiceDeclaration::Name() const -> std::string { return name; }
|
||||
case DeclarationKind::StructDeclaration: {
|
||||
const StructDefinition& struct_def = d.GetStructDeclaration().definition;
|
||||
std::list<Member*> fields;
|
||||
for (Member* m : struct_def.members) {
|
||||
switch (m->tag()) {
|
||||
case MemberKind::FieldMember:
|
||||
// TODO: Interpret the type expression and store the result.
|
||||
fields.push_back(m);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Declaration::MakeStructDeclaration(
|
||||
struct_def.line_num, struct_def.name, std::move(fields));
|
||||
}
|
||||
|
||||
// Returns the name of the declared variable.
|
||||
auto VariableDeclaration::Name() const -> std::string { return name; }
|
||||
case DeclarationKind::ChoiceDeclaration:
|
||||
// TODO
|
||||
return d;
|
||||
|
||||
auto StructDeclaration::TypeChecked(TypeEnv types, Env values) const
|
||||
-> Declaration {
|
||||
auto fields = new std::list<Member*>();
|
||||
for (Member* m : *definition.members) {
|
||||
switch (m->tag()) {
|
||||
case MemberKind::FieldMember:
|
||||
// TODO: Interpret the type expression and store the result.
|
||||
fields->push_back(m);
|
||||
break;
|
||||
case DeclarationKind::VariableDeclaration: {
|
||||
const auto& var = d.GetVariableDeclaration();
|
||||
// Signals a type error if the initializing expression does not have
|
||||
// the declared type of the variable, otherwise returns this
|
||||
// declaration with annotated types.
|
||||
TCResult type_checked_initializer = TypeCheckExp(
|
||||
var.initializer, types, values, nullptr, TCContext::ValueContext);
|
||||
const Value* declared_type = InterpExp(values, var.type);
|
||||
ExpectType(var.source_location, "initializer of variable", declared_type,
|
||||
type_checked_initializer.type);
|
||||
return d;
|
||||
}
|
||||
}
|
||||
return StructDeclaration(definition.line_num, *definition.name, fields);
|
||||
}
|
||||
|
||||
auto FunctionDeclaration::TypeChecked(TypeEnv types, Env values) const
|
||||
-> Declaration {
|
||||
return FunctionDeclaration(*TypeCheckFunDef(&definition, types, values));
|
||||
}
|
||||
static void TopLevel(const Declaration& d, TypeCheckContext* tops) {
|
||||
switch (d.tag()) {
|
||||
case DeclarationKind::FunctionDeclaration: {
|
||||
const FunctionDefinition& func_def =
|
||||
d.GetFunctionDeclaration().definition;
|
||||
auto t = TypeOfFunDef(tops->types, tops->values, &func_def);
|
||||
tops->types.Set(func_def.name, t);
|
||||
InitEnv(d, &tops->values);
|
||||
break;
|
||||
}
|
||||
|
||||
auto ChoiceDeclaration::TypeChecked(TypeEnv types, Env values) const
|
||||
-> Declaration {
|
||||
return *this; // TODO.
|
||||
}
|
||||
case DeclarationKind::StructDeclaration: {
|
||||
const StructDefinition& struct_def = d.GetStructDeclaration().definition;
|
||||
auto st = TypeOfStructDef(&struct_def, tops->types, tops->values);
|
||||
Address a = state->heap.AllocateValue(st);
|
||||
tops->values.Set(struct_def.name, a); // Is this obsolete?
|
||||
std::vector<TupleElement> field_types;
|
||||
for (const auto& [field_name, field_value] : st->GetStructType().fields) {
|
||||
field_types.push_back({.name = field_name, .value = field_value});
|
||||
}
|
||||
auto fun_ty = Value::MakeFunctionType(
|
||||
Value::MakeTupleValue(std::move(field_types)), st);
|
||||
tops->types.Set(struct_def.name, fun_ty);
|
||||
break;
|
||||
}
|
||||
|
||||
// Signals a type error if the initializing expression does not have
|
||||
// the declared type of the variable, otherwise returns this
|
||||
// declaration with annotated types.
|
||||
auto VariableDeclaration::TypeChecked(TypeEnv types, Env values) const
|
||||
-> Declaration {
|
||||
TCResult type_checked_initializer = TypeCheckExp(
|
||||
initializer, types, values, nullptr, TCContext::ValueContext);
|
||||
const Value* declared_type = InterpExp(values, type);
|
||||
ExpectType(source_location, "initializer of variable", declared_type,
|
||||
type_checked_initializer.type);
|
||||
return *this;
|
||||
case DeclarationKind::ChoiceDeclaration: {
|
||||
const auto& choice = d.GetChoiceDeclaration();
|
||||
VarValues alts;
|
||||
for (const auto& [name, signature] : choice.alternatives) {
|
||||
auto t = InterpExp(tops->values, signature);
|
||||
alts.push_back(std::make_pair(name, t));
|
||||
}
|
||||
auto ct = Value::MakeChoiceType(choice.name, std::move(alts));
|
||||
Address a = state->heap.AllocateValue(ct);
|
||||
tops->values.Set(choice.name, a); // Is this obsolete?
|
||||
tops->types.Set(choice.name, ct);
|
||||
break;
|
||||
}
|
||||
|
||||
case DeclarationKind::VariableDeclaration: {
|
||||
const auto& var = d.GetVariableDeclaration();
|
||||
// Associate the variable name with it's declared type in the
|
||||
// compile-time symbol table.
|
||||
const Value* declared_type = InterpExp(tops->values, var.type);
|
||||
tops->types.Set(var.name, declared_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto TopLevel(std::list<Declaration>* fs) -> TypeCheckContext {
|
||||
@@ -747,10 +802,10 @@ auto TopLevel(std::list<Declaration>* fs) -> TypeCheckContext {
|
||||
bool found_main = false;
|
||||
|
||||
for (auto const& d : *fs) {
|
||||
if (d.Name() == "main") {
|
||||
if (GetName(d) == "main") {
|
||||
found_main = true;
|
||||
}
|
||||
d.TopLevel(tops);
|
||||
TopLevel(d, &tops);
|
||||
}
|
||||
|
||||
if (found_main == false) {
|
||||
@@ -761,42 +816,4 @@ auto TopLevel(std::list<Declaration>* fs) -> TypeCheckContext {
|
||||
return tops;
|
||||
}
|
||||
|
||||
auto FunctionDeclaration::TopLevel(TypeCheckContext& tops) const -> void {
|
||||
auto t = TypeOfFunDef(tops.types, tops.values, &definition);
|
||||
tops.types.Set(Name(), t);
|
||||
InitGlobals(tops.values);
|
||||
}
|
||||
|
||||
auto StructDeclaration::TopLevel(TypeCheckContext& tops) const -> void {
|
||||
auto st = TypeOfStructDef(&definition, tops.types, tops.values);
|
||||
Address a = state->heap.AllocateValue(st);
|
||||
tops.values.Set(Name(), a); // Is this obsolete?
|
||||
std::vector<TupleElement> field_types;
|
||||
for (const auto& [field_name, field_value] : st->GetStructType().fields) {
|
||||
field_types.push_back({.name = field_name, .value = field_value});
|
||||
}
|
||||
auto fun_ty = Value::MakeFunctionType(
|
||||
Value::MakeTupleValue(std::move(field_types)), st);
|
||||
tops.types.Set(Name(), fun_ty);
|
||||
}
|
||||
|
||||
auto ChoiceDeclaration::TopLevel(TypeCheckContext& tops) const -> void {
|
||||
VarValues alts;
|
||||
for (const auto& [name, signature] : alternatives) {
|
||||
auto t = InterpExp(tops.values, signature);
|
||||
alts.push_back(std::make_pair(name, t));
|
||||
}
|
||||
auto ct = Value::MakeChoiceType(name, std::move(alts));
|
||||
Address a = state->heap.AllocateValue(ct);
|
||||
tops.values.Set(Name(), a); // Is this obsolete?
|
||||
tops.types.Set(Name(), ct);
|
||||
}
|
||||
|
||||
// Associate the variable name with it's declared type in the
|
||||
// compile-time symbol table.
|
||||
auto VariableDeclaration::TopLevel(TypeCheckContext& tops) const -> void {
|
||||
const Value* declared_type = InterpExp(tops.values, type);
|
||||
tops.types.Set(Name(), declared_type);
|
||||
}
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
@@ -45,6 +45,8 @@ auto TypeCheckStmt(const Statement*, TypeEnv, Env, Value const*&)
|
||||
auto TypeCheckFunDef(struct FunctionDefinition*, TypeEnv)
|
||||
-> struct FunctionDefinition*;
|
||||
|
||||
auto MakeTypeChecked(const Declaration& decl, const TypeEnv& types,
|
||||
const Env& values) -> Declaration;
|
||||
auto TopLevel(std::list<Declaration>* fs) -> TypeCheckContext;
|
||||
|
||||
void PrintErrorString(const std::string& s);
|
||||
|
||||
@@ -106,7 +106,7 @@ void yy::parser::error(
|
||||
%type <const Carbon::Expression*> tuple
|
||||
%type <Carbon::Member*> variable_declaration
|
||||
%type <Carbon::Member*> member
|
||||
%type <std::list<Carbon::Member*>*> member_list
|
||||
%type <std::list<Carbon::Member*>> member_list
|
||||
%type <Carbon::FieldInitializer> field_initializer
|
||||
%type <Carbon::ParenContents> paren_contents
|
||||
%type <std::vector<Carbon::FieldInitializer>> paren_contents_without_trailing_comma
|
||||
@@ -391,9 +391,9 @@ member: VAR variable_declaration ";"
|
||||
;
|
||||
member_list:
|
||||
// Empty
|
||||
{ $$ = new std::list<Carbon::Member*>(); }
|
||||
{ $$ = std::list<Carbon::Member*>(); }
|
||||
| member member_list
|
||||
{ $$ = $2; $$->push_front($1); }
|
||||
{ $$ = $2; $$.push_front($1); }
|
||||
;
|
||||
alternative:
|
||||
identifier tuple
|
||||
@@ -417,24 +417,21 @@ alternative_list:
|
||||
;
|
||||
declaration:
|
||||
function_definition
|
||||
{ $$ = Carbon::Declaration(Carbon::FunctionDeclaration{$1}); }
|
||||
{ $$ = Carbon::Declaration::MakeFunctionDeclaration(std::move($1)); }
|
||||
| function_declaration
|
||||
{ $$ = Carbon::Declaration(Carbon::FunctionDeclaration{$1}); }
|
||||
{ $$ = Carbon::Declaration::MakeFunctionDeclaration(std::move($1)); }
|
||||
| STRUCT identifier "{" member_list "}"
|
||||
{
|
||||
$$ = Carbon::Declaration(
|
||||
Carbon::StructDeclaration{yylineno, $2, $4});
|
||||
$$ = Carbon::Declaration::MakeStructDeclaration(yylineno, $2, $4);
|
||||
}
|
||||
| CHOICE identifier "{" alternative_list "}"
|
||||
{
|
||||
$$ = Carbon::Declaration(
|
||||
Carbon::ChoiceDeclaration{yylineno, $2, $4});
|
||||
$$ = Carbon::Declaration::MakeChoiceDeclaration(yylineno, $2, $4);
|
||||
}
|
||||
| VAR variable_declaration "=" expression ";"
|
||||
{
|
||||
$$ = Carbon::Declaration(
|
||||
Carbon::VariableDeclaration(yylineno, $2->GetFieldMember().name,
|
||||
$2->GetFieldMember().type, $4));
|
||||
$$ = Carbon::Declaration::MakeVariableDeclaration(
|
||||
yylineno, $2->GetFieldMember().name, $2->GetFieldMember().type, $4);
|
||||
}
|
||||
;
|
||||
declaration_list:
|
||||
|
||||
@@ -26,7 +26,7 @@ void ExecProgram(std::list<Declaration>* fs) {
|
||||
Env ct_top = p.values;
|
||||
std::list<Declaration> new_decls;
|
||||
for (const auto& decl : *fs) {
|
||||
new_decls.push_back(decl.TypeChecked(top, ct_top));
|
||||
new_decls.push_back(MakeTypeChecked(decl, top, ct_top));
|
||||
}
|
||||
if (tracing_output) {
|
||||
std::cout << std::endl;
|
||||
|
||||
Reference in New Issue
Block a user