this->register_builtin_type(gogo, "bool", BUILTIN_BOOL);
this->register_builtin_type(gogo, "string", BUILTIN_STRING);
this->register_builtin_type(gogo, "error", BUILTIN_ERROR);
+ this->register_builtin_type(gogo, "byte", BUILTIN_BYTE);
+ this->register_builtin_type(gogo, "rune", BUILTIN_RUNE);
}
// Register one builtin type in the export table.
go_assert(ins.second);
// We also insert the underlying type. We can see the underlying
- // type at least for string and bool.
- Type* real_type = named_object->type_value()->real_type();
- ins = this->type_refs_.insert(std::make_pair(real_type, code));
- go_assert(ins.second);
+ // type at least for string and bool. We skip the type aliases byte
+ // and rune here.
+ if (code != BUILTIN_BYTE && code != BUILTIN_RUNE)
+ {
+ Type* real_type = named_object->type_value()->real_type();
+ ins = this->type_refs_.insert(std::make_pair(real_type, code));
+ go_assert(ins.second);
+ }
}
// Class Export::Stream.
BUILTIN_COMPLEX64 = -17,
BUILTIN_COMPLEX128 = -18,
BUILTIN_ERROR = -19,
+ BUILTIN_BYTE = -20,
+ BUILTIN_RUNE = -21,
- SMALLEST_BUILTIN_CODE = -19
+ SMALLEST_BUILTIN_CODE = -21
};
// This class manages exporting Go declarations. It handles the main
class Integer_expression : public Expression
{
public:
- Integer_expression(const mpz_t* val, Type* type, Location location)
+ Integer_expression(const mpz_t* val, Type* type, bool is_character_constant,
+ Location location)
: Expression(EXPRESSION_INTEGER, location),
- type_(type)
+ type_(type), is_character_constant_(is_character_constant)
{ mpz_init_set(this->val_, *val); }
static Expression*
Expression*
do_copy()
- { return Expression::make_integer(&this->val_, this->type_,
- this->location()); }
+ {
+ if (this->is_character_constant_)
+ return Expression::make_character(&this->val_, this->type_,
+ this->location());
+ else
+ return Expression::make_integer(&this->val_, this->type_,
+ this->location());
+ }
void
do_export(Export*) const;
mpz_t val_;
// The type so far.
Type* type_;
+ // Whether this is a character constant.
+ bool is_character_constant_;
};
// Return an integer constant value.
Integer_expression::do_type()
{
if (this->type_ == NULL)
- this->type_ = Type::make_abstract_integer_type();
+ {
+ if (this->is_character_constant_)
+ this->type_ = Type::make_abstract_character_type();
+ else
+ this->type_ = Type::make_abstract_integer_type();
+ }
return this->type_;
}
|| context->type->complex_type() != NULL))
this->type_ = context->type;
else if (!context->may_be_abstract)
- this->type_ = Type::lookup_integer_type("int");
+ {
+ if (this->is_character_constant_)
+ this->type_ = Type::lookup_integer_type("int32");
+ else
+ this->type_ = Type::lookup_integer_type("int");
+ }
}
// Return true if the integer VAL fits in the range of the type TYPE.
Integer_expression::do_export(Export* exp) const
{
Integer_expression::export_integer(exp, this->val_);
+ if (this->is_character_constant_)
+ exp->write_c_string("'");
// A trailing space lets us reliably identify the end of the number.
exp->write_c_string(" ");
}
else if (num.find('.') == std::string::npos
&& num.find('E') == std::string::npos)
{
+ bool is_character_constant = (!num.empty()
+ && num[num.length() - 1] == '\'');
+ if (is_character_constant)
+ num = num.substr(0, num.length() - 1);
mpz_t val;
if (mpz_init_set_str(val, num.c_str(), 10) != 0)
{
num.c_str());
return Expression::make_error(imp->location());
}
- Expression* ret = Expression::make_integer(&val, NULL, imp->location());
+ Expression* ret;
+ if (is_character_constant)
+ ret = Expression::make_character(&val, NULL, imp->location());
+ else
+ ret = Expression::make_integer(&val, NULL, imp->location());
mpz_clear(val);
return ret;
}
void
Integer_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
{
+ if (this->is_character_constant_)
+ ast_dump_context->ostream() << '\'';
Integer_expression::export_integer(ast_dump_context, this->val_);
+ if (this->is_character_constant_)
+ ast_dump_context->ostream() << '\'';
}
// Build a new integer value.
Expression*
-Expression::make_integer(const mpz_t* val, Type* type,
- Location location)
+Expression::make_integer(const mpz_t* val, Type* type, Location location)
+{
+ return new Integer_expression(val, type, false, location);
+}
+
+// Build a new character constant value.
+
+Expression*
+Expression::make_character(const mpz_t* val, Type* type, Location location)
{
- return new Integer_expression(val, type, location);
+ return new Integer_expression(val, type, true, location);
}
// Floats.
static Expression*
make_string(const std::string&, Location);
+ // Make a character constant expression. TYPE should be NULL for an
+ // abstract type.
+ static Expression*
+ make_character(const mpz_t*, Type*, Location);
+
// Make a constant integer expression. TYPE should be NULL for an
// abstract type.
static Expression*
RUNTIME_TYPE_KIND_INT8));
this->add_named_type(Type::make_integer_type("int16", false, 16,
RUNTIME_TYPE_KIND_INT16));
- this->add_named_type(Type::make_integer_type("int32", false, 32,
- RUNTIME_TYPE_KIND_INT32));
+ Named_type* int32_type = Type::make_integer_type("int32", false, 32,
+ RUNTIME_TYPE_KIND_INT32);
+ this->add_named_type(int32_type);
this->add_named_type(Type::make_integer_type("int64", false, 64,
RUNTIME_TYPE_KIND_INT64));
RUNTIME_TYPE_KIND_INT);
this->add_named_type(int_type);
- // "byte" is an alias for "uint8". Construct a Named_object which
- // points to UINT8_TYPE. Note that this breaks the normal pairing
- // in which a Named_object points to a Named_type which points back
- // to the same Named_object.
- Named_object* byte_type = this->declare_type("byte", loc);
- byte_type->set_type_value(uint8_type);
- uint8_type->integer_type()->set_is_byte();
-
- // "rune" is an alias for "int".
- Named_object* rune_type = this->declare_type("rune", loc);
- rune_type->set_type_value(int_type);
- int_type->integer_type()->set_is_rune();
-
this->add_named_type(Type::make_integer_type("uintptr", true,
pointer_size,
RUNTIME_TYPE_KIND_UINTPTR));
+ // "byte" is an alias for "uint8".
+ uint8_type->integer_type()->set_is_byte();
+ Named_object* byte_type = Named_object::make_type("byte", NULL, uint8_type,
+ loc);
+ this->add_named_type(byte_type->type_value());
+
+ // "rune" is an alias for "int32".
+ int32_type->integer_type()->set_is_rune();
+ Named_object* rune_type = Named_object::make_type("rune", NULL, int32_type,
+ loc);
+ this->add_named_type(rune_type->type_value());
+
this->add_named_type(Type::make_named_bool_type());
this->add_named_type(Type::make_named_string_type());
return t->deref()->array_type()->element_type();
}
else if (t->is_string_type())
- return Type::lookup_integer_type("int");
+ {
+ if (get_index_type)
+ return Type::lookup_integer_type("int");
+ else
+ return Type::lookup_integer_type("int32");
+ }
else if (t->map_type() != NULL)
{
if (get_index_type)
this->register_builtin_type(gogo, "bool", BUILTIN_BOOL);
this->register_builtin_type(gogo, "string", BUILTIN_STRING);
this->register_builtin_type(gogo, "error", BUILTIN_ERROR);
+ this->register_builtin_type(gogo, "byte", BUILTIN_BYTE);
+ this->register_builtin_type(gogo, "rune", BUILTIN_RUNE);
}
// Register a single builtin type.
void
Token::clear()
{
- if (this->classification_ == TOKEN_INTEGER)
+ if (this->classification_ == TOKEN_INTEGER
+ || this->classification_ == TOKEN_CHARACTER)
mpz_clear(this->u_.integer_value);
else if (this->classification_ == TOKEN_FLOAT
|| this->classification_ == TOKEN_IMAGINARY)
case TOKEN_OPERATOR:
this->u_.op = tok.u_.op;
break;
+ case TOKEN_CHARACTER:
case TOKEN_INTEGER:
mpz_init_set(this->u_.integer_value, tok.u_.integer_value);
break;
case TOKEN_OPERATOR:
this->u_.op = tok.u_.op;
break;
+ case TOKEN_CHARACTER:
case TOKEN_INTEGER:
mpz_init_set(this->u_.integer_value, tok.u_.integer_value);
break;
case TOKEN_STRING:
fprintf(file, "quoted string \"%s\"", this->u_.string_value->c_str());
break;
+ case TOKEN_CHARACTER:
+ fprintf(file, "character ");
+ mpz_out_str(file, 10, this->u_.integer_value);
+ break;
case TOKEN_INTEGER:
fprintf(file, "integer ");
mpz_out_str(file, 10, this->u_.integer_value);
Location location = this->location();
this->lineoff_ = p + 1 - this->linebuf_;
- Token ret = Token::make_integer_token(val, location);
+ Token ret = Token::make_character_token(val, location);
mpz_clear(val);
return ret;
}
TOKEN_STRING,
// Token is an operator.
TOKEN_OPERATOR,
+ // Token is a character constant.
+ TOKEN_CHARACTER,
// Token is an integer.
TOKEN_INTEGER,
// Token is a floating point number.
return tok;
}
+ // Make a character constant token.
+ static Token
+ make_character_token(mpz_t val, Location location)
+ {
+ Token tok(TOKEN_CHARACTER, location);
+ mpz_init(tok.u_.integer_value);
+ mpz_swap(tok.u_.integer_value, val);
+ return tok;
+ }
+
// Make an integer token.
static Token
make_integer_token(mpz_t val, Location location)
return *this->u_.string_value;
}
+ // Return the value of a character constant.
+ const mpz_t*
+ character_value() const
+ {
+ go_assert(this->classification_ == TOKEN_CHARACTER);
+ return &this->u_.integer_value;
+ }
+
// Return the value of an integer.
const mpz_t*
integer_value() const
} identifier_value;
// The string value for TOKEN_STRING.
std::string* string_value;
- // The token value for TOKEN_INTEGER.
+ // The token value for TOKEN_CHARACTER or TOKEN_INTEGER.
mpz_t integer_value;
// The token value for TOKEN_FLOAT or TOKEN_IMAGINARY.
mpfr_t float_value;
this->advance_token();
return ret;
+ case Token::TOKEN_CHARACTER:
+ ret = Expression::make_character(token->character_value(), NULL,
+ token->location());
+ this->advance_token();
+ return ret;
+
case Token::TOKEN_INTEGER:
ret = Expression::make_integer(token->integer_value(), NULL,
token->location());
default:
return false;
}
+ case Token::TOKEN_CHARACTER:
case Token::TOKEN_INTEGER:
case Token::TOKEN_FLOAT:
case Token::TOKEN_IMAGINARY:
break;
case Token::TOKEN_STRING:
+ case Token::TOKEN_CHARACTER:
case Token::TOKEN_INTEGER:
case Token::TOKEN_FLOAT:
case Token::TOKEN_IMAGINARY:
return this->expression_may_start_here();
case Token::TOKEN_STRING:
+ case Token::TOKEN_CHARACTER:
case Token::TOKEN_INTEGER:
case Token::TOKEN_FLOAT:
case Token::TOKEN_IMAGINARY:
RFT_UINT64,
// Go type uintptr, C type uintptr_t.
RFT_UINTPTR,
+ // Go type rune, C type int32_t.
+ RFT_RUNE,
// Go type float64, C type double.
RFT_FLOAT64,
// Go type complex128, C type __complex double.
t = Type::lookup_integer_type("uint64");
break;
+ case RFT_RUNE:
+ t = Type::lookup_integer_type("int32");
+ break;
+
case RFT_UINTPTR:
t = Type::lookup_integer_type("uintptr");
break;
case RFT_INT64:
case RFT_UINT64:
case RFT_UINTPTR:
+ case RFT_RUNE:
case RFT_FLOAT64:
case RFT_COMPLEX128:
case RFT_STRING:
// Range over a string, returning the next index and character.
DEF_GO_RUNTIME(STRINGITER2, "runtime.stringiter2", P2(STRING, INT),
- R2(INT, INT))
+ R2(INT, RUNE))
// Concatenate two strings.
DEF_GO_RUNTIME(STRING_PLUS, "__go_string_plus", P2(STRING, STRING), R1(STRING))
else if (range_type->is_string_type())
{
index_type = Type::lookup_integer_type("int");
- value_type = index_type;
+ value_type = Type::lookup_integer_type("int32");
}
else if (range_type->map_type() != NULL)
{
switch (this->classification())
{
case TYPE_INTEGER:
- return Type::lookup_integer_type("int");
+ if (this->integer_type()->is_rune())
+ return Type::lookup_integer_type("int32");
+ else
+ return Type::lookup_integer_type("int");
case TYPE_FLOAT:
return Type::lookup_float_type("float64");
case TYPE_COMPLEX:
t1 = t1->forwarded();
t2 = t2->forwarded();
+ // Ignore aliases for purposes of type identity.
+ if (t1->named_type() != NULL && t1->named_type()->is_alias())
+ t1 = t1->named_type()->real_type();
+ if (t2->named_type() != NULL && t2->named_type()->is_alias())
+ t2 = t2->named_type()->real_type();
+
if (t1 == t2)
return true;
Type::type_descriptor_pointer(Gogo* gogo, Location location)
{
Type* t = this->forwarded();
+ if (t->named_type() != NULL && t->named_type()->is_alias())
+ t = t->named_type()->real_type();
if (t->type_descriptor_var_ == NULL)
{
t->make_type_descriptor_var(gogo);
return abstract_type;
}
+// Create a new abstract character type.
+
+Integer_type*
+Integer_type::create_abstract_character_type()
+{
+ static Integer_type* abstract_type;
+ if (abstract_type == NULL)
+ {
+ abstract_type = new Integer_type(true, false, 32,
+ RUNTIME_TYPE_KIND_INT32);
+ abstract_type->set_is_rune();
+ }
+ return abstract_type;
+}
+
// Integer type compatibility.
bool
return Integer_type::create_abstract_integer_type();
}
+// Make an abstract character type.
+
+Integer_type*
+Type::make_abstract_character_type()
+{
+ return Integer_type::create_abstract_character_type();
+}
+
// Look up an integer type.
Named_type*
return this->named_object_->message_name();
}
+// Whether this is an alias. There are currently only two aliases so
+// we just recognize them by name.
+
+bool
+Named_type::is_alias() const
+{
+ if (!this->is_builtin())
+ return false;
+ const std::string& name(this->name());
+ return name == "byte" || name == "rune";
+}
+
// Return the base type for this type. We have to be careful about
// circular type definitions, which are invalid but may be seen here.
unsigned int
Named_type::do_hash_for_method(Gogo* gogo) const
{
+ if (this->is_alias())
+ return this->type_->named_type()->do_hash_for_method(gogo);
+
const std::string& name(this->named_object()->name());
unsigned int ret = Type::hash_string(name, 0);
Expression*
Named_type::do_type_descriptor(Gogo* gogo, Named_type* name)
{
+ if (name == NULL && this->is_alias())
+ return this->type_->type_descriptor(gogo, this->type_);
+
// If NAME is not NULL, then we don't really want the type
// descriptor for this type; we want the descriptor for the
// underlying type, giving it the name NAME.
void
Named_type::do_reflection(Gogo* gogo, std::string* ret) const
{
- if (!Linemap::is_predeclared_location(this->location()))
+ if (this->is_alias())
+ {
+ this->append_reflection(this->type_, gogo, ret);
+ return;
+ }
+ if (!this->is_builtin())
{
const Package* package = this->named_object_->package();
if (package != NULL)
void
Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
+ if (this->is_alias())
+ {
+ this->append_mangled_name(this->type_, gogo, ret);
+ return;
+ }
Named_object* no = this->named_object_;
std::string name;
- if (Linemap::is_predeclared_location(this->location()))
+ if (this->is_builtin())
go_assert(this->in_function_ == NULL);
else
{
static Integer_type*
make_abstract_integer_type();
+ // Make an abstract type for a character constant.
+ static Integer_type*
+ make_abstract_character_type();
+
// Make a named integer type with a specified size.
// RUNTIME_TYPE_KIND is the code to use in reflection information,
// to distinguish int and int32.
static Integer_type*
create_abstract_integer_type();
+ // Create an abstract character type.
+ static Integer_type*
+ create_abstract_character_type();
+
// Whether this is an abstract integer type.
bool
is_abstract() const
is_builtin() const
{ return Linemap::is_predeclared_location(this->location_); }
+ // Whether this is an alias. There are currently two aliases: byte
+ // and rune.
+ bool
+ is_alias() const;
+
// Whether this is a circular type: a pointer or function type that
// refers to itself, which is not possible in C.
bool
package main
func main() {
- nchar := 0;
- a := []int { '日', '本', '語', 0xFFFD };
+ nchar := 0
+ a := []rune{'日', '本', '語', 0xFFFD}
for _, char := range "日本語\xc0" {
if nchar >= len(a) {
- println("BUG");
- break;
+ println("BUG")
+ break
}
if char != a[nchar] {
- println("expected", a[nchar], "got", char);
- println("BUG");
- break;
+ println("expected", a[nchar], "got", char)
+ println("BUG")
+ break
}
- nchar++;
+ nchar++
}
}
}
/* create string with int array */
- var z2 [3]int
+ var z2 [3]rune
z2[0] = 'a'
z2[1] = '\u1234'
z2[2] = 'c'
}
func teststring() {
- s := 0
+ var s rune
nmake = 0
for _, v := range makestring() {
s += v
func makemap() map[int]int {
nmake++
- return map[int]int{0:'a', 1:'b', 2:'c', 3:'d', 4:'☺'}
+ return map[int]int{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: '☺'}
}
func testmap() {
// The board must be surrounded by 2 illegal fields in each direction
// so that move() doesn't need to check the board boundaries. Periods
// represent illegal fields, ● are pegs, and ○ are holes.
-var board = []int(
+var board = []rune(
`...........
...........
....●●●....
...........
`)
-
// center is the position of the center hole if there is a single one;
// otherwise it is -1.
var center int
}
}
-
var moves int // number of times move is called
// move tests if there is a peg at position pos that can jump over another peg
return false
}
-
// unmove reverts a previously executed valid move.
func unmove(pos, dir int) {
board[pos] = '●'
board[pos+2*dir] = '○'
}
-
// solve tries to find a sequence of moves such that there is only one peg left
// at the end; if center is >= 0, that last peg must be in the center position.
// If a solution is found, solve prints the board after each move in a backward
return false
}
-
func main() {
if !solve() {
println("no solution found")
}
const (
- gx1 = "aä本☺"
- gx2 = "aä\xFF\xFF本☺"
+ gx1 = "aä本☺"
+ gx2 = "aä\xFF\xFF本☺"
gx2fix = "aä\uFFFD\uFFFD本☺"
)
var (
- gr1 = []int(gx1)
- gr2 = []int(gx2)
+ gr1 = []rune(gx1)
+ gr2 = []rune(gx2)
gb1 = []byte(gx1)
gb2 = []byte(gx2)
)
// test large runes. perhaps not the most logical place for this test.
var r int32
- r = 0x10ffff; // largest rune value
+ r = 0x10ffff // largest rune value
s = string(r)
assert(s, "\xf4\x8f\xbf\xbf", "largest rune")
r = 0x10ffff + 1
s = string(r)
assert(s, "\xef\xbf\xbd", "too-large rune")
- assert(string(gr1), gx1, "global ->[]int")
- assert(string(gr2), gx2fix, "global invalid ->[]int")
+ assert(string(gr1), gx1, "global ->[]rune")
+ assert(string(gr2), gx2fix, "global invalid ->[]rune")
assert(string(gb1), gx1, "->[]byte")
assert(string(gb2), gx2, "global invalid ->[]byte")
var (
- r1 = []int(gx1)
- r2 = []int(gx2)
+ r1 = []rune(gx1)
+ r2 = []rune(gx2)
b1 = []byte(gx1)
b2 = []byte(gx2)
)
- assert(string(r1), gx1, "->[]int")
- assert(string(r2), gx2fix, "invalid ->[]int")
+ assert(string(r1), gx1, "->[]rune")
+ assert(string(r2), gx2fix, "invalid ->[]rune")
assert(string(b1), gx1, "->[]byte")
assert(string(b2), gx2, "invalid ->[]byte")