Expr* Parser::on_int(Token tok) { Type const* t = get_integer_type(); int v = tok.integer_symbol()->value(); return init<Literal_expr>(tok.location(), t, v); }
Expr* Elaborator::elaborate(Literal_expr* e) { if (is<Boolean_sym>(e->symbol())) e->type(get_boolean_type()); else if (is<Integer_sym>(e->symbol())) e->type(get_integer_type()); else throw std::runtime_error("untyped literal"); return e; }
// 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); if (e->type() == get_boolean_type()) return build.getInt1(v.get_integer()); if (e->type() == get_integer_type()) return build.getInt32(v.get_integer()); 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 if (match_if(bool_kw)) return get_boolean_type(); // char if (match_if(char_kw)) return get_character_type(); // int else if (match_if(int_kw)) return get_integer_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"); }
Expr* gather(Expr_seq const& subkeys) { // maintain the largest allowable key buffer uint512_t buf = 0; Evaluator ev; // maintain the position to start writing int pos = 0; for (auto subkey : subkeys) { // get the precision of the subkey int prec = precision(subkey->type()); Value const& val = ev.eval(subkey); // FIXME: for now we're only dealing with unsigned integer values assert(val.is_integer()); std::stringstream ss; ss << val.get_integer().decimal_str(); uint512_t i = 0; ss >> i; // shift the integer over by the amount already written i = i << pos; // add the length of the current integer to the pos pos += prec; // log-and the integer into the buffer buf |= i; } char* bytes = new char[pos / 8]; char* key = reinterpret_cast<char*>(&buf); std::copy(key, key + (pos / 8), bytes); Array_value arr { bytes, (size_t) pos / 8 }; Type const* z = get_integer_type(); Expr* n = new Literal_expr(z, arr.len + 1); // Create the array type. Type const* c = get_character_type(); Type const* t = get_array_type(c, n); return new Literal_expr(t, arr); }
// 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"); }
// TODO: Default precision depends on configuration. Integer_type& Builder::get_uint_type() { return get_integer_type(false, 32); }
// TODO: Default precision depends on configuration. Integer_type& Builder::get_int_type() { return get_integer_type(true, 32); }
// TODO: See comments above. Integer_type& Builder::get_uint_type(Type_category c, Qualifier_set q) { return get_integer_type(c, false, 32, q); }
Integer_type& Builder::get_integer_type(bool s, int p, Qualifier_set q) { return get_integer_type(object_type, s, p, q); }
// 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"); }