mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-03-06 12:23:13 +01:00
[svn r90] Major updates to the gen directory. Redesigned the 'elem' struct. Much more... !!!
Lots of bugfixes. Added support for special foreach on strings. Added std.array, std.utf, std.ctype and std.uni to phobos. Changed all the .c files in the gen dir to .cpp (it *is* C++ after all)
This commit is contained in:
@@ -527,6 +527,7 @@ struct FuncDeclaration : Declaration
|
||||
llvm::Value* llvmArguments;
|
||||
llvm::Value* llvmArgPtr;
|
||||
llvm::Constant* llvmDwarfSubProgram;
|
||||
bool llvmRunTimeHack;
|
||||
};
|
||||
|
||||
struct FuncAliasDeclaration : FuncDeclaration
|
||||
|
||||
@@ -56,11 +56,16 @@ enum TOK;
|
||||
struct IRState;
|
||||
struct dt_t;
|
||||
|
||||
#if IN_LLVM
|
||||
struct DValue;
|
||||
typedef DValue elem;
|
||||
#else
|
||||
#ifdef IN_GCC
|
||||
union tree_node; typedef union tree_node elem;
|
||||
#else
|
||||
struct elem;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void initPrecedence();
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC s
|
||||
llvmArguments = NULL;
|
||||
llvmArgPtr = NULL;
|
||||
llvmDwarfSubProgram = NULL;
|
||||
llvmRunTimeHack = false;
|
||||
}
|
||||
|
||||
Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s)
|
||||
|
||||
@@ -26,11 +26,16 @@ struct Escape;
|
||||
struct VarDeclaration;
|
||||
|
||||
// Back end
|
||||
#if IN_GCC
|
||||
#if IN_LLVM
|
||||
struct DValue;
|
||||
typedef DValue elem;
|
||||
#else
|
||||
#ifdef IN_GCC
|
||||
union tree_node; typedef union tree_node elem;
|
||||
#else
|
||||
struct elem;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct Package : ScopeDsymbol
|
||||
{
|
||||
|
||||
@@ -1438,6 +1438,7 @@ Statement *ForeachStatement::semantic(Scope *sc)
|
||||
fdapply = FuncDeclaration::genCfunc(Type::tindex, "_aaApply2");
|
||||
else
|
||||
fdapply = FuncDeclaration::genCfunc(Type::tindex, "_aaApply");
|
||||
fdapply->llvmRunTimeHack = true;
|
||||
ec = new VarExp(0, fdapply);
|
||||
Expressions *exps = new Expressions();
|
||||
exps->push(aggr);
|
||||
@@ -1479,6 +1480,7 @@ Statement *ForeachStatement::semantic(Scope *sc)
|
||||
int j = sprintf(fdname, "_aApply%s%.*s%d", r, 2, fntab[flag], dim);
|
||||
assert(j < sizeof(fdname));
|
||||
fdapply = FuncDeclaration::genCfunc(Type::tindex, fdname);
|
||||
fdapply->llvmRunTimeHack = true;
|
||||
|
||||
ec = new VarExp(0, fdapply);
|
||||
Expressions *exps = new Expressions();
|
||||
@@ -3464,7 +3466,7 @@ LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement)
|
||||
this->statement = statement;
|
||||
this->tf = NULL;
|
||||
this->lblock = NULL;
|
||||
this->isReturnLabel = 0;
|
||||
this->isReturnLabel = 0;
|
||||
this->llvmBB = NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,19 +51,24 @@ enum TOK;
|
||||
|
||||
namespace llvm
|
||||
{
|
||||
class Value;
|
||||
class Value;
|
||||
class BasicBlock;
|
||||
}
|
||||
|
||||
// Back end
|
||||
struct IRState;
|
||||
struct Blockx;
|
||||
#if IN_LLVM
|
||||
struct DValue;
|
||||
typedef DValue elem;
|
||||
#endif
|
||||
|
||||
#if IN_GCC
|
||||
union tree_node; typedef union tree_node block;
|
||||
union tree_node; typedef union tree_node elem;
|
||||
//union tree_node; typedef union tree_node elem;
|
||||
#else
|
||||
struct block;
|
||||
struct elem;
|
||||
//struct elem;
|
||||
#endif
|
||||
struct code;
|
||||
|
||||
@@ -715,8 +720,8 @@ struct LabelStatement : Statement
|
||||
|
||||
Statement *inlineScan(InlineScanState *iss);
|
||||
|
||||
void toIR(IRState *irs);
|
||||
|
||||
void toIR(IRState *irs);
|
||||
|
||||
llvm::BasicBlock* llvmBB;
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "gen/arrays.h"
|
||||
#include "gen/runtime.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/elem.h"
|
||||
#include "gen/dvalue.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -125,17 +125,18 @@ void DtoArrayInit(llvm::Value* l, llvm::Value* r)
|
||||
{
|
||||
const llvm::PointerType* ptrty = llvm::cast<llvm::PointerType>(l->getType());
|
||||
const llvm::Type* t = ptrty->getContainedType(0);
|
||||
const llvm::ArrayType* arrty = llvm::cast_or_null<llvm::ArrayType>(t);
|
||||
const llvm::ArrayType* arrty = llvm::dyn_cast<llvm::ArrayType>(t);
|
||||
if (arrty)
|
||||
{
|
||||
llvm::Value* ptr = DtoGEPi(l,0,0,"tmp",gIR->scopebb());
|
||||
llvm::Value* dim = llvm::ConstantInt::get(DtoSize_t(), arrty->getNumElements(), false);
|
||||
llvm::Value* val = r;
|
||||
DtoArrayInit(ptr, dim, val);
|
||||
DtoArrayInit(ptr, dim, r);
|
||||
}
|
||||
else if (llvm::isa<llvm::StructType>(t))
|
||||
{
|
||||
assert(0 && "Only static arrays support initialisers atm");
|
||||
llvm::Value* dim = DtoLoad(DtoGEPi(l, 0,0, "tmp"));
|
||||
llvm::Value* ptr = DtoLoad(DtoGEPi(l, 0,1, "tmp"));
|
||||
DtoArrayInit(ptr, dim, r);
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
@@ -159,6 +160,8 @@ static size_t checkRectArrayInit(const llvm::Type* pt, constLLVMTypeP& finalty)
|
||||
|
||||
void DtoArrayInit(llvm::Value* ptr, llvm::Value* dim, llvm::Value* val)
|
||||
{
|
||||
Logger::println("HELLO");
|
||||
Logger::cout() << "array: " << *ptr << " dim: " << *dim << " val: " << *val << '\n';
|
||||
const llvm::Type* pt = ptr->getType()->getContainedType(0);
|
||||
const llvm::Type* t = val->getType();
|
||||
const llvm::Type* finalTy;
|
||||
@@ -250,9 +253,20 @@ llvm::Constant* DtoConstArrayInitializer(ArrayInitializer* arrinit)
|
||||
{
|
||||
Logger::println("arr init begin");
|
||||
Type* arrinittype = DtoDType(arrinit->type);
|
||||
assert(arrinittype->ty == Tsarray);
|
||||
TypeSArray* t = (TypeSArray*)arrinittype;
|
||||
integer_t tdim = t->dim->toInteger();
|
||||
|
||||
Type* t;
|
||||
integer_t tdim;
|
||||
if (arrinittype->ty == Tsarray) {
|
||||
TypeSArray* tsa = (TypeSArray*)arrinittype;
|
||||
tdim = tsa->dim->toInteger();
|
||||
t = tsa;
|
||||
}
|
||||
else if (arrinittype->ty == Tarray) {
|
||||
t = arrinittype;
|
||||
tdim = arrinit->dim;
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
|
||||
std::vector<llvm::Constant*> inits(tdim, 0);
|
||||
|
||||
@@ -308,32 +322,41 @@ llvm::Constant* DtoConstArrayInitializer(ArrayInitializer* arrinit)
|
||||
inits[i] = v;
|
||||
}
|
||||
|
||||
const llvm::ArrayType* arrty = DtoStaticArrayType(t);
|
||||
return llvm::ConstantArray::get(arrty, inits);
|
||||
const llvm::ArrayType* arrty = llvm::ArrayType::get(elemty,tdim);
|
||||
llvm::Constant* constarr = llvm::ConstantArray::get(arrty, inits);
|
||||
|
||||
if (arrinittype->ty == Tsarray)
|
||||
return constarr;
|
||||
else
|
||||
assert(arrinittype->ty == Tarray);
|
||||
|
||||
llvm::GlobalVariable* gvar = new llvm::GlobalVariable(arrty,true,llvm::GlobalValue::InternalLinkage,constarr,"constarray",gIR->module);
|
||||
llvm::Constant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) };
|
||||
llvm::Constant* gep = llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2);
|
||||
return DtoConstSlice(DtoConstSize_t(tdim),gep);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
static llvm::Value* get_slice_ptr(elem* e, llvm::Value*& sz)
|
||||
static llvm::Value* get_slice_ptr(DSliceValue* e, llvm::Value*& sz)
|
||||
{
|
||||
assert(e->mem);
|
||||
const llvm::Type* t = e->mem->getType()->getContainedType(0);
|
||||
const llvm::Type* t = e->ptr->getType()->getContainedType(0);
|
||||
llvm::Value* ret = 0;
|
||||
if (e->arg != 0) {
|
||||
if (e->len != 0) {
|
||||
// this means it's a real slice
|
||||
ret = e->mem;
|
||||
ret = e->ptr;
|
||||
|
||||
size_t elembsz = gTargetData->getTypeSize(ret->getType());
|
||||
llvm::ConstantInt* elemsz = llvm::ConstantInt::get(DtoSize_t(), elembsz, false);
|
||||
|
||||
if (llvm::isa<llvm::ConstantInt>(e->arg)) {
|
||||
sz = llvm::ConstantExpr::getMul(elemsz, llvm::cast<llvm::Constant>(e->arg));
|
||||
if (llvm::isa<llvm::ConstantInt>(e->len)) {
|
||||
sz = llvm::ConstantExpr::getMul(elemsz, llvm::cast<llvm::Constant>(e->len));
|
||||
}
|
||||
else {
|
||||
sz = llvm::BinaryOperator::createMul(elemsz,e->arg,"tmp",gIR->scopebb());
|
||||
sz = llvm::BinaryOperator::createMul(elemsz,e->len,"tmp",gIR->scopebb());
|
||||
}
|
||||
}
|
||||
else if (llvm::isa<llvm::ArrayType>(t)) {
|
||||
ret = DtoGEPi(e->mem, 0, 0, "tmp", gIR->scopebb());
|
||||
ret = DtoGEPi(e->ptr, 0, 0, "tmp", gIR->scopebb());
|
||||
|
||||
size_t elembsz = gTargetData->getTypeSize(ret->getType()->getContainedType(0));
|
||||
llvm::ConstantInt* elemsz = llvm::ConstantInt::get(DtoSize_t(), elembsz, false);
|
||||
@@ -344,13 +367,13 @@ static llvm::Value* get_slice_ptr(elem* e, llvm::Value*& sz)
|
||||
sz = llvm::ConstantExpr::getMul(elemsz, nelems);
|
||||
}
|
||||
else if (llvm::isa<llvm::StructType>(t)) {
|
||||
ret = DtoGEPi(e->mem, 0, 1, "tmp", gIR->scopebb());
|
||||
ret = DtoGEPi(e->ptr, 0, 1, "tmp", gIR->scopebb());
|
||||
ret = new llvm::LoadInst(ret, "tmp", gIR->scopebb());
|
||||
|
||||
size_t elembsz = gTargetData->getTypeSize(ret->getType()->getContainedType(0));
|
||||
llvm::ConstantInt* elemsz = llvm::ConstantInt::get(DtoSize_t(), elembsz, false);
|
||||
|
||||
llvm::Value* len = DtoGEPi(e->mem, 0, 0, "tmp", gIR->scopebb());
|
||||
llvm::Value* len = DtoGEPi(e->ptr, 0, 0, "tmp", gIR->scopebb());
|
||||
len = new llvm::LoadInst(len, "tmp", gIR->scopebb());
|
||||
sz = llvm::BinaryOperator::createMul(len,elemsz,"tmp",gIR->scopebb());
|
||||
}
|
||||
@@ -360,13 +383,8 @@ static llvm::Value* get_slice_ptr(elem* e, llvm::Value*& sz)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DtoArrayCopy(elem* dst, elem* src)
|
||||
void DtoArrayCopy(DSliceValue* dst, DSliceValue* src)
|
||||
{
|
||||
Logger::cout() << "Array copy ((((" << *src->mem << ")))) into ((((" << *dst->mem << "))))\n";
|
||||
|
||||
assert(dst->type == elem::SLICE);
|
||||
assert(src->type == elem::SLICE);
|
||||
|
||||
llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty);
|
||||
|
||||
llvm::Value* sz1;
|
||||
@@ -435,9 +453,8 @@ llvm::Value* DtoNewDynArray(llvm::Value* dst, llvm::Value* dim, Type* dty, bool
|
||||
llvm::Value* newptr = DtoRealloc(nullptr, bytesize);
|
||||
|
||||
if (doinit) {
|
||||
elem* e = dty->defaultInit()->toElem(gIR);
|
||||
DtoArrayInit(newptr,dim,e->getValue());
|
||||
delete e;
|
||||
DValue* e = dty->defaultInit()->toElem(gIR);
|
||||
DtoArrayInit(newptr,dim,e->getRVal());
|
||||
}
|
||||
|
||||
llvm::Value* lenptr = DtoGEPi(dst,0,0,"tmp",gIR->scopebb());
|
||||
@@ -449,7 +466,7 @@ llvm::Value* DtoNewDynArray(llvm::Value* dst, llvm::Value* dim, Type* dty, bool
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
void DtoResizeDynArray(llvm::Value* arr, llvm::Value* sz)
|
||||
llvm::Value* DtoResizeDynArray(llvm::Value* arr, llvm::Value* sz)
|
||||
{
|
||||
llvm::Value* ptr = DtoGEPi(arr, 0, 1, "tmp", gIR->scopebb());
|
||||
llvm::Value* ptrld = new llvm::LoadInst(ptr,"tmp",gIR->scopebb());
|
||||
@@ -463,25 +480,52 @@ void DtoResizeDynArray(llvm::Value* arr, llvm::Value* sz)
|
||||
|
||||
llvm::Value* len = DtoGEPi(arr, 0, 0, "tmp", gIR->scopebb());
|
||||
new llvm::StoreInst(sz,len,gIR->scopebb());
|
||||
|
||||
return newptr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
void DtoCatAssignElement(llvm::Value* arr, Expression* exp)
|
||||
{
|
||||
llvm::Value* ptr = DtoGEPi(arr, 0, 0, "tmp", gIR->scopebb());
|
||||
llvm::Value* idx = new llvm::LoadInst(ptr, "tmp", gIR->scopebb());
|
||||
llvm::Value* ptr = DtoGEPi(arr, 0, 0, "tmp");
|
||||
llvm::Value* idx = DtoLoad(ptr);
|
||||
llvm::Value* one = llvm::ConstantInt::get(idx->getType(),1,false);
|
||||
llvm::Value* len = llvm::BinaryOperator::createAdd(idx, one, "tmp", gIR->scopebb());
|
||||
DtoResizeDynArray(arr,len);
|
||||
|
||||
ptr = DtoGEPi(arr, 0, 1, "tmp", gIR->scopebb());
|
||||
ptr = new llvm::LoadInst(ptr, "tmp", gIR->scopebb());
|
||||
ptr = DtoLoad(DtoGEPi(arr, 0, 1, "tmp"));
|
||||
ptr = new llvm::GetElementPtrInst(ptr, idx, "tmp", gIR->scopebb());
|
||||
|
||||
elem* e = exp->toElem(gIR);
|
||||
Type* et = DtoDType(exp->type);
|
||||
DtoAssign(et, ptr, e->getValue());
|
||||
delete e;
|
||||
DValue* dptr = new DVarValue(exp->type, ptr, true);
|
||||
|
||||
gIR->exps.push_back(IRExp(0,exp,dptr));
|
||||
DValue* e = exp->toElem(gIR);
|
||||
gIR->exps.pop_back();
|
||||
|
||||
if (!e->inPlace())
|
||||
DtoAssign(dptr, e);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
void DtoCatAssignArray(llvm::Value* arr, Expression* exp)
|
||||
{
|
||||
DValue* e = exp->toElem(gIR);
|
||||
|
||||
llvm::Value *len1, *len2, *src1, *src2, *res;
|
||||
|
||||
DValue* darr = new DVarValue(exp->type, arr, true);
|
||||
|
||||
len1 = DtoArrayLen(darr);
|
||||
len2 = DtoArrayLen(e);
|
||||
res = gIR->ir->CreateAdd(len1,len2,"tmp");
|
||||
|
||||
llvm::Value* mem = DtoResizeDynArray(arr,res);
|
||||
|
||||
src1 = DtoArrayPtr(darr);
|
||||
src2 = DtoArrayPtr(e);
|
||||
|
||||
mem = gIR->ir->CreateGEP(mem,len1,"tmp");
|
||||
DtoMemCpy(mem,src2,len2);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -493,13 +537,11 @@ void DtoCatArrays(llvm::Value* arr, Expression* exp1, Expression* exp2)
|
||||
assert(t1->ty == Tarray);
|
||||
assert(t1->ty == t2->ty);
|
||||
|
||||
elem* e1 = exp1->toElem(gIR);
|
||||
llvm::Value* a = e1->getValue();
|
||||
delete e1;
|
||||
DValue* e1 = exp1->toElem(gIR);
|
||||
llvm::Value* a = e1->getRVal();
|
||||
|
||||
elem* e2 = exp2->toElem(gIR);
|
||||
llvm::Value* b = e2->getValue();
|
||||
delete e2;
|
||||
DValue* e2 = exp2->toElem(gIR);
|
||||
llvm::Value* b = e2->getRVal();
|
||||
|
||||
llvm::Value *len1, *len2, *src1, *src2, *res;
|
||||
len1 = gIR->ir->CreateLoad(DtoGEPi(a,0,0,"tmp"),"tmp");
|
||||
@@ -670,3 +712,43 @@ llvm::Constant* DtoConstStaticArray(const llvm::Type* t, llvm::Constant* c)
|
||||
initvals.resize(at->getNumElements(), c);
|
||||
return llvm::ConstantArray::get(at, initvals);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
llvm::Value* DtoArrayLen(DValue* v)
|
||||
{
|
||||
Type* t = DtoDType(v->getType());
|
||||
if (t->ty == Tarray) {
|
||||
if (DSliceValue* s = v->isSlice()) {
|
||||
if (s->len) return s->len;
|
||||
DValue* next = new DVarValue(t,s->ptr,true);
|
||||
return DtoArrayLen(next);
|
||||
}
|
||||
return DtoLoad(DtoGEPi(v->getRVal(), 0,0, "tmp"));
|
||||
}
|
||||
else if (t->ty == Tsarray) {
|
||||
const llvm::ArrayType* t = llvm::cast<llvm::ArrayType>(v->getLVal()->getType());
|
||||
return DtoConstSize_t(t->getNumElements());
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
llvm::Value* DtoArrayPtr(DValue* v)
|
||||
{
|
||||
Type* t = DtoDType(v->getType());
|
||||
if (t->ty == Tarray) {
|
||||
if (DSliceValue* s = v->isSlice()) {
|
||||
if (s->len) return s->ptr;
|
||||
DValue* next = new DVarValue(t,s->ptr,true);
|
||||
return DtoArrayPtr(next);
|
||||
}
|
||||
return DtoLoad(DtoGEPi(v->getRVal(), 0,1, "tmp"));
|
||||
}
|
||||
else if (t->ty == Tsarray) {
|
||||
return DtoGEPi(v->getRVal(), 0,0, "tmp");
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
11
gen/arrays.h
11
gen/arrays.h
@@ -1,6 +1,8 @@
|
||||
#ifndef LLVMC_GEN_ARRAYS_H
|
||||
#define LLVMC_GEN_ARRAYS_H
|
||||
|
||||
struct DSliceValue;
|
||||
|
||||
const llvm::StructType* DtoArrayType(Type* t);
|
||||
const llvm::ArrayType* DtoStaticArrayType(Type* t);
|
||||
|
||||
@@ -8,7 +10,8 @@ llvm::Constant* DtoConstArrayInitializer(ArrayInitializer* si);
|
||||
llvm::Constant* DtoConstSlice(llvm::Constant* dim, llvm::Constant* ptr);
|
||||
llvm::Constant* DtoConstStaticArray(const llvm::Type* t, llvm::Constant* c);
|
||||
|
||||
void DtoArrayCopy(elem* dst, elem* src);
|
||||
void DtoArrayCopy(DSliceValue* dst, DSliceValue* src);
|
||||
|
||||
void DtoArrayInit(llvm::Value* l, llvm::Value* r);
|
||||
void DtoArrayInit(llvm::Value* ptr, llvm::Value* dim, llvm::Value* val);
|
||||
void DtoArrayAssign(llvm::Value* l, llvm::Value* r);
|
||||
@@ -16,9 +19,10 @@ void DtoSetArray(llvm::Value* arr, llvm::Value* dim, llvm::Value* ptr);
|
||||
void DtoNullArray(llvm::Value* v);
|
||||
|
||||
llvm::Value* DtoNewDynArray(llvm::Value* dst, llvm::Value* dim, Type* dty, bool doinit=true);
|
||||
void DtoResizeDynArray(llvm::Value* arr, llvm::Value* sz);
|
||||
llvm::Value* DtoResizeDynArray(llvm::Value* arr, llvm::Value* sz);
|
||||
|
||||
void DtoCatAssignElement(llvm::Value* arr, Expression* exp);
|
||||
void DtoCatAssignArray(llvm::Value* arr, Expression* exp);
|
||||
void DtoCatArrays(llvm::Value* arr, Expression* e1, Expression* e2);
|
||||
|
||||
void DtoStaticArrayCopy(llvm::Value* dst, llvm::Value* src);
|
||||
@@ -30,4 +34,7 @@ llvm::Value* DtoDynArrayIs(TOK op, llvm::Value* l, llvm::Value* r);
|
||||
|
||||
llvm::Value* DtoArrayCastLength(llvm::Value* len, const llvm::Type* elemty, const llvm::Type* newelemty);
|
||||
|
||||
llvm::Value* DtoArrayLen(DValue* v);
|
||||
llvm::Value* DtoArrayPtr(DValue* v);
|
||||
|
||||
#endif // LLVMC_GEN_ARRAYS_H
|
||||
|
||||
56
gen/binops.cpp
Normal file
56
gen/binops.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#include "gen/llvm.h"
|
||||
|
||||
#include "declaration.h"
|
||||
|
||||
#include "gen/irstate.h"
|
||||
#include "gen/dvalue.h"
|
||||
|
||||
DValue* DtoBinAdd(DValue* lhs, DValue* rhs)
|
||||
{
|
||||
llvm::Value* v = gIR->ir->CreateAdd(lhs->getRVal(), rhs->getRVal(), "tmp");
|
||||
return new DImValue( lhs->getType(), v );
|
||||
}
|
||||
|
||||
DValue* DtoBinSub(DValue* lhs, DValue* rhs)
|
||||
{
|
||||
llvm::Value* v = gIR->ir->CreateSub(lhs->getRVal(), rhs->getRVal(), "tmp");
|
||||
return new DImValue( lhs->getType(), v );
|
||||
}
|
||||
|
||||
DValue* DtoBinMul(DValue* lhs, DValue* rhs)
|
||||
{
|
||||
llvm::Value* v = gIR->ir->CreateMul(lhs->getRVal(), rhs->getRVal(), "tmp");
|
||||
return new DImValue( lhs->getType(), v );
|
||||
}
|
||||
|
||||
DValue* DtoBinDiv(DValue* lhs, DValue* rhs)
|
||||
{
|
||||
Type* t = lhs->getType();
|
||||
llvm::Value *l, *r;
|
||||
l = lhs->getRVal();
|
||||
r = rhs->getRVal();
|
||||
llvm::Value* res;
|
||||
if (t->isfloating())
|
||||
res = gIR->ir->CreateFDiv(l, r, "tmp");
|
||||
else if (!t->isunsigned())
|
||||
res = gIR->ir->CreateSDiv(l, r, "tmp");
|
||||
else
|
||||
res = gIR->ir->CreateUDiv(l, r, "tmp");
|
||||
return new DImValue( lhs->getType(), res );
|
||||
}
|
||||
|
||||
DValue* DtoBinRem(DValue* lhs, DValue* rhs)
|
||||
{
|
||||
Type* t = lhs->getType();
|
||||
llvm::Value *l, *r;
|
||||
l = lhs->getRVal();
|
||||
r = rhs->getRVal();
|
||||
llvm::Value* res;
|
||||
if (t->isfloating())
|
||||
res = gIR->ir->CreateFRem(l, r, "tmp");
|
||||
else if (!t->isunsigned())
|
||||
res = gIR->ir->CreateSRem(l, r, "tmp");
|
||||
else
|
||||
res = gIR->ir->CreateURem(l, r, "tmp");
|
||||
return new DImValue( lhs->getType(), res );
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
/*
|
||||
#include <iostream>
|
||||
|
||||
#include "gen/llvm.h"
|
||||
@@ -5,11 +6,14 @@
|
||||
#include "gen/elem.h"
|
||||
#include "gen/irstate.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/dvalue.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
elem::elem()
|
||||
elem::elem(Expression* e)
|
||||
{
|
||||
exp = e;
|
||||
|
||||
mem = 0;
|
||||
val = 0;
|
||||
arg = 0;
|
||||
@@ -24,10 +28,22 @@ elem::elem()
|
||||
|
||||
vardecl = 0;
|
||||
funcdecl = 0;
|
||||
|
||||
dvalue = 0;
|
||||
}
|
||||
|
||||
elem::~elem()
|
||||
{
|
||||
delete dvalue;
|
||||
}
|
||||
|
||||
llvm::Value* elem::getValue()
|
||||
{
|
||||
if (dvalue && !dvalue->isSlice()) {
|
||||
Logger::println("HAS DVALUE");
|
||||
return dvalue->getRVal();
|
||||
}
|
||||
|
||||
assert(val || mem);
|
||||
switch(type)
|
||||
{
|
||||
@@ -66,3 +82,4 @@ llvm::Value* elem::getValue()
|
||||
assert(0 && "type == invalid value");
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
16
gen/elem.h
16
gen/elem.h
@@ -1,10 +1,17 @@
|
||||
#ifndef LLVMDC_GEN_ELEM_H
|
||||
#define LLVMDC_GEN_ELEM_H
|
||||
|
||||
#include "dvalue.h"
|
||||
typedef DValue elem;
|
||||
|
||||
/*
|
||||
|
||||
#include "root.h"
|
||||
#include "declaration.h"
|
||||
#include "aggregate.h"
|
||||
|
||||
struct DValue;
|
||||
|
||||
// represents a value. be it a constant literal, a variable etc.
|
||||
// maintains all the information for doing load/store appropriately
|
||||
struct elem : Object
|
||||
@@ -22,7 +29,10 @@ struct elem : Object
|
||||
};
|
||||
|
||||
public:
|
||||
elem();
|
||||
elem(Expression* e);
|
||||
virtual ~elem();
|
||||
|
||||
Expression* exp;
|
||||
|
||||
llvm::Value* mem;
|
||||
llvm::Value* val;
|
||||
@@ -41,7 +51,11 @@ public:
|
||||
llvm::Value* getValue();
|
||||
//llvm::Value* getMemory();
|
||||
|
||||
DValue* dvalue;
|
||||
|
||||
bool isNull() {return !(mem || val);}
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
#endif // LLVMDC_GEN_ELEM_H
|
||||
|
||||
@@ -164,7 +164,7 @@ IRExp::IRExp()
|
||||
v = NULL;
|
||||
}
|
||||
|
||||
IRExp::IRExp(Expression* l, Expression* r, llvm::Value* val)
|
||||
IRExp::IRExp(Expression* l, Expression* r, DValue* val)
|
||||
{
|
||||
e1 = l;
|
||||
e2 = r;
|
||||
@@ -101,9 +101,9 @@ struct IRExp
|
||||
{
|
||||
Expression* e1;
|
||||
Expression* e2;
|
||||
llvm::Value* v;
|
||||
DValue* v;
|
||||
IRExp();
|
||||
IRExp(Expression* l, Expression* r, llvm::Value* val);
|
||||
IRExp(Expression* l, Expression* r, DValue* val);
|
||||
};
|
||||
|
||||
// represents the module
|
||||
@@ -158,7 +158,7 @@ struct IRState
|
||||
// might be a better way but it works. problem is I only get a
|
||||
// VarDeclaration for __dollar, but I can't see how to get the
|
||||
// array pointer from this :(
|
||||
std::vector<llvm::Value*> arrays;
|
||||
std::vector<DValue*> arrays;
|
||||
|
||||
// builder helper
|
||||
IRBuilderHelper ir;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "gen/runtime.h"
|
||||
#include "gen/arrays.h"
|
||||
#include "gen/todebug.h"
|
||||
#include "gen/dvalue.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -66,34 +67,14 @@ void ReturnStatement::toIR(IRState* p)
|
||||
|
||||
if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum);
|
||||
|
||||
p->exps.push_back(IRExp(NULL,exp,f->llvmRetArg));
|
||||
elem* e = exp->toElem(p);
|
||||
DValue* rvar = new DVarValue(f->next, f->llvmRetArg, true);
|
||||
|
||||
p->exps.push_back(IRExp(NULL,exp,rvar));
|
||||
DValue* e = exp->toElem(p);
|
||||
p->exps.pop_back();
|
||||
|
||||
if (expty == Tstruct) {
|
||||
if (!e->inplace)
|
||||
DtoStructCopy(f->llvmRetArg,e->getValue());
|
||||
}
|
||||
else if (expty == Tdelegate) {
|
||||
if (!e->inplace)
|
||||
DtoDelegateCopy(f->llvmRetArg,e->getValue());
|
||||
}
|
||||
else if (expty == Tarray) {
|
||||
if (e->type == elem::SLICE) {
|
||||
assert(e->mem);
|
||||
DtoSetArray(f->llvmRetArg,e->arg,e->mem);
|
||||
}
|
||||
else if (!e->inplace) {
|
||||
if (e->type == elem::NUL) {
|
||||
DtoNullArray(f->llvmRetArg);
|
||||
}
|
||||
else {
|
||||
DtoArrayAssign(f->llvmRetArg, e->getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
if (!e->inPlace())
|
||||
DtoAssign(rvar, e);
|
||||
|
||||
IRFunction::FinallyVec& fin = p->func().finallys;
|
||||
if (fin.empty()) {
|
||||
@@ -103,12 +84,11 @@ void ReturnStatement::toIR(IRState* p)
|
||||
else {
|
||||
new llvm::BranchInst(fin.back().retbb, p->scopebb());
|
||||
}
|
||||
delete e;
|
||||
}
|
||||
else {
|
||||
if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum);
|
||||
elem* e = exp->toElem(p);
|
||||
llvm::Value* v = e->getValue();
|
||||
DValue* e = exp->toElem(p);
|
||||
llvm::Value* v = e->getRVal();
|
||||
delete e;
|
||||
Logger::cout() << "return value is '" <<*v << "'\n";
|
||||
|
||||
@@ -174,8 +154,8 @@ void IfStatement::toIR(IRState* p)
|
||||
Logger::println("IfStatement::toIR(%d): %s", wsi++, toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
elem* cond_e = condition->toElem(p);
|
||||
llvm::Value* cond_val = cond_e->getValue();
|
||||
DValue* cond_e = condition->toElem(p);
|
||||
llvm::Value* cond_val = cond_e->getRVal();
|
||||
delete cond_e;
|
||||
|
||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||
@@ -265,8 +245,8 @@ void WhileStatement::toIR(IRState* p)
|
||||
gIR->scope() = IRScope(whilebb,endbb);
|
||||
|
||||
// create the condition
|
||||
elem* cond_e = condition->toElem(p);
|
||||
llvm::Value* cond_val = DtoBoolean(cond_e->getValue());
|
||||
DValue* cond_e = condition->toElem(p);
|
||||
llvm::Value* cond_val = DtoBoolean(cond_e->getRVal());
|
||||
delete cond_e;
|
||||
|
||||
// conditional branch
|
||||
@@ -308,8 +288,8 @@ void DoStatement::toIR(IRState* p)
|
||||
body->toIR(p);
|
||||
|
||||
// create the condition
|
||||
elem* cond_e = condition->toElem(p);
|
||||
llvm::Value* cond_val = DtoBoolean(cond_e->getValue());
|
||||
DValue* cond_e = condition->toElem(p);
|
||||
llvm::Value* cond_val = DtoBoolean(cond_e->getRVal());
|
||||
delete cond_e;
|
||||
|
||||
// conditional branch
|
||||
@@ -347,8 +327,8 @@ void ForStatement::toIR(IRState* p)
|
||||
gIR->scope() = IRScope(forbb,forbodybb);
|
||||
|
||||
// create the condition
|
||||
elem* cond_e = condition->toElem(p);
|
||||
llvm::Value* cond_val = DtoBoolean(cond_e->getValue());
|
||||
DValue* cond_e = condition->toElem(p);
|
||||
llvm::Value* cond_val = DtoBoolean(cond_e->getRVal());
|
||||
delete cond_e;
|
||||
|
||||
// conditional branch
|
||||
@@ -366,7 +346,7 @@ void ForStatement::toIR(IRState* p)
|
||||
|
||||
// increment
|
||||
if (increment) {
|
||||
elem* inc = increment->toElem(p);
|
||||
DValue* inc = increment->toElem(p);
|
||||
delete inc;
|
||||
}
|
||||
|
||||
@@ -543,7 +523,7 @@ void ThrowStatement::toIR(IRState* p)
|
||||
|
||||
/*
|
||||
assert(exp);
|
||||
elem* e = exp->toElem(p);
|
||||
DValue* e = exp->toElem(p);
|
||||
delete e;
|
||||
*/
|
||||
}
|
||||
@@ -565,9 +545,10 @@ void SwitchStatement::toIR(IRState* p)
|
||||
CaseStatement* cs = (CaseStatement*)cases->data[i];
|
||||
|
||||
// get the case value
|
||||
elem* e = cs->exp->toElem(p);
|
||||
assert(e->val && llvm::isa<llvm::ConstantInt>(e->val));
|
||||
llvm::ConstantInt* ec = llvm::cast<llvm::ConstantInt>(e->val);
|
||||
DValue* e = cs->exp->toElem(p);
|
||||
DConstValue* ce = e->isConst();
|
||||
assert(ce && llvm::isa<llvm::ConstantInt>(ce->c));
|
||||
llvm::ConstantInt* ec = llvm::cast<llvm::ConstantInt>(ce->c);
|
||||
delete e;
|
||||
|
||||
// create the case bb with a nice label
|
||||
@@ -587,8 +568,8 @@ void SwitchStatement::toIR(IRState* p)
|
||||
llvm::BasicBlock* endbb = new llvm::BasicBlock("switchend", p->topfunc(), oldend);
|
||||
|
||||
// condition var
|
||||
elem* cond = condition->toElem(p);
|
||||
llvm::SwitchInst* si = new llvm::SwitchInst(cond->getValue(), defbb ? defbb : endbb, cases->dim, p->scopebb());
|
||||
DValue* cond = condition->toElem(p);
|
||||
llvm::SwitchInst* si = new llvm::SwitchInst(cond->getRVal(), defbb ? defbb : endbb, cases->dim, p->scopebb());
|
||||
delete cond;
|
||||
|
||||
// add the cases
|
||||
@@ -678,9 +659,12 @@ void ForeachStatement::toIR(IRState* p)
|
||||
Logger::println("aggr = %s", aggr->toChars());
|
||||
Logger::println("func = %s", func->toChars());
|
||||
|
||||
elem* arr = aggr->toElem(p);
|
||||
llvm::Value* val = arr->getValue();
|
||||
Logger::cout() << "aggr2llvm = " << *val << '\n';
|
||||
DValue* arr = aggr->toElem(p);
|
||||
llvm::Value* val = 0;
|
||||
if (!arr->isSlice()) {
|
||||
val = arr->getRVal();
|
||||
Logger::cout() << "aggr2llvm = " << *val << '\n';
|
||||
}
|
||||
|
||||
llvm::Value* numiters = 0;
|
||||
|
||||
@@ -689,7 +673,7 @@ void ForeachStatement::toIR(IRState* p)
|
||||
if (key) key->llvmValue = keyvar;
|
||||
|
||||
const llvm::Type* valtype = DtoType(value->type);
|
||||
llvm::Value* valvar = !value->isRef() ? new llvm::AllocaInst(valtype, "foreachval", p->topallocapoint()) : NULL;
|
||||
llvm::Value* valvar = !(value->isRef() || value->isOut()) ? new llvm::AllocaInst(valtype, "foreachval", p->topallocapoint()) : NULL;
|
||||
|
||||
Type* aggrtype = DtoDType(aggr->type);
|
||||
if (aggrtype->ty == Tsarray)
|
||||
@@ -702,9 +686,9 @@ void ForeachStatement::toIR(IRState* p)
|
||||
}
|
||||
else if (aggrtype->ty == Tarray)
|
||||
{
|
||||
if (arr->type == elem::SLICE) {
|
||||
numiters = arr->arg;
|
||||
val = arr->mem;
|
||||
if (DSliceValue* slice = arr->isSlice()) {
|
||||
numiters = slice->len;
|
||||
val = slice->ptr;
|
||||
}
|
||||
else {
|
||||
numiters = p->ir->CreateLoad(DtoGEPi(val,0,0,"tmp",p->scopebb()));
|
||||
@@ -760,12 +744,12 @@ void ForeachStatement::toIR(IRState* p)
|
||||
else if (aggrtype->ty == Tarray)
|
||||
value->llvmValue = new llvm::GetElementPtrInst(val,loadedKey,"tmp",p->scopebb());
|
||||
|
||||
if (!value->isRef()) {
|
||||
elem* e = new elem;
|
||||
e->mem = value->llvmValue;
|
||||
e->type = elem::VAR;
|
||||
DtoAssign(DtoDType(value->type), valvar, e->getValue());
|
||||
delete e;
|
||||
if (!value->isRef() && !value->isOut()) {
|
||||
DValue* dst = new DVarValue(value->type, valvar, true);
|
||||
DValue* src = new DVarValue(value->type, value->llvmValue, true);
|
||||
DtoAssign(dst, src);
|
||||
delete dst;
|
||||
delete src;
|
||||
value->llvmValue = valvar;
|
||||
}
|
||||
|
||||
@@ -798,9 +782,12 @@ void LabelStatement::toIR(IRState* p)
|
||||
else
|
||||
llvmBB = new llvm::BasicBlock("label", p->topfunc(), oldend);
|
||||
|
||||
new llvm::BranchInst(llvmBB, p->scopebb());
|
||||
if (!p->scopereturned())
|
||||
new llvm::BranchInst(llvmBB, p->scopebb());
|
||||
|
||||
p->scope() = IRScope(llvmBB,oldend);
|
||||
statement->toIR(p);
|
||||
if (statement)
|
||||
statement->toIR(p);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -817,6 +804,7 @@ void GotoStatement::toIR(IRState* p)
|
||||
|
||||
if (label->statement->llvmBB == NULL)
|
||||
label->statement->llvmBB = new llvm::BasicBlock("label", p->topfunc());
|
||||
assert(!p->scopereturned());
|
||||
new llvm::BranchInst(label->statement->llvmBB, p->scopebb());
|
||||
p->scope() = IRScope(bb,oldend);
|
||||
}
|
||||
@@ -831,8 +819,8 @@ void WithStatement::toIR(IRState* p)
|
||||
assert(exp);
|
||||
assert(body);
|
||||
|
||||
elem* e = exp->toElem(p);
|
||||
wthis->llvmValue = e->getValue();
|
||||
DValue* e = exp->toElem(p);
|
||||
wthis->llvmValue = e->getRVal();
|
||||
delete e;
|
||||
|
||||
body->toIR(p);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,13 +12,13 @@
|
||||
#include "gen/irstate.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/runtime.h"
|
||||
#include "gen/elem.h"
|
||||
#include "gen/arrays.h"
|
||||
#include "gen/dvalue.h"
|
||||
|
||||
bool DtoIsPassedByRef(Type* type)
|
||||
{
|
||||
TY t = DtoDType(type)->ty;
|
||||
return (t == Tstruct || t == Tarray || t == Tdelegate);
|
||||
return (t == Tstruct || t == Tarray || t == Tdelegate || t == Tsarray);
|
||||
}
|
||||
|
||||
Type* DtoDType(Type* t)
|
||||
@@ -890,7 +890,7 @@ llvm::Constant* DtoConstInitializer(Type* type, Initializer* init)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
elem* DtoInitializer(Initializer* init)
|
||||
DValue* DtoInitializer(Initializer* init)
|
||||
{
|
||||
if (ExpInitializer* ex = init->isExpInitializer())
|
||||
{
|
||||
@@ -1069,7 +1069,7 @@ llvm::Function* DtoDeclareFunction(FuncDeclaration* fdecl)
|
||||
{
|
||||
Argument* arg = Argument::getNth(f->parameters, k++);
|
||||
//arg->llvmValue = iarg;
|
||||
//printf("identifier: '%s' %p\n", arg->ident->toChars(), arg->ident);
|
||||
//Logger::println("identifier: '%s' %p\n", arg->ident->toChars(), arg->ident);
|
||||
if (arg && arg->ident != 0) {
|
||||
if (arg->vardecl) {
|
||||
arg->vardecl->llvmValue = iarg;
|
||||
@@ -1094,6 +1094,8 @@ llvm::Function* DtoDeclareFunction(FuncDeclaration* fdecl)
|
||||
}
|
||||
}
|
||||
|
||||
Logger::cout() << "func decl: " << *func << '\n';
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
@@ -1163,15 +1165,13 @@ llvm::Value* DtoArgument(const llvm::Type* paramtype, Argument* fnarg, Expressio
|
||||
if (haslvals)
|
||||
gIR->exps.push_back(IRExp(NULL,NULL,NULL));
|
||||
|
||||
elem* arg = argexp->toElem(gIR);
|
||||
DValue* arg = argexp->toElem(gIR);
|
||||
|
||||
if (haslvals)
|
||||
gIR->exps.pop_back();
|
||||
|
||||
if (arg->inplace) {
|
||||
assert(arg->mem != 0);
|
||||
retval = arg->mem;
|
||||
delete arg;
|
||||
if (arg->inPlace()) {
|
||||
retval = arg->getRVal();
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -1179,8 +1179,13 @@ llvm::Value* DtoArgument(const llvm::Type* paramtype, Argument* fnarg, Expressio
|
||||
TY argty = realtype->ty;
|
||||
if (DtoIsPassedByRef(realtype)) {
|
||||
if (!fnarg || !fnarg->llvmCopy) {
|
||||
retval = arg->getValue();
|
||||
assert(retval != 0);
|
||||
if (DSliceValue* sv = arg->isSlice()) {
|
||||
retval = new llvm::AllocaInst(DtoType(realtype), "tmpparam", gIR->topallocapoint());
|
||||
DtoSetArray(retval, DtoArrayLen(sv), DtoArrayPtr(sv));
|
||||
}
|
||||
else {
|
||||
retval = arg->getRVal();
|
||||
}
|
||||
}
|
||||
else {
|
||||
llvm::Value* allocaInst = 0;
|
||||
@@ -1190,54 +1195,61 @@ llvm::Value* DtoArgument(const llvm::Type* paramtype, Argument* fnarg, Expressio
|
||||
const llvm::PointerType* pty = llvm::PointerType::get(realtypell);
|
||||
if (argty == Tstruct) {
|
||||
allocaInst = new llvm::AllocaInst(pty->getElementType(), "tmpparam", gIR->topallocapoint());
|
||||
DtoStructCopy(allocaInst,arg->mem);
|
||||
DValue* dst = new DVarValue(realtype, allocaInst, true);
|
||||
DtoAssign(dst,arg);
|
||||
delete dst;
|
||||
}
|
||||
else if (argty == Tdelegate) {
|
||||
allocaInst = new llvm::AllocaInst(pty->getElementType(), "tmpparam", gIR->topallocapoint());
|
||||
DtoDelegateCopy(allocaInst,arg->mem);
|
||||
DValue* dst = new DVarValue(realtype, allocaInst, true);
|
||||
DtoAssign(dst,arg);
|
||||
delete dst;
|
||||
}
|
||||
else if (argty == Tarray) {
|
||||
if (arg->type == elem::SLICE) {
|
||||
if (arg->isSlice()) {
|
||||
allocaInst = new llvm::AllocaInst(realtypell, "tmpparam", gIR->topallocapoint());
|
||||
DtoSetArray(allocaInst, arg->arg, arg->mem);
|
||||
}
|
||||
else if (arg->temp) {
|
||||
allocaInst = arg->mem;
|
||||
}
|
||||
else {
|
||||
allocaInst = new llvm::AllocaInst(pty->getElementType(), "tmpparam", gIR->topallocapoint());
|
||||
DtoArrayAssign(allocaInst,arg->mem);
|
||||
}
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
|
||||
DValue* dst = new DVarValue(realtype, allocaInst, true);
|
||||
DtoAssign(dst,arg);
|
||||
delete dst;
|
||||
|
||||
retval = allocaInst;
|
||||
}
|
||||
}
|
||||
else if (!fnarg || fnarg->llvmCopy) {
|
||||
Logger::println("regular arg");
|
||||
assert(arg->type != elem::SLICE);
|
||||
if (arg->mem) Logger::cout() << "mem = " << *arg->mem << '\n';
|
||||
if (arg->val) Logger::cout() << "val = " << *arg->val << '\n';
|
||||
if (arg->arg) Logger::cout() << "arg = " << *arg->arg << '\n';
|
||||
retval = arg->arg ? arg->arg : arg->field ? arg->mem : arg->getValue();
|
||||
if (DSliceValue* sl = arg->isSlice()) {
|
||||
if (sl->ptr) Logger::cout() << "ptr = " << *sl->ptr << '\n';
|
||||
if (sl->len) Logger::cout() << "len = " << *sl->len << '\n';
|
||||
assert(0);
|
||||
}
|
||||
else {
|
||||
retval = arg->getRVal();
|
||||
}
|
||||
}
|
||||
else {
|
||||
Logger::println("as ptr arg");
|
||||
retval = arg->mem ? arg->mem : arg->val;
|
||||
retval = arg->getLVal();
|
||||
if (paramtype && retval->getType() != paramtype)
|
||||
{
|
||||
assert(retval->getType() == paramtype->getContainedType(0));
|
||||
new llvm::StoreInst(retval, arg->mem, gIR->scopebb());
|
||||
retval = arg->mem;
|
||||
assert(0);
|
||||
/*assert(retval->getType() == paramtype->getContainedType(0));
|
||||
new llvm::StoreInst(retval, arg->getLVal(), gIR->scopebb());
|
||||
retval = arg->getLVal();*/
|
||||
}
|
||||
}
|
||||
|
||||
if (fnarg && paramtype && retval->getType() != paramtype) {
|
||||
// this is unfortunately needed with the way SymOffExp is overused
|
||||
// and static arrays can end up being a pointer to their element type
|
||||
if (arg->field) {
|
||||
if (arg->isField()) {
|
||||
retval = gIR->ir->CreateBitCast(retval, paramtype, "tmp");
|
||||
}
|
||||
else {
|
||||
@@ -1307,29 +1319,78 @@ llvm::Value* DtoNestedVariable(VarDeclaration* vd)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoAssign(Type* t, llvm::Value* lhs, llvm::Value* rhs)
|
||||
void DtoAssign(DValue* lhs, DValue* rhs)
|
||||
{
|
||||
Logger::cout() << "assignment:" << '\n' << *lhs << *rhs << '\n';
|
||||
Type* t = DtoDType(lhs->getType());
|
||||
Type* t2 = DtoDType(rhs->getType());
|
||||
|
||||
if (t->ty == Tstruct) {
|
||||
assert(lhs->getType() == rhs->getType());
|
||||
DtoStructCopy(lhs,rhs);
|
||||
if (t2 != t) {
|
||||
// TODO: fix this, use 'rhs' for something
|
||||
DtoStructZeroInit(lhs->getLVal());
|
||||
}
|
||||
else if (!rhs->inPlace()) {
|
||||
DtoStructCopy(lhs->getLVal(),rhs->getRVal());
|
||||
}
|
||||
}
|
||||
else if (t->ty == Tarray) {
|
||||
assert(lhs->getType() == rhs->getType());
|
||||
DtoArrayAssign(lhs,rhs);
|
||||
// lhs is slice
|
||||
if (DSliceValue* s = lhs->isSlice()) {
|
||||
if (DSliceValue* s2 = rhs->isSlice()) {
|
||||
DtoArrayCopy(s, s2);
|
||||
}
|
||||
else if (t->next == t2) {
|
||||
if (s->len)
|
||||
DtoArrayInit(s->ptr, s->len, rhs->getRVal());
|
||||
else
|
||||
DtoArrayInit(s->ptr, rhs->getRVal());
|
||||
}
|
||||
else
|
||||
assert(rhs->inPlace());
|
||||
}
|
||||
// rhs is slice
|
||||
else if (DSliceValue* s = rhs->isSlice()) {
|
||||
DtoSetArray(lhs->getLVal(),s->len,s->ptr);
|
||||
}
|
||||
// null
|
||||
else if (rhs->isNull()) {
|
||||
DtoNullArray(lhs->getLVal());
|
||||
}
|
||||
// reference assignment
|
||||
else {
|
||||
DtoArrayAssign(lhs->getLVal(), rhs->getRVal());
|
||||
}
|
||||
}
|
||||
else if (t->ty == Tsarray) {
|
||||
assert(lhs->getType() == rhs->getType());
|
||||
DtoStaticArrayCopy(lhs,rhs);
|
||||
DtoStaticArrayCopy(lhs->getLVal(), rhs->getRVal());
|
||||
}
|
||||
else if (t->ty == Tdelegate) {
|
||||
assert(lhs->getType() == rhs->getType());
|
||||
DtoDelegateCopy(lhs,rhs);
|
||||
if (rhs->isNull())
|
||||
DtoNullDelegate(lhs->getLVal());
|
||||
else if (!rhs->inPlace())
|
||||
DtoDelegateCopy(lhs->getLVal(), rhs->getRVal());
|
||||
}
|
||||
else if (t->ty == Tclass) {
|
||||
assert(t2->ty == Tclass);
|
||||
// assignment to this in constructor special case
|
||||
if (lhs->isThis()) {
|
||||
llvm::Value* tmp = rhs->getRVal();
|
||||
FuncDeclaration* fdecl = gIR->func().decl;
|
||||
// respecify the this param
|
||||
if (!llvm::isa<llvm::AllocaInst>(fdecl->llvmThisVar))
|
||||
fdecl->llvmThisVar = new llvm::AllocaInst(tmp->getType(), "newthis", gIR->topallocapoint());
|
||||
DtoStore(tmp, fdecl->llvmThisVar);
|
||||
}
|
||||
// regular class ref -> class ref assignment
|
||||
else {
|
||||
DtoStore(rhs->getRVal(), lhs->getLVal());
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(lhs->getType()->getContainedType(0) == rhs->getType());
|
||||
gIR->ir->CreateStore(rhs, lhs);
|
||||
llvm::Value* r = rhs->getRVal();
|
||||
llvm::Value* l = lhs->getLVal();
|
||||
Logger::cout() << "assign\nlhs: " << *l << "rhs: " << *r << '\n';
|
||||
gIR->ir->CreateStore(r, l);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1409,6 +1470,31 @@ void DtoMemCpy(llvm::Value* dst, llvm::Value* src, llvm::Value* nbytes)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
llvm::Value* DtoLoad(llvm::Value* src)
|
||||
{
|
||||
return gIR->ir->CreateLoad(src,"tmp");
|
||||
}
|
||||
|
||||
void DtoStore(llvm::Value* src, llvm::Value* dst)
|
||||
{
|
||||
gIR->ir->CreateStore(src,dst);
|
||||
}
|
||||
|
||||
bool DtoCanLoad(llvm::Value* ptr)
|
||||
{
|
||||
if (llvm::isa<llvm::PointerType>(ptr->getType())) {
|
||||
return ptr->getType()->getContainedType(0)->isFirstClassType();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm::Value* DtoBitCast(llvm::Value* v, const llvm::Type* t)
|
||||
{
|
||||
return gIR->ir->CreateBitCast(v, t, "tmp");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, unsigned os, std::vector<unsigned>& idxs)
|
||||
{
|
||||
Logger::println("checking for offset %u type %s:", os, t->toChars());
|
||||
@@ -1470,7 +1556,7 @@ llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, un
|
||||
|
||||
bool DtoIsTemplateInstance(Dsymbol* s)
|
||||
{
|
||||
assert(s);
|
||||
if (!s) return false;
|
||||
if (s->isTemplateInstance() && !s->isTemplateMixin())
|
||||
return true;
|
||||
else if (s->parent)
|
||||
27
gen/tollvm.h
27
gen/tollvm.h
@@ -1,6 +1,10 @@
|
||||
#ifndef LLVMDC_GEN_TOLLVM_H
|
||||
#define LLVMDC_GEN_TOLLVM_H
|
||||
|
||||
// D -> LLVM helpers
|
||||
|
||||
struct StructInitializer;
|
||||
struct DValue;
|
||||
|
||||
const llvm::Type* DtoType(Type* t);
|
||||
bool DtoIsPassedByRef(Type* type);
|
||||
@@ -55,8 +59,6 @@ llvm::Value* DtoArgument(const llvm::Type* paramtype, Argument* fnarg, Expressio
|
||||
|
||||
llvm::Value* DtoNestedVariable(VarDeclaration* vd);
|
||||
|
||||
void DtoAssign(Type* lhsType, llvm::Value* lhs, llvm::Value* rhs);
|
||||
|
||||
llvm::ConstantInt* DtoConstSize_t(size_t);
|
||||
llvm::ConstantInt* DtoConstUint(unsigned i);
|
||||
llvm::ConstantInt* DtoConstInt(int i);
|
||||
@@ -64,10 +66,27 @@ llvm::Constant* DtoConstString(const char*);
|
||||
llvm::Constant* DtoConstStringPtr(const char* str, const char* section = 0);
|
||||
llvm::Constant* DtoConstBool(bool);
|
||||
|
||||
void DtoMemCpy(llvm::Value* dst, llvm::Value* src, llvm::Value* nbytes);
|
||||
|
||||
llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, unsigned os, std::vector<unsigned>& idxs);
|
||||
|
||||
bool DtoIsTemplateInstance(Dsymbol* s);
|
||||
|
||||
// llvm wrappers
|
||||
void DtoMemCpy(llvm::Value* dst, llvm::Value* src, llvm::Value* nbytes);
|
||||
bool DtoCanLoad(llvm::Value* ptr);
|
||||
llvm::Value* DtoLoad(llvm::Value* src);
|
||||
void DtoStore(llvm::Value* src, llvm::Value* dst);
|
||||
llvm::Value* DtoBitCast(llvm::Value* v, const llvm::Type* t);
|
||||
|
||||
// basic operations
|
||||
void DtoAssign(DValue* lhs, DValue* rhs);
|
||||
|
||||
// binary operations
|
||||
DValue* DtoBinAdd(DValue* lhs, DValue* rhs);
|
||||
DValue* DtoBinSub(DValue* lhs, DValue* rhs);
|
||||
DValue* DtoBinMul(DValue* lhs, DValue* rhs);
|
||||
DValue* DtoBinDiv(DValue* lhs, DValue* rhs);
|
||||
DValue* DtoBinRem(DValue* lhs, DValue* rhs);
|
||||
|
||||
#include "enums.h"
|
||||
|
||||
#endif // LLVMDC_GEN_TOLLVM_H
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "gen/tollvm.h"
|
||||
#include "gen/arrays.h"
|
||||
#include "gen/todebug.h"
|
||||
#include "gen/runtime.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -628,8 +629,11 @@ void VarDeclaration::toObjFile()
|
||||
gIR->ir->CreateCondBr(cond, initbb, endinitbb);
|
||||
gIR->scope() = IRScope(initbb,endinitbb);
|
||||
elem* ie = DtoInitializer(init);
|
||||
if (!ie->inplace)
|
||||
DtoAssign(t, gvar, ie->getValue());
|
||||
if (!ie->inPlace()) {
|
||||
DValue* dst = new DVarValue(t, gvar, true);
|
||||
DtoAssign(dst, ie);
|
||||
delete dst;
|
||||
}
|
||||
gIR->ir->CreateStore(DtoConstBool(true), gflag);
|
||||
gIR->ir->CreateBr(endinitbb);
|
||||
gIR->scope() = IRScope(endinitbb,oldend);
|
||||
@@ -754,6 +758,13 @@ void FuncDeclaration::toObjFile()
|
||||
return;
|
||||
}
|
||||
|
||||
if (llvmRunTimeHack) {
|
||||
Logger::println("runtime hack func chars: %s", toChars());
|
||||
if (!llvmValue)
|
||||
llvmValue = LLVM_D_GetRuntimeFunction(gIR->module, toChars());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isUnitTestDeclaration()) {
|
||||
Logger::println("*** ATTENTION: ignoring unittest declaration: %s", toChars());
|
||||
return;
|
||||
@@ -763,6 +774,8 @@ void FuncDeclaration::toObjFile()
|
||||
TypeFunction* f = (TypeFunction*)t;
|
||||
|
||||
bool declareOnly = false;
|
||||
if (parent)
|
||||
{
|
||||
if (TemplateInstance* tinst = parent->isTemplateInstance()) {
|
||||
TemplateDeclaration* tempdecl = tinst->tempdecl;
|
||||
if (tempdecl->llvmInternal == LLVMva_start)
|
||||
@@ -778,6 +791,7 @@ void FuncDeclaration::toObjFile()
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Function* func = DtoDeclareFunction(this);
|
||||
|
||||
@@ -802,8 +816,7 @@ void FuncDeclaration::toObjFile()
|
||||
const llvm::FunctionType* functype = llvm::cast<llvm::FunctionType>(llvmValue->getType()->getContainedType(0));
|
||||
|
||||
// template instances should have weak linkage
|
||||
assert(parent);
|
||||
if (DtoIsTemplateInstance(parent)) {
|
||||
if (parent && DtoIsTemplateInstance(parent)) {
|
||||
func->setLinkage(llvm::GlobalValue::WeakLinkage);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ echo "compiling common runtime"
|
||||
rebuild internal/arrays.d \
|
||||
internal/mem.d \
|
||||
internal/moduleinit.d \
|
||||
-c -oqobj -dc=llvmdc-posix || exit 1
|
||||
-c -oqobj -dc=llvmdc-posix -explicit || exit 1
|
||||
|
||||
echo "compiling module init backend"
|
||||
llvm-as -f -o=obj/moduleinit_backend.bc internal/moduleinit_backend.ll || exit 1
|
||||
@@ -30,18 +30,21 @@ echo "compiling typeinfo 2"
|
||||
rebuild typeinfos2.d -c -oqobj -dc=llvmdc-posix || exit 1
|
||||
llvm-link -f -o=../lib/llvmdcore.bc `ls obj/typeinfo2.*.bc` ../lib/llvmdcore.bc || exit 1
|
||||
|
||||
echo "compiling string foreach runtime support"
|
||||
llvmdc internal/aApply.d -c -odobj || exit 1
|
||||
llvmdc internal/aApplyR.d -c -odobj || exit 1
|
||||
llvm-link -f -o=../lib/llvmdcore.bc obj/aApply.bc obj/aApplyR.bc ../lib/llvmdcore.bc || exit 1
|
||||
|
||||
echo "compiling llvm runtime support"
|
||||
rebuild llvmsupport.d -c -oqobj -dc=llvmdc-posix || exit
|
||||
llvm-link -f -o=../lib/llvmdcore.bc `ls obj/llvm.*.bc` ../lib/llvmdcore.bc || exit 1
|
||||
|
||||
echo "compiling phobos"
|
||||
rebuild phobos.d -c -oqobj -dc=llvmdc-posix || exit 1
|
||||
llvm-link -f -o=../lib/llvmdcore.bc `ls obj/std.*.bc` ../lib/llvmdcore.bc || exit 1
|
||||
|
||||
echo "optimizing"
|
||||
opt -f -std-compile-opts -o=../lib/llvmdcore.bc ../lib/llvmdcore.bc || exit 1
|
||||
|
||||
# build phobos
|
||||
echo "compiling phobos"
|
||||
rebuild phobos.d -c -oqobj -dc=llvmdc-posix || exit 1
|
||||
llvm-link -f -o=../lib/lphobos.bc `ls obj/std.*.bc` || exit 1
|
||||
opt -f -std-compile-opts -o=../lib/lphobos.bc ../lib/lphobos.bc || exit 1
|
||||
|
||||
echo "SUCCESS"
|
||||
|
||||
410
lphobos/internal/aApply.d
Normal file
410
lphobos/internal/aApply.d
Normal file
@@ -0,0 +1,410 @@
|
||||
|
||||
/**
|
||||
* Part of the D programming language runtime library.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, in both source and binary form, subject to the following
|
||||
* restrictions:
|
||||
*
|
||||
* o The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* o Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
* o This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
/* This code handles decoding UTF strings for foreach loops.
|
||||
* There are 6 combinations of conversions between char, wchar,
|
||||
* and dchar, and 2 of each of those.
|
||||
*/
|
||||
|
||||
import std.utf;
|
||||
|
||||
//debug=apply;
|
||||
|
||||
/**********************************************
|
||||
*/
|
||||
|
||||
// dg is D, but _aApplycd() is C
|
||||
extern (D) typedef int delegate(void *) dg_t;
|
||||
|
||||
extern (C) int _aApplycd1(char[] aa, dg_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplycd1(), len = %d\n", len);
|
||||
for (i = 0; i < len; )
|
||||
{ dchar d;
|
||||
|
||||
d = aa[i];
|
||||
if (d & 0x80)
|
||||
d = std.utf.decode(aa, i);
|
||||
else
|
||||
i++;
|
||||
result = dg(cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplywd1(wchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplywd1(), len = %d\n", len);
|
||||
for (i = 0; i < len; )
|
||||
{ dchar d;
|
||||
|
||||
d = aa[i];
|
||||
if (d & ~0x7F)
|
||||
d = std.utf.decode(aa, i);
|
||||
else
|
||||
i++;
|
||||
result = dg(cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplycw1(char[] aa, dg_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplycw1(), len = %d\n", len);
|
||||
for (i = 0; i < len; )
|
||||
{ dchar d;
|
||||
wchar w;
|
||||
|
||||
w = aa[i];
|
||||
if (w & 0x80)
|
||||
{ d = std.utf.decode(aa, i);
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
}
|
||||
else
|
||||
i++;
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplywc1(wchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplywc1(), len = %d\n", len);
|
||||
for (i = 0; i < len; )
|
||||
{ dchar d;
|
||||
wchar w;
|
||||
char c;
|
||||
|
||||
w = aa[i];
|
||||
if (w & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
char[] b;
|
||||
|
||||
d = std.utf.decode(aa, i);
|
||||
b = std.utf.toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{ c = cast(char)w;
|
||||
i++;
|
||||
}
|
||||
result = dg(cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplydc1(dchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplydc1(), len = %d\n", aa.length);
|
||||
foreach (dchar d; aa)
|
||||
{
|
||||
char c;
|
||||
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
char[] b;
|
||||
|
||||
b = std.utf.toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = cast(char)d;
|
||||
}
|
||||
result = dg(cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplydw1(dchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplydw1(), len = %d\n", aa.length);
|
||||
foreach (dchar d; aa)
|
||||
{
|
||||
wchar w;
|
||||
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
// dg is D, but _aApplycd2() is C
|
||||
extern (D) typedef int delegate(void *, void *) dg2_t;
|
||||
|
||||
extern (C) int _aApplycd2(char[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t n;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplycd2(), len = %d\n", len);
|
||||
for (i = 0; i < len; i += n)
|
||||
{ dchar d;
|
||||
|
||||
d = aa[i];
|
||||
if (d & 0x80)
|
||||
{
|
||||
n = i;
|
||||
d = std.utf.decode(aa, n);
|
||||
n -= i;
|
||||
}
|
||||
else
|
||||
n = 1;
|
||||
result = dg(&i, cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplywd2(wchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t n;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplywd2(), len = %d\n", len);
|
||||
for (i = 0; i < len; i += n)
|
||||
{ dchar d;
|
||||
|
||||
d = aa[i];
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
n = i;
|
||||
d = std.utf.decode(aa, n);
|
||||
n -= i;
|
||||
}
|
||||
else
|
||||
n = 1;
|
||||
result = dg(&i, cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplycw2(char[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t n;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplycw2(), len = %d\n", len);
|
||||
for (i = 0; i < len; i += n)
|
||||
{ dchar d;
|
||||
wchar w;
|
||||
|
||||
w = aa[i];
|
||||
if (w & 0x80)
|
||||
{ n = i;
|
||||
d = std.utf.decode(aa, n);
|
||||
n -= i;
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
}
|
||||
else
|
||||
n = 1;
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplywc2(wchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t n;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplywc2(), len = %d\n", len);
|
||||
for (i = 0; i < len; i += n)
|
||||
{ dchar d;
|
||||
wchar w;
|
||||
char c;
|
||||
|
||||
w = aa[i];
|
||||
if (w & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
char[] b;
|
||||
|
||||
n = i;
|
||||
d = std.utf.decode(aa, n);
|
||||
n -= i;
|
||||
b = std.utf.toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(&i, cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{ c = cast(char)w;
|
||||
n = 1;
|
||||
}
|
||||
result = dg(&i, cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplydc2(dchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplydc2(), len = %d\n", len);
|
||||
for (i = 0; i < len; i++)
|
||||
{ dchar d;
|
||||
char c;
|
||||
|
||||
d = aa[i];
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
char[] b;
|
||||
|
||||
b = std.utf.toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(&i, cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{ c = cast(char)d;
|
||||
}
|
||||
result = dg(&i, cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplydw2(dchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplydw2(), len = %d\n", aa.length);
|
||||
foreach (size_t i, dchar d; aa)
|
||||
{
|
||||
wchar w;
|
||||
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
977
lphobos/internal/aApplyR.d
Normal file
977
lphobos/internal/aApplyR.d
Normal file
@@ -0,0 +1,977 @@
|
||||
|
||||
/**
|
||||
* Part of the D programming language runtime library.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, in both source and binary form, subject to the following
|
||||
* restrictions:
|
||||
*
|
||||
* o The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* o Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
* o This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
/* This code handles decoding UTF strings for foreach_reverse loops.
|
||||
* There are 6 combinations of conversions between char, wchar,
|
||||
* and dchar, and 2 of each of those.
|
||||
*/
|
||||
|
||||
import std.utf;
|
||||
|
||||
//debug=apply;
|
||||
|
||||
/**********************************************/
|
||||
/* 1 argument versions */
|
||||
|
||||
// dg is D, but _aApplyRcd() is C
|
||||
extern (D) typedef int delegate(void *) dg_t;
|
||||
|
||||
extern (C) int _aApplyRcd1(char[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRcd1(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
|
||||
i--;
|
||||
d = aa[i];
|
||||
if (d & 0x80)
|
||||
{ char c = cast(char)d;
|
||||
uint j;
|
||||
uint m = 0x3F;
|
||||
d = 0;
|
||||
while ((c & 0xC0) != 0xC0)
|
||||
{ if (i == 0)
|
||||
throw new std.utf.UtfException("Invalid UTF-8 sequence", 0);
|
||||
i--;
|
||||
d |= (c & 0x3F) << j;
|
||||
j += 6;
|
||||
m >>= 1;
|
||||
c = aa[i];
|
||||
}
|
||||
d |= (c & m) << j;
|
||||
}
|
||||
result = dg(cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRcd1.unittest\n");
|
||||
|
||||
char[] s = "hello";
|
||||
int i;
|
||||
|
||||
foreach_reverse(dchar d; s)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(dchar d; s)
|
||||
{
|
||||
//printf("i = %d, d = %x\n", i, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); break;
|
||||
case 1: assert(d == '\U00100456'); break;
|
||||
case 2: assert(d == '\u1234'); break;
|
||||
case 3: assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 4);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRwd1(wchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRwd1(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
|
||||
i--;
|
||||
d = aa[i];
|
||||
if (d >= 0xDC00 && d <= 0xDFFF)
|
||||
{ if (i == 0)
|
||||
throw new std.utf.UtfException("Invalid UTF-16 sequence", 0);
|
||||
i--;
|
||||
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
|
||||
}
|
||||
result = dg(cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRwd1.unittest\n");
|
||||
|
||||
wchar[] s = "hello";
|
||||
int i;
|
||||
|
||||
foreach_reverse(dchar d; s)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(dchar d; s)
|
||||
{
|
||||
//printf("i = %d, d = %x\n", i, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); break;
|
||||
case 1: assert(d == '\U00100456'); break;
|
||||
case 2: assert(d == '\u1234'); break;
|
||||
case 3: assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 4);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRcw1(char[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRcw1(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
wchar w;
|
||||
|
||||
i--;
|
||||
w = aa[i];
|
||||
if (w & 0x80)
|
||||
{ char c = cast(char)w;
|
||||
uint j;
|
||||
uint m = 0x3F;
|
||||
d = 0;
|
||||
while ((c & 0xC0) != 0xC0)
|
||||
{ if (i == 0)
|
||||
throw new std.utf.UtfException("Invalid UTF-8 sequence", 0);
|
||||
i--;
|
||||
d |= (c & 0x3F) << j;
|
||||
j += 6;
|
||||
m >>= 1;
|
||||
c = aa[i];
|
||||
}
|
||||
d |= (c & m) << j;
|
||||
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
}
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRcw1.unittest\n");
|
||||
|
||||
char[] s = "hello";
|
||||
int i;
|
||||
|
||||
foreach_reverse(wchar d; s)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(wchar d; s)
|
||||
{
|
||||
//printf("i = %d, d = %x\n", i, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); break;
|
||||
case 1: assert(d == 0xDBC1); break;
|
||||
case 2: assert(d == 0xDC56); break;
|
||||
case 3: assert(d == 0x1234); break;
|
||||
case 4: assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRwc1(wchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRwc1(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
char c;
|
||||
|
||||
i--;
|
||||
d = aa[i];
|
||||
if (d >= 0xDC00 && d <= 0xDFFF)
|
||||
{ if (i == 0)
|
||||
throw new std.utf.UtfException("Invalid UTF-16 sequence", 0);
|
||||
i--;
|
||||
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
|
||||
}
|
||||
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
char[] b;
|
||||
|
||||
b = std.utf.toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
c = cast(char)d;
|
||||
result = dg(cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRwc1.unittest\n");
|
||||
|
||||
wchar[] s = "hello";
|
||||
int i;
|
||||
|
||||
foreach_reverse(char d; s)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(char d; s)
|
||||
{
|
||||
//printf("i = %d, d = %x\n", i, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); break;
|
||||
case 1: assert(d == 0xF4); break;
|
||||
case 2: assert(d == 0x80); break;
|
||||
case 3: assert(d == 0x91); break;
|
||||
case 4: assert(d == 0x96); break;
|
||||
case 5: assert(d == 0xE1); break;
|
||||
case 6: assert(d == 0x88); break;
|
||||
case 7: assert(d == 0xB4); break;
|
||||
case 8: assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 9);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRdc1(dchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRdc1(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0;)
|
||||
{ dchar d = aa[--i];
|
||||
char c;
|
||||
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
char[] b;
|
||||
|
||||
b = std.utf.toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = cast(char)d;
|
||||
}
|
||||
result = dg(cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRdc1.unittest\n");
|
||||
|
||||
dchar[] s = "hello";
|
||||
int i;
|
||||
|
||||
foreach_reverse(char d; s)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(char d; s)
|
||||
{
|
||||
//printf("i = %d, d = %x\n", i, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); break;
|
||||
case 1: assert(d == 0xF4); break;
|
||||
case 2: assert(d == 0x80); break;
|
||||
case 3: assert(d == 0x91); break;
|
||||
case 4: assert(d == 0x96); break;
|
||||
case 5: assert(d == 0xE1); break;
|
||||
case 6: assert(d == 0x88); break;
|
||||
case 7: assert(d == 0xB4); break;
|
||||
case 8: assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 9);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRdw1(dchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRdw1(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d = aa[--i];
|
||||
wchar w;
|
||||
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRdw1.unittest\n");
|
||||
|
||||
dchar[] s = "hello";
|
||||
int i;
|
||||
|
||||
foreach_reverse(wchar d; s)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(wchar d; s)
|
||||
{
|
||||
//printf("i = %d, d = %x\n", i, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); break;
|
||||
case 1: assert(d == 0xDBC1); break;
|
||||
case 2: assert(d == 0xDC56); break;
|
||||
case 3: assert(d == 0x1234); break;
|
||||
case 4: assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/* 2 argument versions */
|
||||
|
||||
// dg is D, but _aApplyRcd2() is C
|
||||
extern (D) typedef int delegate(void *, void *) dg2_t;
|
||||
|
||||
extern (C) int _aApplyRcd2(char[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplyRcd2(), len = %d\n", len);
|
||||
for (i = len; i != 0; )
|
||||
{ dchar d;
|
||||
|
||||
i--;
|
||||
d = aa[i];
|
||||
if (d & 0x80)
|
||||
{ char c = cast(char)d;
|
||||
uint j;
|
||||
uint m = 0x3F;
|
||||
d = 0;
|
||||
while ((c & 0xC0) != 0xC0)
|
||||
{ if (i == 0)
|
||||
throw new std.utf.UtfException("Invalid UTF-8 sequence", 0);
|
||||
i--;
|
||||
d |= (c & 0x3F) << j;
|
||||
j += 6;
|
||||
m >>= 1;
|
||||
c = aa[i];
|
||||
}
|
||||
d |= (c & m) << j;
|
||||
}
|
||||
result = dg(&i, cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRcd2.unittest\n");
|
||||
|
||||
char[] s = "hello";
|
||||
int i;
|
||||
|
||||
foreach_reverse(k, dchar d; s)
|
||||
{
|
||||
assert(k == 4 - i);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(k, dchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); assert(k == 8); break;
|
||||
case 1: assert(d == '\U00100456'); assert(k == 4); break;
|
||||
case 2: assert(d == '\u1234'); assert(k == 1); break;
|
||||
case 3: assert(d == 'a'); assert(k == 0); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 4);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRwd2(wchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRwd2(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
|
||||
i--;
|
||||
d = aa[i];
|
||||
if (d >= 0xDC00 && d <= 0xDFFF)
|
||||
{ if (i == 0)
|
||||
throw new std.utf.UtfException("Invalid UTF-16 sequence", 0);
|
||||
i--;
|
||||
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
|
||||
}
|
||||
result = dg(&i, cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRwd2.unittest\n");
|
||||
|
||||
wchar[] s = "hello";
|
||||
int i;
|
||||
|
||||
foreach_reverse(k, dchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
assert(k == 4 - i);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(k, dchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(k == 4); assert(d == 'b'); break;
|
||||
case 1: assert(k == 2); assert(d == '\U00100456'); break;
|
||||
case 2: assert(k == 1); assert(d == '\u1234'); break;
|
||||
case 3: assert(k == 0); assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 4);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRcw2(char[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRcw2(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
wchar w;
|
||||
|
||||
i--;
|
||||
w = aa[i];
|
||||
if (w & 0x80)
|
||||
{ char c = cast(char)w;
|
||||
uint j;
|
||||
uint m = 0x3F;
|
||||
d = 0;
|
||||
while ((c & 0xC0) != 0xC0)
|
||||
{ if (i == 0)
|
||||
throw new std.utf.UtfException("Invalid UTF-8 sequence", 0);
|
||||
i--;
|
||||
d |= (c & 0x3F) << j;
|
||||
j += 6;
|
||||
m >>= 1;
|
||||
c = aa[i];
|
||||
}
|
||||
d |= (c & m) << j;
|
||||
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
}
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRcw2.unittest\n");
|
||||
|
||||
char[] s = "hello";
|
||||
int i;
|
||||
|
||||
foreach_reverse(k, wchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
assert(k == 4 - i);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(k, wchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(k == 8); assert(d == 'b'); break;
|
||||
case 1: assert(k == 4); assert(d == 0xDBC1); break;
|
||||
case 2: assert(k == 4); assert(d == 0xDC56); break;
|
||||
case 3: assert(k == 1); assert(d == 0x1234); break;
|
||||
case 4: assert(k == 0); assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRwc2(wchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRwc2(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
char c;
|
||||
|
||||
i--;
|
||||
d = aa[i];
|
||||
if (d >= 0xDC00 && d <= 0xDFFF)
|
||||
{ if (i == 0)
|
||||
throw new std.utf.UtfException("Invalid UTF-16 sequence", 0);
|
||||
i--;
|
||||
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
|
||||
}
|
||||
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
char[] b;
|
||||
|
||||
b = std.utf.toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(&i, cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
c = cast(char)d;
|
||||
result = dg(&i, cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRwc2.unittest\n");
|
||||
|
||||
wchar[] s = "hello";
|
||||
int i;
|
||||
|
||||
foreach_reverse(k, char d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
assert(k == 4 - i);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(k, char d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(k == 4); assert(d == 'b'); break;
|
||||
case 1: assert(k == 2); assert(d == 0xF4); break;
|
||||
case 2: assert(k == 2); assert(d == 0x80); break;
|
||||
case 3: assert(k == 2); assert(d == 0x91); break;
|
||||
case 4: assert(k == 2); assert(d == 0x96); break;
|
||||
case 5: assert(k == 1); assert(d == 0xE1); break;
|
||||
case 6: assert(k == 1); assert(d == 0x88); break;
|
||||
case 7: assert(k == 1); assert(d == 0xB4); break;
|
||||
case 8: assert(k == 0); assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 9);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRdc2(dchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRdc2(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d = aa[--i];
|
||||
char c;
|
||||
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
char[] b;
|
||||
|
||||
b = std.utf.toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(&i, cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{ c = cast(char)d;
|
||||
}
|
||||
result = dg(&i, cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRdc2.unittest\n");
|
||||
|
||||
dchar[] s = "hello";
|
||||
int i;
|
||||
|
||||
foreach_reverse(k, char d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
assert(k == 4 - i);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(k, char d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(k == 3); assert(d == 'b'); break;
|
||||
case 1: assert(k == 2); assert(d == 0xF4); break;
|
||||
case 2: assert(k == 2); assert(d == 0x80); break;
|
||||
case 3: assert(k == 2); assert(d == 0x91); break;
|
||||
case 4: assert(k == 2); assert(d == 0x96); break;
|
||||
case 5: assert(k == 1); assert(d == 0xE1); break;
|
||||
case 6: assert(k == 1); assert(d == 0x88); break;
|
||||
case 7: assert(k == 1); assert(d == 0xB4); break;
|
||||
case 8: assert(k == 0); assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 9);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRdw2(dchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRdw2(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d = aa[--i];
|
||||
wchar w;
|
||||
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRdw2.unittest\n");
|
||||
|
||||
dchar[] s = "hello";
|
||||
int i;
|
||||
|
||||
foreach_reverse(k, wchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
assert(k == 4 - i);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(k, wchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(k == 3); assert(d == 'b'); break;
|
||||
case 1: assert(k == 2); assert(d == 0xDBC1); break;
|
||||
case 2: assert(k == 2); assert(d == 0xDC56); break;
|
||||
case 3: assert(k == 1); assert(d == 0x1234); break;
|
||||
case 4: assert(k == 0); assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
}
|
||||
|
||||
|
||||
@@ -1135,6 +1135,12 @@ class Exception : Object
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
void print()
|
||||
{
|
||||
char[] s = toString();
|
||||
printf("%.*s\n", s.length, s.ptr);
|
||||
}
|
||||
|
||||
char[] toString() { return msg; }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
module phobos;
|
||||
|
||||
import
|
||||
std.array,
|
||||
std.ctype,
|
||||
std.stdio,
|
||||
std.stdarg;
|
||||
std.stdarg,
|
||||
std.uni,
|
||||
std.utf;
|
||||
38
lphobos/std/array.d
Normal file
38
lphobos/std/array.d
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
module std.array;
|
||||
|
||||
private import std.c.stdio;
|
||||
|
||||
class ArrayBoundsError : Error
|
||||
{
|
||||
private:
|
||||
|
||||
uint linnum;
|
||||
char[] filename;
|
||||
|
||||
public:
|
||||
this(char[] filename, uint linnum)
|
||||
{
|
||||
this.linnum = linnum;
|
||||
this.filename = filename;
|
||||
|
||||
char[] buffer = new char[19 + filename.length + linnum.sizeof * 3 + 1];
|
||||
int len;
|
||||
len = sprintf(buffer.ptr, "ArrayBoundsError %.*s(%u)", filename, linnum);
|
||||
super(buffer[0..len]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************
|
||||
* Called by the compiler generated module assert function.
|
||||
* Builds an ArrayBoundsError exception and throws it.
|
||||
*/
|
||||
|
||||
extern (C) static void _d_array_bounds(char[] filename, uint line)
|
||||
{
|
||||
//printf("_d_assert(%s, %d)\n", (char *)filename, line);
|
||||
ArrayBoundsError a = new ArrayBoundsError(filename, line);
|
||||
//printf("assertion %p created\n", a);
|
||||
throw a;
|
||||
}
|
||||
154
lphobos/std/ctype.d
Normal file
154
lphobos/std/ctype.d
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Placed into the Public Domain.
|
||||
* Digital Mars, www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*/
|
||||
|
||||
/**
|
||||
* Simple ASCII character classification functions.
|
||||
* For Unicode classification, see $(LINK2 std_uni.html, std.uni).
|
||||
* References:
|
||||
* $(LINK2 http://www.digitalmars.com/d/ascii-table.html, ASCII Table),
|
||||
* $(LINK2 http://en.wikipedia.org/wiki/Ascii, Wikipedia)
|
||||
* Macros:
|
||||
* WIKI=Phobos/StdCtype
|
||||
*/
|
||||
|
||||
module std.ctype;
|
||||
|
||||
/**
|
||||
* Returns !=0 if c is a letter in the range (0..9, a..z, A..Z).
|
||||
*/
|
||||
int isalnum(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG) : 0; }
|
||||
|
||||
/**
|
||||
* Returns !=0 if c is an ascii upper or lower case letter.
|
||||
*/
|
||||
int isalpha(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_ALP) : 0; }
|
||||
|
||||
/**
|
||||
* Returns !=0 if c is a control character.
|
||||
*/
|
||||
int iscntrl(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_CTL) : 0; }
|
||||
|
||||
/**
|
||||
* Returns !=0 if c is a digit.
|
||||
*/
|
||||
int isdigit(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_DIG) : 0; }
|
||||
|
||||
/**
|
||||
* Returns !=0 if c is lower case ascii letter.
|
||||
*/
|
||||
int islower(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_LC) : 0; }
|
||||
|
||||
/**
|
||||
* Returns !=0 if c is a punctuation character.
|
||||
*/
|
||||
int ispunct(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_PNC) : 0; }
|
||||
|
||||
/**
|
||||
* Returns !=0 if c is a space, tab, vertical tab, form feed,
|
||||
* carriage return, or linefeed.
|
||||
*/
|
||||
int isspace(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_SPC) : 0; }
|
||||
|
||||
/**
|
||||
* Returns !=0 if c is an upper case ascii character.
|
||||
*/
|
||||
int isupper(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_UC) : 0; }
|
||||
|
||||
/**
|
||||
* Returns !=0 if c is a hex digit (0..9, a..f, A..F).
|
||||
*/
|
||||
int isxdigit(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_HEX) : 0; }
|
||||
|
||||
/**
|
||||
* Returns !=0 if c is a printing character except for the space character.
|
||||
*/
|
||||
int isgraph(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG|_PNC) : 0; }
|
||||
|
||||
/**
|
||||
* Returns !=0 if c is a printing character including the space character.
|
||||
*/
|
||||
int isprint(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG|_PNC|_BLK) : 0; }
|
||||
|
||||
/**
|
||||
* Returns !=0 if c is in the ascii character set, i.e. in the range 0..0x7F.
|
||||
*/
|
||||
int isascii(dchar c) { return c <= 0x7F; }
|
||||
|
||||
|
||||
/**
|
||||
* If c is an upper case ascii character,
|
||||
* return the lower case equivalent, otherwise return c.
|
||||
*/
|
||||
dchar tolower(dchar c)
|
||||
out (result)
|
||||
{
|
||||
assert(!isupper(result));
|
||||
}
|
||||
body
|
||||
{
|
||||
return isupper(c) ? c + (cast(dchar)'a' - 'A') : c;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If c is a lower case ascii character,
|
||||
* return the upper case equivalent, otherwise return c.
|
||||
*/
|
||||
dchar toupper(dchar c)
|
||||
out (result)
|
||||
{
|
||||
assert(!islower(result));
|
||||
}
|
||||
body
|
||||
{
|
||||
return islower(c) ? c - (cast(dchar)'a' - 'A') : c;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
enum
|
||||
{
|
||||
_SPC = 8,
|
||||
_CTL = 0x20,
|
||||
_BLK = 0x40,
|
||||
_HEX = 0x80,
|
||||
_UC = 1,
|
||||
_LC = 2,
|
||||
_PNC = 0x10,
|
||||
_DIG = 4,
|
||||
_ALP = _UC|_LC,
|
||||
}
|
||||
|
||||
ubyte _ctype[128] =
|
||||
[
|
||||
_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
|
||||
_CTL,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL,_CTL,
|
||||
_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
|
||||
_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
|
||||
_SPC|_BLK,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
|
||||
_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
|
||||
_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,
|
||||
_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,
|
||||
_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
|
||||
_PNC,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC,
|
||||
_UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC,
|
||||
_UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC,
|
||||
_UC,_UC,_UC,_PNC,_PNC,_PNC,_PNC,_PNC,
|
||||
_PNC,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC,
|
||||
_LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC,
|
||||
_LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC,
|
||||
_LC,_LC,_LC,_PNC,_PNC,_PNC,_PNC,_CTL
|
||||
];
|
||||
|
||||
|
||||
unittest
|
||||
{
|
||||
assert(isspace(' '));
|
||||
assert(!isspace('z'));
|
||||
assert(toupper('a') == 'A');
|
||||
assert(tolower('Q') == 'q');
|
||||
assert(!isxdigit('G'));
|
||||
}
|
||||
630
lphobos/std/uni.d
Normal file
630
lphobos/std/uni.d
Normal file
@@ -0,0 +1,630 @@
|
||||
|
||||
// Written in the D programming language.
|
||||
|
||||
/*
|
||||
* Placed into the Public Domain.
|
||||
* Digital Mars, www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*/
|
||||
|
||||
/**
|
||||
* Simple Unicode character classification functions.
|
||||
* For ASCII classification, see $(LINK2 std_ctype.html, std.ctype).
|
||||
* Macros:
|
||||
* WIKI=Phobos/StdUni
|
||||
* References:
|
||||
* $(LINK2 http://www.digitalmars.com/d/ascii-table.html, ASCII Table),
|
||||
* $(LINK2 http://en.wikipedia.org/wiki/Unicode, Wikipedia),
|
||||
* $(LINK2 http://www.unicode.org, The Unicode Consortium)
|
||||
* Trademarks:
|
||||
* Unicode(tm) is a trademark of Unicode, Inc.
|
||||
*/
|
||||
|
||||
|
||||
module std.uni;
|
||||
|
||||
/**
|
||||
* Returns !=0 if c is a Unicode lower case character.
|
||||
*/
|
||||
int isUniLower(dchar c)
|
||||
{
|
||||
if (c <= 0x7F)
|
||||
return (c >= 'a' && c <= 'z');
|
||||
|
||||
return isUniAlpha(c) && c == toUniLower(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns !=0 if c is a Unicode upper case character.
|
||||
*/
|
||||
int isUniUpper(dchar c)
|
||||
{
|
||||
if (c <= 0x7F)
|
||||
return (c >= 'A' && c <= 'Z');
|
||||
|
||||
return isUniAlpha(c) && c == toUniUpper(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* If c is a Unicode upper case character, return the lower case
|
||||
* equivalent, otherwise return c.
|
||||
*/
|
||||
dchar toUniLower(dchar c)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
{
|
||||
c += 32;
|
||||
}
|
||||
else if (c >= 0x00C0)
|
||||
{
|
||||
if ((c >= 0x00C0 && c <= 0x00D6) || (c >= 0x00D8 && c<=0x00DE))
|
||||
{
|
||||
c += 32;
|
||||
}
|
||||
else if ((c >= 0x0100 && c < 0x0138) || (c > 0x0149 && c < 0x0178))
|
||||
{
|
||||
if (c == 0x0130)
|
||||
c = 0x0069;
|
||||
else if ((c & 1) == 0)
|
||||
c += 1;
|
||||
}
|
||||
else if (c == 0x0178)
|
||||
{
|
||||
c = 0x00FF;
|
||||
}
|
||||
else if ((c >= 0x0139 && c < 0x0149) || (c > 0x0178 && c < 0x017F))
|
||||
{
|
||||
if (c & 1)
|
||||
c += 1;
|
||||
}
|
||||
else if (c >= 0x0200 && c <= 0x0217)
|
||||
{
|
||||
if ((c & 1) == 0)
|
||||
c += 1;
|
||||
}
|
||||
else if ((c >= 0x0401 && c <= 0x040C) || (c>= 0x040E && c <= 0x040F))
|
||||
{
|
||||
c += 80;
|
||||
}
|
||||
else if (c >= 0x0410 && c <= 0x042F)
|
||||
{
|
||||
c += 32;
|
||||
}
|
||||
else if (c >= 0x0460 && c <= 0x047F)
|
||||
{
|
||||
if ((c & 1) == 0)
|
||||
c += 1;
|
||||
}
|
||||
else if (c >= 0x0531 && c <= 0x0556)
|
||||
{
|
||||
c += 48;
|
||||
}
|
||||
else if (c >= 0x10A0 && c <= 0x10C5)
|
||||
{
|
||||
c += 48;
|
||||
}
|
||||
else if (c >= 0xFF21 && c <= 0xFF3A)
|
||||
{
|
||||
c += 32;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* If c is a Unicode lower case character, return the upper case
|
||||
* equivalent, otherwise return c.
|
||||
*/
|
||||
dchar toUniUpper(dchar c)
|
||||
{
|
||||
if (c >= 'a' && c <= 'z')
|
||||
{
|
||||
c -= 32;
|
||||
}
|
||||
else if (c >= 0x00E0)
|
||||
{
|
||||
if ((c >= 0x00E0 && c <= 0x00F6) || (c >= 0x00F8 && c <= 0x00FE))
|
||||
{
|
||||
c -= 32;
|
||||
}
|
||||
else if (c == 0x00FF)
|
||||
{
|
||||
c = 0x0178;
|
||||
}
|
||||
else if ((c >= 0x0100 && c < 0x0138) || (c > 0x0149 && c < 0x0178))
|
||||
{
|
||||
if (c == 0x0131)
|
||||
c = 0x0049;
|
||||
else if (c & 1)
|
||||
c -= 1;
|
||||
}
|
||||
else if ((c >= 0x0139 && c < 0x0149) || (c > 0x0178 && c < 0x017F))
|
||||
{
|
||||
if ((c & 1) == 0)
|
||||
c = c-1;
|
||||
}
|
||||
else if (c == 0x017F)
|
||||
{
|
||||
c = 0x0053;
|
||||
}
|
||||
else if (c >= 0x0200 && c <= 0x0217)
|
||||
{
|
||||
if (c & 1)
|
||||
c = c-1;
|
||||
}
|
||||
else if (c >= 0x0430 && c<= 0x044F)
|
||||
{
|
||||
c -= 32;
|
||||
}
|
||||
else if ((c >= 0x0451 && c <= 0x045C) || (c >=0x045E && c<= 0x045F))
|
||||
{
|
||||
c -= 80;
|
||||
}
|
||||
else if (c >= 0x0460 && c <= 0x047F)
|
||||
{
|
||||
if (c & 1)
|
||||
c -= 1;
|
||||
}
|
||||
else if (c >= 0x0561 && c < 0x0587)
|
||||
{
|
||||
c -= 48;
|
||||
}
|
||||
else if (c >= 0xFF41 && c <= 0xFF5A)
|
||||
{
|
||||
c -= 32;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
* Return !=0 if u is a Unicode alpha character.
|
||||
* (general Unicode category: Lu, Ll, Lt, Lm and Lo)
|
||||
*
|
||||
* Standards: Unicode 5.0.0
|
||||
*/
|
||||
|
||||
int isUniAlpha(dchar u)
|
||||
{
|
||||
static dchar table[][2] =
|
||||
[
|
||||
[ 'A', 'Z' ],
|
||||
[ 'a', 'z' ],
|
||||
[ 0x00AA, 0x00AA ],
|
||||
[ 0x00B5, 0x00B5 ],
|
||||
[ 0x00BA, 0x00BA ],
|
||||
[ 0x00C0, 0x00D6 ],
|
||||
[ 0x00D8, 0x00F6 ],
|
||||
[ 0x00F8, 0x02C1 ],
|
||||
[ 0x02C6, 0x02D1 ],
|
||||
[ 0x02E0, 0x02E4 ],
|
||||
[ 0x02EE, 0x02EE ],
|
||||
[ 0x037A, 0x037D ],
|
||||
[ 0x0386, 0x0386 ],
|
||||
[ 0x0388, 0x038A ],
|
||||
[ 0x038C, 0x038C ],
|
||||
[ 0x038E, 0x03A1 ],
|
||||
[ 0x03A3, 0x03CE ],
|
||||
[ 0x03D0, 0x03F5 ],
|
||||
[ 0x03F7, 0x0481 ],
|
||||
[ 0x048A, 0x0513 ],
|
||||
[ 0x0531, 0x0556 ],
|
||||
[ 0x0559, 0x0559 ],
|
||||
[ 0x0561, 0x0587 ],
|
||||
[ 0x05D0, 0x05EA ],
|
||||
[ 0x05F0, 0x05F2 ],
|
||||
[ 0x0621, 0x063A ],
|
||||
[ 0x0640, 0x064A ],
|
||||
[ 0x066E, 0x066F ],
|
||||
[ 0x0671, 0x06D3 ],
|
||||
[ 0x06D5, 0x06D5 ],
|
||||
[ 0x06E5, 0x06E6 ],
|
||||
[ 0x06EE, 0x06EF ],
|
||||
[ 0x06FA, 0x06FC ],
|
||||
[ 0x06FF, 0x06FF ],
|
||||
[ 0x0710, 0x0710 ],
|
||||
[ 0x0712, 0x072F ],
|
||||
[ 0x074D, 0x076D ],
|
||||
[ 0x0780, 0x07A5 ],
|
||||
[ 0x07B1, 0x07B1 ],
|
||||
[ 0x07CA, 0x07EA ],
|
||||
[ 0x07F4, 0x07F5 ],
|
||||
[ 0x07FA, 0x07FA ],
|
||||
[ 0x0904, 0x0939 ],
|
||||
[ 0x093D, 0x093D ],
|
||||
[ 0x0950, 0x0950 ],
|
||||
[ 0x0958, 0x0961 ],
|
||||
[ 0x097B, 0x097F ],
|
||||
[ 0x0985, 0x098C ],
|
||||
[ 0x098F, 0x0990 ],
|
||||
[ 0x0993, 0x09A8 ],
|
||||
[ 0x09AA, 0x09B0 ],
|
||||
[ 0x09B2, 0x09B2 ],
|
||||
[ 0x09B6, 0x09B9 ],
|
||||
[ 0x09BD, 0x09BD ],
|
||||
[ 0x09CE, 0x09CE ],
|
||||
[ 0x09DC, 0x09DD ],
|
||||
[ 0x09DF, 0x09E1 ],
|
||||
[ 0x09F0, 0x09F1 ],
|
||||
[ 0x0A05, 0x0A0A ],
|
||||
[ 0x0A0F, 0x0A10 ],
|
||||
[ 0x0A13, 0x0A28 ],
|
||||
[ 0x0A2A, 0x0A30 ],
|
||||
[ 0x0A32, 0x0A33 ],
|
||||
[ 0x0A35, 0x0A36 ],
|
||||
[ 0x0A38, 0x0A39 ],
|
||||
[ 0x0A59, 0x0A5C ],
|
||||
[ 0x0A5E, 0x0A5E ],
|
||||
[ 0x0A72, 0x0A74 ],
|
||||
[ 0x0A85, 0x0A8D ],
|
||||
[ 0x0A8F, 0x0A91 ],
|
||||
[ 0x0A93, 0x0AA8 ],
|
||||
[ 0x0AAA, 0x0AB0 ],
|
||||
[ 0x0AB2, 0x0AB3 ],
|
||||
[ 0x0AB5, 0x0AB9 ],
|
||||
[ 0x0ABD, 0x0ABD ],
|
||||
[ 0x0AD0, 0x0AD0 ],
|
||||
[ 0x0AE0, 0x0AE1 ],
|
||||
[ 0x0B05, 0x0B0C ],
|
||||
[ 0x0B0F, 0x0B10 ],
|
||||
[ 0x0B13, 0x0B28 ],
|
||||
[ 0x0B2A, 0x0B30 ],
|
||||
[ 0x0B32, 0x0B33 ],
|
||||
[ 0x0B35, 0x0B39 ],
|
||||
[ 0x0B3D, 0x0B3D ],
|
||||
[ 0x0B5C, 0x0B5D ],
|
||||
[ 0x0B5F, 0x0B61 ],
|
||||
[ 0x0B71, 0x0B71 ],
|
||||
[ 0x0B83, 0x0B83 ],
|
||||
[ 0x0B85, 0x0B8A ],
|
||||
[ 0x0B8E, 0x0B90 ],
|
||||
[ 0x0B92, 0x0B95 ],
|
||||
[ 0x0B99, 0x0B9A ],
|
||||
[ 0x0B9C, 0x0B9C ],
|
||||
[ 0x0B9E, 0x0B9F ],
|
||||
[ 0x0BA3, 0x0BA4 ],
|
||||
[ 0x0BA8, 0x0BAA ],
|
||||
[ 0x0BAE, 0x0BB9 ],
|
||||
[ 0x0C05, 0x0C0C ],
|
||||
[ 0x0C0E, 0x0C10 ],
|
||||
[ 0x0C12, 0x0C28 ],
|
||||
[ 0x0C2A, 0x0C33 ],
|
||||
[ 0x0C35, 0x0C39 ],
|
||||
[ 0x0C60, 0x0C61 ],
|
||||
[ 0x0C85, 0x0C8C ],
|
||||
[ 0x0C8E, 0x0C90 ],
|
||||
[ 0x0C92, 0x0CA8 ],
|
||||
[ 0x0CAA, 0x0CB3 ],
|
||||
[ 0x0CB5, 0x0CB9 ],
|
||||
[ 0x0CBD, 0x0CBD ],
|
||||
[ 0x0CDE, 0x0CDE ],
|
||||
[ 0x0CE0, 0x0CE1 ],
|
||||
[ 0x0D05, 0x0D0C ],
|
||||
[ 0x0D0E, 0x0D10 ],
|
||||
[ 0x0D12, 0x0D28 ],
|
||||
[ 0x0D2A, 0x0D39 ],
|
||||
[ 0x0D60, 0x0D61 ],
|
||||
[ 0x0D85, 0x0D96 ],
|
||||
[ 0x0D9A, 0x0DB1 ],
|
||||
[ 0x0DB3, 0x0DBB ],
|
||||
[ 0x0DBD, 0x0DBD ],
|
||||
[ 0x0DC0, 0x0DC6 ],
|
||||
[ 0x0E01, 0x0E30 ],
|
||||
[ 0x0E32, 0x0E33 ],
|
||||
[ 0x0E40, 0x0E46 ],
|
||||
[ 0x0E81, 0x0E82 ],
|
||||
[ 0x0E84, 0x0E84 ],
|
||||
[ 0x0E87, 0x0E88 ],
|
||||
[ 0x0E8A, 0x0E8A ],
|
||||
[ 0x0E8D, 0x0E8D ],
|
||||
[ 0x0E94, 0x0E97 ],
|
||||
[ 0x0E99, 0x0E9F ],
|
||||
[ 0x0EA1, 0x0EA3 ],
|
||||
[ 0x0EA5, 0x0EA5 ],
|
||||
[ 0x0EA7, 0x0EA7 ],
|
||||
[ 0x0EAA, 0x0EAB ],
|
||||
[ 0x0EAD, 0x0EB0 ],
|
||||
[ 0x0EB2, 0x0EB3 ],
|
||||
[ 0x0EBD, 0x0EBD ],
|
||||
[ 0x0EC0, 0x0EC4 ],
|
||||
[ 0x0EC6, 0x0EC6 ],
|
||||
[ 0x0EDC, 0x0EDD ],
|
||||
[ 0x0F00, 0x0F00 ],
|
||||
[ 0x0F40, 0x0F47 ],
|
||||
[ 0x0F49, 0x0F6A ],
|
||||
[ 0x0F88, 0x0F8B ],
|
||||
[ 0x1000, 0x1021 ],
|
||||
[ 0x1023, 0x1027 ],
|
||||
[ 0x1029, 0x102A ],
|
||||
[ 0x1050, 0x1055 ],
|
||||
[ 0x10A0, 0x10C5 ],
|
||||
[ 0x10D0, 0x10FA ],
|
||||
[ 0x10FC, 0x10FC ],
|
||||
[ 0x1100, 0x1159 ],
|
||||
[ 0x115F, 0x11A2 ],
|
||||
[ 0x11A8, 0x11F9 ],
|
||||
[ 0x1200, 0x1248 ],
|
||||
[ 0x124A, 0x124D ],
|
||||
[ 0x1250, 0x1256 ],
|
||||
[ 0x1258, 0x1258 ],
|
||||
[ 0x125A, 0x125D ],
|
||||
[ 0x1260, 0x1288 ],
|
||||
[ 0x128A, 0x128D ],
|
||||
[ 0x1290, 0x12B0 ],
|
||||
[ 0x12B2, 0x12B5 ],
|
||||
[ 0x12B8, 0x12BE ],
|
||||
[ 0x12C0, 0x12C0 ],
|
||||
[ 0x12C2, 0x12C5 ],
|
||||
[ 0x12C8, 0x12D6 ],
|
||||
[ 0x12D8, 0x1310 ],
|
||||
[ 0x1312, 0x1315 ],
|
||||
[ 0x1318, 0x135A ],
|
||||
[ 0x1380, 0x138F ],
|
||||
[ 0x13A0, 0x13F4 ],
|
||||
[ 0x1401, 0x166C ],
|
||||
[ 0x166F, 0x1676 ],
|
||||
[ 0x1681, 0x169A ],
|
||||
[ 0x16A0, 0x16EA ],
|
||||
[ 0x1700, 0x170C ],
|
||||
[ 0x170E, 0x1711 ],
|
||||
[ 0x1720, 0x1731 ],
|
||||
[ 0x1740, 0x1751 ],
|
||||
[ 0x1760, 0x176C ],
|
||||
[ 0x176E, 0x1770 ],
|
||||
[ 0x1780, 0x17B3 ],
|
||||
[ 0x17D7, 0x17D7 ],
|
||||
[ 0x17DC, 0x17DC ],
|
||||
[ 0x1820, 0x1877 ],
|
||||
[ 0x1880, 0x18A8 ],
|
||||
[ 0x1900, 0x191C ],
|
||||
[ 0x1950, 0x196D ],
|
||||
[ 0x1970, 0x1974 ],
|
||||
[ 0x1980, 0x19A9 ],
|
||||
[ 0x19C1, 0x19C7 ],
|
||||
[ 0x1A00, 0x1A16 ],
|
||||
[ 0x1B05, 0x1B33 ],
|
||||
[ 0x1B45, 0x1B4B ],
|
||||
[ 0x1D00, 0x1DBF ],
|
||||
[ 0x1E00, 0x1E9B ],
|
||||
[ 0x1EA0, 0x1EF9 ],
|
||||
[ 0x1F00, 0x1F15 ],
|
||||
[ 0x1F18, 0x1F1D ],
|
||||
[ 0x1F20, 0x1F45 ],
|
||||
[ 0x1F48, 0x1F4D ],
|
||||
[ 0x1F50, 0x1F57 ],
|
||||
[ 0x1F59, 0x1F59 ],
|
||||
[ 0x1F5B, 0x1F5B ],
|
||||
[ 0x1F5D, 0x1F5D ],
|
||||
[ 0x1F5F, 0x1F7D ],
|
||||
[ 0x1F80, 0x1FB4 ],
|
||||
[ 0x1FB6, 0x1FBC ],
|
||||
[ 0x1FBE, 0x1FBE ],
|
||||
[ 0x1FC2, 0x1FC4 ],
|
||||
[ 0x1FC6, 0x1FCC ],
|
||||
[ 0x1FD0, 0x1FD3 ],
|
||||
[ 0x1FD6, 0x1FDB ],
|
||||
[ 0x1FE0, 0x1FEC ],
|
||||
[ 0x1FF2, 0x1FF4 ],
|
||||
[ 0x1FF6, 0x1FFC ],
|
||||
[ 0x2071, 0x2071 ],
|
||||
[ 0x207F, 0x207F ],
|
||||
[ 0x2090, 0x2094 ],
|
||||
[ 0x2102, 0x2102 ],
|
||||
[ 0x2107, 0x2107 ],
|
||||
[ 0x210A, 0x2113 ],
|
||||
[ 0x2115, 0x2115 ],
|
||||
[ 0x2119, 0x211D ],
|
||||
[ 0x2124, 0x2124 ],
|
||||
[ 0x2126, 0x2126 ],
|
||||
[ 0x2128, 0x2128 ],
|
||||
[ 0x212A, 0x212D ],
|
||||
[ 0x212F, 0x2139 ],
|
||||
[ 0x213C, 0x213F ],
|
||||
[ 0x2145, 0x2149 ],
|
||||
[ 0x214E, 0x214E ],
|
||||
[ 0x2183, 0x2184 ],
|
||||
[ 0x2C00, 0x2C2E ],
|
||||
[ 0x2C30, 0x2C5E ],
|
||||
[ 0x2C60, 0x2C6C ],
|
||||
[ 0x2C74, 0x2C77 ],
|
||||
[ 0x2C80, 0x2CE4 ],
|
||||
[ 0x2D00, 0x2D25 ],
|
||||
[ 0x2D30, 0x2D65 ],
|
||||
[ 0x2D6F, 0x2D6F ],
|
||||
[ 0x2D80, 0x2D96 ],
|
||||
[ 0x2DA0, 0x2DA6 ],
|
||||
[ 0x2DA8, 0x2DAE ],
|
||||
[ 0x2DB0, 0x2DB6 ],
|
||||
[ 0x2DB8, 0x2DBE ],
|
||||
[ 0x2DC0, 0x2DC6 ],
|
||||
[ 0x2DC8, 0x2DCE ],
|
||||
[ 0x2DD0, 0x2DD6 ],
|
||||
[ 0x2DD8, 0x2DDE ],
|
||||
[ 0x3005, 0x3006 ],
|
||||
[ 0x3031, 0x3035 ],
|
||||
[ 0x303B, 0x303C ],
|
||||
[ 0x3041, 0x3096 ],
|
||||
[ 0x309D, 0x309F ],
|
||||
[ 0x30A1, 0x30FA ],
|
||||
[ 0x30FC, 0x30FF ],
|
||||
[ 0x3105, 0x312C ],
|
||||
[ 0x3131, 0x318E ],
|
||||
[ 0x31A0, 0x31B7 ],
|
||||
[ 0x31F0, 0x31FF ],
|
||||
[ 0x3400, 0x4DB5 ],
|
||||
[ 0x4E00, 0x9FBB ],
|
||||
[ 0xA000, 0xA48C ],
|
||||
[ 0xA717, 0xA71A ],
|
||||
[ 0xA800, 0xA801 ],
|
||||
[ 0xA803, 0xA805 ],
|
||||
[ 0xA807, 0xA80A ],
|
||||
[ 0xA80C, 0xA822 ],
|
||||
[ 0xA840, 0xA873 ],
|
||||
[ 0xAC00, 0xD7A3 ],
|
||||
[ 0xF900, 0xFA2D ],
|
||||
[ 0xFA30, 0xFA6A ],
|
||||
[ 0xFA70, 0xFAD9 ],
|
||||
[ 0xFB00, 0xFB06 ],
|
||||
[ 0xFB13, 0xFB17 ],
|
||||
[ 0xFB1D, 0xFB1D ],
|
||||
[ 0xFB1F, 0xFB28 ],
|
||||
[ 0xFB2A, 0xFB36 ],
|
||||
[ 0xFB38, 0xFB3C ],
|
||||
[ 0xFB3E, 0xFB3E ],
|
||||
[ 0xFB40, 0xFB41 ],
|
||||
[ 0xFB43, 0xFB44 ],
|
||||
[ 0xFB46, 0xFBB1 ],
|
||||
[ 0xFBD3, 0xFD3D ],
|
||||
[ 0xFD50, 0xFD8F ],
|
||||
[ 0xFD92, 0xFDC7 ],
|
||||
[ 0xFDF0, 0xFDFB ],
|
||||
[ 0xFE70, 0xFE74 ],
|
||||
[ 0xFE76, 0xFEFC ],
|
||||
[ 0xFF21, 0xFF3A ],
|
||||
[ 0xFF41, 0xFF5A ],
|
||||
[ 0xFF66, 0xFFBE ],
|
||||
[ 0xFFC2, 0xFFC7 ],
|
||||
[ 0xFFCA, 0xFFCF ],
|
||||
[ 0xFFD2, 0xFFD7 ],
|
||||
[ 0xFFDA, 0xFFDC ],
|
||||
[ 0x10000, 0x1000B ],
|
||||
[ 0x1000D, 0x10026 ],
|
||||
[ 0x10028, 0x1003A ],
|
||||
[ 0x1003C, 0x1003D ],
|
||||
[ 0x1003F, 0x1004D ],
|
||||
[ 0x10050, 0x1005D ],
|
||||
[ 0x10080, 0x100FA ],
|
||||
[ 0x10300, 0x1031E ],
|
||||
[ 0x10330, 0x10340 ],
|
||||
[ 0x10342, 0x10349 ],
|
||||
[ 0x10380, 0x1039D ],
|
||||
[ 0x103A0, 0x103C3 ],
|
||||
[ 0x103C8, 0x103CF ],
|
||||
[ 0x10400, 0x1049D ],
|
||||
[ 0x10800, 0x10805 ],
|
||||
[ 0x10808, 0x10808 ],
|
||||
[ 0x1080A, 0x10835 ],
|
||||
[ 0x10837, 0x10838 ],
|
||||
[ 0x1083C, 0x1083C ],
|
||||
[ 0x1083F, 0x1083F ],
|
||||
[ 0x10900, 0x10915 ],
|
||||
[ 0x10A00, 0x10A00 ],
|
||||
[ 0x10A10, 0x10A13 ],
|
||||
[ 0x10A15, 0x10A17 ],
|
||||
[ 0x10A19, 0x10A33 ],
|
||||
[ 0x12000, 0x1236E ],
|
||||
[ 0x1D400, 0x1D454 ],
|
||||
[ 0x1D456, 0x1D49C ],
|
||||
[ 0x1D49E, 0x1D49F ],
|
||||
[ 0x1D4A2, 0x1D4A2 ],
|
||||
[ 0x1D4A5, 0x1D4A6 ],
|
||||
[ 0x1D4A9, 0x1D4AC ],
|
||||
[ 0x1D4AE, 0x1D4B9 ],
|
||||
[ 0x1D4BB, 0x1D4BB ],
|
||||
[ 0x1D4BD, 0x1D4C3 ],
|
||||
[ 0x1D4C5, 0x1D505 ],
|
||||
[ 0x1D507, 0x1D50A ],
|
||||
[ 0x1D50D, 0x1D514 ],
|
||||
[ 0x1D516, 0x1D51C ],
|
||||
[ 0x1D51E, 0x1D539 ],
|
||||
[ 0x1D53B, 0x1D53E ],
|
||||
[ 0x1D540, 0x1D544 ],
|
||||
[ 0x1D546, 0x1D546 ],
|
||||
[ 0x1D54A, 0x1D550 ],
|
||||
[ 0x1D552, 0x1D6A5 ],
|
||||
[ 0x1D6A8, 0x1D6C0 ],
|
||||
[ 0x1D6C2, 0x1D6DA ],
|
||||
[ 0x1D6DC, 0x1D6FA ],
|
||||
[ 0x1D6FC, 0x1D714 ],
|
||||
[ 0x1D716, 0x1D734 ],
|
||||
[ 0x1D736, 0x1D74E ],
|
||||
[ 0x1D750, 0x1D76E ],
|
||||
[ 0x1D770, 0x1D788 ],
|
||||
[ 0x1D78A, 0x1D7A8 ],
|
||||
[ 0x1D7AA, 0x1D7C2 ],
|
||||
[ 0x1D7C4, 0x1D7CB ],
|
||||
[ 0x20000, 0x2A6D6 ],
|
||||
[ 0x2F800, 0x2FA1D ],
|
||||
];
|
||||
|
||||
debug
|
||||
{
|
||||
for (int i = 0; i < table.length; i++)
|
||||
{
|
||||
assert(table[i][0] <= table[i][1]);
|
||||
if (i < table.length - 1)
|
||||
{
|
||||
if (table[i][1] >= table[i + 1][0])
|
||||
printf("table[%d][1] = x%x, table[%d][0] = x%x\n", i, table[i][1], i + 1, table[i + 1][0]);
|
||||
assert(table[i][1] < table[i + 1][0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (u < 0xAA)
|
||||
{
|
||||
if (u < 'A')
|
||||
goto Lisnot;
|
||||
if (u <= 'Z')
|
||||
goto Lis;
|
||||
if (u < 'a')
|
||||
goto Lisnot;
|
||||
if (u <= 'z')
|
||||
goto Lis;
|
||||
goto Lisnot;
|
||||
}
|
||||
|
||||
// Binary search
|
||||
uint mid;
|
||||
uint low;
|
||||
uint high;
|
||||
|
||||
low = 0;
|
||||
high = table.length - 1;
|
||||
while (cast(int)low <= cast(int)high)
|
||||
{
|
||||
mid = (low + high) >> 1;
|
||||
if (u < table[mid][0])
|
||||
high = mid - 1;
|
||||
else if (u > table[mid][1])
|
||||
low = mid + 1;
|
||||
else
|
||||
goto Lis;
|
||||
}
|
||||
|
||||
Lisnot:
|
||||
debug
|
||||
{
|
||||
for (int i = 0; i < table.length; i++)
|
||||
{
|
||||
assert(u < table[i][0] || u > table[i][1]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
Lis:
|
||||
debug
|
||||
{
|
||||
for (int i = 0; i < table.length; i++)
|
||||
{
|
||||
if (u >= table[i][0] && u <= table[i][1])
|
||||
return 1;
|
||||
}
|
||||
assert(0); // should have been in table
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
for (uint i = 0; i < 0x80; i++)
|
||||
{
|
||||
if (i >= 'A' && i <= 'Z')
|
||||
assert(isUniAlpha(i));
|
||||
else if (i >= 'a' && i <= 'z')
|
||||
assert(isUniAlpha(i));
|
||||
else
|
||||
assert(!isUniAlpha(i));
|
||||
}
|
||||
}
|
||||
969
lphobos/std/utf.d
Normal file
969
lphobos/std/utf.d
Normal file
@@ -0,0 +1,969 @@
|
||||
// utf.d
|
||||
|
||||
/*
|
||||
* Copyright (C) 2003-2004 by Digital Mars, www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* o The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* o Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
* o This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
/********************************************
|
||||
* Encode and decode UTF-8, UTF-16 and UTF-32 strings.
|
||||
*
|
||||
* For Win32 systems, the C wchar_t type is UTF-16 and corresponds to the D
|
||||
* wchar type.
|
||||
* For linux systems, the C wchar_t type is UTF-32 and corresponds to
|
||||
* the D utf.dchar type.
|
||||
*
|
||||
* UTF character support is restricted to (\u0000 <= character <= \U0010FFFF).
|
||||
*
|
||||
* See_Also:
|
||||
* $(LINK2 http://en.wikipedia.org/wiki/Unicode, Wikipedia)<br>
|
||||
* $(LINK http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8)<br>
|
||||
* $(LINK http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335)
|
||||
* Macros:
|
||||
* WIKI = Phobos/StdUtf
|
||||
*/
|
||||
|
||||
module std.utf;
|
||||
|
||||
private import std.stdio;
|
||||
|
||||
//debug=utf; // uncomment to turn on debugging printf's
|
||||
|
||||
deprecated class UtfError : Error
|
||||
{
|
||||
size_t idx; // index in string of where error occurred
|
||||
|
||||
this(char[] s, size_t i)
|
||||
{
|
||||
idx = i;
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************
|
||||
* Exception class that is thrown upon any errors.
|
||||
*/
|
||||
|
||||
class UtfException : Exception
|
||||
{
|
||||
size_t idx; /// index in string of where error occurred
|
||||
|
||||
this(char[] s, size_t i)
|
||||
{
|
||||
idx = i;
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************
|
||||
* Test if c is a valid UTF-32 character.
|
||||
*
|
||||
* \uFFFE and \uFFFF are considered valid by this function,
|
||||
* as they are permitted for internal use by an application,
|
||||
* but they are not allowed for interchange by the Unicode standard.
|
||||
*
|
||||
* Returns: true if it is, false if not.
|
||||
*/
|
||||
|
||||
bool isValidDchar(dchar c)
|
||||
{
|
||||
/* Note: FFFE and FFFF are specifically permitted by the
|
||||
* Unicode standard for application internal use, but are not
|
||||
* allowed for interchange.
|
||||
* (thanks to Arcane Jill)
|
||||
*/
|
||||
|
||||
return c < 0xD800 ||
|
||||
(c > 0xDFFF && c <= 0x10FFFF /*&& c != 0xFFFE && c != 0xFFFF*/);
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(utf) printf("utf.isValidDchar.unittest\n");
|
||||
assert(isValidDchar(cast(dchar)'a') == true);
|
||||
assert(isValidDchar(cast(dchar)0x1FFFFF) == false);
|
||||
}
|
||||
|
||||
|
||||
ubyte[256] UTF8stride =
|
||||
[
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||
4,4,4,4,4,4,4,4,5,5,5,5,6,6,0xFF,0xFF,
|
||||
];
|
||||
|
||||
/**
|
||||
* stride() returns the length of a UTF-8 sequence starting at index i
|
||||
* in string s.
|
||||
* Returns:
|
||||
* The number of bytes in the UTF-8 sequence or
|
||||
* 0xFF meaning s[i] is not the start of of UTF-8 sequence.
|
||||
*/
|
||||
|
||||
uint stride(char[] s, size_t i)
|
||||
{
|
||||
return UTF8stride[s[i]];
|
||||
}
|
||||
|
||||
/**
|
||||
* stride() returns the length of a UTF-16 sequence starting at index i
|
||||
* in string s.
|
||||
*/
|
||||
|
||||
uint stride(wchar[] s, size_t i)
|
||||
{ uint u = s[i];
|
||||
return 1 + (u >= 0xD800 && u <= 0xDBFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* stride() returns the length of a UTF-32 sequence starting at index i
|
||||
* in string s.
|
||||
* Returns: The return value will always be 1.
|
||||
*/
|
||||
|
||||
uint stride(dchar[] s, size_t i)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
* Given an index i into an array of characters s[],
|
||||
* and assuming that index i is at the start of a UTF character,
|
||||
* determine the number of UCS characters up to that index i.
|
||||
*/
|
||||
|
||||
size_t toUCSindex(char[] s, size_t i)
|
||||
{
|
||||
size_t n;
|
||||
size_t j;
|
||||
size_t stride;
|
||||
|
||||
for (j = 0; j < i; j += stride)
|
||||
{
|
||||
stride = UTF8stride[s[j]];
|
||||
if (stride == 0xFF)
|
||||
goto Lerr;
|
||||
n++;
|
||||
}
|
||||
if (j > i)
|
||||
{
|
||||
Lerr:
|
||||
throw new UtfException("1invalid UTF-8 sequence", j);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
size_t toUCSindex(wchar[] s, size_t i)
|
||||
{
|
||||
size_t n;
|
||||
size_t j;
|
||||
|
||||
for (j = 0; j < i; )
|
||||
{ uint u = s[j];
|
||||
|
||||
j += 1 + (u >= 0xD800 && u <= 0xDBFF);
|
||||
n++;
|
||||
}
|
||||
if (j > i)
|
||||
{
|
||||
Lerr:
|
||||
throw new UtfException("2invalid UTF-16 sequence", j);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
size_t toUCSindex(dchar[] s, size_t i)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Given a UCS index n into an array of characters s[], return the UTF index.
|
||||
*/
|
||||
|
||||
size_t toUTFindex(char[] s, size_t n)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
while (n--)
|
||||
{
|
||||
uint j = UTF8stride[s[i]];
|
||||
if (j == 0xFF)
|
||||
throw new UtfException("3invalid UTF-8 sequence", i);
|
||||
i += j;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
size_t toUTFindex(wchar[] s, size_t n)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
while (n--)
|
||||
{ wchar u = s[i];
|
||||
|
||||
i += 1 + (u >= 0xD800 && u <= 0xDBFF);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
size_t toUTFindex(dchar[] s, size_t n)
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
/* =================== Decode ======================= */
|
||||
|
||||
/***************
|
||||
* Decodes and returns character starting at s[idx]. idx is advanced past the
|
||||
* decoded character. If the character is not well formed, a UtfException is
|
||||
* thrown and idx remains unchanged.
|
||||
*/
|
||||
|
||||
dchar decode(char[] s, inout size_t idx)
|
||||
in
|
||||
{
|
||||
assert(idx >= 0 && idx < s.length);
|
||||
}
|
||||
out (result)
|
||||
{
|
||||
assert(isValidDchar(result));
|
||||
}
|
||||
body
|
||||
{
|
||||
size_t len = s.length;
|
||||
dchar V;
|
||||
size_t i = idx;
|
||||
char u = s[i];
|
||||
|
||||
if (u & 0x80)
|
||||
{ uint n;
|
||||
char u2;
|
||||
|
||||
/* The following encodings are valid, except for the 5 and 6 byte
|
||||
* combinations:
|
||||
* 0xxxxxxx
|
||||
* 110xxxxx 10xxxxxx
|
||||
* 1110xxxx 10xxxxxx 10xxxxxx
|
||||
* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
*/
|
||||
for (n = 1; ; n++)
|
||||
{
|
||||
if (n > 4)
|
||||
goto Lerr; // only do the first 4 of 6 encodings
|
||||
if (((u << n) & 0x80) == 0)
|
||||
{
|
||||
if (n == 1)
|
||||
goto Lerr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Pick off (7 - n) significant bits of B from first byte of octet
|
||||
V = cast(dchar)(u & ((1 << (7 - n)) - 1));
|
||||
|
||||
if (i + (n - 1) >= len)
|
||||
goto Lerr; // off end of string
|
||||
|
||||
/* The following combinations are overlong, and illegal:
|
||||
* 1100000x (10xxxxxx)
|
||||
* 11100000 100xxxxx (10xxxxxx)
|
||||
* 11110000 1000xxxx (10xxxxxx 10xxxxxx)
|
||||
* 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx)
|
||||
* 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx)
|
||||
*/
|
||||
u2 = s[i + 1];
|
||||
if ((u & 0xFE) == 0xC0 ||
|
||||
(u == 0xE0 && (u2 & 0xE0) == 0x80) ||
|
||||
(u == 0xF0 && (u2 & 0xF0) == 0x80) ||
|
||||
(u == 0xF8 && (u2 & 0xF8) == 0x80) ||
|
||||
(u == 0xFC && (u2 & 0xFC) == 0x80))
|
||||
goto Lerr; // overlong combination
|
||||
|
||||
for (uint j = 1; j != n; j++)
|
||||
{
|
||||
u = s[i + j];
|
||||
if ((u & 0xC0) != 0x80)
|
||||
goto Lerr; // trailing bytes are 10xxxxxx
|
||||
V = (V << 6) | (u & 0x3F);
|
||||
}
|
||||
if (!isValidDchar(V))
|
||||
goto Lerr;
|
||||
i += n;
|
||||
}
|
||||
else
|
||||
{
|
||||
V = cast(dchar) u;
|
||||
i++;
|
||||
}
|
||||
|
||||
idx = i;
|
||||
return V;
|
||||
|
||||
Lerr:
|
||||
//printf("\ndecode: idx = %d, i = %d, length = %d s = \n'%.*s'\n%x\n'%.*s'\n", idx, i, s.length, s, s[i], s[i .. length]);
|
||||
throw new UtfException("4invalid UTF-8 sequence", i);
|
||||
}
|
||||
|
||||
unittest
|
||||
{ size_t i;
|
||||
dchar c;
|
||||
|
||||
debug(utf) printf("utf.decode.unittest\n");
|
||||
|
||||
static char[] s1 = "abcd";
|
||||
i = 0;
|
||||
c = decode(s1, i);
|
||||
assert(c == cast(dchar)'a');
|
||||
assert(i == 1);
|
||||
c = decode(s1, i);
|
||||
assert(c == cast(dchar)'b');
|
||||
assert(i == 2);
|
||||
|
||||
static char[] s2 = "\xC2\xA9";
|
||||
i = 0;
|
||||
c = decode(s2, i);
|
||||
assert(c == cast(dchar)'\u00A9');
|
||||
assert(i == 2);
|
||||
|
||||
static char[] s3 = "\xE2\x89\xA0";
|
||||
i = 0;
|
||||
c = decode(s3, i);
|
||||
assert(c == cast(dchar)'\u2260');
|
||||
assert(i == 3);
|
||||
|
||||
static char[][] s4 =
|
||||
[ "\xE2\x89", // too short
|
||||
"\xC0\x8A",
|
||||
"\xE0\x80\x8A",
|
||||
"\xF0\x80\x80\x8A",
|
||||
"\xF8\x80\x80\x80\x8A",
|
||||
"\xFC\x80\x80\x80\x80\x8A",
|
||||
];
|
||||
|
||||
for (int j = 0; j < s4.length; j++)
|
||||
{
|
||||
try
|
||||
{
|
||||
i = 0;
|
||||
c = decode(s4[j], i);
|
||||
assert(0);
|
||||
}
|
||||
catch (UtfException u)
|
||||
{
|
||||
i = 23;
|
||||
delete u;
|
||||
}
|
||||
assert(i == 23);
|
||||
}
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
dchar decode(wchar[] s, inout size_t idx)
|
||||
in
|
||||
{
|
||||
assert(idx >= 0 && idx < s.length);
|
||||
}
|
||||
out (result)
|
||||
{
|
||||
assert(isValidDchar(result));
|
||||
}
|
||||
body
|
||||
{
|
||||
char[] msg;
|
||||
dchar V;
|
||||
size_t i = idx;
|
||||
uint u = s[i];
|
||||
|
||||
if (u & ~0x7F)
|
||||
{ if (u >= 0xD800 && u <= 0xDBFF)
|
||||
{ uint u2;
|
||||
|
||||
if (i + 1 == s.length)
|
||||
{ msg = "surrogate UTF-16 high value past end of string";
|
||||
goto Lerr;
|
||||
}
|
||||
u2 = s[i + 1];
|
||||
if (u2 < 0xDC00 || u2 > 0xDFFF)
|
||||
{ msg = "surrogate UTF-16 low value out of range";
|
||||
goto Lerr;
|
||||
}
|
||||
u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00);
|
||||
i += 2;
|
||||
}
|
||||
else if (u >= 0xDC00 && u <= 0xDFFF)
|
||||
{ msg = "unpaired surrogate UTF-16 value";
|
||||
goto Lerr;
|
||||
}
|
||||
else if (u == 0xFFFE || u == 0xFFFF)
|
||||
{ msg = "illegal UTF-16 value";
|
||||
goto Lerr;
|
||||
}
|
||||
else
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
idx = i;
|
||||
return cast(dchar)u;
|
||||
|
||||
Lerr:
|
||||
throw new UtfException(msg, i);
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
dchar decode(dchar[] s, inout size_t idx)
|
||||
in
|
||||
{
|
||||
assert(idx >= 0 && idx < s.length);
|
||||
}
|
||||
body
|
||||
{
|
||||
size_t i = idx;
|
||||
dchar c = s[i];
|
||||
|
||||
if (!isValidDchar(c))
|
||||
goto Lerr;
|
||||
idx = i + 1;
|
||||
return c;
|
||||
|
||||
Lerr:
|
||||
throw new UtfException("5invalid UTF-32 value", i);
|
||||
}
|
||||
|
||||
|
||||
/* =================== Encode ======================= */
|
||||
|
||||
/*******************************
|
||||
* Encodes character c and appends it to array s[].
|
||||
*/
|
||||
|
||||
void encode(inout char[] s, dchar c)
|
||||
in
|
||||
{
|
||||
assert(isValidDchar(c));
|
||||
}
|
||||
body
|
||||
{
|
||||
char[] r = s;
|
||||
|
||||
if (c <= 0x7F)
|
||||
{
|
||||
r ~= cast(char) c;
|
||||
}
|
||||
else
|
||||
{
|
||||
char[4] buf;
|
||||
uint L;
|
||||
|
||||
if (c <= 0x7FF)
|
||||
{
|
||||
buf[0] = cast(char)(0xC0 | (c >> 6));
|
||||
buf[1] = cast(char)(0x80 | (c & 0x3F));
|
||||
L = 2;
|
||||
}
|
||||
else if (c <= 0xFFFF)
|
||||
{
|
||||
buf[0] = cast(char)(0xE0 | (c >> 12));
|
||||
buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F));
|
||||
buf[2] = cast(char)(0x80 | (c & 0x3F));
|
||||
L = 3;
|
||||
}
|
||||
else if (c <= 0x10FFFF)
|
||||
{
|
||||
buf[0] = cast(char)(0xF0 | (c >> 18));
|
||||
buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F));
|
||||
buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F));
|
||||
buf[3] = cast(char)(0x80 | (c & 0x3F));
|
||||
L = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
r ~= buf[0 .. L];
|
||||
}
|
||||
s = r;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(utf) printf("utf.encode.unittest\n");
|
||||
|
||||
char[] s = "abcd";
|
||||
encode(s, cast(dchar)'a');
|
||||
assert(s.length == 5);
|
||||
assert(s == "abcda");
|
||||
|
||||
encode(s, cast(dchar)'\u00A9');
|
||||
assert(s.length == 7);
|
||||
assert(s == "abcda\xC2\xA9");
|
||||
//assert(s == "abcda\u00A9"); // BUG: fix compiler
|
||||
|
||||
encode(s, cast(dchar)'\u2260');
|
||||
assert(s.length == 10);
|
||||
assert(s == "abcda\xC2\xA9\xE2\x89\xA0");
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
void encode(inout wchar[] s, dchar c)
|
||||
in
|
||||
{
|
||||
assert(isValidDchar(c));
|
||||
}
|
||||
body
|
||||
{
|
||||
wchar[] r = s;
|
||||
|
||||
if (c <= 0xFFFF)
|
||||
{
|
||||
r ~= cast(wchar) c;
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar[2] buf;
|
||||
|
||||
buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00);
|
||||
r ~= buf;
|
||||
}
|
||||
s = r;
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
void encode(inout dchar[] s, dchar c)
|
||||
in
|
||||
{
|
||||
assert(isValidDchar(c));
|
||||
}
|
||||
body
|
||||
{
|
||||
s ~= c;
|
||||
}
|
||||
|
||||
/* =================== Validation ======================= */
|
||||
|
||||
/***********************************
|
||||
* Checks to see if string is well formed or not. Throws a UtfException if it is
|
||||
* not. Use to check all untrusted input for correctness.
|
||||
*/
|
||||
|
||||
void validate(char[] s)
|
||||
{
|
||||
size_t len = s.length;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; )
|
||||
{
|
||||
decode(s, i);
|
||||
}
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
void validate(wchar[] s)
|
||||
{
|
||||
size_t len = s.length;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; )
|
||||
{
|
||||
decode(s, i);
|
||||
}
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
void validate(dchar[] s)
|
||||
{
|
||||
size_t len = s.length;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; )
|
||||
{
|
||||
decode(s, i);
|
||||
}
|
||||
}
|
||||
|
||||
/* =================== Conversion to UTF8 ======================= */
|
||||
|
||||
char[] toUTF8(char[4] buf, dchar c)
|
||||
in
|
||||
{
|
||||
assert(isValidDchar(c));
|
||||
}
|
||||
body
|
||||
{
|
||||
if (c <= 0x7F)
|
||||
{
|
||||
buf[0] = cast(char) c;
|
||||
return buf[0 .. 1];
|
||||
}
|
||||
else if (c <= 0x7FF)
|
||||
{
|
||||
buf[0] = cast(char)(0xC0 | (c >> 6));
|
||||
buf[1] = cast(char)(0x80 | (c & 0x3F));
|
||||
return buf[0 .. 2];
|
||||
}
|
||||
else if (c <= 0xFFFF)
|
||||
{
|
||||
buf[0] = cast(char)(0xE0 | (c >> 12));
|
||||
buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F));
|
||||
buf[2] = cast(char)(0x80 | (c & 0x3F));
|
||||
return buf[0 .. 3];
|
||||
}
|
||||
else if (c <= 0x10FFFF)
|
||||
{
|
||||
buf[0] = cast(char)(0xF0 | (c >> 18));
|
||||
buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F));
|
||||
buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F));
|
||||
buf[3] = cast(char)(0x80 | (c & 0x3F));
|
||||
return buf[0 .. 4];
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/*******************
|
||||
* Encodes string s into UTF-8 and returns the encoded string.
|
||||
*/
|
||||
|
||||
char[] toUTF8(char[] s)
|
||||
in
|
||||
{
|
||||
validate(s);
|
||||
}
|
||||
body
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
char[] toUTF8(wchar[] s)
|
||||
{
|
||||
char[] r;
|
||||
size_t i;
|
||||
size_t slen = s.length;
|
||||
|
||||
r.length = slen;
|
||||
|
||||
for (i = 0; i < slen; i++)
|
||||
{ wchar c = s[i];
|
||||
|
||||
if (c <= 0x7F)
|
||||
r[i] = cast(char)c; // fast path for ascii
|
||||
else
|
||||
{
|
||||
r.length = i;
|
||||
foreach (dchar c; s[i .. slen])
|
||||
{
|
||||
encode(r, c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
char[] toUTF8(dchar[] s)
|
||||
{
|
||||
char[] r;
|
||||
size_t i;
|
||||
size_t slen = s.length;
|
||||
|
||||
r.length = slen;
|
||||
|
||||
for (i = 0; i < slen; i++)
|
||||
{ dchar c = s[i];
|
||||
|
||||
if (c <= 0x7F)
|
||||
r[i] = cast(char)c; // fast path for ascii
|
||||
else
|
||||
{
|
||||
r.length = i;
|
||||
foreach (dchar d; s[i .. slen])
|
||||
{
|
||||
encode(r, d);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* =================== Conversion to UTF16 ======================= */
|
||||
|
||||
wchar[] toUTF16(wchar[2] buf, dchar c)
|
||||
in
|
||||
{
|
||||
assert(isValidDchar(c));
|
||||
}
|
||||
body
|
||||
{
|
||||
if (c <= 0xFFFF)
|
||||
{
|
||||
buf[0] = cast(wchar) c;
|
||||
return buf[0 .. 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00);
|
||||
return buf[0 .. 2];
|
||||
}
|
||||
}
|
||||
|
||||
/****************
|
||||
* Encodes string s into UTF-16 and returns the encoded string.
|
||||
* toUTF16z() is suitable for calling the 'W' functions in the Win32 API that take
|
||||
* an LPWSTR or LPCWSTR argument.
|
||||
*/
|
||||
|
||||
wchar[] toUTF16(char[] s)
|
||||
{
|
||||
wchar[] r;
|
||||
size_t slen = s.length;
|
||||
|
||||
r.length = slen;
|
||||
r.length = 0;
|
||||
for (size_t i = 0; i < slen; )
|
||||
{
|
||||
dchar c = s[i];
|
||||
if (c <= 0x7F)
|
||||
{
|
||||
i++;
|
||||
r ~= cast(wchar)c;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = decode(s, i);
|
||||
encode(r, c);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
wchar* toUTF16z(char[] s)
|
||||
{
|
||||
wchar[] r;
|
||||
size_t slen = s.length;
|
||||
|
||||
r.length = slen + 1;
|
||||
r.length = 0;
|
||||
for (size_t i = 0; i < slen; )
|
||||
{
|
||||
dchar c = s[i];
|
||||
if (c <= 0x7F)
|
||||
{
|
||||
i++;
|
||||
r ~= cast(wchar)c;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = decode(s, i);
|
||||
encode(r, c);
|
||||
}
|
||||
}
|
||||
r ~= "\000";
|
||||
return r.ptr;
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
wchar[] toUTF16(wchar[] s)
|
||||
in
|
||||
{
|
||||
validate(s);
|
||||
}
|
||||
body
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
wchar[] toUTF16(dchar[] s)
|
||||
{
|
||||
wchar[] r;
|
||||
size_t slen = s.length;
|
||||
|
||||
r.length = slen;
|
||||
r.length = 0;
|
||||
for (size_t i = 0; i < slen; i++)
|
||||
{
|
||||
encode(r, s[i]);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* =================== Conversion to UTF32 ======================= */
|
||||
|
||||
/*****
|
||||
* Encodes string s into UTF-32 and returns the encoded string.
|
||||
*/
|
||||
|
||||
dchar[] toUTF32(char[] s)
|
||||
{
|
||||
dchar[] r;
|
||||
size_t slen = s.length;
|
||||
size_t j = 0;
|
||||
|
||||
r.length = slen; // r[] will never be longer than s[]
|
||||
for (size_t i = 0; i < slen; )
|
||||
{
|
||||
dchar c = s[i];
|
||||
if (c >= 0x80)
|
||||
c = decode(s, i);
|
||||
else
|
||||
i++; // c is ascii, no need for decode
|
||||
r[j++] = c;
|
||||
}
|
||||
return r[0 .. j];
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
dchar[] toUTF32(wchar[] s)
|
||||
{
|
||||
dchar[] r;
|
||||
size_t slen = s.length;
|
||||
size_t j = 0;
|
||||
|
||||
r.length = slen; // r[] will never be longer than s[]
|
||||
for (size_t i = 0; i < slen; )
|
||||
{
|
||||
dchar c = s[i];
|
||||
if (c >= 0x80)
|
||||
c = decode(s, i);
|
||||
else
|
||||
i++; // c is ascii, no need for decode
|
||||
r[j++] = c;
|
||||
}
|
||||
return r[0 .. j];
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
dchar[] toUTF32(dchar[] s)
|
||||
in
|
||||
{
|
||||
validate(s);
|
||||
}
|
||||
body
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
/* ================================ tests ================================== */
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(utf) printf("utf.toUTF.unittest\n");
|
||||
|
||||
char[] c;
|
||||
wchar[] w;
|
||||
dchar[] d;
|
||||
|
||||
c = "hello";
|
||||
w = toUTF16(c);
|
||||
assert(w == "hello");
|
||||
d = toUTF32(c);
|
||||
assert(d == "hello");
|
||||
|
||||
c = toUTF8(w);
|
||||
assert(c == "hello");
|
||||
d = toUTF32(w);
|
||||
assert(d == "hello");
|
||||
|
||||
c = toUTF8(d);
|
||||
assert(c == "hello");
|
||||
w = toUTF16(d);
|
||||
assert(w == "hello");
|
||||
|
||||
|
||||
c = "hel\u1234o";
|
||||
w = toUTF16(c);
|
||||
assert(w == "hel\u1234o");
|
||||
d = toUTF32(c);
|
||||
assert(d == "hel\u1234o");
|
||||
|
||||
c = toUTF8(w);
|
||||
assert(c == "hel\u1234o");
|
||||
d = toUTF32(w);
|
||||
assert(d == "hel\u1234o");
|
||||
|
||||
c = toUTF8(d);
|
||||
assert(c == "hel\u1234o");
|
||||
w = toUTF16(d);
|
||||
assert(w == "hel\u1234o");
|
||||
|
||||
|
||||
c = "he\U0010AAAAllo";
|
||||
w = toUTF16(c);
|
||||
//foreach (wchar c; w) printf("c = x%x\n", c);
|
||||
//foreach (wchar c; cast(wchar[])"he\U0010AAAAllo") printf("c = x%x\n", c);
|
||||
assert(w == "he\U0010AAAAllo");
|
||||
d = toUTF32(c);
|
||||
assert(d == "he\U0010AAAAllo");
|
||||
|
||||
c = toUTF8(w);
|
||||
assert(c == "he\U0010AAAAllo");
|
||||
d = toUTF32(w);
|
||||
assert(d == "he\U0010AAAAllo");
|
||||
|
||||
c = toUTF8(d);
|
||||
assert(c == "he\U0010AAAAllo");
|
||||
w = toUTF16(d);
|
||||
assert(w == "he\U0010AAAAllo");
|
||||
}
|
||||
@@ -21,13 +21,13 @@ package.bindir = "bin"
|
||||
package.name = "llvmdc"
|
||||
package.kind = "exe"
|
||||
package.language = "c++"
|
||||
package.files = { matchfiles("dmd/*.c"), matchfiles("gen/*.c") }
|
||||
package.files = { matchfiles("dmd/*.c"), matchfiles("gen/*.cpp") }
|
||||
package.excludes = { "dmd/idgen.c", "dmd/impcnvgen.c" }
|
||||
package.buildoptions = { "-x c++", "`llvm-config --cxxflags`" }
|
||||
package.linkoptions = { "`llvm-config --libs native bitwriter bitreader`", "`llvm-config --ldflags`" }
|
||||
package.defines = { "IN_LLVM", "_DH" }
|
||||
package.config.Release.defines = { "LLVMD_NO_LOGGER" }
|
||||
package.config.Debug.buildoptions = { "-g" }
|
||||
package.config.Debug.buildoptions = { "-g -O0" }
|
||||
--package.targetprefix = "llvm"
|
||||
package.includepaths = { ".", "dmd" }
|
||||
--package.postbuildcommands = { "cd runtime; ./build.sh; cd .." }
|
||||
|
||||
7
test/arrays10.d
Normal file
7
test/arrays10.d
Normal file
@@ -0,0 +1,7 @@
|
||||
module arrays10;
|
||||
|
||||
void main()
|
||||
{
|
||||
int[] a = new int[10];
|
||||
a[] = 3;
|
||||
}
|
||||
@@ -1,18 +1,29 @@
|
||||
module arrays7;
|
||||
|
||||
pragma(LLVM_internal, "notypeinfo")
|
||||
struct S
|
||||
{
|
||||
int i;
|
||||
float f;
|
||||
long l;
|
||||
|
||||
void print()
|
||||
{
|
||||
printf("%d %f %lx\n", i, f, l);
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
S[] arr;
|
||||
S s;
|
||||
assert(arr.length == 0);
|
||||
arr ~= s;
|
||||
assert(arr.length == 1);
|
||||
arr ~= S(1,2.64,0xFFFF_FFFF_FFFF);
|
||||
assert(arr.length == 2);
|
||||
arr[0].print();
|
||||
arr[1].print();
|
||||
assert(arr[1].i == 1);
|
||||
assert(arr[1].f > 2.63 && arr[1].f < 2.65);
|
||||
assert(arr[1].l == 0xFFFF_FFFF_FFFF);
|
||||
|
||||
8
test/arrays9.d
Normal file
8
test/arrays9.d
Normal file
@@ -0,0 +1,8 @@
|
||||
module arrays9;
|
||||
|
||||
const int[] g = [1,2,3,4];
|
||||
|
||||
void main()
|
||||
{
|
||||
|
||||
}
|
||||
4
test/b.d
4
test/b.d
@@ -10,7 +10,7 @@ void main()
|
||||
{
|
||||
S s;
|
||||
int i = s.i;
|
||||
int* p = &s.i;
|
||||
/*int* p = &s.i;
|
||||
*p = 42;
|
||||
printf("%d == %d\n", *p, s.i);
|
||||
|
||||
@@ -19,5 +19,5 @@ void main()
|
||||
*f = 3.1415;
|
||||
printf("%f == %f\n", *f, s.f[0]);
|
||||
s.f[0] = 123.456;
|
||||
printf("%f == %f\n", *f, s.f[0]);
|
||||
printf("%f == %f\n", *f, s.f[0]);*/
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ void main()
|
||||
assert((s>>1) == -5);
|
||||
assert((s>>>1) != -5);
|
||||
}
|
||||
|
||||
|
||||
{ ushort a = 0xFFF0;
|
||||
ushort b = 0x0FFF;
|
||||
auto t = a;
|
||||
@@ -70,6 +70,6 @@ void main()
|
||||
s.i &= s.l;
|
||||
assert(s.i == 0x00FF_FF00);
|
||||
}
|
||||
|
||||
|
||||
printf(" SUCCESS\n");
|
||||
}
|
||||
|
||||
10
test/bug48.d
Normal file
10
test/bug48.d
Normal file
@@ -0,0 +1,10 @@
|
||||
module bug48;
|
||||
|
||||
size_t func(void *p)
|
||||
{
|
||||
return cast(size_t)*cast(void* *)p;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
}
|
||||
16
test/bug49.d
Normal file
16
test/bug49.d
Normal file
@@ -0,0 +1,16 @@
|
||||
module bug49;
|
||||
|
||||
pragma(LLVM_internal, "notypeinfo")
|
||||
struct S
|
||||
{
|
||||
int i;
|
||||
long l;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
S s;
|
||||
s.i = 0x__FFFF_FF00;
|
||||
s.l = 0xFF00FF_FF00;
|
||||
s.i &= s.l;
|
||||
}
|
||||
28
test/bug50.d
Normal file
28
test/bug50.d
Normal file
@@ -0,0 +1,28 @@
|
||||
module bug50;
|
||||
|
||||
pragma(LLVM_internal, "notypeinfo")
|
||||
struct S
|
||||
{
|
||||
int i;
|
||||
float f;
|
||||
long l;
|
||||
|
||||
void print()
|
||||
{
|
||||
printf("%d %f %lx\n", i, f, l);
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
S s;
|
||||
s.print();
|
||||
s = S(1,2,3);
|
||||
s.print();
|
||||
|
||||
S[] arr;
|
||||
{arr ~= s;}
|
||||
{arr[0].print();}
|
||||
{arr ~= S(1,2,3);}
|
||||
{arr[1].print();}
|
||||
}
|
||||
Reference in New Issue
Block a user