runtime/builtins-module.cpp (759 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
#include "builtins-module.h"
#include <cerrno>
#include <cmath>
#include <csignal>
#include "attributedict.h"
#include "builtins.h"
#include "bytes-builtins.h"
#include "capi.h"
#include "dict-builtins.h"
#include "exception-builtins.h"
#include "formatter.h"
#include "int-builtins.h"
#include "list-builtins.h"
#include "marshal.h"
#include "module-builtins.h"
#include "modules.h"
#include "object-builtins.h"
#include "objects.h"
#include "range-builtins.h"
#include "runtime.h"
#include "set-builtins.h"
#include "str-builtins.h"
#include "tuple-builtins.h"
#include "type-builtins.h"
namespace py {
RawObject delAttribute(Thread* thread, const Object& object,
const Object& name) {
HandleScope scope(thread);
Object interned(&scope, attributeName(thread, name));
if (interned.isErrorException()) return *interned;
Object result(&scope,
thread->runtime()->attributeDel(thread, object, interned));
if (result.isErrorException()) return *result;
return NoneType::object();
}
RawObject getAttribute(Thread* thread, const Object& object,
const Object& name) {
HandleScope scope(thread);
Object interned(&scope, attributeName(thread, name));
if (interned.isErrorException()) return *interned;
return thread->runtime()->attributeAt(thread, object, interned);
}
RawObject hasAttribute(Thread* thread, const Object& object,
const Object& name) {
HandleScope scope(thread);
Object interned(&scope, attributeName(thread, name));
if (interned.isErrorException()) return *interned;
Object result(&scope,
thread->runtime()->attributeAt(thread, object, interned));
if (!result.isErrorException()) {
return Bool::trueObj();
}
if (!thread->pendingExceptionMatches(LayoutId::kAttributeError)) {
return *result;
}
thread->clearPendingException();
return Bool::falseObj();
}
RawObject setAttribute(Thread* thread, const Object& object, const Object& name,
const Object& value) {
HandleScope scope(thread);
Object interned(&scope, attributeName(thread, name));
if (interned.isErrorException()) return *interned;
Object result(
&scope, thread->invokeMethod3(object, ID(__setattr__), interned, value));
if (result.isErrorException()) return *result;
return NoneType::object();
}
bool FUNC(builtins, _index_intrinsic)(Thread* thread) {
RawObject value = thread->stackTop();
if (thread->runtime()->isInstanceOfInt(value)) {
thread->stackPop();
thread->stackSetTop(value);
return true;
}
return false;
}
bool FUNC(builtins, _index_or_int_intrinsic)(Thread* thread) {
RawObject value = thread->stackTop();
if (value.isBool()) {
thread->stackPop();
thread->stackSetTop(convertBoolToInt(value));
return true;
}
if (value.isSmallInt() || value.isLargeInt()) {
thread->stackPop();
thread->stackSetTop(value);
}
return false;
}
bool FUNC(builtins, _obj_as_int_intrinsic)(Thread* thread) {
RawObject value = thread->stackTop();
if (value.isBool()) {
thread->stackPop();
thread->stackSetTop(convertBoolToInt(value));
return true;
}
if (thread->runtime()->isInstanceOfInt(value)) {
thread->stackPop();
thread->stackSetTop(intUnderlying(value));
return true;
}
return false;
}
bool FUNC(builtins, abs_intrinsic)(Thread* thread) {
RawObject obj = thread->stackTop();
if (obj.isSmallInt()) {
thread->stackPop();
word value = SmallInt::cast(obj).value();
if (value < 0) {
obj = SmallInt::fromWord(-value);
}
thread->stackSetTop(obj);
return true;
}
if (obj.isFloat()) {
thread->stackPop();
double value = Float::cast(obj).value();
thread->stackSetTop(thread->runtime()->newFloat(std::fabs(value)));
return true;
}
return false;
}
bool FUNC(builtins, next_intrinsic)(Thread* thread) {
RawObject value = thread->stackTop();
switch (value.layoutId()) {
case LayoutId::kDictKeyIterator: {
HandleScope scope(thread);
DictKeyIterator iter(&scope, value);
RawObject result = dictKeyIteratorNext(thread, iter);
if (result.isErrorNoMoreItems()) {
return false;
}
thread->stackPop();
thread->stackSetTop(result);
return true;
}
case LayoutId::kListIterator: {
HandleScope scope(thread);
ListIterator list_iterator(&scope, value);
RawObject result = listIteratorNext(thread, list_iterator);
if (result.isErrorOutOfBounds()) {
return false;
}
thread->stackPop();
thread->stackSetTop(result);
return true;
}
case LayoutId::kRangeIterator: {
HandleScope scope(thread);
RangeIterator iter(&scope, value);
RawObject result = rangeIteratorNext(iter);
if (result.isErrorNoMoreItems()) {
return false;
}
thread->stackPop();
thread->stackSetTop(result);
return true;
}
case LayoutId::kSetIterator: {
HandleScope scope(thread);
SetIterator set_iterator(&scope, value);
RawObject result = setIteratorNext(thread, set_iterator);
if (result.isErrorNoMoreItems()) {
return false;
}
thread->stackPop();
thread->stackSetTop(result);
return true;
}
case LayoutId::kStrIterator: {
HandleScope scope(thread);
StrIterator str_iterator(&scope, value);
RawObject result = strIteratorNext(thread, str_iterator);
if (result.isErrorNoMoreItems()) {
return false;
}
thread->stackPop();
thread->stackSetTop(result);
return true;
}
case LayoutId::kTupleIterator: {
HandleScope scope(thread);
TupleIterator tuple_iterator(&scope, value);
RawObject result = tupleIteratorNext(thread, tuple_iterator);
if (result.isErrorNoMoreItems()) {
return false;
}
thread->stackPop();
thread->stackSetTop(result);
return true;
}
default: {
return false;
}
}
}
bool FUNC(builtins, _number_check_intrinsic)(Thread* thread) {
Runtime* runtime = thread->runtime();
RawObject arg = thread->stackTop();
if (runtime->isInstanceOfInt(arg) || runtime->isInstanceOfFloat(arg)) {
thread->stackPop();
thread->stackSetTop(Bool::trueObj());
return true;
}
return false;
}
bool FUNC(builtins, _slice_index_intrinsic)(Thread* thread) {
RawObject value = thread->stackPeek(0);
if (value.isNoneType() || thread->runtime()->isInstanceOfInt(value)) {
thread->stackPop();
thread->stackSetTop(value);
return true;
}
return false;
}
bool FUNC(builtins, _slice_index_not_none_intrinsic)(Thread* thread) {
RawObject value = thread->stackTop();
if (thread->runtime()->isInstanceOfInt(value)) {
thread->stackPop();
thread->stackSetTop(value);
return true;
}
return false;
}
bool FUNC(builtins, isinstance_intrinsic)(Thread* thread) {
RawObject obj = thread->stackPeek(1);
RawObject type = thread->stackPeek(0);
Runtime* runtime = thread->runtime();
RawType obj_type = runtime->typeOf(obj);
if (obj_type == type) {
thread->stackDrop(2);
thread->stackSetTop(Bool::trueObj());
return true;
}
if (type.isType()) {
if (typeIsSubclass(obj_type, type)) {
thread->stackDrop(2);
thread->stackSetTop(Bool::trueObj());
return true;
}
if (obj_type.hasFlag(Type::Flag::kHasObjectDunderClass)) {
// obj_type.__class__ is object.__class__, so type(obj) is guaranteed to
// be obj_type. See _object_class_set implementation.
thread->stackDrop(2);
thread->stackSetTop(Bool::falseObj());
return true;
}
} else if (type.isTuple()) {
RawTuple types = Tuple::cast(type);
word length = types.length();
for (word i = 0; i < length; i++) {
RawObject item = types.at(i);
if (!item.isType()) {
return false;
}
if (typeIsSubclass(obj_type, item)) {
thread->stackDrop(2);
thread->stackSetTop(Bool::trueObj());
return true;
}
}
}
return false;
}
bool FUNC(builtins, len_intrinsic)(Thread* thread) {
RawObject arg = thread->stackTop();
word length;
switch (arg.layoutId()) {
case LayoutId::kBytearray:
length = Bytearray::cast(arg).numItems();
break;
case LayoutId::kDict:
length = Dict::cast(arg).numItems();
break;
case LayoutId::kFrozenSet:
length = FrozenSet::cast(arg).numItems();
break;
case LayoutId::kLargeBytes:
length = LargeBytes::cast(arg).length();
break;
case LayoutId::kLargeStr:
length = LargeStr::cast(arg).codePointLength();
break;
case LayoutId::kList:
length = List::cast(arg).numItems();
break;
case LayoutId::kSet:
length = Set::cast(arg).numItems();
break;
case LayoutId::kSmallBytes:
length = SmallBytes::cast(arg).length();
break;
case LayoutId::kSmallStr:
length = SmallStr::cast(arg).codePointLength();
break;
case LayoutId::kTuple:
length = Tuple::cast(arg).length();
break;
default:
return false;
}
thread->stackPop();
thread->stackSetTop(SmallInt::fromWord(length));
return true;
}
void FUNC(builtins, __init_module__)(Thread* thread, const Module& module,
View<byte> bytecode) {
Runtime* runtime = thread->runtime();
runtime->setBuiltinsModuleId(module.id());
runtime->cacheBuildClass(thread, module);
HandleScope scope(thread);
// Add module variables
{
Object dunder_debug(&scope, Bool::falseObj());
moduleAtPutById(thread, module, ID(__debug__), dunder_debug);
Object false_obj(&scope, Bool::falseObj());
moduleAtPutById(thread, module, ID(False), false_obj);
Object none(&scope, NoneType::object());
moduleAtPutById(thread, module, ID(None), none);
Object not_implemented(&scope, NotImplementedType::object());
moduleAtPutById(thread, module, ID(NotImplemented), not_implemented);
Object true_obj(&scope, Bool::trueObj());
moduleAtPutById(thread, module, ID(True), true_obj);
}
executeFrozenModule(thread, module, bytecode);
}
static RawObject calculateMetaclass(Thread* thread, const Type& metaclass_type,
const Tuple& bases) {
Runtime* runtime = thread->runtime();
RawObject result = *metaclass_type;
for (word i = 0, num_bases = bases.length(); i < num_bases; i++) {
RawObject base_type = runtime->typeOf(bases.at(i));
if (typeIsSubclass(base_type, result)) {
result = base_type;
} else if (!typeIsSubclass(result, base_type)) {
return thread->raiseWithFmt(
LayoutId::kTypeError,
"metaclass conflict: the metaclass of a derived class must be a "
"(non-strict) subclass of the metaclasses of all its bases");
}
}
return result;
}
RawObject FUNC(builtins, bin)(Thread* thread, Arguments args) {
HandleScope scope(thread);
Object number(&scope, args.get(0));
number = intFromIndex(thread, number);
if (number.isError()) {
return *number;
}
Int number_int(&scope, intUnderlying(*number));
return formatIntBinarySimple(thread, number_int);
}
RawObject FUNC(builtins, delattr)(Thread* thread, Arguments args) {
HandleScope scope(thread);
Object self(&scope, args.get(0));
Object name(&scope, args.get(1));
Object result(&scope, delAttribute(thread, self, name));
return *result;
}
static RawObject replaceNonTypeBases(Thread* thread, const Tuple& bases) {
Runtime* runtime = thread->runtime();
word num_bases = bases.length();
bool has_nontype_base = false;
for (word i = 0; i < num_bases; i++) {
if (!runtime->isInstanceOfType(bases.at(i))) {
has_nontype_base = true;
break;
}
}
if (!has_nontype_base) {
return *bases;
}
HandleScope scope(thread);
List new_bases(&scope, runtime->newList());
Object base(&scope, NoneType::object());
Object replacements(&scope, NoneType::object());
Tuple entries(&scope, runtime->emptyTuple());
for (word i = 0; i < num_bases; i++) {
base = bases.at(i);
if (runtime->isInstanceOfType(*base)) {
runtime->listAdd(thread, new_bases, base);
continue;
}
replacements = thread->invokeMethod2(base, ID(__mro_entries__), bases);
if (replacements.isErrorException()) return *replacements;
if (replacements.isErrorNotFound()) {
runtime->listAdd(thread, new_bases, base);
continue;
}
if (!replacements.isTuple()) {
return thread->raiseWithFmt(LayoutId::kTypeError,
"__mro_entries__ must return a tuple");
}
entries = *replacements;
listExtend(thread, new_bases, entries, entries.length());
}
Tuple new_bases_items(&scope, new_bases.items());
return runtime->tupleSubseq(thread, new_bases_items, 0, new_bases.numItems());
}
static void pickBuiltinTypeCtorFunction(Thread* thread, const Type& type) {
HandleScope scope(thread);
Object ctor(&scope, NoneType::object());
LayoutId layout_id = type.instanceLayoutId();
Runtime* runtime = thread->runtime();
switch (layout_id) {
case LayoutId::kInt: {
Module under_builtins(&scope, runtime->findModuleById(ID(_builtins)));
ctor = moduleAtById(thread, under_builtins, ID(_int_ctor));
break;
}
case LayoutId::kList: {
Module under_builtins(&scope, runtime->findModuleById(ID(_builtins)));
ctor = moduleAtById(thread, under_builtins, ID(_list_ctor));
break;
}
case LayoutId::kStr: {
Module under_builtins(&scope, runtime->findModuleById(ID(_builtins)));
ctor = moduleAtById(thread, under_builtins, ID(_str_ctor));
break;
}
case LayoutId::kStopIteration: {
Module under_builtins(&scope, runtime->findModuleById(ID(_builtins)));
ctor = moduleAtById(thread, under_builtins, ID(_stop_iteration_ctor));
break;
}
case LayoutId::kStrArray: {
Module under_builtins(&scope, runtime->findModuleById(ID(_builtins)));
ctor = moduleAtById(thread, under_builtins, ID(_str_array_ctor));
break;
}
case LayoutId::kSuper: {
Module under_builtins(&scope, runtime->findModuleById(ID(_builtins)));
ctor = moduleAtById(thread, under_builtins, ID(_super_ctor));
break;
}
default: {
if (typeAtById(thread, type, ID(__init__)).isErrorNotFound()) {
// Use __new__ as _ctor if __init__ is undefined.
Object dunder_new(&scope, typeAtById(thread, type, ID(__new__)));
if (!dunder_new.isErrorNotFound()) {
ctor = StaticMethod::cast(*dunder_new).function();
}
}
}
}
if (ctor.isNoneType()) {
ctor = runtime->lookupNameInModule(thread, ID(_builtins),
ID(_type_dunder_call));
}
CHECK(ctor.isFunction(), "ctor is expected to be a function");
type.setCtor(*ctor);
}
RawObject FUNC(builtins, __build_class__)(Thread* thread, Arguments args) {
Runtime* runtime = thread->runtime();
HandleScope scope(thread);
Object body_obj(&scope, args.get(0));
if (!body_obj.isFunction()) {
return thread->raiseWithFmt(LayoutId::kTypeError,
"__build_class__: func must be a function");
}
Function body(&scope, *body_obj);
Object name(&scope, args.get(1));
if (!runtime->isInstanceOfStr(*name)) {
return thread->raiseWithFmt(LayoutId::kTypeError,
"__build_class__: name is not a string");
}
Object metaclass(&scope, args.get(2));
Object bootstrap(&scope, args.get(3));
Tuple orig_bases(&scope, args.get(4));
Tuple bases(&scope, *orig_bases);
Dict kwargs(&scope, args.get(5));
if (bootstrap == Bool::trueObj()) {
CHECK(name.isStr(), "bootstrap class names must not be str subclass");
name = Runtime::internStr(thread, name);
Object type_obj(&scope, findBuiltinTypeWithName(thread, name));
CHECK(!type_obj.isErrorNotFound(), "Unknown builtin type");
Type type(&scope, *type_obj);
if (bases.length() == 0 && name != runtime->symbols()->at(ID(object))) {
bases = runtime->implicitBases();
}
Tuple builtin_bases(&scope, type.bases());
word bases_length = bases.length();
CHECK(builtin_bases.length() == bases_length, "mismatching bases for '%s'",
Str::cast(*name).toCStr());
for (word i = 0; i < bases_length; i++) {
CHECK(builtin_bases.at(i) == bases.at(i), "mismatching bases for '%s'",
Str::cast(*name).toCStr());
}
if (type.mro().isNoneType()) {
Type superclass(&scope, bases.at(0));
DCHECK(!superclass.mro().isNoneType(), "superclass not initialized yet");
Tuple superclass_mro(&scope, superclass.mro());
word mro_length = superclass_mro.length() + 1;
MutableTuple mro(&scope, runtime->newMutableTuple(mro_length));
mro.atPut(0, *type);
mro.replaceFromWith(1, *superclass_mro, mro_length - 1);
type.setMro(mro.becomeImmutable());
}
Dict type_dict(&scope, runtime->newDict());
Object result(&scope,
thread->callFunctionWithImplicitGlobals(body, type_dict));
if (result.isError()) return *result;
CHECK(!typeAssignFromDict(thread, type, type_dict).isErrorException(),
"error while assigning bootstrap type dict");
// TODO(T53997177): Centralize type initialization
Object module_name(&scope, typeAtById(thread, type, ID(__module__)));
// non-heap-types in CPython have no `__module__` unless there is a
// "." in `tp_name`. Remove the attribute when it equals "builtins".
if (module_name.isStr() &&
Str::cast(*module_name).equals(runtime->symbols()->at(ID(builtins)))) {
typeRemoveById(thread, type, ID(__module__));
}
Object qualname(&scope, NoneType::object());
if (type.instanceLayoutId() == LayoutId::kType) {
qualname = *name;
// Note: `type` is the only type allowed to have a descriptor instead of
// a string for `__qualname__`.
} else {
qualname = typeRemoveById(thread, type, ID(__qualname__));
DCHECK(qualname.isStr() && Str::cast(*qualname).equals(Str::cast(*name)),
"unexpected __qualname__ attribute");
}
type.setQualname(*qualname);
typeAddDocstring(thread, type);
if (Layout::cast(type.instanceLayout()).hasTupleOverflow() &&
typeAtById(thread, type, ID(__dict__)).isErrorNotFound()) {
typeAddInstanceDict(thread, type);
}
if (DCHECK_IS_ON()) {
Object dunder_new(&scope, typeAtById(thread, type, ID(__new__)));
if (!dunder_new.isStaticMethod()) {
if (!(dunder_new.isNoneType() || dunder_new.isErrorNotFound())) {
DCHECK(false, "__new__ for %s should be a staticmethod",
Str::cast(*name).toCStr());
}
}
}
pickBuiltinTypeCtorFunction(thread, type);
runtime->builtinTypeCreated(thread, type);
return *type;
}
Object updated_bases(&scope, replaceNonTypeBases(thread, bases));
if (updated_bases.isErrorException()) {
return *updated_bases;
}
bases = *updated_bases;
bool metaclass_is_class;
if (metaclass.isUnbound()) {
metaclass_is_class = true;
if (bases.length() == 0) {
metaclass = runtime->typeAt(LayoutId::kType);
} else {
metaclass = runtime->typeOf(bases.at(0));
}
} else {
metaclass_is_class = runtime->isInstanceOfType(*metaclass);
}
if (metaclass_is_class) {
Type metaclass_type(&scope, *metaclass);
metaclass = calculateMetaclass(thread, metaclass_type, bases);
if (metaclass.isError()) return *metaclass;
}
Object dict_obj(&scope, NoneType::object());
Object prepare_method(
&scope, runtime->attributeAtById(thread, metaclass, ID(__prepare__)));
if (prepare_method.isError()) {
Object given(&scope, thread->pendingExceptionType());
Object exc(&scope, runtime->typeAt(LayoutId::kAttributeError));
if (!givenExceptionMatches(thread, given, exc)) {
return *prepare_method;
}
thread->clearPendingException();
dict_obj = runtime->newDict();
} else {
thread->stackPush(*prepare_method);
Tuple pargs(&scope, runtime->newTupleWith2(name, bases));
thread->stackPush(*pargs);
thread->stackPush(*kwargs);
dict_obj = Interpreter::callEx(thread, CallFunctionExFlag::VAR_KEYWORDS);
if (dict_obj.isError()) return *dict_obj;
}
if (!runtime->isMapping(thread, dict_obj)) {
if (metaclass_is_class) {
Type metaclass_type(&scope, *metaclass);
Str metaclass_type_name(&scope, metaclass_type.name());
return thread->raiseWithFmt(
LayoutId::kTypeError,
"%S.__prepare__() must return a mapping, not %T",
&metaclass_type_name, &dict_obj);
}
return thread->raiseWithFmt(
LayoutId::kTypeError,
"<metaclass>.__prepare__() must return a mapping, not %T", &dict_obj);
}
Dict type_dict(&scope, *dict_obj);
// TODO(cshapiro): might need to do some kind of callback here and we want
// backtraces to work correctly. The key to doing that would be to put some
// state on the stack in between the the incoming arguments from the builtin
// caller and the on-stack state for the class body function call.
Object body_result(&scope,
thread->callFunctionWithImplicitGlobals(body, type_dict));
if (body_result.isError()) return *body_result;
if (bases != orig_bases) {
dictAtPutById(thread, type_dict, ID(__orig_bases__), orig_bases);
}
thread->stackPush(*metaclass);
Tuple pargs(&scope, runtime->newTupleWith3(name, bases, type_dict));
thread->stackPush(*pargs);
thread->stackPush(*kwargs);
return Interpreter::callEx(thread, CallFunctionExFlag::VAR_KEYWORDS);
}
RawObject FUNC(builtins, callable)(Thread* thread, Arguments args) {
HandleScope scope(thread);
Object arg(&scope, args.get(0));
return Bool::fromBool(thread->runtime()->isCallable(thread, arg));
}
RawObject FUNC(builtins, chr)(Thread* thread, Arguments args) {
HandleScope scope(thread);
Object arg(&scope, args.get(0));
Runtime* runtime = thread->runtime();
if (!runtime->isInstanceOfInt(*arg)) {
return thread->raiseWithFmt(LayoutId::kTypeError,
"an integer is required (got type %T)", &arg);
}
Int num(&scope, intUnderlying(*arg));
if (!num.isSmallInt()) {
return thread->raiseWithFmt(LayoutId::kOverflowError,
"Python int too large to convert to C int");
}
word code_point = num.asWord();
if (code_point < 0 || code_point > kMaxUnicode) {
return thread->raiseWithFmt(LayoutId::kValueError,
"chr() arg not in range(0x110000)");
}
return SmallStr::fromCodePoint(static_cast<int32_t>(code_point));
}
RawObject compile(Thread* thread, const Object& source, const Object& filename,
SymbolId mode, word flags, int optimize) {
HandleScope scope(thread);
Runtime* runtime = thread->runtime();
Object mode_str(&scope, runtime->symbols()->at(mode));
Object flags_int(&scope, runtime->newInt(flags));
Object optimize_int(&scope, SmallInt::fromWord(optimize));
Object dunder_import(&scope, runtime->lookupNameInModule(thread, ID(builtins),
ID(__import__)));
if (dunder_import.isErrorException()) return *dunder_import;
Object compiler_name(&scope, runtime->symbols()->at(ID(_compiler)));
Object import_result(
&scope, Interpreter::call1(thread, dunder_import, compiler_name));
if (import_result.isErrorException()) return *import_result;
Object none(&scope, NoneType::object());
return thread->invokeFunction6(ID(_compiler), ID(compile), source, filename,
mode_str, flags_int, none, optimize_int);
}
RawObject FUNC(builtins, id)(Thread* thread, Arguments args) {
// NOTE: This pins a handle until the runtime exits.
// TODO(emacs): Either determine that this function is used so little that it
// does not matter or add a section to the GC to clean up handles created by
// id().
Runtime* runtime = thread->runtime();
return runtime->newIntFromCPtr(objectNewReference(runtime, args.get(0)));
}
RawObject FUNC(builtins, oct)(Thread* thread, Arguments args) {
HandleScope scope(thread);
Object number(&scope, args.get(0));
number = intFromIndex(thread, number);
if (number.isError()) {
return *number;
}
Int number_int(&scope, intUnderlying(*number));
return formatIntOctalSimple(thread, number_int);
}
RawObject FUNC(builtins, ord)(Thread* thread, Arguments args) {
HandleScope scope(thread);
Object obj(&scope, args.get(0));
Runtime* runtime = thread->runtime();
if (runtime->isInstanceOfBytes(*obj)) {
Bytes bytes(&scope, bytesUnderlying(*obj));
if (bytes.length() == 1) {
int32_t code_point = bytes.byteAt(0);
return SmallInt::fromWord(code_point);
}
} else if (runtime->isInstanceOfStr(*obj)) {
Str str(&scope, strUnderlying(*obj));
if (str.isSmallStr() && *str != Str::empty()) {
word num_bytes;
int32_t code_point = str.codePointAt(0, &num_bytes);
if (num_bytes == str.length()) {
return SmallInt::fromWord(code_point);
}
}
} else if (runtime->isInstanceOfBytearray(*obj)) {
Bytearray byte_array(&scope, *obj);
if (byte_array.numItems() == 1) {
int32_t code_point = byte_array.byteAt(0);
return SmallInt::fromWord(code_point);
}
} else {
return thread->raiseWithFmt(LayoutId::kTypeError,
"Unsupported type in builtin 'ord'");
}
return thread->raiseWithFmt(LayoutId::kTypeError,
"Builtin 'ord' expects string of length 1");
}
RawObject FUNC(builtins, __import__)(Thread* thread, Arguments args) {
// Note that this is a simplified __import__ implementation that is used
// during early bootstrap; it is replaced by importlib.__import__ once
// import lib is fully initialized.
HandleScope scope(thread);
Str name(&scope, args.get(0));
name = Runtime::internStr(thread, name);
// We ignore arg1, arg2, arg3.
DCHECK(args.get(4) == SmallInt::fromWord(0), "only supports level=0");
Runtime* runtime = thread->runtime();
Object module(&scope, ensureBuiltinModule(thread, name));
if (module.isErrorNotFound() || !runtime->isInstanceOfModule(*module)) {
return thread->raiseWithFmt(LayoutId::kImportError,
"failed to import %S (bootstrap importer)",
&name);
}
return *module;
}
RawObject FUNC(builtins, _debug_break)(Thread*, Arguments) {
#if __has_builtin(__builtin_debugtrap)
__builtin_debugtrap();
#elif defined(__i386__) || defined(__x86_64__)
__asm__ volatile("int $0x03");
#else
std::raise(SIGTRAP);
#endif
return NoneType::object();
}
// TODO(T39322942): Turn this into the Range constructor (__init__ or __new__)
RawObject FUNC(builtins, getattr)(Thread* thread, Arguments args) {
HandleScope scope(thread);
Object self(&scope, args.get(0));
Object name(&scope, args.get(1));
Object default_obj(&scope, args.get(2));
Object result(&scope, getAttribute(thread, self, name));
Runtime* runtime = thread->runtime();
if (result.isError() && !default_obj.isUnbound()) {
Type given(&scope, thread->pendingExceptionType());
Type exc(&scope, runtime->typeAt(LayoutId::kAttributeError));
if (givenExceptionMatches(thread, given, exc)) {
thread->clearPendingException();
result = *default_obj;
}
}
return *result;
}
RawObject FUNC(builtins, hasattr)(Thread* thread, Arguments args) {
HandleScope scope(thread);
Object self(&scope, args.get(0));
Object name(&scope, args.get(1));
return hasAttribute(thread, self, name);
}
RawObject FUNC(builtins, hash)(Thread* thread, Arguments args) {
HandleScope scope(thread);
Object object(&scope, args.get(0));
return Interpreter::hash(thread, object);
}
RawObject FUNC(builtins, hex)(Thread* thread, Arguments args) {
HandleScope scope(thread);
Object number(&scope, args.get(0));
number = intFromIndex(thread, number);
if (number.isError()) {
return *number;
}
Int number_int(&scope, intUnderlying(*number));
return formatIntHexadecimalSimple(thread, number_int);
}
RawObject FUNC(builtins, setattr)(Thread* thread, Arguments args) {
HandleScope scope(thread);
Object self(&scope, args.get(0));
Object name(&scope, args.get(1));
Object value(&scope, args.get(2));
return setAttribute(thread, self, name, value);
}
} // namespace py