From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- gcc/go/gofrontend/expressions.h | 1923 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 1923 insertions(+) create mode 100644 gcc/go/gofrontend/expressions.h (limited to 'gcc/go/gofrontend/expressions.h') diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h new file mode 100644 index 000000000..1dc408d55 --- /dev/null +++ b/gcc/go/gofrontend/expressions.h @@ -0,0 +1,1923 @@ +// 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) -- cgit v1.2.3