// Build a new string literal. String literals // are arrays of characters. Expr* Parser::on_str(Token tok) { // Build the string value. String_sym const* s = tok.string_symbol(); Array_value v { s->value().c_str(), s->value().size() }; // Create the extent of the literal array. This is // explicitly more than the length of the string, // and includes the null character. Type const* z = get_integer_type(); Expr* n = new Literal_expr(z, v.len + 1); // Create the array type. Type const* c = get_character_type(); Type const* t = get_array_type(c, n); return init<Literal_expr>(tok.location(), t, v); }
// Return the value corresponding to a literal expression. llvm::Value* Generator::gen(Literal_expr const* e) { // TODO: Write better type queries. // // TODO: Write a better interface for values. Value v = evaluate(e); Type const* t = e->type(); if (t == get_boolean_type()) return build.getInt1(v.get_integer()); if (t == get_character_type()) return build.getInt8(v.get_integer()); if (t == get_integer_type()) return build.getInt32(v.get_integer()); // FIXME: How should we generate array literals? Are // these global constants or are they local alloca // objects. Does it depend on context? // A string literal produces a new global string constant. // and returns a pointer to an array of N characters. if (is_string(t)) { Array_value a = v.get_array(); String s = a.get_string(); // FIXME: This does not unify equivalent strings. // Maybe we needt maintain a mapping in order to // avoid redunancies. auto iter = strings.find(s); if (iter == strings.end()) { llvm::Value* v = build.CreateGlobalString(s); iter = strings.emplace(s, v).first; } return iter->second; } else throw std::runtime_error("cannot generate function literal"); }
// Parse a primary type. // // primary-type -> 'bool' // | 'int' // | 'char' // | id-type // | function-type // // function-type -> '(' type-list ')' '->' type // // type-list -> type | type-list ',' type Type const* Parser::primary_type() { // id-type if (Token tok = match_if(identifier_tok)) return on_id_type(tok); // bool else if (match_if(bool_kw)) return get_boolean_type(); // char else if (match_if(char_kw)) return get_character_type(); // int else if (match_if(int_kw)) return get_integer_type(); // uint else if (match_if(uint_kw)) return get_integer_type(false); // short else if (match_if(short_kw)) return get_integer_type(16); // ushort else if (match_if(ushort_kw)) return get_integer_type(false, 16); // long else if (match_if(long_kw)) return get_integer_type(64); // ulong else if (match_if(ulong_kw)) return get_integer_type(false, 64); // int16 else if (match_if(int16_kw)) return get_integer_type(16); // uint16 else if (match_if(uint16_kw)) return get_integer_type(false, 16); // int32 else if (match_if(int32_kw)) return get_integer_type(); // uint32 else if (match_if(uint32_kw)) return get_integer_type(false); // int64 else if (match_if(int64_kw)) return get_integer_type(64); // uint64 else if (match_if(uint64_kw)) return get_integer_type(false, 64); // float else if (match_if(float_kw)) return get_float_type(); // double else if (match_if(double_kw)) return get_double_type(); // function-type else if (match_if(lparen_tok)) { Type_seq ts; while (true) { ts.push_back(type()); if (match_if(comma_tok)) continue; else break; } match(rparen_tok); match(arrow_tok); Type const* t = type(); return on_function_type(ts, t); } // error // // TODO: Make this a little less vague. else error("invalid type"); }