diff --git a/executable_semantics/ast/declaration.h b/executable_semantics/ast/declaration.h index 0953c8f9ab59..b4df411cdece 100644 --- a/executable_semantics/ast/declaration.h +++ b/executable_semantics/ast/declaration.h @@ -24,12 +24,15 @@ struct Declaration { DeclarationKind tag; union { struct FunctionDefinition* fun_def; + struct StructDefinition* struct_def; + struct { int line_num; std::string* name; std::list>* alternatives; } choice_def; + } u; }; diff --git a/executable_semantics/ast/expression.h b/executable_semantics/ast/expression.h index e7e0afe05812..ff40931b6d62 100644 --- a/executable_semantics/ast/expression.h +++ b/executable_semantics/ast/expression.h @@ -26,6 +26,7 @@ enum class ExpressionKind { TypeT, Variable, }; + enum class Operator { Add, And, @@ -43,35 +44,44 @@ struct Expression { struct { std::string* name; } variable; + struct { Expression* aggregate; std::string* field; } get_field; + struct { Expression* aggregate; Expression* offset; } index; + struct { std::string* name; Expression* type; } pattern_variable; + int integer; bool boolean; + struct { std::vector>* fields; } tuple; + struct { Operator op; std::vector* arguments; } primitive_op; + struct { Expression* function; Expression* argument; } call; + struct { Expression* parameter; Expression* return_type; } function_type; + } u; }; diff --git a/executable_semantics/ast/statement.h b/executable_semantics/ast/statement.h index 5a6137748d8c..cdefcd030320 100644 --- a/executable_semantics/ast/statement.h +++ b/executable_semantics/ast/statement.h @@ -28,37 +28,47 @@ enum class StatementKind { struct Statement { int line_num; StatementKind tag; + union { Expression* exp; + struct { Expression* lhs; Expression* rhs; } assign; + struct { Expression* pat; Expression* init; } variable_definition; + struct { Expression* cond; Statement* then_stmt; Statement* else_stmt; } if_stmt; + Expression* return_stmt; + struct { Statement* stmt; Statement* next; } sequence; + struct { Statement* stmt; } block; + struct { Expression* cond; Statement* body; } while_stmt; + struct { Expression* exp; std::list>* clauses; } match_stmt; + } u; }; diff --git a/executable_semantics/interpreter/typecheck.cpp b/executable_semantics/interpreter/typecheck.cpp index c452eabebb57..9fa30f631688 100644 --- a/executable_semantics/interpreter/typecheck.cpp +++ b/executable_semantics/interpreter/typecheck.cpp @@ -132,9 +132,26 @@ auto ReifyType(Value* t, int line_num) -> Expression* { } } +// The TypeCheckExp function performs semantic analysis on an expression. +// It returns a new version of the expression, its type, and an +// updated environment which are bundled into a TCResult object. +// The purpose of the updated environment is +// to bring pattern variables into scope, for example, in a match case. +// The new version of the expression may include more information, +// for example, the type arguments deduced for the type parameters of a +// generic. +// +// e is the expression to be analyzed. +// env maps variable names to the type of their run-time value. +// ct_env maps variable names to their compile-time values. It is not +// directly used in this function but is passed to InterExp. +// expected is the type that this expression is expected to have. +// This parameter is non-null when the expression is in a pattern context +// and it is used to implement `auto`, otherwise it is null. +// context says what kind of position this expression is nested in, +// whether it's a position that expects a value, a pattern, or a type. auto TypeCheckExp(Expression* e, TypeEnv* env, Env* ct_env, Value* expected, - TCContext context) - -> TCResult { // expected can be null + TCContext context) -> TCResult { switch (e->tag) { case ExpressionKind::PatternVariable: { if (context != TCContext::PatternContext) { @@ -389,6 +406,13 @@ auto TypecheckCase(Value* expected, Expression* pat, Statement* body, return std::make_pair(pat, res.stmt); } +// The TypeCheckStmt function performs semantic analysis on a statement. +// It returns a new version of the statement and a new type environment. +// +// The ret_type parameter is used for analyzing return statements. +// It is the 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(Statement* s, TypeEnv* env, Env* ct_env, Value* ret_type) -> TCStatement { if (!s) {