mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Make the AST mutable (#849)
The code is pretty intertwined: having the AST be truly mutable means (to me) changing parser.ypp to return non-const values, but then the way things are passed around between objects should be non-const (particularly an issue with lists), which then creates issues with construction of lists in the TypeChecker, which then TypeChecker needs to mostly be non-const. Due to the difficulties in breaking this apart, whereas I'd previously considering refactoring accessor naming in the same PR, I've largely avoided doing so. The intent is then that this PR focuses mainly on const -> non-const AST behavior. call_main moves out of interpreter.cpp so that interpreter.cpp can receive a fully const AST.
This commit is contained in:
@@ -22,7 +22,7 @@ struct AST {
|
||||
// Import directives.
|
||||
std::vector<LibraryName> imports;
|
||||
// The file's ordered declarations.
|
||||
std::vector<Nonnull<const Declaration*>> declarations;
|
||||
std::vector<Nonnull<Declaration*>> declarations;
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "executable_semantics/ast/pattern.h"
|
||||
#include "executable_semantics/ast/source_location.h"
|
||||
#include "executable_semantics/common/nonnull.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace Carbon {
|
||||
@@ -60,7 +61,7 @@ class Declaration {
|
||||
|
||||
class FunctionDeclaration : public Declaration {
|
||||
public:
|
||||
FunctionDeclaration(Nonnull<const FunctionDefinition*> definition)
|
||||
FunctionDeclaration(Nonnull<FunctionDefinition*> definition)
|
||||
: Declaration(Kind::FunctionDeclaration, definition->source_loc()),
|
||||
definition(definition) {}
|
||||
|
||||
@@ -69,9 +70,10 @@ class FunctionDeclaration : public Declaration {
|
||||
}
|
||||
|
||||
auto Definition() const -> const FunctionDefinition& { return *definition; }
|
||||
auto Definition() -> FunctionDefinition& { return *definition; }
|
||||
|
||||
private:
|
||||
Nonnull<const FunctionDefinition*> definition;
|
||||
Nonnull<FunctionDefinition*> definition;
|
||||
};
|
||||
|
||||
class ClassDeclaration : public Declaration {
|
||||
@@ -88,6 +90,7 @@ class ClassDeclaration : public Declaration {
|
||||
}
|
||||
|
||||
auto Definition() const -> const ClassDefinition& { return definition; }
|
||||
auto Definition() -> ClassDefinition& { return definition; }
|
||||
|
||||
private:
|
||||
ClassDefinition definition;
|
||||
@@ -97,7 +100,7 @@ class ChoiceDeclaration : public Declaration {
|
||||
public:
|
||||
class Alternative {
|
||||
public:
|
||||
Alternative(std::string name, Nonnull<const Expression*> signature)
|
||||
Alternative(std::string name, Nonnull<Expression*> signature)
|
||||
: name_(name), signature_(signature) {}
|
||||
|
||||
auto name() const -> const std::string& { return name_; }
|
||||
@@ -105,7 +108,7 @@ class ChoiceDeclaration : public Declaration {
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
Nonnull<const Expression*> signature_;
|
||||
Nonnull<Expression*> signature_;
|
||||
};
|
||||
|
||||
ChoiceDeclaration(SourceLocation loc, std::string name,
|
||||
@@ -131,9 +134,8 @@ class ChoiceDeclaration : public Declaration {
|
||||
// Global variable definition implements the Declaration concept.
|
||||
class VariableDeclaration : public Declaration {
|
||||
public:
|
||||
VariableDeclaration(SourceLocation loc,
|
||||
Nonnull<const BindingPattern*> binding,
|
||||
Nonnull<const Expression*> initializer)
|
||||
VariableDeclaration(SourceLocation loc, Nonnull<BindingPattern*> binding,
|
||||
Nonnull<Expression*> initializer)
|
||||
: Declaration(Kind::VariableDeclaration, loc),
|
||||
binding(binding),
|
||||
initializer(initializer) {}
|
||||
@@ -143,14 +145,16 @@ class VariableDeclaration : public Declaration {
|
||||
}
|
||||
|
||||
auto Binding() const -> Nonnull<const BindingPattern*> { return binding; }
|
||||
auto Binding() -> Nonnull<BindingPattern*> { return binding; }
|
||||
auto Initializer() const -> Nonnull<const Expression*> { return initializer; }
|
||||
auto Initializer() -> Nonnull<Expression*> { return initializer; }
|
||||
|
||||
private:
|
||||
// TODO: split this into a non-optional name and a type, initialized by
|
||||
// a constructor that takes a BindingPattern and handles errors like a
|
||||
// missing name.
|
||||
Nonnull<const BindingPattern*> binding;
|
||||
Nonnull<const Expression*> initializer;
|
||||
Nonnull<BindingPattern*> binding;
|
||||
Nonnull<Expression*> initializer;
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
@@ -18,10 +18,8 @@ using llvm::cast;
|
||||
|
||||
auto ExpressionFromParenContents(
|
||||
Nonnull<Arena*> arena, SourceLocation loc,
|
||||
const ParenContents<Expression>& paren_contents)
|
||||
-> Nonnull<const Expression*> {
|
||||
std::optional<Nonnull<const Expression*>> single_term =
|
||||
paren_contents.SingleTerm();
|
||||
const ParenContents<Expression>& paren_contents) -> Nonnull<Expression*> {
|
||||
std::optional<Nonnull<Expression*>> single_term = paren_contents.SingleTerm();
|
||||
if (single_term.has_value()) {
|
||||
return *single_term;
|
||||
} else {
|
||||
@@ -31,8 +29,7 @@ auto ExpressionFromParenContents(
|
||||
|
||||
auto TupleExpressionFromParenContents(
|
||||
Nonnull<Arena*> arena, SourceLocation loc,
|
||||
const ParenContents<Expression>& paren_contents)
|
||||
-> Nonnull<const Expression*> {
|
||||
const ParenContents<Expression>& paren_contents) -> Nonnull<Expression*> {
|
||||
return arena->New<TupleLiteral>(
|
||||
loc, paren_contents.TupleElements<FieldInitializer>(loc));
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "executable_semantics/ast/paren_contents.h"
|
||||
#include "executable_semantics/ast/source_location.h"
|
||||
#include "executable_semantics/common/arena.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace Carbon {
|
||||
@@ -64,26 +65,24 @@ class Expression {
|
||||
// tuple otherwise.
|
||||
auto ExpressionFromParenContents(
|
||||
Nonnull<Arena*> arena, SourceLocation loc,
|
||||
const ParenContents<Expression>& paren_contents)
|
||||
-> Nonnull<const Expression*>;
|
||||
const ParenContents<Expression>& paren_contents) -> Nonnull<Expression*>;
|
||||
|
||||
// Converts paren_contents to an Expression, interpreting the parentheses as
|
||||
// forming a tuple.
|
||||
auto TupleExpressionFromParenContents(
|
||||
Nonnull<Arena*> arena, SourceLocation loc,
|
||||
const ParenContents<Expression>& paren_contents)
|
||||
-> Nonnull<const Expression*>;
|
||||
const ParenContents<Expression>& paren_contents) -> Nonnull<Expression*>;
|
||||
|
||||
// A FieldInitializer represents the initialization of a single tuple field.
|
||||
struct FieldInitializer {
|
||||
FieldInitializer(std::string name, Nonnull<const Expression*> expression)
|
||||
FieldInitializer(std::string name, Nonnull<Expression*> expression)
|
||||
: name(std::move(name)), expression(expression) {}
|
||||
|
||||
// The field name. Cannot be empty.
|
||||
std::string name;
|
||||
|
||||
// The expression that initializes the field.
|
||||
Nonnull<const Expression*> expression;
|
||||
Nonnull<Expression*> expression;
|
||||
};
|
||||
|
||||
enum class Operator {
|
||||
@@ -117,7 +116,7 @@ class IdentifierExpression : public Expression {
|
||||
class FieldAccessExpression : public Expression {
|
||||
public:
|
||||
explicit FieldAccessExpression(SourceLocation loc,
|
||||
Nonnull<const Expression*> aggregate,
|
||||
Nonnull<Expression*> aggregate,
|
||||
std::string field)
|
||||
: Expression(Kind::FieldAccessExpression, loc),
|
||||
aggregate(aggregate),
|
||||
@@ -128,18 +127,18 @@ class FieldAccessExpression : public Expression {
|
||||
}
|
||||
|
||||
auto Aggregate() const -> Nonnull<const Expression*> { return aggregate; }
|
||||
auto Aggregate() -> Nonnull<Expression*> { return aggregate; }
|
||||
auto Field() const -> const std::string& { return field; }
|
||||
|
||||
private:
|
||||
Nonnull<const Expression*> aggregate;
|
||||
Nonnull<Expression*> aggregate;
|
||||
std::string field;
|
||||
};
|
||||
|
||||
class IndexExpression : public Expression {
|
||||
public:
|
||||
explicit IndexExpression(SourceLocation loc,
|
||||
Nonnull<const Expression*> aggregate,
|
||||
Nonnull<const Expression*> offset)
|
||||
explicit IndexExpression(SourceLocation loc, Nonnull<Expression*> aggregate,
|
||||
Nonnull<Expression*> offset)
|
||||
: Expression(Kind::IndexExpression, loc),
|
||||
aggregate(aggregate),
|
||||
offset(offset) {}
|
||||
@@ -149,11 +148,13 @@ class IndexExpression : public Expression {
|
||||
}
|
||||
|
||||
auto Aggregate() const -> Nonnull<const Expression*> { return aggregate; }
|
||||
auto Aggregate() -> Nonnull<Expression*> { return aggregate; }
|
||||
auto Offset() const -> Nonnull<const Expression*> { return offset; }
|
||||
auto Offset() -> Nonnull<Expression*> { return offset; }
|
||||
|
||||
private:
|
||||
Nonnull<const Expression*> aggregate;
|
||||
Nonnull<const Expression*> offset;
|
||||
Nonnull<Expression*> aggregate;
|
||||
Nonnull<Expression*> offset;
|
||||
};
|
||||
|
||||
class IntLiteral : public Expression {
|
||||
@@ -233,7 +234,7 @@ class PrimitiveOperatorExpression : public Expression {
|
||||
public:
|
||||
explicit PrimitiveOperatorExpression(
|
||||
SourceLocation loc, Operator op,
|
||||
std::vector<Nonnull<const Expression*>> arguments)
|
||||
std::vector<Nonnull<Expression*>> arguments)
|
||||
: Expression(Kind::PrimitiveOperatorExpression, loc),
|
||||
op(op),
|
||||
arguments(std::move(arguments)) {}
|
||||
@@ -243,20 +244,22 @@ class PrimitiveOperatorExpression : public Expression {
|
||||
}
|
||||
|
||||
auto Op() const -> Operator { return op; }
|
||||
auto Arguments() const -> const std::vector<Nonnull<const Expression*>>& {
|
||||
auto Arguments() const -> llvm::ArrayRef<Nonnull<Expression*>> {
|
||||
return arguments;
|
||||
}
|
||||
auto Arguments() -> llvm::MutableArrayRef<Nonnull<Expression*>> {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
private:
|
||||
Operator op;
|
||||
std::vector<Nonnull<const Expression*>> arguments;
|
||||
std::vector<Nonnull<Expression*>> arguments;
|
||||
};
|
||||
|
||||
class CallExpression : public Expression {
|
||||
public:
|
||||
explicit CallExpression(SourceLocation loc,
|
||||
Nonnull<const Expression*> function,
|
||||
Nonnull<const Expression*> argument)
|
||||
explicit CallExpression(SourceLocation loc, Nonnull<Expression*> function,
|
||||
Nonnull<Expression*> argument)
|
||||
: Expression(Kind::CallExpression, loc),
|
||||
function(function),
|
||||
argument(argument) {}
|
||||
@@ -266,18 +269,20 @@ class CallExpression : public Expression {
|
||||
}
|
||||
|
||||
auto Function() const -> Nonnull<const Expression*> { return function; }
|
||||
auto Function() -> Nonnull<Expression*> { return function; }
|
||||
auto Argument() const -> Nonnull<const Expression*> { return argument; }
|
||||
auto Argument() -> Nonnull<Expression*> { return argument; }
|
||||
|
||||
private:
|
||||
Nonnull<const Expression*> function;
|
||||
Nonnull<const Expression*> argument;
|
||||
Nonnull<Expression*> function;
|
||||
Nonnull<Expression*> argument;
|
||||
};
|
||||
|
||||
class FunctionTypeLiteral : public Expression {
|
||||
public:
|
||||
explicit FunctionTypeLiteral(SourceLocation loc,
|
||||
Nonnull<const Expression*> parameter,
|
||||
Nonnull<const Expression*> return_type,
|
||||
Nonnull<Expression*> parameter,
|
||||
Nonnull<Expression*> return_type,
|
||||
bool is_omitted_return_type)
|
||||
: Expression(Kind::FunctionTypeLiteral, loc),
|
||||
parameter(parameter),
|
||||
@@ -289,12 +294,14 @@ class FunctionTypeLiteral : public Expression {
|
||||
}
|
||||
|
||||
auto Parameter() const -> Nonnull<const Expression*> { return parameter; }
|
||||
auto Parameter() -> Nonnull<Expression*> { return parameter; }
|
||||
auto ReturnType() const -> Nonnull<const Expression*> { return return_type; }
|
||||
auto ReturnType() -> Nonnull<Expression*> { return return_type; }
|
||||
auto IsOmittedReturnType() const -> bool { return is_omitted_return_type; }
|
||||
|
||||
private:
|
||||
Nonnull<const Expression*> parameter;
|
||||
Nonnull<const Expression*> return_type;
|
||||
Nonnull<Expression*> parameter;
|
||||
Nonnull<Expression*> return_type;
|
||||
bool is_omitted_return_type;
|
||||
};
|
||||
|
||||
|
||||
@@ -26,13 +26,12 @@ class FunctionDefinition {
|
||||
public:
|
||||
FunctionDefinition(SourceLocation source_loc, std::string name,
|
||||
std::vector<GenericBinding> deduced_params,
|
||||
Nonnull<const TuplePattern*> param_pattern,
|
||||
Nonnull<const Pattern*> return_type,
|
||||
bool is_omitted_return_type,
|
||||
std::optional<Nonnull<const Statement*>> body)
|
||||
Nonnull<TuplePattern*> param_pattern,
|
||||
Nonnull<Pattern*> return_type, bool is_omitted_return_type,
|
||||
std::optional<Nonnull<Statement*>> body)
|
||||
: source_loc_(source_loc),
|
||||
name_(std::move(name)),
|
||||
deduced_parameters_(deduced_params),
|
||||
deduced_parameters_(std::move(deduced_params)),
|
||||
param_pattern_(param_pattern),
|
||||
return_type_(return_type),
|
||||
is_omitted_return_type_(is_omitted_return_type),
|
||||
@@ -48,6 +47,7 @@ class FunctionDefinition {
|
||||
return deduced_parameters_;
|
||||
}
|
||||
auto param_pattern() const -> const TuplePattern& { return *param_pattern_; }
|
||||
auto param_pattern() -> TuplePattern& { return *param_pattern_; }
|
||||
auto return_type() const -> const Pattern& { return *return_type_; }
|
||||
auto is_omitted_return_type() const -> bool {
|
||||
return is_omitted_return_type_;
|
||||
@@ -55,15 +55,16 @@ class FunctionDefinition {
|
||||
auto body() const -> std::optional<Nonnull<const Statement*>> {
|
||||
return body_;
|
||||
}
|
||||
auto body() -> std::optional<Nonnull<Statement*>> { return body_; }
|
||||
|
||||
private:
|
||||
SourceLocation source_loc_;
|
||||
std::string name_;
|
||||
std::vector<GenericBinding> deduced_parameters_;
|
||||
Nonnull<const TuplePattern*> param_pattern_;
|
||||
Nonnull<const Pattern*> return_type_;
|
||||
Nonnull<TuplePattern*> param_pattern_;
|
||||
Nonnull<Pattern*> return_type_;
|
||||
bool is_omitted_return_type_;
|
||||
std::optional<Nonnull<const Statement*>> body_;
|
||||
std::optional<Nonnull<Statement*>> body_;
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
@@ -28,16 +28,16 @@ template <typename Term>
|
||||
struct ParenContents {
|
||||
struct Element {
|
||||
std::optional<std::string> name;
|
||||
Nonnull<const Term*> term;
|
||||
Nonnull<Term*> term;
|
||||
};
|
||||
|
||||
// If this object represents a single term, with no name and no trailing
|
||||
// comma, this method returns that term. This typically means the parentheses
|
||||
// can be interpreted as grouping.
|
||||
auto SingleTerm() const -> std::optional<Nonnull<const Term*>>;
|
||||
auto SingleTerm() const -> std::optional<Nonnull<Term*>>;
|
||||
|
||||
// Converts `elements` to std::vector<TupleElement>. TupleElement must
|
||||
// have a constructor that takes a std::string and a Nonnull<const Term*>.
|
||||
// have a constructor that takes a std::string and a Nonnull<Term*>.
|
||||
//
|
||||
// TODO: Find a way to deduce TupleElement from Term.
|
||||
template <typename TupleElement>
|
||||
@@ -50,8 +50,7 @@ struct ParenContents {
|
||||
// Implementation details only below here.
|
||||
|
||||
template <typename Term>
|
||||
auto ParenContents<Term>::SingleTerm() const
|
||||
-> std::optional<Nonnull<const Term*>> {
|
||||
auto ParenContents<Term>::SingleTerm() const -> std::optional<Nonnull<Term*>> {
|
||||
if (elements.size() == 1 && !elements.front().name.has_value() &&
|
||||
!has_trailing_comma) {
|
||||
return elements.front().term;
|
||||
|
||||
@@ -55,7 +55,7 @@ void Pattern::Print(llvm::raw_ostream& out) const {
|
||||
}
|
||||
|
||||
TuplePattern::TuplePattern(Nonnull<Arena*> arena,
|
||||
Nonnull<const Expression*> tuple_literal)
|
||||
Nonnull<Expression*> tuple_literal)
|
||||
: Pattern(Kind::TuplePattern, tuple_literal->SourceLoc()) {
|
||||
const auto& tuple = cast<TupleLiteral>(*tuple_literal);
|
||||
for (const FieldInitializer& init : tuple.Fields()) {
|
||||
@@ -66,9 +66,8 @@ TuplePattern::TuplePattern(Nonnull<Arena*> arena,
|
||||
|
||||
auto PatternFromParenContents(Nonnull<Arena*> arena, SourceLocation loc,
|
||||
const ParenContents<Pattern>& paren_contents)
|
||||
-> Nonnull<const Pattern*> {
|
||||
std::optional<Nonnull<const Pattern*>> single_term =
|
||||
paren_contents.SingleTerm();
|
||||
-> Nonnull<Pattern*> {
|
||||
std::optional<Nonnull<Pattern*>> single_term = paren_contents.SingleTerm();
|
||||
if (single_term.has_value()) {
|
||||
return *single_term;
|
||||
} else {
|
||||
@@ -78,7 +77,7 @@ auto PatternFromParenContents(Nonnull<Arena*> arena, SourceLocation loc,
|
||||
|
||||
auto TuplePatternFromParenContents(Nonnull<Arena*> arena, SourceLocation loc,
|
||||
const ParenContents<Pattern>& paren_contents)
|
||||
-> Nonnull<const TuplePattern*> {
|
||||
-> Nonnull<TuplePattern*> {
|
||||
return arena->New<TuplePattern>(
|
||||
loc, paren_contents.TupleElements<TuplePattern::Field>(loc));
|
||||
}
|
||||
@@ -86,8 +85,8 @@ auto TuplePatternFromParenContents(Nonnull<Arena*> arena, SourceLocation loc,
|
||||
// Used by AlternativePattern for constructor initialization. Produces a helpful
|
||||
// error for incorrect expressions, rather than letting a default cast error
|
||||
// apply.
|
||||
static const FieldAccessExpression& RequireFieldAccess(
|
||||
Nonnull<const Expression*> alternative) {
|
||||
static auto RequireFieldAccess(Nonnull<Expression*> alternative)
|
||||
-> FieldAccessExpression& {
|
||||
if (alternative->Tag() != Expression::Kind::FieldAccessExpression) {
|
||||
FATAL_PROGRAM_ERROR(alternative->SourceLoc())
|
||||
<< "Alternative pattern must have the form of a field access.";
|
||||
@@ -96,8 +95,8 @@ static const FieldAccessExpression& RequireFieldAccess(
|
||||
}
|
||||
|
||||
AlternativePattern::AlternativePattern(SourceLocation loc,
|
||||
Nonnull<const Expression*> alternative,
|
||||
Nonnull<const TuplePattern*> arguments)
|
||||
Nonnull<Expression*> alternative,
|
||||
Nonnull<TuplePattern*> arguments)
|
||||
: Pattern(Kind::AlternativePattern, loc),
|
||||
choice_type(RequireFieldAccess(alternative).Aggregate()),
|
||||
alternative_name(RequireFieldAccess(alternative).Field()),
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "common/ostream.h"
|
||||
#include "executable_semantics/ast/expression.h"
|
||||
#include "executable_semantics/ast/source_location.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
@@ -71,7 +72,7 @@ class AutoPattern : public Pattern {
|
||||
class BindingPattern : public Pattern {
|
||||
public:
|
||||
BindingPattern(SourceLocation loc, std::optional<std::string> name,
|
||||
Nonnull<const Pattern*> type)
|
||||
Nonnull<Pattern*> type)
|
||||
: Pattern(Kind::BindingPattern, loc), name(std::move(name)), type(type) {}
|
||||
|
||||
static auto classof(const Pattern* pattern) -> bool {
|
||||
@@ -83,10 +84,11 @@ class BindingPattern : public Pattern {
|
||||
|
||||
// The pattern specifying the type of values that this pattern matches.
|
||||
auto Type() const -> Nonnull<const Pattern*> { return type; }
|
||||
auto Type() -> Nonnull<Pattern*> { return type; }
|
||||
|
||||
private:
|
||||
std::optional<std::string> name;
|
||||
Nonnull<const Pattern*> type;
|
||||
Nonnull<Pattern*> type;
|
||||
};
|
||||
|
||||
// A pattern that matches a tuple value field-wise.
|
||||
@@ -94,14 +96,14 @@ class TuplePattern : public Pattern {
|
||||
public:
|
||||
// Represents a portion of a tuple pattern corresponding to a single field.
|
||||
struct Field {
|
||||
Field(std::string name, Nonnull<const Pattern*> pattern)
|
||||
Field(std::string name, Nonnull<Pattern*> pattern)
|
||||
: name(std::move(name)), pattern(pattern) {}
|
||||
|
||||
// The field name. Cannot be empty
|
||||
std::string name;
|
||||
|
||||
// The pattern the field must match.
|
||||
Nonnull<const Pattern*> pattern;
|
||||
Nonnull<Pattern*> pattern;
|
||||
};
|
||||
|
||||
TuplePattern(SourceLocation loc, std::vector<Field> fields)
|
||||
@@ -111,13 +113,14 @@ class TuplePattern : public Pattern {
|
||||
// ExpressionPattern.
|
||||
//
|
||||
// REQUIRES: tuple_literal->Tag() == Expression::Kind::TupleLiteral
|
||||
TuplePattern(Nonnull<Arena*> arena, Nonnull<const Expression*> tuple_literal);
|
||||
TuplePattern(Nonnull<Arena*> arena, Nonnull<Expression*> tuple_literal);
|
||||
|
||||
static auto classof(const Pattern* pattern) -> bool {
|
||||
return pattern->Tag() == Kind::TuplePattern;
|
||||
}
|
||||
|
||||
auto Fields() const -> const std::vector<Field>& { return fields; }
|
||||
auto Fields() const -> llvm::ArrayRef<Field> { return fields; }
|
||||
auto Fields() -> llvm::MutableArrayRef<Field> { return fields; }
|
||||
|
||||
private:
|
||||
std::vector<Field> fields;
|
||||
@@ -128,13 +131,13 @@ class TuplePattern : public Pattern {
|
||||
// tuple otherwise.
|
||||
auto PatternFromParenContents(Nonnull<Arena*> arena, SourceLocation loc,
|
||||
const ParenContents<Pattern>& paren_contents)
|
||||
-> Nonnull<const Pattern*>;
|
||||
-> Nonnull<Pattern*>;
|
||||
|
||||
// Converts paren_contents to a TuplePattern, interpreting the parentheses as
|
||||
// forming a tuple.
|
||||
auto TuplePatternFromParenContents(Nonnull<Arena*> arena, SourceLocation loc,
|
||||
const ParenContents<Pattern>& paren_contents)
|
||||
-> Nonnull<const TuplePattern*>;
|
||||
-> Nonnull<TuplePattern*>;
|
||||
|
||||
// Converts `contents` to ParenContents<Pattern> by replacing each Expression
|
||||
// with an ExpressionPattern.
|
||||
@@ -148,9 +151,9 @@ class AlternativePattern : public Pattern {
|
||||
// Constructs an AlternativePattern that matches a value of the type
|
||||
// specified by choice_type if it represents an alternative named
|
||||
// alternative_name, and its arguments match `arguments`.
|
||||
AlternativePattern(SourceLocation loc, Nonnull<const Expression*> choice_type,
|
||||
AlternativePattern(SourceLocation loc, Nonnull<Expression*> choice_type,
|
||||
std::string alternative_name,
|
||||
Nonnull<const TuplePattern*> arguments)
|
||||
Nonnull<TuplePattern*> arguments)
|
||||
: Pattern(Kind::AlternativePattern, loc),
|
||||
choice_type(choice_type),
|
||||
alternative_name(std::move(alternative_name)),
|
||||
@@ -158,30 +161,32 @@ class AlternativePattern : public Pattern {
|
||||
|
||||
// Constructs an AlternativePattern that matches the alternative specified
|
||||
// by `alternative`, if its arguments match `arguments`.
|
||||
AlternativePattern(SourceLocation loc, Nonnull<const Expression*> alternative,
|
||||
Nonnull<const TuplePattern*> arguments);
|
||||
AlternativePattern(SourceLocation loc, Nonnull<Expression*> alternative,
|
||||
Nonnull<TuplePattern*> arguments);
|
||||
|
||||
static auto classof(const Pattern* pattern) -> bool {
|
||||
return pattern->Tag() == Kind::AlternativePattern;
|
||||
}
|
||||
|
||||
auto ChoiceType() const -> Nonnull<const Expression*> { return choice_type; }
|
||||
auto ChoiceType() -> Nonnull<Expression*> { return choice_type; }
|
||||
auto AlternativeName() const -> const std::string& {
|
||||
return alternative_name;
|
||||
}
|
||||
auto Arguments() const -> Nonnull<const TuplePattern*> { return arguments; }
|
||||
auto Arguments() -> Nonnull<TuplePattern*> { return arguments; }
|
||||
|
||||
private:
|
||||
Nonnull<const Expression*> choice_type;
|
||||
Nonnull<Expression*> choice_type;
|
||||
std::string alternative_name;
|
||||
Nonnull<const TuplePattern*> arguments;
|
||||
Nonnull<TuplePattern*> arguments;
|
||||
};
|
||||
|
||||
// A pattern that matches a value if it is equal to the value of a given
|
||||
// expression.
|
||||
class ExpressionPattern : public Pattern {
|
||||
public:
|
||||
ExpressionPattern(Nonnull<const Expression*> expression)
|
||||
ExpressionPattern(Nonnull<Expression*> expression)
|
||||
: Pattern(Kind::ExpressionPattern, expression->SourceLoc()),
|
||||
expression(expression) {}
|
||||
|
||||
@@ -190,9 +195,10 @@ class ExpressionPattern : public Pattern {
|
||||
}
|
||||
|
||||
auto Expression() const -> Nonnull<const Expression*> { return expression; }
|
||||
auto Expression() -> Nonnull<Carbon::Expression*> { return expression; }
|
||||
|
||||
private:
|
||||
Nonnull<const Carbon::Expression*> expression;
|
||||
Nonnull<Carbon::Expression*> expression;
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "executable_semantics/ast/pattern.h"
|
||||
#include "executable_semantics/ast/source_location.h"
|
||||
#include "executable_semantics/common/arena.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace Carbon {
|
||||
@@ -58,7 +59,7 @@ class Statement {
|
||||
|
||||
class ExpressionStatement : public Statement {
|
||||
public:
|
||||
ExpressionStatement(SourceLocation loc, Nonnull<const Expression*> exp)
|
||||
ExpressionStatement(SourceLocation loc, Nonnull<Expression*> exp)
|
||||
: Statement(Kind::ExpressionStatement, loc), exp(exp) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
@@ -66,15 +67,15 @@ class ExpressionStatement : public Statement {
|
||||
}
|
||||
|
||||
auto Exp() const -> Nonnull<const Expression*> { return exp; }
|
||||
auto Exp() -> Nonnull<Expression*> { return exp; }
|
||||
|
||||
private:
|
||||
Nonnull<const Expression*> exp;
|
||||
Nonnull<Expression*> exp;
|
||||
};
|
||||
|
||||
class Assign : public Statement {
|
||||
public:
|
||||
Assign(SourceLocation loc, Nonnull<const Expression*> lhs,
|
||||
Nonnull<const Expression*> rhs)
|
||||
Assign(SourceLocation loc, Nonnull<Expression*> lhs, Nonnull<Expression*> rhs)
|
||||
: Statement(Kind::Assign, loc), lhs(lhs), rhs(rhs) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
@@ -82,17 +83,19 @@ class Assign : public Statement {
|
||||
}
|
||||
|
||||
auto Lhs() const -> Nonnull<const Expression*> { return lhs; }
|
||||
auto Lhs() -> Nonnull<Expression*> { return lhs; }
|
||||
auto Rhs() const -> Nonnull<const Expression*> { return rhs; }
|
||||
auto Rhs() -> Nonnull<Expression*> { return rhs; }
|
||||
|
||||
private:
|
||||
Nonnull<const Expression*> lhs;
|
||||
Nonnull<const Expression*> rhs;
|
||||
Nonnull<Expression*> lhs;
|
||||
Nonnull<Expression*> rhs;
|
||||
};
|
||||
|
||||
class VariableDefinition : public Statement {
|
||||
public:
|
||||
VariableDefinition(SourceLocation loc, Nonnull<const Pattern*> pat,
|
||||
Nonnull<const Expression*> init)
|
||||
VariableDefinition(SourceLocation loc, Nonnull<Pattern*> pat,
|
||||
Nonnull<Expression*> init)
|
||||
: Statement(Kind::VariableDefinition, loc), pat(pat), init(init) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
@@ -100,18 +103,20 @@ class VariableDefinition : public Statement {
|
||||
}
|
||||
|
||||
auto Pat() const -> Nonnull<const Pattern*> { return pat; }
|
||||
auto Pat() -> Nonnull<Pattern*> { return pat; }
|
||||
auto Init() const -> Nonnull<const Expression*> { return init; }
|
||||
auto Init() -> Nonnull<Expression*> { return init; }
|
||||
|
||||
private:
|
||||
Nonnull<const Pattern*> pat;
|
||||
Nonnull<const Expression*> init;
|
||||
Nonnull<Pattern*> pat;
|
||||
Nonnull<Expression*> init;
|
||||
};
|
||||
|
||||
class If : public Statement {
|
||||
public:
|
||||
If(SourceLocation loc, Nonnull<const Expression*> cond,
|
||||
Nonnull<const Statement*> then_stmt,
|
||||
std::optional<Nonnull<const Statement*>> else_stmt)
|
||||
If(SourceLocation loc, Nonnull<Expression*> cond,
|
||||
Nonnull<Statement*> then_stmt,
|
||||
std::optional<Nonnull<Statement*>> else_stmt)
|
||||
: Statement(Kind::If, loc),
|
||||
cond(cond),
|
||||
then_stmt(then_stmt),
|
||||
@@ -122,23 +127,25 @@ class If : public Statement {
|
||||
}
|
||||
|
||||
auto Cond() const -> Nonnull<const Expression*> { return cond; }
|
||||
auto Cond() -> Nonnull<Expression*> { return cond; }
|
||||
auto ThenStmt() const -> Nonnull<const Statement*> { return then_stmt; }
|
||||
auto ThenStmt() -> Nonnull<Statement*> { return then_stmt; }
|
||||
auto ElseStmt() const -> std::optional<Nonnull<const Statement*>> {
|
||||
return else_stmt;
|
||||
}
|
||||
auto ElseStmt() -> std::optional<Nonnull<Statement*>> { return else_stmt; }
|
||||
|
||||
private:
|
||||
Nonnull<const Expression*> cond;
|
||||
Nonnull<const Statement*> then_stmt;
|
||||
std::optional<Nonnull<const Statement*>> else_stmt;
|
||||
Nonnull<Expression*> cond;
|
||||
Nonnull<Statement*> then_stmt;
|
||||
std::optional<Nonnull<Statement*>> else_stmt;
|
||||
};
|
||||
|
||||
class Return : public Statement {
|
||||
public:
|
||||
Return(Nonnull<Arena*> arena, SourceLocation loc)
|
||||
: Return(loc, arena->New<TupleLiteral>(loc), true) {}
|
||||
Return(SourceLocation loc, Nonnull<const Expression*> exp,
|
||||
bool is_omitted_exp)
|
||||
Return(SourceLocation loc, Nonnull<Expression*> exp, bool is_omitted_exp)
|
||||
: Statement(Kind::Return, loc),
|
||||
exp(exp),
|
||||
is_omitted_exp(is_omitted_exp) {}
|
||||
@@ -148,17 +155,18 @@ class Return : public Statement {
|
||||
}
|
||||
|
||||
auto Exp() const -> Nonnull<const Expression*> { return exp; }
|
||||
auto Exp() -> Nonnull<Expression*> { return exp; }
|
||||
auto IsOmittedExp() const -> bool { return is_omitted_exp; }
|
||||
|
||||
private:
|
||||
Nonnull<const Expression*> exp;
|
||||
Nonnull<Expression*> exp;
|
||||
bool is_omitted_exp;
|
||||
};
|
||||
|
||||
class Sequence : public Statement {
|
||||
public:
|
||||
Sequence(SourceLocation loc, Nonnull<const Statement*> stmt,
|
||||
std::optional<Nonnull<const Statement*>> next)
|
||||
Sequence(SourceLocation loc, Nonnull<Statement*> stmt,
|
||||
std::optional<Nonnull<Statement*>> next)
|
||||
: Statement(Kind::Sequence, loc), stmt(stmt), next(next) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
@@ -166,16 +174,18 @@ class Sequence : public Statement {
|
||||
}
|
||||
|
||||
auto Stmt() const -> Nonnull<const Statement*> { return stmt; }
|
||||
auto Stmt() -> Nonnull<Statement*> { return stmt; }
|
||||
auto Next() const -> std::optional<Nonnull<const Statement*>> { return next; }
|
||||
auto Next() -> std::optional<Nonnull<Statement*>> { return next; }
|
||||
|
||||
private:
|
||||
Nonnull<const Statement*> stmt;
|
||||
std::optional<Nonnull<const Statement*>> next;
|
||||
Nonnull<Statement*> stmt;
|
||||
std::optional<Nonnull<Statement*>> next;
|
||||
};
|
||||
|
||||
class Block : public Statement {
|
||||
public:
|
||||
Block(SourceLocation loc, std::optional<Nonnull<const Statement*>> stmt)
|
||||
Block(SourceLocation loc, std::optional<Nonnull<Statement*>> stmt)
|
||||
: Statement(Kind::Block, loc), stmt(stmt) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
@@ -183,15 +193,15 @@ class Block : public Statement {
|
||||
}
|
||||
|
||||
auto Stmt() const -> std::optional<Nonnull<const Statement*>> { return stmt; }
|
||||
auto Stmt() -> std::optional<Nonnull<Statement*>> { return stmt; }
|
||||
|
||||
private:
|
||||
std::optional<Nonnull<const Statement*>> stmt;
|
||||
std::optional<Nonnull<Statement*>> stmt;
|
||||
};
|
||||
|
||||
class While : public Statement {
|
||||
public:
|
||||
While(SourceLocation loc, Nonnull<const Expression*> cond,
|
||||
Nonnull<const Statement*> body)
|
||||
While(SourceLocation loc, Nonnull<Expression*> cond, Nonnull<Statement*> body)
|
||||
: Statement(Kind::While, loc), cond(cond), body(body) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
@@ -199,11 +209,13 @@ class While : public Statement {
|
||||
}
|
||||
|
||||
auto Cond() const -> Nonnull<const Expression*> { return cond; }
|
||||
auto Cond() -> Nonnull<Expression*> { return cond; }
|
||||
auto Body() const -> Nonnull<const Statement*> { return body; }
|
||||
auto Body() -> Nonnull<Statement*> { return body; }
|
||||
|
||||
private:
|
||||
Nonnull<const Expression*> cond;
|
||||
Nonnull<const Statement*> body;
|
||||
Nonnull<Expression*> cond;
|
||||
Nonnull<Statement*> body;
|
||||
};
|
||||
|
||||
class Break : public Statement {
|
||||
@@ -226,10 +238,8 @@ class Continue : public Statement {
|
||||
|
||||
class Match : public Statement {
|
||||
public:
|
||||
Match(
|
||||
SourceLocation loc, Nonnull<const Expression*> exp,
|
||||
std::vector<std::pair<Nonnull<const Pattern*>, Nonnull<const Statement*>>>
|
||||
clauses)
|
||||
Match(SourceLocation loc, Nonnull<Expression*> exp,
|
||||
std::vector<std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>> clauses)
|
||||
: Statement(Kind::Match, loc), exp(exp), clauses(std::move(clauses)) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
@@ -237,15 +247,15 @@ class Match : public Statement {
|
||||
}
|
||||
|
||||
auto Exp() const -> Nonnull<const Expression*> { return exp; }
|
||||
auto Clauses() const -> const std::vector<
|
||||
std::pair<Nonnull<const Pattern*>, Nonnull<const Statement*>>>& {
|
||||
auto Exp() -> Nonnull<Expression*> { return exp; }
|
||||
auto Clauses() const
|
||||
-> llvm::ArrayRef<std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>> {
|
||||
return clauses;
|
||||
}
|
||||
|
||||
private:
|
||||
Nonnull<const Expression*> exp;
|
||||
std::vector<std::pair<Nonnull<const Pattern*>, Nonnull<const Statement*>>>
|
||||
clauses;
|
||||
Nonnull<Expression*> exp;
|
||||
std::vector<std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>> clauses;
|
||||
};
|
||||
|
||||
// A continuation statement.
|
||||
@@ -256,7 +266,7 @@ class Match : public Statement {
|
||||
class Continuation : public Statement {
|
||||
public:
|
||||
Continuation(SourceLocation loc, std::string continuation_variable,
|
||||
Nonnull<const Statement*> body)
|
||||
Nonnull<Statement*> body)
|
||||
: Statement(Kind::Continuation, loc),
|
||||
continuation_variable(std::move(continuation_variable)),
|
||||
body(body) {}
|
||||
@@ -269,10 +279,11 @@ class Continuation : public Statement {
|
||||
return continuation_variable;
|
||||
}
|
||||
auto Body() const -> Nonnull<const Statement*> { return body; }
|
||||
auto Body() -> Nonnull<Statement*> { return body; }
|
||||
|
||||
private:
|
||||
std::string continuation_variable;
|
||||
Nonnull<const Statement*> body;
|
||||
Nonnull<Statement*> body;
|
||||
};
|
||||
|
||||
// A run statement.
|
||||
@@ -280,7 +291,7 @@ class Continuation : public Statement {
|
||||
// __run <argument>;
|
||||
class Run : public Statement {
|
||||
public:
|
||||
Run(SourceLocation loc, Nonnull<const Expression*> argument)
|
||||
Run(SourceLocation loc, Nonnull<Expression*> argument)
|
||||
: Statement(Kind::Run, loc), argument(argument) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
@@ -288,9 +299,10 @@ class Run : public Statement {
|
||||
}
|
||||
|
||||
auto Argument() const -> Nonnull<const Expression*> { return argument; }
|
||||
auto Argument() -> Nonnull<Expression*> { return argument; }
|
||||
|
||||
private:
|
||||
Nonnull<const Expression*> argument;
|
||||
Nonnull<Expression*> argument;
|
||||
};
|
||||
|
||||
// An await statement.
|
||||
|
||||
@@ -15,9 +15,8 @@ namespace Carbon {
|
||||
|
||||
// Adds builtins, currently only Print(). Note Print() is experimental, not
|
||||
// standardized, but is made available for printing state in tests.
|
||||
static void AddIntrinsics(
|
||||
Nonnull<Arena*> arena,
|
||||
std::vector<Nonnull<const Declaration*>>* declarations) {
|
||||
static void AddIntrinsics(Nonnull<Arena*> arena,
|
||||
std::vector<Nonnull<Declaration*>>* declarations) {
|
||||
SourceLocation loc("<intrinsic>", 0);
|
||||
std::vector<TuplePattern::Field> print_fields = {TuplePattern::Field(
|
||||
"0",
|
||||
@@ -47,7 +46,7 @@ void ExecProgram(Nonnull<Arena*> arena, AST ast) {
|
||||
llvm::outs() << "********** type checking **********\n";
|
||||
}
|
||||
TypeChecker type_checker(arena);
|
||||
TypeChecker::TypeCheckContext p = type_checker.TopLevel(ast.declarations);
|
||||
TypeChecker::TypeCheckContext p = type_checker.TopLevel(&ast.declarations);
|
||||
TypeEnv top = p.types;
|
||||
Env ct_top = p.values;
|
||||
std::vector<Nonnull<const Declaration*>> new_decls;
|
||||
@@ -62,7 +61,12 @@ void ExecProgram(Nonnull<Arena*> arena, AST ast) {
|
||||
}
|
||||
llvm::outs() << "********** starting execution **********\n";
|
||||
}
|
||||
int result = Interpreter(arena).InterpProgram(new_decls);
|
||||
|
||||
SourceLocation loc("<main()>", 0);
|
||||
Nonnull<Expression*> call_main = arena->New<CallExpression>(
|
||||
loc, arena->New<IdentifierExpression>(loc, "main"),
|
||||
arena->New<TupleLiteral>(loc));
|
||||
int result = Interpreter(arena).InterpProgram(new_decls, call_main);
|
||||
llvm::outs() << "result: " << result << "\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -1133,7 +1133,8 @@ void Interpreter::Step() {
|
||||
}
|
||||
|
||||
auto Interpreter::InterpProgram(
|
||||
const std::vector<Nonnull<const Declaration*>>& fs) -> int {
|
||||
const std::vector<Nonnull<const Declaration*>>& fs,
|
||||
Nonnull<const Expression*> call_main) -> int {
|
||||
// Check that the interpreter is in a clean state.
|
||||
CHECK(globals.IsEmpty());
|
||||
CHECK(stack.IsEmpty());
|
||||
@@ -1144,11 +1145,6 @@ auto Interpreter::InterpProgram(
|
||||
}
|
||||
InitGlobals(fs);
|
||||
|
||||
SourceLocation loc("<InterpProgram()>", 0);
|
||||
|
||||
Nonnull<const Expression*> arg = arena->New<TupleLiteral>(loc);
|
||||
Nonnull<const Expression*> call_main = arena->New<CallExpression>(
|
||||
loc, arena->New<IdentifierExpression>(loc, "main"), arg);
|
||||
auto todo = Stack<Nonnull<Action*>>(arena->New<ExpressionAction>(call_main));
|
||||
auto scopes = Stack<Nonnull<Scope*>>(arena->New<Scope>(globals));
|
||||
stack = Stack<Nonnull<Frame*>>(arena->New<Frame>("top", scopes, todo));
|
||||
|
||||
@@ -28,7 +28,8 @@ class Interpreter {
|
||||
: arena(arena), globals(arena), heap(arena) {}
|
||||
|
||||
// Interpret the whole program.
|
||||
auto InterpProgram(const std::vector<Nonnull<const Declaration*>>& fs) -> int;
|
||||
auto InterpProgram(const std::vector<Nonnull<const Declaration*>>& fs,
|
||||
Nonnull<const Expression*> call_main) -> int;
|
||||
|
||||
// Interpret an expression at compile-time.
|
||||
auto InterpExp(Env values, Nonnull<const Expression*> e)
|
||||
|
||||
@@ -52,7 +52,7 @@ static void ExpectPointerType(SourceLocation loc, const std::string& context,
|
||||
}
|
||||
|
||||
auto TypeChecker::ReifyType(Nonnull<const Value*> t, SourceLocation loc)
|
||||
-> Nonnull<const Expression*> {
|
||||
-> Nonnull<Expression*> {
|
||||
switch (t->Tag()) {
|
||||
case Value::Kind::IntType:
|
||||
return arena->New<IntTypeLiteral>(loc);
|
||||
@@ -83,7 +83,7 @@ auto TypeChecker::ReifyType(Nonnull<const Value*> t, SourceLocation loc)
|
||||
case Value::Kind::PointerType:
|
||||
return arena->New<PrimitiveOperatorExpression>(
|
||||
loc, Operator::Ptr,
|
||||
std::vector<Nonnull<const Expression*>>(
|
||||
std::vector<Nonnull<Expression*>>(
|
||||
{ReifyType(cast<PointerType>(*t).Type(), loc)}));
|
||||
case Value::Kind::VariableType:
|
||||
return arena->New<IdentifierExpression>(loc,
|
||||
@@ -248,7 +248,7 @@ auto TypeChecker::Substitute(TypeEnv dict, Nonnull<const Value*> type)
|
||||
}
|
||||
}
|
||||
|
||||
auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types,
|
||||
auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e, TypeEnv types,
|
||||
Env values) -> TCExpression {
|
||||
if (tracing_output) {
|
||||
llvm::outs() << "checking expression " << *e << "\ntypes: ";
|
||||
@@ -259,7 +259,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types,
|
||||
}
|
||||
switch (e->Tag()) {
|
||||
case Expression::Kind::IndexExpression: {
|
||||
const auto& index = cast<IndexExpression>(*e);
|
||||
auto& index = cast<IndexExpression>(*e);
|
||||
auto res = TypeCheckExp(index.Aggregate(), types, values);
|
||||
auto t = res.type;
|
||||
switch (t->Tag()) {
|
||||
@@ -298,7 +298,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types,
|
||||
return TCExpression(tuple_e, tuple_t, new_types);
|
||||
}
|
||||
case Expression::Kind::FieldAccessExpression: {
|
||||
const auto& access = cast<FieldAccessExpression>(*e);
|
||||
auto& access = cast<FieldAccessExpression>(*e);
|
||||
auto res = TypeCheckExp(access.Aggregate(), types, values);
|
||||
auto t = res.type;
|
||||
switch (t->Tag()) {
|
||||
@@ -307,18 +307,16 @@ auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types,
|
||||
// Search for a field
|
||||
for (auto& field : t_class.Fields()) {
|
||||
if (access.Field() == field.first) {
|
||||
Nonnull<const Expression*> new_e =
|
||||
arena->New<FieldAccessExpression>(e->SourceLoc(), res.exp,
|
||||
access.Field());
|
||||
Nonnull<Expression*> new_e = arena->New<FieldAccessExpression>(
|
||||
e->SourceLoc(), res.exp, access.Field());
|
||||
return TCExpression(new_e, field.second, res.types);
|
||||
}
|
||||
}
|
||||
// Search for a method
|
||||
for (auto& method : t_class.Methods()) {
|
||||
if (access.Field() == method.first) {
|
||||
Nonnull<const Expression*> new_e =
|
||||
arena->New<FieldAccessExpression>(e->SourceLoc(), res.exp,
|
||||
access.Field());
|
||||
Nonnull<Expression*> new_e = arena->New<FieldAccessExpression>(
|
||||
e->SourceLoc(), res.exp, access.Field());
|
||||
return TCExpression(new_e, method.second, res.types);
|
||||
}
|
||||
}
|
||||
@@ -343,9 +341,8 @@ auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types,
|
||||
const auto& choice = cast<ChoiceType>(*t);
|
||||
for (const auto& vt : choice.Alternatives()) {
|
||||
if (access.Field() == vt.first) {
|
||||
Nonnull<const Expression*> new_e =
|
||||
arena->New<FieldAccessExpression>(e->SourceLoc(), res.exp,
|
||||
access.Field());
|
||||
Nonnull<Expression*> new_e = arena->New<FieldAccessExpression>(
|
||||
e->SourceLoc(), res.exp, access.Field());
|
||||
auto fun_ty = arena->New<FunctionType>(
|
||||
std::vector<GenericBinding>(), vt.second, t);
|
||||
return TCExpression(new_e, fun_ty, res.types);
|
||||
@@ -377,10 +374,10 @@ auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types,
|
||||
return TCExpression(e, arena->New<BoolType>(), types);
|
||||
case Expression::Kind::PrimitiveOperatorExpression: {
|
||||
const auto& op = cast<PrimitiveOperatorExpression>(*e);
|
||||
std::vector<Nonnull<const Expression*>> es;
|
||||
std::vector<Nonnull<Expression*>> es;
|
||||
std::vector<Nonnull<const Value*>> ts;
|
||||
auto new_types = types;
|
||||
for (Nonnull<const Expression*> argument : op.Arguments()) {
|
||||
for (Nonnull<Expression*> argument : op.Arguments()) {
|
||||
auto res = TypeCheckExp(argument, types, values);
|
||||
new_types = res.types;
|
||||
es.push_back(res.exp);
|
||||
@@ -435,7 +432,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types,
|
||||
break;
|
||||
}
|
||||
case Expression::Kind::CallExpression: {
|
||||
const auto& call = cast<CallExpression>(*e);
|
||||
auto& call = cast<CallExpression>(*e);
|
||||
auto fun_res = TypeCheckExp(call.Function(), types, values);
|
||||
switch (fun_res.type->Tag()) {
|
||||
case Value::Kind::FunctionType: {
|
||||
@@ -499,7 +496,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types,
|
||||
}
|
||||
|
||||
auto TypeChecker::TypeCheckPattern(
|
||||
Nonnull<const Pattern*> p, TypeEnv types, Env values,
|
||||
Nonnull<Pattern*> p, TypeEnv types, Env values,
|
||||
std::optional<Nonnull<const Value*>> expected) -> TCPattern {
|
||||
if (tracing_output) {
|
||||
llvm::outs() << "checking pattern " << *p;
|
||||
@@ -517,7 +514,7 @@ auto TypeChecker::TypeCheckPattern(
|
||||
return {.pattern = p, .type = arena->New<TypeType>(), .types = types};
|
||||
}
|
||||
case Pattern::Kind::BindingPattern: {
|
||||
const auto& binding = cast<BindingPattern>(*p);
|
||||
auto& binding = cast<BindingPattern>(*p);
|
||||
TCPattern binding_type_result =
|
||||
TypeCheckPattern(binding.Type(), types, values, std::nullopt);
|
||||
Nonnull<const Value*> type =
|
||||
@@ -543,7 +540,7 @@ auto TypeChecker::TypeCheckPattern(
|
||||
return {.pattern = new_p, .type = type, .types = types};
|
||||
}
|
||||
case Pattern::Kind::TuplePattern: {
|
||||
const auto& tuple = cast<TuplePattern>(*p);
|
||||
auto& tuple = cast<TuplePattern>(*p);
|
||||
std::vector<TuplePattern::Field> new_fields;
|
||||
std::vector<TupleElement> field_types;
|
||||
auto new_types = types;
|
||||
@@ -556,7 +553,7 @@ auto TypeChecker::TypeCheckPattern(
|
||||
<< "tuples of different length";
|
||||
}
|
||||
for (size_t i = 0; i < tuple.Fields().size(); ++i) {
|
||||
const TuplePattern::Field& field = tuple.Fields()[i];
|
||||
TuplePattern::Field& field = tuple.Fields()[i];
|
||||
std::optional<Nonnull<const Value*>> expected_field_type;
|
||||
if (expected) {
|
||||
const TupleElement& expected_element =
|
||||
@@ -580,7 +577,7 @@ auto TypeChecker::TypeCheckPattern(
|
||||
return {.pattern = new_tuple, .type = tuple_t, .types = new_types};
|
||||
}
|
||||
case Pattern::Kind::AlternativePattern: {
|
||||
const auto& alternative = cast<AlternativePattern>(*p);
|
||||
auto& alternative = cast<AlternativePattern>(*p);
|
||||
Nonnull<const Value*> choice_type =
|
||||
interpreter.InterpExp(values, alternative.ChoiceType());
|
||||
if (choice_type->Tag() != Value::Kind::ChoiceType) {
|
||||
@@ -603,8 +600,8 @@ auto TypeChecker::TypeCheckPattern(
|
||||
values, *parameter_types);
|
||||
// TODO: Think about a cleaner way to cast between Ptr types.
|
||||
// (multiple TODOs)
|
||||
auto arguments = Nonnull<const TuplePattern*>(
|
||||
cast<const TuplePattern>(arg_results.pattern));
|
||||
auto arguments =
|
||||
Nonnull<TuplePattern*>(cast<const TuplePattern>(arg_results.pattern));
|
||||
return {.pattern = arena->New<AlternativePattern>(
|
||||
alternative.SourceLoc(),
|
||||
ReifyType(choice_type, alternative.SourceLoc()),
|
||||
@@ -623,26 +620,26 @@ auto TypeChecker::TypeCheckPattern(
|
||||
}
|
||||
|
||||
auto TypeChecker::TypeCheckCase(Nonnull<const Value*> expected,
|
||||
Nonnull<const Pattern*> pat,
|
||||
Nonnull<const Statement*> body, TypeEnv types,
|
||||
Env values, Nonnull<const Value*>& ret_type,
|
||||
Nonnull<Pattern*> pat, Nonnull<Statement*> body,
|
||||
TypeEnv types, Env values,
|
||||
Nonnull<const Value*>& ret_type,
|
||||
bool is_omitted_ret_type)
|
||||
-> std::pair<Nonnull<const Pattern*>, Nonnull<const Statement*>> {
|
||||
-> std::pair<Nonnull<Pattern*>, Nonnull<Statement*>> {
|
||||
auto pat_res = TypeCheckPattern(pat, types, values, expected);
|
||||
auto res =
|
||||
TypeCheckStmt(body, pat_res.types, values, ret_type, is_omitted_ret_type);
|
||||
return std::make_pair(pat, res.stmt);
|
||||
}
|
||||
|
||||
auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
auto TypeChecker::TypeCheckStmt(Nonnull<Statement*> s, TypeEnv types,
|
||||
Env values, Nonnull<const Value*>& ret_type,
|
||||
bool is_omitted_ret_type) -> TCStatement {
|
||||
switch (s->Tag()) {
|
||||
case Statement::Kind::Match: {
|
||||
const auto& match = cast<Match>(*s);
|
||||
auto& match = cast<Match>(*s);
|
||||
auto res = TypeCheckExp(match.Exp(), types, values);
|
||||
auto res_type = res.type;
|
||||
std::vector<std::pair<Nonnull<const Pattern*>, Nonnull<const Statement*>>>
|
||||
std::vector<std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>>
|
||||
new_clauses;
|
||||
for (auto& clause : match.Clauses()) {
|
||||
new_clauses.push_back(TypeCheckCase(res_type, clause.first,
|
||||
@@ -653,7 +650,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
return TCStatement(new_s, types);
|
||||
}
|
||||
case Statement::Kind::While: {
|
||||
const auto& while_stmt = cast<While>(*s);
|
||||
auto& while_stmt = cast<While>(*s);
|
||||
auto cnd_res = TypeCheckExp(while_stmt.Cond(), types, values);
|
||||
ExpectType(s->SourceLoc(), "condition of `while`", arena->New<BoolType>(),
|
||||
cnd_res.type);
|
||||
@@ -667,7 +664,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
case Statement::Kind::Continue:
|
||||
return TCStatement(s, types);
|
||||
case Statement::Kind::Block: {
|
||||
const auto& block = cast<Block>(*s);
|
||||
auto& block = cast<Block>(*s);
|
||||
if (block.Stmt()) {
|
||||
auto stmt_res = TypeCheckStmt(*block.Stmt(), types, values, ret_type,
|
||||
is_omitted_ret_type);
|
||||
@@ -678,7 +675,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
}
|
||||
}
|
||||
case Statement::Kind::VariableDefinition: {
|
||||
const auto& var = cast<VariableDefinition>(*s);
|
||||
auto& var = cast<VariableDefinition>(*s);
|
||||
auto res = TypeCheckExp(var.Init(), types, values);
|
||||
Nonnull<const Value*> rhs_ty = res.type;
|
||||
auto lhs_res = TypeCheckPattern(var.Pat(), types, values, rhs_ty);
|
||||
@@ -687,11 +684,11 @@ auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
return TCStatement(new_s, lhs_res.types);
|
||||
}
|
||||
case Statement::Kind::Sequence: {
|
||||
const auto& seq = cast<Sequence>(*s);
|
||||
auto& seq = cast<Sequence>(*s);
|
||||
auto stmt_res = TypeCheckStmt(seq.Stmt(), types, values, ret_type,
|
||||
is_omitted_ret_type);
|
||||
auto checked_types = stmt_res.types;
|
||||
std::optional<Nonnull<const Statement*>> next_stmt;
|
||||
std::optional<Nonnull<Statement*>> next_stmt;
|
||||
if (seq.Next()) {
|
||||
auto next_res = TypeCheckStmt(*seq.Next(), checked_types, values,
|
||||
ret_type, is_omitted_ret_type);
|
||||
@@ -703,7 +700,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
checked_types);
|
||||
}
|
||||
case Statement::Kind::Assign: {
|
||||
const auto& assign = cast<Assign>(*s);
|
||||
auto& assign = cast<Assign>(*s);
|
||||
auto rhs_res = TypeCheckExp(assign.Rhs(), types, values);
|
||||
auto rhs_t = rhs_res.type;
|
||||
auto lhs_res = TypeCheckExp(assign.Lhs(), types, values);
|
||||
@@ -719,13 +716,13 @@ auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
return TCStatement(new_s, types);
|
||||
}
|
||||
case Statement::Kind::If: {
|
||||
const auto& if_stmt = cast<If>(*s);
|
||||
auto& if_stmt = cast<If>(*s);
|
||||
auto cnd_res = TypeCheckExp(if_stmt.Cond(), types, values);
|
||||
ExpectType(s->SourceLoc(), "condition of `if`", arena->New<BoolType>(),
|
||||
cnd_res.type);
|
||||
auto then_res = TypeCheckStmt(if_stmt.ThenStmt(), types, values, ret_type,
|
||||
is_omitted_ret_type);
|
||||
std::optional<Nonnull<const Statement*>> else_stmt;
|
||||
std::optional<Nonnull<Statement*>> else_stmt;
|
||||
if (if_stmt.ElseStmt()) {
|
||||
auto else_res = TypeCheckStmt(*if_stmt.ElseStmt(), types, values,
|
||||
ret_type, is_omitted_ret_type);
|
||||
@@ -736,7 +733,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
return TCStatement(new_s, types);
|
||||
}
|
||||
case Statement::Kind::Return: {
|
||||
const auto& ret = cast<Return>(*s);
|
||||
auto& ret = cast<Return>(*s);
|
||||
auto res = TypeCheckExp(ret.Exp(), types, values);
|
||||
if (ret_type->Tag() == Value::Kind::AutoType) {
|
||||
// The following infers the return type from the first 'return'
|
||||
@@ -756,7 +753,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
types);
|
||||
}
|
||||
case Statement::Kind::Continuation: {
|
||||
const auto& cont = cast<Continuation>(*s);
|
||||
auto& cont = cast<Continuation>(*s);
|
||||
TCStatement body_result = TypeCheckStmt(cont.Body(), types, values,
|
||||
ret_type, is_omitted_ret_type);
|
||||
auto new_continuation = arena->New<Continuation>(
|
||||
@@ -780,8 +777,8 @@ auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
}
|
||||
|
||||
auto TypeChecker::CheckOrEnsureReturn(
|
||||
std::optional<Nonnull<const Statement*>> opt_stmt, bool omitted_ret_type,
|
||||
SourceLocation loc) -> Nonnull<const Statement*> {
|
||||
std::optional<Nonnull<Statement*>> opt_stmt, bool omitted_ret_type,
|
||||
SourceLocation loc) -> Nonnull<Statement*> {
|
||||
if (!opt_stmt) {
|
||||
if (omitted_ret_type) {
|
||||
return arena->New<Return>(arena, loc);
|
||||
@@ -791,11 +788,11 @@ auto TypeChecker::CheckOrEnsureReturn(
|
||||
"type without reaching a return statement";
|
||||
}
|
||||
}
|
||||
Nonnull<const Statement*> stmt = *opt_stmt;
|
||||
Nonnull<Statement*> stmt = *opt_stmt;
|
||||
switch (stmt->Tag()) {
|
||||
case Statement::Kind::Match: {
|
||||
const auto& match = cast<Match>(*stmt);
|
||||
std::vector<std::pair<Nonnull<const Pattern*>, Nonnull<const Statement*>>>
|
||||
auto& match = cast<Match>(*stmt);
|
||||
std::vector<std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>>
|
||||
new_clauses;
|
||||
for (const auto& clause : match.Clauses()) {
|
||||
auto s = CheckOrEnsureReturn(clause.second, omitted_ret_type,
|
||||
@@ -810,7 +807,7 @@ auto TypeChecker::CheckOrEnsureReturn(
|
||||
CheckOrEnsureReturn(cast<Block>(*stmt).Stmt(), omitted_ret_type,
|
||||
stmt->SourceLoc()));
|
||||
case Statement::Kind::If: {
|
||||
const auto& if_stmt = cast<If>(*stmt);
|
||||
auto& if_stmt = cast<If>(*stmt);
|
||||
return arena->New<If>(
|
||||
stmt->SourceLoc(), if_stmt.Cond(),
|
||||
CheckOrEnsureReturn(if_stmt.ThenStmt(), omitted_ret_type,
|
||||
@@ -821,7 +818,7 @@ auto TypeChecker::CheckOrEnsureReturn(
|
||||
case Statement::Kind::Return:
|
||||
return stmt;
|
||||
case Statement::Kind::Sequence: {
|
||||
const auto& seq = cast<Sequence>(*stmt);
|
||||
auto& seq = cast<Sequence>(*stmt);
|
||||
if (seq.Next()) {
|
||||
return arena->New<Sequence>(
|
||||
stmt->SourceLoc(), seq.Stmt(),
|
||||
@@ -857,9 +854,8 @@ auto TypeChecker::CheckOrEnsureReturn(
|
||||
// a function.
|
||||
// TODO: Add checking to function definitions to ensure that
|
||||
// all deduced type parameters will be deduced.
|
||||
auto TypeChecker::TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types,
|
||||
Env values)
|
||||
-> Nonnull<const FunctionDefinition*> {
|
||||
auto TypeChecker::TypeCheckFunDef(FunctionDefinition* f, TypeEnv types,
|
||||
Env values) -> Nonnull<FunctionDefinition*> {
|
||||
// Bring the deduced parameters into scope
|
||||
for (const auto& deduced : f->deduced_parameters()) {
|
||||
// auto t = interpreter.InterpExp(values, deduced.type);
|
||||
@@ -877,7 +873,7 @@ auto TypeChecker::TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types,
|
||||
return_type);
|
||||
// TODO: Check that main doesn't have any parameters.
|
||||
}
|
||||
std::optional<Nonnull<const Statement*>> body_stmt;
|
||||
std::optional<Nonnull<Statement*>> body_stmt;
|
||||
if (f->body()) {
|
||||
auto res = TypeCheckStmt(*f->body(), param_res.types, values, return_type,
|
||||
f->is_omitted_return_type());
|
||||
@@ -892,7 +888,7 @@ auto TypeChecker::TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types,
|
||||
}
|
||||
|
||||
auto TypeChecker::TypeOfFunDef(TypeEnv types, Env values,
|
||||
const FunctionDefinition* fun_def)
|
||||
FunctionDefinition* fun_def)
|
||||
-> Nonnull<const Value*> {
|
||||
// Bring the deduced parameters into scope
|
||||
for (const auto& deduced : fun_def->deduced_parameters()) {
|
||||
@@ -961,9 +957,8 @@ static auto GetName(const Declaration& d) -> const std::string& {
|
||||
}
|
||||
}
|
||||
|
||||
auto TypeChecker::MakeTypeChecked(const Nonnull<const Declaration*> d,
|
||||
const TypeEnv& types, const Env& values)
|
||||
-> Nonnull<const Declaration*> {
|
||||
auto TypeChecker::MakeTypeChecked(Nonnull<Declaration*> d, const TypeEnv& types,
|
||||
const Env& values) -> Nonnull<Declaration*> {
|
||||
switch (d->Tag()) {
|
||||
case Declaration::Kind::FunctionDeclaration:
|
||||
return arena->New<FunctionDeclaration>(TypeCheckFunDef(
|
||||
@@ -990,7 +985,7 @@ auto TypeChecker::MakeTypeChecked(const Nonnull<const Declaration*> d,
|
||||
return d;
|
||||
|
||||
case Declaration::Kind::VariableDeclaration: {
|
||||
const auto& var = cast<VariableDeclaration>(*d);
|
||||
auto& var = cast<VariableDeclaration>(*d);
|
||||
// Signals a type error if the initializing expression does not have
|
||||
// the declared type of the variable, otherwise returns this
|
||||
// declaration with annotated types.
|
||||
@@ -1012,19 +1007,19 @@ auto TypeChecker::MakeTypeChecked(const Nonnull<const Declaration*> d,
|
||||
}
|
||||
}
|
||||
|
||||
void TypeChecker::TopLevel(const Declaration& d, TypeCheckContext* tops) {
|
||||
switch (d.Tag()) {
|
||||
void TypeChecker::TopLevel(Nonnull<Declaration*> d, TypeCheckContext* tops) {
|
||||
switch (d->Tag()) {
|
||||
case Declaration::Kind::FunctionDeclaration: {
|
||||
const FunctionDefinition& func_def =
|
||||
cast<FunctionDeclaration>(d).Definition();
|
||||
FunctionDefinition& func_def = cast<FunctionDeclaration>(*d).Definition();
|
||||
auto t = TypeOfFunDef(tops->types, tops->values, &func_def);
|
||||
tops->types.Set(func_def.name(), t);
|
||||
interpreter.InitEnv(d, &tops->values);
|
||||
interpreter.InitEnv(*d, &tops->values);
|
||||
break;
|
||||
}
|
||||
|
||||
case Declaration::Kind::ClassDeclaration: {
|
||||
const ClassDefinition& class_def = cast<ClassDeclaration>(d).Definition();
|
||||
const ClassDefinition& class_def =
|
||||
cast<ClassDeclaration>(*d).Definition();
|
||||
auto st = TypeOfClassDef(&class_def, tops->types, tops->values);
|
||||
Address a = interpreter.AllocateValue(st);
|
||||
tops->values.Set(class_def.name, a); // Is this obsolete?
|
||||
@@ -1041,7 +1036,7 @@ void TypeChecker::TopLevel(const Declaration& d, TypeCheckContext* tops) {
|
||||
}
|
||||
|
||||
case Declaration::Kind::ChoiceDeclaration: {
|
||||
const auto& choice = cast<ChoiceDeclaration>(d);
|
||||
const auto& choice = cast<ChoiceDeclaration>(*d);
|
||||
VarValues alts;
|
||||
for (const auto& alternative : choice.Alternatives()) {
|
||||
auto t = interpreter.InterpExp(tops->values, &alternative.signature());
|
||||
@@ -1055,10 +1050,10 @@ void TypeChecker::TopLevel(const Declaration& d, TypeCheckContext* tops) {
|
||||
}
|
||||
|
||||
case Declaration::Kind::VariableDeclaration: {
|
||||
const auto& var = cast<VariableDeclaration>(d);
|
||||
auto& var = cast<VariableDeclaration>(*d);
|
||||
// Associate the variable name with it's declared type in the
|
||||
// compile-time symbol table.
|
||||
Nonnull<const Expression*> type =
|
||||
Nonnull<Expression*> type =
|
||||
cast<ExpressionPattern>(*var.Binding()->Type()).Expression();
|
||||
Nonnull<const Value*> declared_type =
|
||||
interpreter.InterpExp(tops->values, type);
|
||||
@@ -1068,16 +1063,16 @@ void TypeChecker::TopLevel(const Declaration& d, TypeCheckContext* tops) {
|
||||
}
|
||||
}
|
||||
|
||||
auto TypeChecker::TopLevel(const std::vector<Nonnull<const Declaration*>>& fs)
|
||||
auto TypeChecker::TopLevel(std::vector<Nonnull<Declaration*>>* fs)
|
||||
-> TypeCheckContext {
|
||||
TypeCheckContext tops(arena);
|
||||
bool found_main = false;
|
||||
|
||||
for (auto const& d : fs) {
|
||||
for (auto const& d : *fs) {
|
||||
if (GetName(*d) == "main") {
|
||||
found_main = true;
|
||||
}
|
||||
TopLevel(*d, &tops);
|
||||
TopLevel(d, &tops);
|
||||
}
|
||||
|
||||
if (found_main == false) {
|
||||
|
||||
@@ -32,35 +32,31 @@ class TypeChecker {
|
||||
Env values;
|
||||
};
|
||||
|
||||
auto MakeTypeChecked(const Nonnull<const Declaration*> d,
|
||||
const TypeEnv& types, const Env& values)
|
||||
-> Nonnull<const Declaration*>;
|
||||
auto MakeTypeChecked(Nonnull<Declaration*> d, const TypeEnv& types,
|
||||
const Env& values) -> Nonnull<Declaration*>;
|
||||
|
||||
auto TopLevel(const std::vector<Nonnull<const Declaration*>>& fs)
|
||||
-> TypeCheckContext;
|
||||
auto TopLevel(std::vector<Nonnull<Declaration*>>* fs) -> TypeCheckContext;
|
||||
|
||||
private:
|
||||
struct TCExpression {
|
||||
TCExpression(Nonnull<const Expression*> e, Nonnull<const Value*> t,
|
||||
TypeEnv types)
|
||||
TCExpression(Nonnull<Expression*> e, Nonnull<const Value*> t, TypeEnv types)
|
||||
: exp(e), type(t), types(types) {}
|
||||
|
||||
Nonnull<const Expression*> exp;
|
||||
Nonnull<Expression*> exp;
|
||||
Nonnull<const Value*> type;
|
||||
TypeEnv types;
|
||||
};
|
||||
|
||||
struct TCPattern {
|
||||
Nonnull<const Pattern*> pattern;
|
||||
Nonnull<Pattern*> pattern;
|
||||
Nonnull<const Value*> type;
|
||||
TypeEnv types;
|
||||
};
|
||||
|
||||
struct TCStatement {
|
||||
TCStatement(Nonnull<const Statement*> s, TypeEnv types)
|
||||
: stmt(s), types(types) {}
|
||||
TCStatement(Nonnull<Statement*> s, TypeEnv types) : stmt(s), types(types) {}
|
||||
|
||||
Nonnull<const Statement*> stmt;
|
||||
Nonnull<Statement*> stmt;
|
||||
TypeEnv types;
|
||||
};
|
||||
|
||||
@@ -75,14 +71,14 @@ class TypeChecker {
|
||||
// types maps variable names to the type of their run-time value.
|
||||
// values maps variable names to their compile-time values. It is not
|
||||
// directly used in this function but is passed to InterExp.
|
||||
auto TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types, Env values)
|
||||
auto TypeCheckExp(Nonnull<Expression*> e, TypeEnv types, Env values)
|
||||
-> TCExpression;
|
||||
|
||||
// Equivalent to TypeCheckExp, but operates on Patterns instead of
|
||||
// Expressions. `expected` is the type that this pattern is expected to have,
|
||||
// if the surrounding context gives us that information. Otherwise, it is
|
||||
// nullopt.
|
||||
auto TypeCheckPattern(Nonnull<const Pattern*> p, TypeEnv types, Env values,
|
||||
auto TypeCheckPattern(Nonnull<Pattern*> p, TypeEnv types, Env values,
|
||||
std::optional<Nonnull<const Value*>> expected)
|
||||
-> TCPattern;
|
||||
|
||||
@@ -93,33 +89,32 @@ class TypeChecker {
|
||||
// declared return type of the enclosing function definition. If the return
|
||||
// type is "auto", then the return type is inferred from the first return
|
||||
// statement.
|
||||
auto TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types, Env values,
|
||||
auto TypeCheckStmt(Nonnull<Statement*> s, TypeEnv types, Env values,
|
||||
Nonnull<const Value*>& ret_type, bool is_omitted_ret_type)
|
||||
-> TCStatement;
|
||||
|
||||
auto TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types, Env values)
|
||||
-> Nonnull<const FunctionDefinition*>;
|
||||
auto TypeCheckFunDef(FunctionDefinition* f, TypeEnv types, Env values)
|
||||
-> Nonnull<FunctionDefinition*>;
|
||||
|
||||
auto TypeCheckCase(Nonnull<const Value*> expected,
|
||||
Nonnull<const Pattern*> pat,
|
||||
Nonnull<const Statement*> body, TypeEnv types, Env values,
|
||||
auto TypeCheckCase(Nonnull<const Value*> expected, Nonnull<Pattern*> pat,
|
||||
Nonnull<Statement*> body, TypeEnv types, Env values,
|
||||
Nonnull<const Value*>& ret_type, bool is_omitted_ret_type)
|
||||
-> std::pair<Nonnull<const Pattern*>, Nonnull<const Statement*>>;
|
||||
-> std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>;
|
||||
|
||||
auto TypeOfFunDef(TypeEnv types, Env values,
|
||||
const FunctionDefinition* fun_def) -> Nonnull<const Value*>;
|
||||
auto TypeOfFunDef(TypeEnv types, Env values, FunctionDefinition* fun_def)
|
||||
-> Nonnull<const Value*>;
|
||||
auto TypeOfClassDef(const ClassDefinition* sd, TypeEnv /*types*/, Env ct_top)
|
||||
-> Nonnull<const Value*>;
|
||||
|
||||
void TopLevel(const Declaration& d, TypeCheckContext* tops);
|
||||
void TopLevel(Nonnull<Declaration*> d, TypeCheckContext* tops);
|
||||
|
||||
auto CheckOrEnsureReturn(std::optional<Nonnull<const Statement*>> opt_stmt,
|
||||
auto CheckOrEnsureReturn(std::optional<Nonnull<Statement*>> opt_stmt,
|
||||
bool omitted_ret_type, SourceLocation loc)
|
||||
-> Nonnull<const Statement*>;
|
||||
-> Nonnull<Statement*>;
|
||||
|
||||
// Reify type to type expression.
|
||||
auto ReifyType(Nonnull<const Value*> t, SourceLocation loc)
|
||||
-> Nonnull<const Expression*>;
|
||||
-> Nonnull<Expression*>;
|
||||
|
||||
auto Substitute(TypeEnv dict, Nonnull<const Value*> type)
|
||||
-> Nonnull<const Value*>;
|
||||
|
||||
@@ -98,43 +98,43 @@
|
||||
%type <std::vector<LibraryName>> import_directives
|
||||
%type <std::string> optional_library_path
|
||||
%type <bool> api_or_impl
|
||||
%type <Nonnull<const Declaration*>> declaration
|
||||
%type <Nonnull<const FunctionDefinition*>> function_declaration
|
||||
%type <Nonnull<const FunctionDefinition*>> function_definition
|
||||
%type <std::vector<Nonnull<const Declaration*>>> declaration_list
|
||||
%type <Nonnull<const Statement*>> statement
|
||||
%type <Nonnull<const Statement*>> if_statement
|
||||
%type <std::optional<Nonnull<const Statement*>>> optional_else
|
||||
%type <std::pair<Nonnull<const Expression*>, bool>> return_expression
|
||||
%type <Nonnull<const Statement*>> block
|
||||
%type <std::optional<Nonnull<const Statement*>>> statement_list
|
||||
%type <Nonnull<const Expression*>> expression
|
||||
%type <Nonnull<Declaration*>> declaration
|
||||
%type <Nonnull<FunctionDefinition*>> function_declaration
|
||||
%type <Nonnull<FunctionDefinition*>> function_definition
|
||||
%type <std::vector<Nonnull<Declaration*>>> declaration_list
|
||||
%type <Nonnull<Statement*>> statement
|
||||
%type <Nonnull<Statement*>> if_statement
|
||||
%type <std::optional<Nonnull<Statement*>>> optional_else
|
||||
%type <std::pair<Nonnull<Expression*>, bool>> return_expression
|
||||
%type <Nonnull<Statement*>> block
|
||||
%type <std::optional<Nonnull<Statement*>>> statement_list
|
||||
%type <Nonnull<Expression*>> expression
|
||||
%type <GenericBinding> generic_binding
|
||||
%type <std::vector<GenericBinding>> deduced_params
|
||||
%type <std::vector<GenericBinding>> deduced_param_list
|
||||
%type <Nonnull<const Pattern*>> pattern
|
||||
%type <Nonnull<const Pattern*>> non_expression_pattern
|
||||
%type <std::pair<Nonnull<const Expression*>, bool>> return_type
|
||||
%type <Nonnull<const Expression*>> paren_expression
|
||||
%type <Nonnull<const Expression*>> tuple
|
||||
%type <Nonnull<Pattern*>> pattern
|
||||
%type <Nonnull<Pattern*>> non_expression_pattern
|
||||
%type <std::pair<Nonnull<Expression*>, bool>> return_type
|
||||
%type <Nonnull<Expression*>> paren_expression
|
||||
%type <Nonnull<Expression*>> tuple
|
||||
%type <std::optional<std::string>> binding_lhs
|
||||
%type <Nonnull<const BindingPattern*>> variable_declaration
|
||||
%type <Nonnull<BindingPattern*>> variable_declaration
|
||||
%type <Nonnull<Member*>> member
|
||||
%type <std::vector<Nonnull<Member*>>> member_list
|
||||
%type <ParenContents<Expression>::Element> paren_expression_element
|
||||
%type <ParenContents<Expression>> paren_expression_base
|
||||
%type <ParenContents<Expression>> paren_expression_contents
|
||||
%type <Nonnull<const Pattern*>> paren_pattern
|
||||
%type <Nonnull<const TuplePattern*>> tuple_pattern
|
||||
%type <Nonnull<const TuplePattern*>> maybe_empty_tuple_pattern
|
||||
%type <Nonnull<Pattern*>> paren_pattern
|
||||
%type <Nonnull<TuplePattern*>> tuple_pattern
|
||||
%type <Nonnull<TuplePattern*>> maybe_empty_tuple_pattern
|
||||
%type <ParenContents<Pattern>> paren_pattern_base
|
||||
%type <ParenContents<Pattern>::Element> paren_pattern_element
|
||||
%type <ParenContents<Pattern>> paren_pattern_contents
|
||||
%type <BisonWrap<ChoiceDeclaration::Alternative>> alternative
|
||||
%type <std::vector<ChoiceDeclaration::Alternative>> alternative_list
|
||||
%type <std::vector<ChoiceDeclaration::Alternative>> alternative_list_contents
|
||||
%type <std::pair<Nonnull<const Pattern*>, Nonnull<const Statement*>>> clause
|
||||
%type <std::vector<std::pair<Nonnull<const Pattern*>, Nonnull<const Statement*>>>> clause_list
|
||||
%type <std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>> clause
|
||||
%type <std::vector<std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>>> clause_list
|
||||
|
||||
%token
|
||||
// Most tokens have their spelling defined in lexer.lpp.
|
||||
@@ -303,61 +303,61 @@ expression:
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.SourceLoc(), Operator::Eq,
|
||||
std::vector<Nonnull<const Expression*>>({$1, $3}));
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
| expression PLUS expression
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.SourceLoc(), Operator::Add,
|
||||
std::vector<Nonnull<const Expression*>>({$1, $3}));
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
| expression MINUS expression
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.SourceLoc(), Operator::Sub,
|
||||
std::vector<Nonnull<const Expression*>>({$1, $3}));
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
| expression BINARY_STAR expression
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.SourceLoc(), Operator::Mul,
|
||||
std::vector<Nonnull<const Expression*>>({$1, $3}));
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
| expression AND expression
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.SourceLoc(), Operator::And,
|
||||
std::vector<Nonnull<const Expression*>>({$1, $3}));
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
| expression OR expression
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.SourceLoc(), Operator::Or,
|
||||
std::vector<Nonnull<const Expression*>>({$1, $3}));
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
| NOT expression
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.SourceLoc(), Operator::Not,
|
||||
std::vector<Nonnull<const Expression*>>({$2}));
|
||||
std::vector<Nonnull<Expression*>>({$2}));
|
||||
}
|
||||
| MINUS expression %prec UNARY_MINUS
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.SourceLoc(), Operator::Neg,
|
||||
std::vector<Nonnull<const Expression*>>({$2}));
|
||||
std::vector<Nonnull<Expression*>>({$2}));
|
||||
}
|
||||
| PREFIX_STAR expression
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.SourceLoc(), Operator::Deref,
|
||||
std::vector<Nonnull<const Expression*>>({$2}));
|
||||
std::vector<Nonnull<Expression*>>({$2}));
|
||||
}
|
||||
| UNARY_STAR expression %prec PREFIX_STAR
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.SourceLoc(), Operator::Deref,
|
||||
std::vector<Nonnull<const Expression*>>({$2}));
|
||||
std::vector<Nonnull<Expression*>>({$2}));
|
||||
}
|
||||
| expression tuple
|
||||
{ $$ = arena->New<CallExpression>(context.SourceLoc(), $1, $2); }
|
||||
@@ -365,13 +365,13 @@ expression:
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.SourceLoc(), Operator::Ptr,
|
||||
std::vector<Nonnull<const Expression*>>({$1}));
|
||||
std::vector<Nonnull<Expression*>>({$1}));
|
||||
}
|
||||
| expression UNARY_STAR
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.SourceLoc(), Operator::Ptr,
|
||||
std::vector<Nonnull<const Expression*>>({$1}));
|
||||
std::vector<Nonnull<Expression*>>({$1}));
|
||||
}
|
||||
| FNTY tuple return_type
|
||||
{
|
||||
@@ -501,17 +501,13 @@ maybe_empty_tuple_pattern:
|
||||
;
|
||||
clause:
|
||||
CASE pattern DOUBLE_ARROW statement
|
||||
{
|
||||
$$ =
|
||||
std::pair<Nonnull<const Pattern*>, Nonnull<const Statement*>>($2, $4);
|
||||
}
|
||||
{ $$ = std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>($2, $4); }
|
||||
| DEFAULT DOUBLE_ARROW statement
|
||||
{
|
||||
auto vp = arena -> New<BindingPattern>(
|
||||
context.SourceLoc(), std::nullopt,
|
||||
arena->New<AutoPattern>(context.SourceLoc()));
|
||||
$$ =
|
||||
std::pair<Nonnull<const Pattern*>, Nonnull<const Statement*>>(vp, $3);
|
||||
$$ = std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>(vp, $3);
|
||||
}
|
||||
;
|
||||
clause_list:
|
||||
@@ -701,7 +697,7 @@ declaration_list:
|
||||
| declaration_list declaration
|
||||
{
|
||||
$$ = $1;
|
||||
$$.push_back(Nonnull<const Declaration*>($2));
|
||||
$$.push_back(Nonnull<Declaration*>($2));
|
||||
}
|
||||
;
|
||||
%%
|
||||
|
||||
Reference in New Issue
Block a user