// expressions.h -- Go frontend expression handling. -*- C++ -*- // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. #ifndef GO_EXPRESSIONS_H #define GO_EXPRESSIONS_H #include #include #include "operator.h" class Gogo; class Translate_context; class Traverse; class Type; struct Type_context; class Function_type; class Map_type; class Struct_type; class Struct_field; class Expression_list; class Var_expression; class Temporary_reference_expression; class String_expression; class Binary_expression; class Call_expression; class Func_expression; class Unknown_expression; class Index_expression; class Map_index_expression; class Bound_method_expression; class Field_reference_expression; class Interface_field_reference_expression; class Type_guard_expression; class Receive_expression; class Send_expression; class Named_object; class Export; class Import; class Temporary_statement; class Label; // The base class for all expressions. class Expression { public: // The types of expressions. enum Expression_classification { EXPRESSION_ERROR, EXPRESSION_TYPE, EXPRESSION_UNARY, EXPRESSION_BINARY, EXPRESSION_CONST_REFERENCE, EXPRESSION_VAR_REFERENCE, EXPRESSION_TEMPORARY_REFERENCE, EXPRESSION_SINK, EXPRESSION_FUNC_REFERENCE, EXPRESSION_UNKNOWN_REFERENCE, EXPRESSION_BOOLEAN, EXPRESSION_STRING, EXPRESSION_INTEGER, EXPRESSION_FLOAT, EXPRESSION_COMPLEX, EXPRESSION_NIL, EXPRESSION_IOTA, EXPRESSION_CALL, EXPRESSION_CALL_RESULT, EXPRESSION_BOUND_METHOD, EXPRESSION_INDEX, EXPRESSION_ARRAY_INDEX, EXPRESSION_STRING_INDEX, EXPRESSION_MAP_INDEX, EXPRESSION_SELECTOR, EXPRESSION_FIELD_REFERENCE, EXPRESSION_INTERFACE_FIELD_REFERENCE, EXPRESSION_ALLOCATION, EXPRESSION_MAKE, EXPRESSION_TYPE_GUARD, EXPRESSION_CONVERSION, EXPRESSION_STRUCT_CONSTRUCTION, EXPRESSION_FIXED_ARRAY_CONSTRUCTION, EXPRESSION_OPEN_ARRAY_CONSTRUCTION, EXPRESSION_MAP_CONSTRUCTION, EXPRESSION_COMPOSITE_LITERAL, EXPRESSION_HEAP_COMPOSITE, EXPRESSION_RECEIVE, EXPRESSION_SEND, EXPRESSION_TYPE_DESCRIPTOR, EXPRESSION_TYPE_INFO, EXPRESSION_STRUCT_FIELD_OFFSET, EXPRESSION_LABEL_ADDR }; Expression(Expression_classification, source_location); virtual ~Expression(); // Make an error expression. This is used when a parse error occurs // to prevent cascading errors. static Expression* make_error(source_location); // Make an expression which is really a type. This is used during // parsing. static Expression* make_type(Type*, source_location); // Make a unary expression. static Expression* make_unary(Operator, Expression*, source_location); // Make a binary expression. static Expression* make_binary(Operator, Expression*, Expression*, source_location); // Make a reference to a constant in an expression. static Expression* make_const_reference(Named_object*, source_location); // Make a reference to a variable in an expression. static Expression* make_var_reference(Named_object*, source_location); // Make a reference to a temporary variable. Temporary variables // are always created by a single statement, which is what we use to // refer to them. static Expression* make_temporary_reference(Temporary_statement*, source_location); // Make a sink expression--a reference to the blank identifier _. static Expression* make_sink(source_location); // Make a reference to a function in an expression. static Expression* make_func_reference(Named_object*, Expression* closure, source_location); // Make a reference to an unknown name. In a correct program this // will always be lowered to a real const/var/func reference. static Expression* make_unknown_reference(Named_object*, source_location); // Make a constant bool expression. static Expression* make_boolean(bool val, source_location); // Make a constant string expression. static Expression* make_string(const std::string&, source_location); // Make a constant integer expression. TYPE should be NULL for an // abstract type. static Expression* make_integer(const mpz_t*, Type*, source_location); // Make a constant float expression. TYPE should be NULL for an // abstract type. static Expression* make_float(const mpfr_t*, Type*, source_location); // Make a constant complex expression. TYPE should be NULL for an // abstract type. static Expression* make_complex(const mpfr_t* real, const mpfr_t* imag, Type*, source_location); // Make a nil expression. static Expression* make_nil(source_location); // Make an iota expression. This is used for the predeclared // constant iota. static Expression* make_iota(); // Make a call expression. static Call_expression* make_call(Expression* func, Expression_list* args, bool is_varargs, source_location); // Make a reference to a specific result of a call expression which // returns a tuple. static Expression* make_call_result(Call_expression*, unsigned int index); // Make an expression which is a method bound to its first // parameter. static Bound_method_expression* make_bound_method(Expression* object, Expression* method, source_location); // Make an index or slice expression. This is a parser expression // which represents LEFT[START:END]. END may be NULL, meaning an // index rather than a slice. At parse time we may not know the // type of LEFT. After parsing this is lowered to an array index, a // string index, or a map index. static Expression* make_index(Expression* left, Expression* start, Expression* end, source_location); // Make an array index expression. END may be NULL, in which case // this is an lvalue. static Expression* make_array_index(Expression* array, Expression* start, Expression* end, source_location); // Make a string index expression. END may be NULL. This is never // an lvalue. static Expression* make_string_index(Expression* string, Expression* start, Expression* end, source_location); // Make a map index expression. This is an lvalue. static Map_index_expression* make_map_index(Expression* map, Expression* val, source_location); // Make a selector. This is a parser expression which represents // LEFT.NAME. At parse time we may not know the type of the left // hand side. static Expression* make_selector(Expression* left, const std::string& name, source_location); // Make a reference to a field in a struct. static Field_reference_expression* make_field_reference(Expression*, unsigned int field_index, source_location); // Make a reference to a field of an interface, with an associated // object. static Expression* make_interface_field_reference(Expression*, const std::string&, source_location); // Make an allocation expression. static Expression* make_allocation(Type*, source_location); // Make a call to the builtin function make. static Expression* make_make(Type*, Expression_list*, source_location); // Make a type guard expression. static Expression* make_type_guard(Expression*, Type*, source_location); // Make a type cast expression. static Expression* make_cast(Type*, Expression*, source_location); // Make a composite literal. The DEPTH parameter is how far down we // are in a list of composite literals with omitted types. static Expression* make_composite_literal(Type*, int depth, bool has_keys, Expression_list*, source_location); // Make a struct composite literal. static Expression* make_struct_composite_literal(Type*, Expression_list*, source_location); // Make a slice composite literal. static Expression* make_slice_composite_literal(Type*, Expression_list*, source_location); // Take a composite literal and allocate it on the heap. static Expression* make_heap_composite(Expression*, source_location); // Make a receive expression. VAL is NULL for a unary receive. static Receive_expression* make_receive(Expression* channel, source_location); // Make a send expression. static Send_expression* make_send(Expression* channel, Expression* val, source_location); // Make an expression which evaluates to the type descriptor of a // type. static Expression* make_type_descriptor(Type* type, source_location); // Make an expression which evaluates to some characteristic of a // type. These are only used for type descriptors, so there is no // location parameter. enum Type_info { // The size of a value of the type. TYPE_INFO_SIZE, // The required alignment of a value of the type. TYPE_INFO_ALIGNMENT, // The required alignment of a value of the type when used as a // field in a struct. TYPE_INFO_FIELD_ALIGNMENT }; static Expression* make_type_info(Type* type, Type_info); // Make an expression which evaluates to the offset of a field in a // struct. This is only used for type descriptors, so there is no // location parameter. static Expression* make_struct_field_offset(Struct_type*, const Struct_field*); // Make an expression which evaluates to the address of an unnamed // label. static Expression* make_label_addr(Label*, source_location); // Return the expression classification. Expression_classification classification() const { return this->classification_; } // Return the location of the expression. source_location location() const { return this->location_; } // Return whether this is a constant expression. bool is_constant() const { return this->do_is_constant(); } // If this is not a constant expression with integral type, return // false. If it is one, return true, and set VAL to the value. VAL // should already be initialized. If this returns true, it sets // *PTYPE to the type of the value, or NULL for an abstract type. // If IOTA_IS_CONSTANT is true, then an iota expression is assumed // to have its final value. bool integer_constant_value(bool iota_is_constant, mpz_t val, Type** ptype) const; // If this is not a constant expression with floating point type, // return false. If it is one, return true, and set VAL to the // value. VAL should already be initialized. If this returns true, // it sets *PTYPE to the type of the value, or NULL for an abstract // type. bool float_constant_value(mpfr_t val, Type** ptype) const; // If this is not a constant expression with complex type, return // false. If it is one, return true, and set REAL and IMAG to the // value. REAL and IMAG should already be initialized. If this // return strue, it sets *PTYPE to the type of the value, or NULL // for an abstract type. bool complex_constant_value(mpfr_t real, mpfr_t imag, Type** ptype) const; // If this is not a constant expression with string type, return // false. If it is one, return true, and set VAL to the value. bool string_constant_value(std::string* val) const { return this->do_string_constant_value(val); } // This is called by the parser if the value of this expression is // being discarded. This issues warnings about computed values // being unused, and handles send expressions which act differently // depending upon whether the value is used. void discarding_value() { this->do_discarding_value(); } // Return whether this is an error expression. bool is_error_expression() const { return this->classification_ == EXPRESSION_ERROR; } // Return whether this expression really represents a type. bool is_type_expression() const { return this->classification_ == EXPRESSION_TYPE; } // If this is a variable reference, return the Var_expression // structure. Otherwise, return NULL. This is a controlled dynamic // cast. Var_expression* var_expression() { return this->convert(); } const Var_expression* var_expression() const { return this->convert(); } // If this is a reference to a temporary variable, return the // Temporary_reference_expression. Otherwise, return NULL. Temporary_reference_expression* temporary_reference_expression() { return this->convert(); } // Return whether this is a sink expression. bool is_sink_expression() const { return this->classification_ == EXPRESSION_SINK; } // If this is a string expression, return the String_expression // structure. Otherwise, return NULL. String_expression* string_expression() { return this->convert(); } // Return whether this is the expression nil. bool is_nil_expression() const { return this->classification_ == EXPRESSION_NIL; } // If this is an indirection through a pointer, return the // expression being pointed through. Otherwise return this. Expression* deref(); // If this is a binary expression, return the Binary_expression // structure. Otherwise return NULL. Binary_expression* binary_expression() { return this->convert(); } // If this is a call expression, return the Call_expression // structure. Otherwise, return NULL. This is a controlled dynamic // cast. Call_expression* call_expression() { return this->convert(); } // If this is an expression which refers to a function, return the // Func_expression structure. Otherwise, return NULL. Func_expression* func_expression() { return this->convert(); } const Func_expression* func_expression() const { return this->convert(); } // If this is an expression which refers to an unknown name, return // the Unknown_expression structure. Otherwise, return NULL. Unknown_expression* unknown_expression() { return this->convert(); } const Unknown_expression* unknown_expression() const { return this->convert(); } // If this is an index expression, return the Index_expression // structure. Otherwise, return NULL. Index_expression* index_expression() { return this->convert(); } // If this is an expression which refers to indexing in a map, // return the Map_index_expression structure. Otherwise, return // NULL. Map_index_expression* map_index_expression() { return this->convert(); } // If this is a bound method expression, return the // Bound_method_expression structure. Otherwise, return NULL. Bound_method_expression* bound_method_expression() { return this->convert(); } // If this is a reference to a field in a struct, return the // Field_reference_expression structure. Otherwise, return NULL. Field_reference_expression* field_reference_expression() { return this->convert(); } // If this is a reference to a field in an interface, return the // Interface_field_reference_expression structure. Otherwise, // return NULL. Interface_field_reference_expression* interface_field_reference_expression() { return this->convert(); } // If this is a type guard expression, return the // Type_guard_expression structure. Otherwise, return NULL. Type_guard_expression* type_guard_expression() { return this->convert(); } // If this is a receive expression, return the Receive_expression // structure. Otherwise, return NULL. Receive_expression* receive_expression() { return this->convert(); } // Return true if this is a composite literal. bool is_composite_literal() const; // Return true if this is a composite literal which is not constant. bool is_nonconstant_composite_literal() const; // Return true if this is a reference to a local variable. bool is_local_variable() const; // Traverse an expression. static int traverse(Expression**, Traverse*); // Traverse subexpressions of this expression. int traverse_subexpressions(Traverse*); // Lower an expression. This is called immediately after parsing. // IOTA_VALUE is the value that we should give to any iota // expressions. This function must resolve expressions which could // not be fully parsed into their final form. It returns the same // Expression or a new one. Expression* lower(Gogo* gogo, Named_object* function, int iota_value) { return this->do_lower(gogo, function, iota_value); } // Determine the real type of an expression with abstract integer, // floating point, or complex type. TYPE_CONTEXT describes the // expected type. void determine_type(const Type_context*); // Check types in an expression. void check_types(Gogo* gogo) { this->do_check_types(gogo); } // Determine the type when there is no context. void determine_type_no_context(); // Return the current type of the expression. This may be changed // by determine_type. Type* type() { return this->do_type(); } // Return a copy of an expression. Expression* copy() { return this->do_copy(); } // Return whether the expression is addressable--something which may // be used as the operand of the unary & operator. bool is_addressable() const { return this->do_is_addressable(); } // Note that we are taking the address of this expression. ESCAPES // is true if this address escapes the current function. void address_taken(bool escapes) { this->do_address_taken(escapes); } // Return whether this expression must be evaluated in order // according to the order of evaluation rules. This is basically // true of all expressions with side-effects. bool must_eval_in_order() const { return this->do_must_eval_in_order(); } // Return the tree for this expression. tree get_tree(Translate_context*); // Return a tree handling any conversions which must be done during // assignment. static tree convert_for_assignment(Translate_context*, Type* lhs_type, Type* rhs_type, tree rhs_tree, source_location location); // Return a tree converting a value of one interface type to another // interface type. If FOR_TYPE_GUARD is true this is for a type // assertion. static tree convert_interface_to_interface(Translate_context*, Type* lhs_type, Type* rhs_type, tree rhs_tree, bool for_type_guard, source_location); // Return a tree implementing the comparison LHS_TREE OP RHS_TREE. // TYPE is the type of both sides. static tree comparison_tree(Translate_context*, Operator op, Type* left_type, tree left_tree, Type* right_type, tree right_tree, source_location); // Return a tree for the multi-precision integer VAL in TYPE. static tree integer_constant_tree(mpz_t val, tree type); // Return a tree for the floating point value VAL in TYPE. static tree float_constant_tree(mpfr_t val, tree type); // Return a tree for the complex value REAL/IMAG in TYPE. static tree complex_constant_tree(mpfr_t real, mpfr_t imag, tree type); // Export the expression. This is only used for constants. It will // be used for things like values of named constants and sizes of // arrays. void export_expression(Export* exp) const { this->do_export(exp); } // Import an expression. static Expression* import_expression(Import*); // Return a tree which checks that VAL, of arbitrary integer type, // is non-negative and is not more than the maximum value of // BOUND_TYPE. If SOFAR is not NULL, it is or'red into the result. // The return value may be NULL if SOFAR is NULL. static tree check_bounds(tree val, tree bound_type, tree sofar, source_location); protected: // May be implemented by child class: traverse the expressions. virtual int do_traverse(Traverse*); // Return a lowered expression. virtual Expression* do_lower(Gogo*, Named_object*, int) { return this; } // Return whether this is a constant expression. virtual bool do_is_constant() const { return false; } // Return whether this is a constant expression of integral type, // and set VAL to the value. virtual bool do_integer_constant_value(bool, mpz_t, Type**) const { return false; } // Return whether this is a constant expression of floating point // type, and set VAL to the value. virtual bool do_float_constant_value(mpfr_t, Type**) const { return false; } // Return whether this is a constant expression of complex type, and // set REAL and IMAGE to the value. virtual bool do_complex_constant_value(mpfr_t, mpfr_t, Type**) const { return false; } // Return whether this is a constant expression of string type, and // set VAL to the value. virtual bool do_string_constant_value(std::string*) const { return false; } // Called by the parser if the value is being discarded. virtual void do_discarding_value(); // Child class holds type. virtual Type* do_type() = 0; // Child class implements determining type information. virtual void do_determine_type(const Type_context*) = 0; // Child class implements type checking if needed. virtual void do_check_types(Gogo*) { } // Child class implements copying. virtual Expression* do_copy() = 0; // Child class implements whether the expression is addressable. virtual bool do_is_addressable() const { return false; } // Child class implements taking the address of an expression. virtual void do_address_taken(bool) { } // Child class implements whether this expression must be evaluated // in order. virtual bool do_must_eval_in_order() const { return false; } // Child class implements conversion to tree. virtual tree do_get_tree(Translate_context*) = 0; // Child class implements export. virtual void do_export(Export*) const; // For children to call to warn about an unused value. void warn_about_unused_value(); // For children to call when they detect that they are in error. void set_is_error(); // For children to call to report an error conveniently. void report_error(const char*); private: // Convert to the desired statement classification, or return NULL. // This is a controlled dynamic cast. template Expression_class* convert() { return (this->classification_ == expr_classification ? static_cast(this) : NULL); } template const Expression_class* convert() const { return (this->classification_ == expr_classification ? static_cast(this) : NULL); } static tree convert_type_to_interface(Translate_context*, Type*, Type*, tree, source_location); static tree get_interface_type_descriptor(Translate_context*, Type*, tree, source_location); static tree convert_interface_to_type(Translate_context*, Type*, Type*, tree, source_location); // The expression classification. Expression_classification classification_; // The location in the input file. source_location location_; }; // A list of Expressions. class Expression_list { public: Expression_list() : entries_() { } // Return whether the list is empty. bool empty() const { return this->entries_.empty(); } // Return the number of entries in the list. size_t size() const { return this->entries_.size(); } // Add an entry to the end of the list. void push_back(Expression* expr) { this->entries_.push_back(expr); } void append(Expression_list* add) { this->entries_.insert(this->entries_.end(), add->begin(), add->end()); } // Reserve space in the list. void reserve(size_t size) { this->entries_.reserve(size); } // Traverse the expressions in the list. int traverse(Traverse*); // Copy the list. Expression_list* copy(); // Return true if the list contains an error expression. bool contains_error() const; // Return the first and last elements. Expression*& front() { return this->entries_.front(); } Expression* front() const { return this->entries_.front(); } Expression*& back() { return this->entries_.back(); } Expression* back() const { return this->entries_.back(); } // Iterators. typedef std::vector::iterator iterator; typedef std::vector::const_iterator const_iterator; iterator begin() { return this->entries_.begin(); } const_iterator begin() const { return this->entries_.begin(); } iterator end() { return this->entries_.end(); } const_iterator end() const { return this->entries_.end(); } // Erase an entry. void erase(iterator p) { this->entries_.erase(p); } private: std::vector entries_; }; // An abstract base class for an expression which is only used by the // parser, and is lowered in the lowering pass. class Parser_expression : public Expression { public: Parser_expression(Expression_classification classification, source_location location) : Expression(classification, location) { } protected: virtual Expression* do_lower(Gogo*, Named_object*, int) = 0; Type* do_type(); void do_determine_type(const Type_context*) { gcc_unreachable(); } void do_check_types(Gogo*) { gcc_unreachable(); } tree do_get_tree(Translate_context*) { gcc_unreachable(); } }; // An expression which is simply a variable. class Var_expression : public Expression { public: Var_expression(Named_object* variable, source_location location) : Expression(EXPRESSION_VAR_REFERENCE, location), variable_(variable) { } // Return the variable. Named_object* named_object() const { return this->variable_; } protected: Expression* do_lower(Gogo*, Named_object*, int); Type* do_type(); void do_determine_type(const Type_context*); Expression* do_copy() { return this; } bool do_is_addressable() const { return true; } void do_address_taken(bool); tree do_get_tree(Translate_context*); private: // The variable we are referencing. Named_object* variable_; }; // A reference to a temporary variable. class Temporary_reference_expression : public Expression { public: Temporary_reference_expression(Temporary_statement* statement, source_location location) : Expression(EXPRESSION_TEMPORARY_REFERENCE, location), statement_(statement) { } protected: Type* do_type(); void do_determine_type(const Type_context*) { } Expression* do_copy() { return make_temporary_reference(this->statement_, this->location()); } bool do_is_addressable() const { return true; } void do_address_taken(bool); tree do_get_tree(Translate_context*); private: // The statement where the temporary variable is defined. Temporary_statement* statement_; }; // A string expression. class String_expression : public Expression { public: String_expression(const std::string& val, source_location location) : Expression(EXPRESSION_STRING, location), val_(val), type_(NULL) { } const std::string& val() const { return this->val_; } static Expression* do_import(Import*); protected: bool do_is_constant() const { return true; } bool do_string_constant_value(std::string* val) const { *val = this->val_; return true; } Type* do_type(); void do_determine_type(const Type_context*); Expression* do_copy() { return this; } tree do_get_tree(Translate_context*); void do_export(Export*) const; private: // The string value. This is immutable. const std::string val_; // The type as determined by context. Type* type_; }; // A binary expression. class Binary_expression : public Expression { public: Binary_expression(Operator op, Expression* left, Expression* right, source_location location) : Expression(EXPRESSION_BINARY, location), op_(op), left_(left), right_(right) { } // Return the operator. Operator op() { return this->op_; } // Return the left hand expression. Expression* left() { return this->left_; } // Return the right hand expression. Expression* right() { return this->right_; } // Apply binary opcode OP to LEFT_VAL and RIGHT_VAL, setting VAL. // LEFT_TYPE is the type of LEFT_VAL, RIGHT_TYPE is the type of // RIGHT_VAL; LEFT_TYPE and/or RIGHT_TYPE may be NULL. Return true // if this could be done, false if not. static bool eval_integer(Operator op, Type* left_type, mpz_t left_val, Type* right_type, mpz_t right_val, source_location, mpz_t val); // Apply binary opcode OP to LEFT_VAL and RIGHT_VAL, setting VAL. // Return true if this could be done, false if not. static bool eval_float(Operator op, Type* left_type, mpfr_t left_val, Type* right_type, mpfr_t right_val, mpfr_t val, source_location); // Apply binary opcode OP to LEFT_REAL/LEFT_IMAG and // RIGHT_REAL/RIGHT_IMAG, setting REAL/IMAG. Return true if this // could be done, false if not. static bool eval_complex(Operator op, Type* left_type, mpfr_t left_real, mpfr_t left_imag, Type* right_type, mpfr_t right_real, mpfr_t right_imag, mpfr_t real, mpfr_t imag, source_location); // Compare integer constants according to OP. static bool compare_integer(Operator op, mpz_t left_val, mpz_t right_val); // Compare floating point constants according to OP. static bool compare_float(Operator op, Type* type, mpfr_t left_val, mpfr_t right_val); // Compare complex constants according to OP. static bool compare_complex(Operator op, Type* type, mpfr_t left_real, mpfr_t left_imag, mpfr_t right_val, mpfr_t right_imag); static Expression* do_import(Import*); // Report an error if OP can not be applied to TYPE. Return whether // it can. static bool check_operator_type(Operator op, Type* type, source_location); protected: int do_traverse(Traverse* traverse); Expression* do_lower(Gogo*, Named_object*, int); bool do_is_constant() const { return this->left_->is_constant() && this->right_->is_constant(); } bool do_integer_constant_value(bool, mpz_t val, Type**) const; bool do_float_constant_value(mpfr_t val, Type**) const; bool do_complex_constant_value(mpfr_t real, mpfr_t imag, Type**) const; void do_discarding_value(); Type* do_type(); void do_determine_type(const Type_context*); void do_check_types(Gogo*); Expression* do_copy() { return Expression::make_binary(this->op_, this->left_->copy(), this->right_->copy(), this->location()); } tree do_get_tree(Translate_context*); void do_export(Export*) const; private: // The binary operator to apply. Operator op_; // The left hand side operand. Expression* left_; // The right hand side operand. Expression* right_; }; // A call expression. The go statement needs to dig inside this. class Call_expression : public Expression { public: Call_expression(Expression* fn, Expression_list* args, bool is_varargs, source_location location) : Expression(EXPRESSION_CALL, location), fn_(fn), args_(args), type_(NULL), tree_(NULL), is_varargs_(is_varargs), varargs_are_lowered_(false), types_are_determined_(false), is_deferred_(false) { } // The function to call. Expression* fn() const { return this->fn_; } // The arguments. Expression_list* args() { return this->args_; } const Expression_list* args() const { return this->args_; } // Get the function type. Function_type* get_function_type() const; // Return the number of values this call will return. size_t result_count() const; // Return whether this is a call to the predeclared function // recover. bool is_recover_call() const; // Set the argument for a call to recover. void set_recover_arg(Expression*); // Whether the last argument is a varargs argument (f(a...)). bool is_varargs() const { return this->is_varargs_; } // Whether this call is being deferred. bool is_deferred() const { return this->is_deferred_; } // Note that the call is being deferred. void set_is_deferred() { this->is_deferred_ = true; } protected: int do_traverse(Traverse*); virtual Expression* do_lower(Gogo*, Named_object*, int); void do_discarding_value() { } virtual Type* do_type(); virtual void do_determine_type(const Type_context*); virtual void do_check_types(Gogo*); Expression* do_copy() { return Expression::make_call(this->fn_->copy(), (this->args_ == NULL ? NULL : this->args_->copy()), this->is_varargs_, this->location()); } bool do_must_eval_in_order() const; virtual tree do_get_tree(Translate_context*); virtual bool do_is_recover_call() const; virtual void do_set_recover_arg(Expression*); // Let a builtin expression change the argument list. void set_args(Expression_list* args) { this->args_ = args; } // Let a builtin expression lower varargs. Expression* lower_varargs(Gogo*, Named_object* function, Type* varargs_type, size_t param_count); // Let a builtin expression check whether types have been // determined. bool determining_types(); private: bool check_argument_type(int, const Type*, const Type*, source_location, bool); tree bound_method_function(Translate_context*, Bound_method_expression*, tree*); tree interface_method_function(Translate_context*, Interface_field_reference_expression*, tree*); // The function to call. Expression* fn_; // The arguments to pass. This may be NULL if there are no // arguments. Expression_list* args_; // The type of the expression, to avoid recomputing it. Type* type_; // The tree for the call, used for a call which returns a tuple. tree tree_; // True if the last argument is a varargs argument (f(a...)). bool is_varargs_; // True if varargs have already been lowered. bool varargs_are_lowered_; // True if types have been determined. bool types_are_determined_; // True if the call is an argument to a defer statement. bool is_deferred_; }; // An expression which represents a pointer to a function. class Func_expression : public Expression { public: Func_expression(Named_object* function, Expression* closure, source_location location) : Expression(EXPRESSION_FUNC_REFERENCE, location), function_(function), closure_(closure) { } // Return the object associated with the function. const Named_object* named_object() const { return this->function_; } // Return the closure for this function. This will return NULL if // the function has no closure, which is the normal case. Expression* closure() { return this->closure_; } // Return a tree for this function without evaluating the closure. tree get_tree_without_closure(Gogo*); protected: int do_traverse(Traverse*); Type* do_type(); void do_determine_type(const Type_context*) { if (this->closure_ != NULL) this->closure_->determine_type_no_context(); } Expression* do_copy() { return Expression::make_func_reference(this->function_, (this->closure_ == NULL ? NULL : this->closure_->copy()), this->location()); } tree do_get_tree(Translate_context*); private: // The function itself. Named_object* function_; // A closure. This is normally NULL. For a nested function, it may // be a heap-allocated struct holding pointers to all the variables // referenced by this function and defined in enclosing functions. Expression* closure_; }; // A reference to an unknown name. class Unknown_expression : public Parser_expression { public: Unknown_expression(Named_object* named_object, source_location location) : Parser_expression(EXPRESSION_UNKNOWN_REFERENCE, location), named_object_(named_object), is_composite_literal_key_(false) { } // The associated named object. Named_object* named_object() const { return this->named_object_; } // The name of the identifier which was unknown. const std::string& name() const; // Note that this expression is being used as the key in a composite // literal, so it may be OK if it is not resolved. void set_is_composite_literal_key() { this->is_composite_literal_key_ = true; } // Note that this expression should no longer be treated as a // composite literal key. void clear_is_composite_literal_key() { this->is_composite_literal_key_ = false; } protected: Expression* do_lower(Gogo*, Named_object*, int); Expression* do_copy() { return new Unknown_expression(this->named_object_, this->location()); } private: // The unknown name. Named_object* named_object_; // True if this is the key in a composite literal. bool is_composite_literal_key_; }; // An index expression. This is lowered to an array index, a string // index, or a map index. class Index_expression : public Parser_expression { public: Index_expression(Expression* left, Expression* start, Expression* end, source_location location) : Parser_expression(EXPRESSION_INDEX, location), left_(left), start_(start), end_(end), is_lvalue_(false) { } // Record that this expression is an lvalue. void set_is_lvalue() { this->is_lvalue_ = true; } protected: int do_traverse(Traverse*); Expression* do_lower(Gogo*, Named_object*, int); Expression* do_copy() { return new Index_expression(this->left_->copy(), this->start_->copy(), (this->end_ == NULL ? NULL : this->end_->copy()), this->location()); } private: // The expression being indexed. Expression* left_; // The first index. Expression* start_; // The second index. This is NULL for an index, non-NULL for a // slice. Expression* end_; // Whether this is being used as an l-value. We set this during the // parse because map index expressions need to know. bool is_lvalue_; }; // An index into a map. class Map_index_expression : public Expression { public: Map_index_expression(Expression* map, Expression* index, source_location location) : Expression(EXPRESSION_MAP_INDEX, location), map_(map), index_(index), is_lvalue_(false), is_in_tuple_assignment_(false) { } // Return the map. Expression* map() { return this->map_; } const Expression* map() const { return this->map_; } // Return the index. Expression* index() { return this->index_; } const Expression* index() const { return this->index_; } // Get the type of the map being indexed. Map_type* get_map_type() const; // Record that this map expression is an lvalue. The difference is // that an lvalue always inserts the key. void set_is_lvalue() { this->is_lvalue_ = true; } // Return whether this map expression occurs in an assignment to a // pair of values. bool is_in_tuple_assignment() const { return this->is_in_tuple_assignment_; } // Record that this map expression occurs in an assignment to a pair // of values. void set_is_in_tuple_assignment() { this->is_in_tuple_assignment_ = true; } // Return a tree for the map index. This returns a tree which // evaluates to a pointer to a value in the map. If INSERT is true, // the key will be inserted if not present, and the value pointer // will be zero initialized. If INSERT is false, and the key is not // present in the map, the pointer will be NULL. tree get_value_pointer(Translate_context*, bool insert); protected: int do_traverse(Traverse*); Type* do_type(); void do_determine_type(const Type_context*); void do_check_types(Gogo*); Expression* do_copy() { return Expression::make_map_index(this->map_->copy(), this->index_->copy(), this->location()); } // A map index expression is an lvalue but it is not addressable. tree do_get_tree(Translate_context*); private: // The map we are looking into. Expression* map_; // The index. Expression* index_; // Whether this is an lvalue. bool is_lvalue_; // Whether this is in a tuple assignment to a pair of values. bool is_in_tuple_assignment_; }; // An expression which represents a method bound to its first // argument. class Bound_method_expression : public Expression { public: Bound_method_expression(Expression* expr, Expression* method, source_location location) : Expression(EXPRESSION_BOUND_METHOD, location), expr_(expr), expr_type_(NULL), method_(method) { } // Return the object which is the first argument. Expression* first_argument() { return this->expr_; } // Return the implicit type of the first argument. This will be // non-NULL when using a method from an anonymous field without // using an explicit stub. Type* first_argument_type() const { return this->expr_type_; } // Return the reference to the method function. Expression* method() { return this->method_; } // Set the implicit type of the expression. void set_first_argument_type(Type* type) { this->expr_type_ = type; } protected: int do_traverse(Traverse*); Type* do_type(); void do_determine_type(const Type_context*); void do_check_types(Gogo*); Expression* do_copy() { return new Bound_method_expression(this->expr_->copy(), this->method_->copy(), this->location()); } tree do_get_tree(Translate_context*); private: // The object used to find the method. This is passed to the method // as the first argument. Expression* expr_; // The implicit type of the object to pass to the method. This is // NULL in the normal case, non-NULL when using a method from an // anonymous field which does not require a stub. Type* expr_type_; // The method itself. This is a Func_expression. Expression* method_; }; // A reference to a field in a struct. class Field_reference_expression : public Expression { public: Field_reference_expression(Expression* expr, unsigned int field_index, source_location location) : Expression(EXPRESSION_FIELD_REFERENCE, location), expr_(expr), field_index_(field_index) { } // Return the struct expression. Expression* expr() const { return this->expr_; } // Return the field index. unsigned int field_index() const { return this->field_index_; } // Set the struct expression. This is used when parsing. void set_struct_expression(Expression* expr) { gcc_assert(this->expr_ == NULL); this->expr_ = expr; } protected: int do_traverse(Traverse* traverse) { return Expression::traverse(&this->expr_, traverse); } Type* do_type(); void do_determine_type(const Type_context*) { this->expr_->determine_type_no_context(); } void do_check_types(Gogo*); Expression* do_copy() { return Expression::make_field_reference(this->expr_->copy(), this->field_index_, this->location()); } bool do_is_addressable() const { return this->expr_->is_addressable(); } tree do_get_tree(Translate_context*); private: // The expression we are looking into. This should have a type of // struct. Expression* expr_; // The zero-based index of the field we are retrieving. unsigned int field_index_; }; // A reference to a field of an interface. class Interface_field_reference_expression : public Expression { public: Interface_field_reference_expression(Expression* expr, const std::string& name, source_location location) : Expression(EXPRESSION_INTERFACE_FIELD_REFERENCE, location), expr_(expr), name_(name) { } // Return the expression for the interface object. Expression* expr() { return this->expr_; } // Return the name of the method to call. const std::string& name() const { return this->name_; } // Return a tree for the pointer to the function to call, given a // tree for the expression. tree get_function_tree(Translate_context*, tree); // Return a tree for the first argument to pass to the interface // function, given a tree for the expression. This is the real // object associated with the interface object. tree get_underlying_object_tree(Translate_context*, tree); protected: int do_traverse(Traverse* traverse); Type* do_type(); void do_determine_type(const Type_context*); void do_check_types(Gogo*); Expression* do_copy() { return Expression::make_interface_field_reference(this->expr_->copy(), this->name_, this->location()); } tree do_get_tree(Translate_context*); private: // The expression for the interface object. This should have a type // of interface or pointer to interface. Expression* expr_; // The field we are retrieving--the name of the method. std::string name_; }; // A type guard expression. class Type_guard_expression : public Expression { public: Type_guard_expression(Expression* expr, Type* type, source_location location) : Expression(EXPRESSION_TYPE_GUARD, location), expr_(expr), type_(type) { } // Return the expression to convert. Expression* expr() { return this->expr_; } // Return the type to which to convert. Type* type() { return this->type_; } protected: int do_traverse(Traverse* traverse); Type* do_type() { return this->type_; } void do_determine_type(const Type_context*) { this->expr_->determine_type_no_context(); } void do_check_types(Gogo*); Expression* do_copy() { return new Type_guard_expression(this->expr_->copy(), this->type_, this->location()); } tree do_get_tree(Translate_context*); private: // The expression to convert. Expression* expr_; // The type to which to convert. Type* type_; }; // A receive expression. class Receive_expression : public Expression { public: Receive_expression(Expression* channel, source_location location) : Expression(EXPRESSION_RECEIVE, location), channel_(channel), is_value_discarded_(false), for_select_(false) { } // Return the channel. Expression* channel() { return this->channel_; } // Note that this is for a select statement. void set_for_select() { this->for_select_ = true; } protected: int do_traverse(Traverse* traverse) { return Expression::traverse(&this->channel_, traverse); } void do_discarding_value() { this->is_value_discarded_ = true; } Type* do_type(); void do_determine_type(const Type_context*) { this->channel_->determine_type_no_context(); } void do_check_types(Gogo*); Expression* do_copy() { return Expression::make_receive(this->channel_->copy(), this->location()); } bool do_must_eval_in_order() const { return true; } tree do_get_tree(Translate_context*); private: // The channel from which we are receiving. Expression* channel_; // Whether the value is being discarded. bool is_value_discarded_; // Whether this is for a select statement. bool for_select_; }; // A send expression. class Send_expression : public Expression { public: Send_expression(Expression* channel, Expression* val, source_location location) : Expression(EXPRESSION_SEND, location), channel_(channel), val_(val), is_value_discarded_(false), for_select_(false) { } // Note that this is for a select statement. void set_for_select() { this->for_select_ = true; } protected: int do_traverse(Traverse* traverse); void do_discarding_value() { this->is_value_discarded_ = true; } Type* do_type(); void do_determine_type(const Type_context*); void do_check_types(Gogo*); Expression* do_copy() { return Expression::make_send(this->channel_->copy(), this->val_->copy(), this->location()); } bool do_must_eval_in_order() const { return true; } tree do_get_tree(Translate_context*); private: // The channel on which to send the value. Expression* channel_; // The value to send. Expression* val_; // Whether the value is being discarded. bool is_value_discarded_; // Whether this is for a select statement. bool for_select_; }; #endif // !defined(GO_EXPRESSIONS_H)